From a9da133c61185a6a7401c8657c9015f197dd5e57 Mon Sep 17 00:00:00 2001 From: Anniek Date: Mon, 2 Nov 2020 10:30:13 +0100 Subject: [PATCH 001/924] Update documentation to include information about support HEIC images. (#3131) --- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ packages/image_picker/image_picker/lib/image_picker.dart | 3 +++ packages/image_picker/image_picker/pubspec.yaml | 2 +- .../image_picker/image_picker_platform_interface/CHANGELOG.md | 4 ++++ .../lib/src/platform_interface/image_picker_platform.dart | 3 +++ .../image_picker/image_picker_platform_interface/pubspec.yaml | 2 +- 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 33ee46894cda..0fb0ce46b4c5 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+13 + +* Update documentation of `getImage()` about HEIC images. + ## 0.6.7+12 * Update android compileSdkVersion to 29. diff --git a/packages/image_picker/image_picker/lib/image_picker.dart b/packages/image_picker/image_picker/lib/image_picker.dart index ff9aa2cbecc3..82c199e007f4 100755 --- a/packages/image_picker/image_picker/lib/image_picker.dart +++ b/packages/image_picker/image_picker/lib/image_picker.dart @@ -76,6 +76,9 @@ class ImagePicker { /// The `source` argument controls where the image comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. /// + /// Where iOS supports HEIC images, Android 8 and below doesn't. Android 9 and above only support HEIC images if used + /// in addition to a size modification, of which the usage is explained below. + /// /// 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. diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index baecbd2d3c38..711d2db1ba0f 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+12 +version: 0.6.7+13 flutter: plugin: diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index e82e62028668..1ed45028f513 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.3 + +* Update documentation of `pickImage()` regarding HEIC images. + ## 1.1.2 * Update documentation of `pickImage()` regarding compression support for specific image types. 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 f33c80bc4995..cbd604187714 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 @@ -120,6 +120,9 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// The `source` argument controls where the image comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. /// + /// Where iOS supports HEIC images, Android 8 and below doesn't. Android 9 and above only support HEIC images if used + /// in addition to a size modification, of which the usage is explained below. + /// /// 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. diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 16300488368b..39a65284e247 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the image_picker plugin. 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.2 +version: 1.1.3 dependencies: flutter: From 8ec679c4ebd0e9a57dd5b0d0d8c534319c25a80d Mon Sep 17 00:00:00 2001 From: Anniek Date: Mon, 2 Nov 2020 10:30:50 +0100 Subject: [PATCH 002/924] Changed the order of the setters for mediaRecorder in MediaRecorderBuilder.java to make it more readable. (#3181) --- packages/camera/CHANGELOG.md | 4 ++++ .../plugins/camera/media/MediaRecorderBuilder.java | 14 +++++++------- .../camera/media/MediaRecorderBuilderTest.java | 4 ++-- packages/camera/pubspec.yaml | 3 +-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/camera/CHANGELOG.md b/packages/camera/CHANGELOG.md index 3aec9b9ce1da..f6ff34d9db9e 100644 --- a/packages/camera/CHANGELOG.md +++ b/packages/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.8+14 + +* Changed the order of the setters for `mediaRecorder` in `MediaRecorderBuilder.java` to make it more readable. + ## 0.5.8+13 * Added Dartdocs for all public APIs. diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java b/packages/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java index 57dc6e633408..b2309c83a4a5 100644 --- a/packages/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java +++ b/packages/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java @@ -49,18 +49,18 @@ public MediaRecorderBuilder setMediaOrientation(int orientation) { public MediaRecorder build() throws IOException { MediaRecorder mediaRecorder = recorderFactory.makeMediaRecorder(); - // There's a specific order that mediaRecorder expects. Do not change the order - // of these function calls. + // There's a fixed order that mediaRecorder expects. Only change these functions accordingly. + // You can find the specifics here: https://developer.android.com/reference/android/media/MediaRecorder. + if (enableAudio) mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); + mediaRecorder.setOutputFormat(recordingProfile.fileFormat); if (enableAudio) { - mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + mediaRecorder.setAudioEncoder(recordingProfile.audioCodec); mediaRecorder.setAudioEncodingBitRate(recordingProfile.audioBitRate); + mediaRecorder.setAudioSamplingRate(recordingProfile.audioSampleRate); } - mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); - mediaRecorder.setOutputFormat(recordingProfile.fileFormat); - if (enableAudio) mediaRecorder.setAudioEncoder(recordingProfile.audioCodec); mediaRecorder.setVideoEncoder(recordingProfile.videoCodec); mediaRecorder.setVideoEncodingBitRate(recordingProfile.videoBitRate); - if (enableAudio) mediaRecorder.setAudioSamplingRate(recordingProfile.audioSampleRate); mediaRecorder.setVideoFrameRate(recordingProfile.videoFrameRate); mediaRecorder.setVideoSize(recordingProfile.videoFrameWidth, recordingProfile.videoFrameHeight); mediaRecorder.setOutputFile(outputFilePath); diff --git a/packages/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java b/packages/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java index f60e85de3903..622b49b660a2 100644 --- a/packages/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java +++ b/packages/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java @@ -69,13 +69,13 @@ public void build_Should_set_values_in_correct_order_When_audio_is_enabled() thr InOrder inOrder = inOrder(recorder); inOrder.verify(recorder).setAudioSource(MediaRecorder.AudioSource.MIC); - inOrder.verify(recorder).setAudioEncodingBitRate(recorderProfile.audioBitRate); inOrder.verify(recorder).setVideoSource(MediaRecorder.VideoSource.SURFACE); inOrder.verify(recorder).setOutputFormat(recorderProfile.fileFormat); inOrder.verify(recorder).setAudioEncoder(recorderProfile.audioCodec); + inOrder.verify(recorder).setAudioEncodingBitRate(recorderProfile.audioBitRate); + inOrder.verify(recorder).setAudioSamplingRate(recorderProfile.audioSampleRate); inOrder.verify(recorder).setVideoEncoder(recorderProfile.videoCodec); inOrder.verify(recorder).setVideoEncodingBitRate(recorderProfile.videoBitRate); - inOrder.verify(recorder).setAudioSamplingRate(recorderProfile.audioSampleRate); inOrder.verify(recorder).setVideoFrameRate(recorderProfile.videoFrameRate); inOrder .verify(recorder) diff --git a/packages/camera/pubspec.yaml b/packages/camera/pubspec.yaml index 5f2debb45584..de7d8b56d035 100644 --- a/packages/camera/pubspec.yaml +++ b/packages/camera/pubspec.yaml @@ -2,8 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.5.8+13 - +version: 0.5.8+14 homepage: https://github.com/flutter/plugins/tree/master/packages/camera dependencies: From 22754b84f5f3297fd3d65ce23fab2d2191550910 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 2 Nov 2020 19:03:03 -0800 Subject: [PATCH 003/924] Remove unused `test` dependencies add missing environment constraints (#3239) --- packages/android_alarm_manager/CHANGELOG.md | 4 + .../example/pubspec.yaml | 4 + packages/android_alarm_manager/pubspec.yaml | 2 +- packages/android_intent/CHANGELOG.md | 4 + packages/android_intent/example/pubspec.yaml | 4 + packages/android_intent/pubspec.yaml | 2 +- packages/battery/battery/CHANGELOG.md | 4 + packages/battery/battery/example/pubspec.yaml | 4 + packages/battery/battery/pubspec.yaml | 2 +- .../connectivity/connectivity/CHANGELOG.md | 5 + .../connectivity/example/pubspec.yaml | 5 +- .../connectivity/connectivity/pubspec.yaml | 3 +- .../connectivity_for_web/CHANGELOG.md | 4 + .../connectivity_for_web/pubspec.yaml | 3 +- .../connectivity_macos/CHANGELOG.md | 5 + .../connectivity_macos/example/pubspec.yaml | 5 +- .../connectivity_macos/pubspec.yaml | 2 +- packages/device_info/device_info/CHANGELOG.md | 4 + .../device_info/example/lib/main.dart | 4 +- .../device_info/example/pubspec.yaml | 4 + packages/device_info/device_info/pubspec.yaml | 2 +- .../google_maps_flutter/CHANGELOG.md | 5 + .../google_maps_flutter/example/pubspec.yaml | 5 +- .../google_maps_flutter/pubspec.yaml | 2 +- packages/local_auth/CHANGELOG.md | 4 + packages/local_auth/example/pubspec.yaml | 4 + packages/local_auth/pubspec.yaml | 2 +- packages/package_info/CHANGELOG.md | 5 + packages/package_info/example/pubspec.yaml | 5 +- packages/package_info/pubspec.yaml | 3 +- .../path_provider/path_provider/CHANGELOG.md | 5 + .../path_provider/example/pubspec.yaml | 5 +- .../path_provider/path_provider/pubspec.yaml | 3 +- .../path_provider_macos/CHANGELOG.md | 5 + .../path_provider_macos/example/pubspec.yaml | 5 +- .../path_provider_macos/pubspec.yaml | 2 +- .../CHANGELOG.md | 4 + .../pubspec.yaml | 3 +- .../path_provider_windows/CHANGELOG.md | 5 + .../example/pubspec.yaml | 5 +- .../path_provider_windows/pubspec.yaml | 2 +- .../shared_preferences/CHANGELOG.md | 4 + .../shared_preferences/example/pubspec.yaml | 1 - .../shared_preferences/pubspec.yaml | 3 +- .../shared_preferences_linux/CHANGELOG.md | 5 + .../example/pubspec.yaml | 4 +- .../shared_preferences_linux/pubspec.yaml | 2 +- .../shared_preferences_macos/CHANGELOG.md | 5 + .../example/pubspec.yaml | 4 +- .../shared_preferences_macos/pubspec.yaml | 3 +- .../shared_preferences_windows/CHANGELOG.md | 4 + .../example/pubspec.yaml | 1 - .../shared_preferences_windows/pubspec.yaml | 2 +- .../url_launcher/url_launcher/CHANGELOG.md | 4 + .../url_launcher/example/pubspec.yaml | 4 + .../url_launcher/url_launcher/pubspec.yaml | 2 +- .../url_launcher_linux/CHANGELOG.md | 4 + .../url_launcher_linux/example/pubspec.yaml | 4 + .../url_launcher_linux/pubspec.yaml | 2 +- .../url_launcher_macos/CHANGELOG.md | 4 + .../url_launcher_macos/example/pubspec.yaml | 4 + .../url_launcher_macos/pubspec.yaml | 2 +- .../url_launcher_windows/CHANGELOG.md | 4 + .../url_launcher_windows/example/pubspec.yaml | 4 + .../url_launcher_windows/pubspec.yaml | 2 +- .../video_player/video_player/CHANGELOG.md | 8 +- .../integration_test/video_player_test.dart | 95 ++++++++++++++----- .../video_player/example/pubspec.yaml | 7 +- .../example/test_driver/video_player.dart | 11 --- .../test_driver/video_player_test.dart | 27 ------ .../video_player/video_player/pubspec.yaml | 2 +- 71 files changed, 274 insertions(+), 109 deletions(-) delete mode 100644 packages/video_player/video_player/example/test_driver/video_player.dart delete mode 100644 packages/video_player/video_player/example/test_driver/video_player_test.dart diff --git a/packages/android_alarm_manager/CHANGELOG.md b/packages/android_alarm_manager/CHANGELOG.md index ab878a6562f4..023a140fbcc9 100644 --- a/packages/android_alarm_manager/CHANGELOG.md +++ b/packages/android_alarm_manager/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.5+17 + +* Update Dart SDK constraint in example. + ## 0.4.5+16 * Remove unnecessary workaround from test. diff --git a/packages/android_alarm_manager/example/pubspec.yaml b/packages/android_alarm_manager/example/pubspec.yaml index 93cbc57d8de5..e636a246376b 100644 --- a/packages/android_alarm_manager/example/pubspec.yaml +++ b/packages/android_alarm_manager/example/pubspec.yaml @@ -21,3 +21,7 @@ dev_dependencies: flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/android_alarm_manager/pubspec.yaml b/packages/android_alarm_manager/pubspec.yaml index 80327326fb8a..9de2d8308419 100644 --- a/packages/android_alarm_manager/pubspec.yaml +++ b/packages/android_alarm_manager/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for accessing the Android AlarmManager service, and # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.5+16 +version: 0.4.5+17 homepage: https://github.com/flutter/plugins/tree/master/packages/android_alarm_manager dependencies: diff --git a/packages/android_intent/CHANGELOG.md b/packages/android_intent/CHANGELOG.md index 5f01fc9298c7..5a3ba03b33eb 100644 --- a/packages/android_intent/CHANGELOG.md +++ b/packages/android_intent/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.7+7 + +* Update Dart SDK constraint in example. + ## 0.3.7+6 * Update android compileSdkVersion to 29. diff --git a/packages/android_intent/example/pubspec.yaml b/packages/android_intent/example/pubspec.yaml index 31d434e8c038..84455d99e618 100644 --- a/packages/android_intent/example/pubspec.yaml +++ b/packages/android_intent/example/pubspec.yaml @@ -17,3 +17,7 @@ dev_dependencies: # The following section is specific to Flutter. flutter: uses-material-design: true + +environment: + sdk: ">=2.3.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/android_intent/pubspec.yaml b/packages/android_intent/pubspec.yaml index fef90e2f7602..8d41d5165c68 100644 --- a/packages/android_intent/pubspec.yaml +++ b/packages/android_intent/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/android_intent # 0.3.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.3.7+6 +version: 0.3.7+7 flutter: plugin: diff --git a/packages/battery/battery/CHANGELOG.md b/packages/battery/battery/CHANGELOG.md index 8a38fde5d937..260f3efeb8ad 100644 --- a/packages/battery/battery/CHANGELOG.md +++ b/packages/battery/battery/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.8 + +* Update Dart SDK constraint in example. + ## 1.0.7 * Update android compileSdkVersion to 29. diff --git a/packages/battery/battery/example/pubspec.yaml b/packages/battery/battery/example/pubspec.yaml index e7a9b1c8b74d..4e7b9ef035eb 100644 --- a/packages/battery/battery/example/pubspec.yaml +++ b/packages/battery/battery/example/pubspec.yaml @@ -16,3 +16,7 @@ dev_dependencies: flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/battery/battery/pubspec.yaml b/packages/battery/battery/pubspec.yaml index d841805c7612..ec747190ac69 100644 --- a/packages/battery/battery/pubspec.yaml +++ b/packages/battery/battery/pubspec.yaml @@ -2,7 +2,7 @@ name: battery description: Flutter plugin for accessing information about the battery state (full, charging, discharging) on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/battery/battery -version: 1.0.7 +version: 1.0.8 flutter: plugin: diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index 8e2802ab5b04..c159f9ed0792 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.1 + +* Remove unused `test` dependency. +* Update Dart SDK constraint in example. + ## 2.0.0 * [Breaking Change] The `getWifiName`, `getWifiBSSID` and `getWifiIP` are removed to [wifi_info_flutter](https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter) diff --git a/packages/connectivity/connectivity/example/pubspec.yaml b/packages/connectivity/connectivity/example/pubspec.yaml index 1d07f7d19e60..bff35483d763 100644 --- a/packages/connectivity/connectivity/example/pubspec.yaml +++ b/packages/connectivity/connectivity/example/pubspec.yaml @@ -10,10 +10,13 @@ dependencies: dev_dependencies: flutter_driver: sdk: flutter - test: any integration_test: path: ../../../integration_test pedantic: ^1.8.0 flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index af26f703d8b9..d856d1069913 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -2,7 +2,7 @@ name: connectivity description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity -version: 2.0.0 +version: 2.0.1 flutter: plugin: @@ -30,7 +30,6 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: any integration_test: path: ../../integration_test mockito: ^4.1.1 diff --git a/packages/connectivity/connectivity_for_web/CHANGELOG.md b/packages/connectivity/connectivity_for_web/CHANGELOG.md index c2bf6326f69e..f6d83dd3e0cc 100644 --- a/packages/connectivity/connectivity_for_web/CHANGELOG.md +++ b/packages/connectivity/connectivity_for_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.1+4 + +* Remove unused `test` dependency. + ## 0.3.1+3 * Fix homepage in `pubspec.yaml`. diff --git a/packages/connectivity/connectivity_for_web/pubspec.yaml b/packages/connectivity/connectivity_for_web/pubspec.yaml index 21fd80b4b56a..3622b15709b6 100644 --- a/packages/connectivity/connectivity_for_web/pubspec.yaml +++ b/packages/connectivity/connectivity_for_web/pubspec.yaml @@ -1,6 +1,6 @@ name: connectivity_for_web description: An implementation for the web platform of the Flutter `connectivity` plugin. This uses the NetworkInformation Web API, with a fallback to Navigator.onLine. -version: 0.3.1+3 +version: 0.3.1+4 repository: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_for_web flutter: @@ -18,7 +18,6 @@ dependencies: sdk: flutter dev_dependencies: - test: any flutter_driver: sdk: flutter flutter_test: diff --git a/packages/connectivity/connectivity_macos/CHANGELOG.md b/packages/connectivity/connectivity_macos/CHANGELOG.md index e997123ecc89..87910374bb8b 100644 --- a/packages/connectivity/connectivity_macos/CHANGELOG.md +++ b/packages/connectivity/connectivity_macos/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.1.0+7 + +* Remove unused `test` dependency. +* Update Dart SDK constraint in example. + ## 0.1.0+6 * Update license headers. diff --git a/packages/connectivity/connectivity_macos/example/pubspec.yaml b/packages/connectivity/connectivity_macos/example/pubspec.yaml index 7faf3e2f67e7..041c3b364370 100644 --- a/packages/connectivity/connectivity_macos/example/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/example/pubspec.yaml @@ -11,10 +11,13 @@ dependencies: dev_dependencies: flutter_driver: sdk: flutter - test: any integration_test: path: ../../../integration_test pedantic: ^1.8.0 flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.10.0 <2.0.0" diff --git a/packages/connectivity/connectivity_macos/pubspec.yaml b/packages/connectivity/connectivity_macos/pubspec.yaml index 99151ff7418d..2ab493072f8c 100644 --- a/packages/connectivity/connectivity_macos/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the connectivity plugin. # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.0+6 +version: 0.1.0+7 homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_macos flutter: diff --git a/packages/device_info/device_info/CHANGELOG.md b/packages/device_info/device_info/CHANGELOG.md index 836d56232f95..b346c2d5db66 100644 --- a/packages/device_info/device_info/CHANGELOG.md +++ b/packages/device_info/device_info/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.2+10 + +* Update Dart SDK constraint in example. + ## 0.4.2+9 * Update android compileSdkVersion to 29. diff --git a/packages/device_info/device_info/example/lib/main.dart b/packages/device_info/device_info/example/lib/main.dart index 1c1064aa09ee..63912b37c3ce 100644 --- a/packages/device_info/device_info/example/lib/main.dart +++ b/packages/device_info/device_info/example/lib/main.dart @@ -12,9 +12,9 @@ import 'package:flutter/services.dart'; import 'package:device_info/device_info.dart'; void main() { - runZoned(() { + runZonedGuarded(() { runApp(MyApp()); - }, onError: (dynamic error, dynamic stack) { + }, (dynamic error, dynamic stack) { print(error); print(stack); }); diff --git a/packages/device_info/device_info/example/pubspec.yaml b/packages/device_info/device_info/example/pubspec.yaml index e22f6026ba69..58d54cba6d70 100644 --- a/packages/device_info/device_info/example/pubspec.yaml +++ b/packages/device_info/device_info/example/pubspec.yaml @@ -16,3 +16,7 @@ dev_dependencies: flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0<3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/device_info/device_info/pubspec.yaml b/packages/device_info/device_info/pubspec.yaml index bf36bf6f34d9..f041e3e6374d 100644 --- a/packages/device_info/device_info/pubspec.yaml +++ b/packages/device_info/device_info/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/device_info # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.2+9 +version: 0.4.2+10 flutter: plugin: diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index a2e0c1bc3df6..4a7026f01ccd 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.0.6 + +* Update Dart SDK constraint in example. +* Remove unused `test` dependency in the example app. + ## 1.0.5 Overhaul lifecycle management in GoogleMapsPlugin. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml index 7bfc7a6feb9c..e0f79b571cb0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml @@ -1,6 +1,10 @@ name: google_maps_flutter_example description: Demonstrates how to use the google_maps_flutter plugin. +environment: + sdk: ">=2.2.0 <3.0.0" + flutter: ">=1.22.0 <2.0.0" + dependencies: flutter: sdk: flutter @@ -15,7 +19,6 @@ dependencies: dev_dependencies: flutter_driver: sdk: flutter - test: ^1.6.0 integration_test: path: ../../../integration_test pedantic: ^1.8.0 diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index dadedb8cce3b..2e4ae9dca5d1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 1.0.5 +version: 1.0.6 dependencies: flutter: diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index 57295ab32012..96388a76ab4f 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.3+4 + +* Update Dart SDK constraint in example. + ## 0.6.3+3 * Update android compileSdkVersion to 29. diff --git a/packages/local_auth/example/pubspec.yaml b/packages/local_auth/example/pubspec.yaml index 8d17a43efb26..0861c51adbc6 100644 --- a/packages/local_auth/example/pubspec.yaml +++ b/packages/local_auth/example/pubspec.yaml @@ -16,3 +16,7 @@ dev_dependencies: flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 9505c774e24d..6ba77aca6679 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth description: Flutter plugin for Android and iOS device authentication sensors such as Fingerprint Reader and Touch ID. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 0.6.3+3 +version: 0.6.3+4 flutter: plugin: diff --git a/packages/package_info/CHANGELOG.md b/packages/package_info/CHANGELOG.md index 535232fbcd97..21319fe4fbf1 100644 --- a/packages/package_info/CHANGELOG.md +++ b/packages/package_info/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.4.3+2 + +* Remove unused `test` dependency. +* Update Dart SDK constraint in example. + ## 0.4.3+1 * Update android compileSdkVersion to 29. diff --git a/packages/package_info/example/pubspec.yaml b/packages/package_info/example/pubspec.yaml index a6dbbce44811..605c375e9a8e 100644 --- a/packages/package_info/example/pubspec.yaml +++ b/packages/package_info/example/pubspec.yaml @@ -12,8 +12,11 @@ dependencies: dev_dependencies: flutter_driver: sdk: flutter - test: any pedantic: ^1.8.0 flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/package_info/pubspec.yaml b/packages/package_info/pubspec.yaml index 16349a619986..cb46ca66b9a4 100644 --- a/packages/package_info/pubspec.yaml +++ b/packages/package_info/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/package_info # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.3+1 +version: 0.4.3+2 flutter: plugin: @@ -27,7 +27,6 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: any integration_test: path: ../integration_test pedantic: ^1.8.0 diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index ceb2a19187b9..646a2e36bc9e 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.6.24 + +* Remove unused `test` dependency. +* Update Dart SDK constraint in example. + ## 1.6.23 * Check in windows/ directory for example/ diff --git a/packages/path_provider/path_provider/example/pubspec.yaml b/packages/path_provider/path_provider/example/pubspec.yaml index 983b3b82eb53..8659da753e15 100644 --- a/packages/path_provider/path_provider/example/pubspec.yaml +++ b/packages/path_provider/path_provider/example/pubspec.yaml @@ -12,8 +12,11 @@ dev_dependencies: path: ../../../integration_test flutter_driver: sdk: flutter - test: any pedantic: ^1.8.0 flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index 3fda0dcf1458..b3960941acff 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 1.6.23 +version: 1.6.24 flutter: plugin: @@ -33,7 +33,6 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: any uuid: "^1.0.0" pedantic: ^1.8.0 mockito: ^4.1.1 diff --git a/packages/path_provider/path_provider_macos/CHANGELOG.md b/packages/path_provider/path_provider_macos/CHANGELOG.md index b2ca95fbd10c..ba2a38e563d6 100644 --- a/packages/path_provider/path_provider_macos/CHANGELOG.md +++ b/packages/path_provider/path_provider_macos/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.0.4+6 + +* Remove unused `test` dependency. +* Update Dart SDK constraint in example. + ## 0.0.4+5 * Update license header. diff --git a/packages/path_provider/path_provider_macos/example/pubspec.yaml b/packages/path_provider/path_provider_macos/example/pubspec.yaml index aaa6842651b5..01ab42bbe71b 100644 --- a/packages/path_provider/path_provider_macos/example/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/example/pubspec.yaml @@ -17,8 +17,11 @@ dev_dependencies: path: ../../../integration_test flutter_driver: sdk: flutter - test: any pedantic: ^1.8.0 flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.10.0 <2.0.0" diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index 970c8c59fe7a..69241491d29d 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the path_provider plugin # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.4+5 +version: 0.0.4+6 homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_macos flutter: diff --git a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md index 23f71c99a678..744764c3215a 100644 --- a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md +++ b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.4 + +* Remove unused `test` dependency. + ## 1.0.3 * Increase upper range of `package:platform` constraint to allow 3.X versions. diff --git a/packages/path_provider/path_provider_platform_interface/pubspec.yaml b/packages/path_provider/path_provider_platform_interface/pubspec.yaml index 9f1293883826..36b539ba1077 100644 --- a/packages/path_provider/path_provider_platform_interface/pubspec.yaml +++ b/packages/path_provider/path_provider_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the path_provider plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_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.0.3 +version: 1.0.4 dependencies: flutter: @@ -16,7 +16,6 @@ dev_dependencies: flutter_test: sdk: flutter pedantic: ^1.8.0 - test: any environment: sdk: ">=2.1.0 <3.0.0" diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index e142c512d298..bdb0ae5b2d9f 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.0.4+3 + +* Remove unused `test` dependency. +* Update Dart SDK constraint in example. + ## 0.0.4+2 * Check in windows/ directory for example/ diff --git a/packages/path_provider/path_provider_windows/example/pubspec.yaml b/packages/path_provider/path_provider_windows/example/pubspec.yaml index 8dbe6e020906..0e723f502581 100644 --- a/packages/path_provider/path_provider_windows/example/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/example/pubspec.yaml @@ -14,8 +14,11 @@ dev_dependencies: e2e: ^0.2.1 flutter_driver: sdk: flutter - test: any pedantic: ^1.8.0 flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.13+hotfix.4 <2.0.0" diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index 8aa1af58a50f..342774680dc4 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_windows -version: 0.0.4+2 +version: 0.0.4+3 flutter: plugin: diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index c4c64fe47e1c..64a74e4ac684 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.12+4 + +* Remove unused `test` dependency. + ## 0.5.12+3 * Check in windows/ directory for example/ diff --git a/packages/shared_preferences/shared_preferences/example/pubspec.yaml b/packages/shared_preferences/shared_preferences/example/pubspec.yaml index 2b970949bee6..cf0fa64fea46 100644 --- a/packages/shared_preferences/shared_preferences/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/example/pubspec.yaml @@ -10,7 +10,6 @@ dependencies: dev_dependencies: flutter_driver: sdk: flutter - test: any integration_test: path: ../../../integration_test pedantic: ^1.8.0 diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 9ddacf986bf8..c09e2c64d7f9 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/shared_prefere # 0.5.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.5.12+3 +version: 0.5.12+4 flutter: plugin: @@ -42,7 +42,6 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: any integration_test: path: ../../integration_test pedantic: ^1.8.0 diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md index e6d98c7ba333..dd67393b07b0 100644 --- a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.0.2+4 + +* Remove unused `test` dependency. +* Update Dart SDK constraint in example. + ## 0.0.2+3 * Check in linux/ directory for example/ diff --git a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml index 5936e3ace02f..fb79444dc6cd 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml @@ -17,7 +17,6 @@ dependency_overrides: dev_dependencies: flutter_driver: sdk: flutter - test: any integration_test: path: ../../../integration_test pedantic: ^1.8.0 @@ -25,3 +24,6 @@ dev_dependencies: flutter: uses-material-design: true +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.8 <2.0.0" diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml index 791515e669ad..380cee9efb1c 100644 --- a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: shared_preferences_linux description: Linux implementation of the shared_preferences plugin -version: 0.0.2+3 +version: 0.0.2+4 homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux flutter: diff --git a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md index ae79f0169326..177f1f2e02e2 100644 --- a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.0.1+11 + +* Remove unused `test` dependency. +* Update Dart SDK constraint in example. + ## 0.0.1+10 * Remove iOS and Android folders from the example app. diff --git a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml index de4b6ed9d379..93d5d42597cd 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml @@ -11,7 +11,6 @@ dependencies: dev_dependencies: flutter_driver: sdk: flutter - test: any integration_test: path: ../../../integration_test pedantic: ^1.8.0 @@ -19,3 +18,6 @@ dev_dependencies: flutter: uses-material-design: true +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.8 <2.0.0" diff --git a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml index 5657b9e3200a..b161327e3f3d 100644 --- a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the shared_preferences plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.1+10 +version: 0.0.1+11 homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_macos flutter: @@ -22,4 +22,3 @@ dependencies: sdk: flutter dev_dependencies: pedantic: ^1.8.0 - diff --git a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md index 026095c544cb..8604db297ca6 100644 --- a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.1+3 + +* Remove unused `test` dependency. + ## 0.0.1+2 * Check in windows/ directory for example/ diff --git a/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml index 6dd7841ea477..8a44e7874cfb 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml @@ -16,7 +16,6 @@ dependency_overrides: dev_dependencies: flutter_driver: sdk: flutter - test: any e2e: ^0.2.0 pedantic: ^1.8.0 diff --git a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml index b106f87ae014..0de70737bc19 100644 --- a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: shared_preferences_windows description: Windows implementation of shared_preferences homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_windows -version: 0.0.1+2 +version: 0.0.1+3 flutter: plugin: diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 34b9dbf7913a..832c0c62f553 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.7.10 + +* Update Dart SDK constraint in example. + ## 5.7.9 * Check in windows/ directory for example/ diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml index b48445c3a7e9..94df1a4b4959 100644 --- a/packages/url_launcher/url_launcher/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher/example/pubspec.yaml @@ -18,3 +18,7 @@ dev_dependencies: flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 9299086a9046..7fa97388ef91 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 5.7.9 +version: 5.7.10 flutter: plugin: diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md index c6a00423e16a..e0a01ec629f5 100644 --- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.1+4 + +* Update Dart SDK constraint in example. + ## 0.0.1+3 * Add a missing include. diff --git a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml index c9d0c32f5cb6..9604637c336c 100644 --- a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml @@ -17,3 +17,7 @@ dev_dependencies: flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.8 <2.0.0" diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml index c4f6f8c70a73..16448e4020e5 100644 --- a/packages/url_launcher/url_launcher_linux/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: url_launcher_linux description: Linux implementation of the url_launcher plugin. -version: 0.0.1+3 +version: 0.0.1+4 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux flutter: diff --git a/packages/url_launcher/url_launcher_macos/CHANGELOG.md b/packages/url_launcher/url_launcher_macos/CHANGELOG.md index d52bf8c249e6..190aa2887353 100644 --- a/packages/url_launcher/url_launcher_macos/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.0.1+9 + +* Update Dart SDK constraint in example. + # 0.0.1+8 * Remove no-op android folder in the example app. diff --git a/packages/url_launcher/url_launcher_macos/example/pubspec.yaml b/packages/url_launcher/url_launcher_macos/example/pubspec.yaml index 0fab67e8af1b..dbf8951ff408 100644 --- a/packages/url_launcher/url_launcher_macos/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/example/pubspec.yaml @@ -17,3 +17,7 @@ dev_dependencies: flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.8 <2.0.0" diff --git a/packages/url_launcher/url_launcher_macos/pubspec.yaml b/packages/url_launcher/url_launcher_macos/pubspec.yaml index 4775f23fe36a..1a77bc7aeab3 100644 --- a/packages/url_launcher/url_launcher_macos/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the url_launcher plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.1+8 +version: 0.0.1+9 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos flutter: diff --git a/packages/url_launcher/url_launcher_windows/CHANGELOG.md b/packages/url_launcher/url_launcher_windows/CHANGELOG.md index 5dd437efc064..3bf040f964e6 100644 --- a/packages/url_launcher/url_launcher_windows/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.1+3 + +* Update Dart SDK constraint in example. + ## 0.0.1+2 * Check in windows/ directory for example/ diff --git a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml index 8d6c22057bc2..44a5424168c9 100644 --- a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml @@ -17,3 +17,7 @@ dev_dependencies: flutter: uses-material-design: true + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.8 <2.0.0" diff --git a/packages/url_launcher/url_launcher_windows/pubspec.yaml b/packages/url_launcher/url_launcher_windows/pubspec.yaml index 34e410c50313..dd7423d017f8 100644 --- a/packages/url_launcher/url_launcher_windows/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/pubspec.yaml @@ -3,7 +3,7 @@ description: Windows implementation of the url_launcher plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.1+2 +version: 0.0.1+3 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows flutter: diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index e02bd76aa818..4ccedf17823a 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.11.1+5 + +* Update Dart SDK constraint in example. +* Remove `test` dependency. +* Convert disabled driver test to integration_test. + ## 0.11.1+4 * Add `toString()` to `Caption`. @@ -13,7 +19,7 @@ ## 0.11.1+1 * Fixed uncanceled timers when calling `play` on the controller multiple times before `pause`, which - caused value listeners to be called indefinitely (after `pause`) and more often than needed. + caused value listeners to be called indefinitely (after `pause`) and more often than needed. ## 0.11.1 diff --git a/packages/video_player/video_player/example/integration_test/video_player_test.dart b/packages/video_player/video_player/example/integration_test/video_player_test.dart index 0953c8feb6c0..639cca9b8631 100644 --- a/packages/video_player/video_player/example/integration_test/video_player_test.dart +++ b/packages/video_player/video_player/example/integration_test/video_player_test.dart @@ -2,7 +2,7 @@ // for details. 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/material.dart'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:video_player/video_player.dart'; @@ -29,38 +29,81 @@ void main() { const Duration(seconds: 7, milliseconds: 540)); }); - testWidgets('can be played', (WidgetTester tester) async { - await _controller.initialize(); + testWidgets( + 'can be played', + (WidgetTester tester) async { + await _controller.initialize(); - await _controller.play(); - await tester.pumpAndSettle(_playDuration); + await _controller.play(); + await tester.pumpAndSettle(_playDuration); - expect(_controller.value.isPlaying, true); - expect(_controller.value.position, - (Duration position) => position > const Duration(seconds: 0)); - }, skip: Platform.isIOS); + expect(_controller.value.isPlaying, true); + expect(_controller.value.position, + (Duration position) => position > const Duration(seconds: 0)); + }, + ); - testWidgets('can seek', (WidgetTester tester) async { - await _controller.initialize(); + testWidgets( + 'can seek', + (WidgetTester tester) async { + await _controller.initialize(); - await _controller.seekTo(const Duration(seconds: 3)); + await _controller.seekTo(const Duration(seconds: 3)); - expect(_controller.value.position, const Duration(seconds: 3)); - }, skip: Platform.isIOS); + expect(_controller.value.position, const Duration(seconds: 3)); + }, + ); - testWidgets('can be paused', (WidgetTester tester) async { - await _controller.initialize(); + testWidgets( + 'can be paused', + (WidgetTester tester) async { + await _controller.initialize(); - // Play for a second, then pause, and then wait a second. - await _controller.play(); - await tester.pumpAndSettle(_playDuration); - await _controller.pause(); - final Duration pausedPosition = _controller.value.position; - await tester.pumpAndSettle(_playDuration); + // Play for a second, then pause, and then wait a second. + await _controller.play(); + await tester.pumpAndSettle(_playDuration); + await _controller.pause(); + final Duration pausedPosition = _controller.value.position; + await tester.pumpAndSettle(_playDuration); - // Verify that we stopped playing after the pause. - expect(_controller.value.isPlaying, false); - expect(_controller.value.position, pausedPosition); - }, skip: Platform.isIOS); + // Verify that we stopped playing after the pause. + expect(_controller.value.isPlaying, false); + expect(_controller.value.position, pausedPosition); + }, + ); + + testWidgets('test video player view with local asset', + (WidgetTester tester) async { + Future started() async { + await _controller.initialize(); + await _controller.play(); + return true; + } + + await tester.pumpWidget(Material( + elevation: 0, + child: Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: FutureBuilder( + future: started(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.data == true) { + return AspectRatio( + aspectRatio: _controller.value.aspectRatio, + child: VideoPlayer(_controller), + ); + } else { + return const Text('waiting for video to load'); + } + }, + ), + ), + ), + )); + + await tester.pumpAndSettle(); + expect(_controller.value.isPlaying, true); + }); }); } diff --git a/packages/video_player/video_player/example/pubspec.yaml b/packages/video_player/video_player/example/pubspec.yaml index e0afa4193dc2..dd8fd8d06bd8 100644 --- a/packages/video_player/video_player/example/pubspec.yaml +++ b/packages/video_player/video_player/example/pubspec.yaml @@ -1,5 +1,7 @@ name: video_player_example description: Demonstrates how to use the video_player plugin. +version: 0.0.1 +publish_to: none dependencies: flutter: @@ -14,7 +16,6 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - test: any pedantic: ^1.8.0 flutter: @@ -23,3 +24,7 @@ flutter: - assets/flutter-mark-square-64.png - assets/Butterfly-209.mp4 - assets/bumble_bee_captions.srt + +environment: + sdk: ">=2.8.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/video_player/video_player/example/test_driver/video_player.dart b/packages/video_player/video_player/example/test_driver/video_player.dart deleted file mode 100644 index cc498f41fccb..000000000000 --- a/packages/video_player/video_player/example/test_driver/video_player.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. 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_driver/driver_extension.dart'; -import 'package:video_player_example/main.dart' as app; - -void main() { - enableFlutterDriverExtension(); - app.main(); -} diff --git a/packages/video_player/video_player/example/test_driver/video_player_test.dart b/packages/video_player/video_player/example/test_driver/video_player_test.dart deleted file mode 100644 index 47f3867d9019..000000000000 --- a/packages/video_player/video_player/example/test_driver/video_player_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. 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:async'; -import 'package:flutter_driver/flutter_driver.dart'; -import 'package:test/test.dart'; - -Future main() async { - final FlutterDriver driver = await FlutterDriver.connect(); - tearDownAll(() async { - await driver.close(); - }); - - //TODO(cyanglaz): Use TabBar tabs to navigate between pages after https://github.com/flutter/flutter/issues/16991 is fixed. - //TODO(cyanglaz): Un-skip the test after https://github.com/flutter/flutter/issues/43012 is fixed - test('Push a page contains video and pop back, do not crash.', () async { - final SerializableFinder pushTab = find.byValueKey('push_tab'); - await driver.waitFor(pushTab); - await driver.tap(pushTab); - await driver.waitForAbsent(pushTab); - await driver.waitFor(find.byValueKey('home_page')); - await driver.waitUntilNoTransientCallbacks(); - final Health health = await driver.checkHealth(); - expect(health.status, HealthStatus.ok); - }, skip: 'Cirrus CI currently hangs while playing videos'); -} diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 8234fee272e3..c12df3fe1194 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for displaying inline video with other Flutter # 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.11.1+4 +version: 0.11.1+5 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: From e014c208909772cee2328a91b7225e667a2681a9 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 2 Nov 2020 20:14:16 -0800 Subject: [PATCH 004/924] [google_sign_in] fix deprecated member use (#3243) --- packages/google_sign_in/google_sign_in/CHANGELOG.md | 4 ++++ packages/google_sign_in/google_sign_in/pubspec.yaml | 2 +- .../google_sign_in/test/google_sign_in_test.dart | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md index 7d3dc2840c0a..7f4bfddfa45a 100644 --- a/packages/google_sign_in/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.5.6 + +* Fix deprecated member warning in tests. + ## 4.5.5 * Update android compileSdkVersion to 29. diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index 26186de065d7..a63091b945b2 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in -version: 4.5.5 +version: 4.5.6 flutter: plugin: diff --git a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart index 3fc3471dcdfb..bc709197d77d 100755 --- a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart @@ -154,9 +154,9 @@ void main() { test('signIn works even if a previous call throws error in other zone', () async { responses['signInSilently'] = Exception('Not a user'); - await runZoned(() async { + await runZonedGuarded(() async { expect(await googleSignIn.signInSilently(), isNull); - }, onError: (dynamic e, dynamic st) {}); + }, (Object e, StackTrace st) {}); expect(await googleSignIn.signIn(), isNotNull); expect( log, From 3d97852622bfcb71d18e4f9d52b42a8cfde5b8c1 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 3 Nov 2020 16:17:46 -0800 Subject: [PATCH 005/924] [video_player][device_info] announce 1.0 (#3221) --- packages/device_info/device_info/CHANGELOG.md | 4 ++++ packages/device_info/device_info/README.md | 7 ------- packages/device_info/device_info/pubspec.yaml | 5 +---- packages/video_player/video_player/CHANGELOG.md | 5 +++++ packages/video_player/video_player/README.md | 7 ------- packages/video_player/video_player/pubspec.yaml | 5 +---- 6 files changed, 11 insertions(+), 22 deletions(-) diff --git a/packages/device_info/device_info/CHANGELOG.md b/packages/device_info/device_info/CHANGELOG.md index b346c2d5db66..06b327f4a198 100644 --- a/packages/device_info/device_info/CHANGELOG.md +++ b/packages/device_info/device_info/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0 + +* Announce 1.0.0. + ## 0.4.2+10 * Update Dart SDK constraint in example. diff --git a/packages/device_info/device_info/README.md b/packages/device_info/device_info/README.md index db846c39690c..128bea5c2a17 100644 --- a/packages/device_info/device_info/README.md +++ b/packages/device_info/device_info/README.md @@ -2,13 +2,6 @@ Get current device information from within the Flutter application. -**Please set your constraint to `device_info: '>=0.4.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.4.y+z`. -Please use `device_info: '>=0.4.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - # Usage Import `package:device_info/device_info.dart`, instantiate `DeviceInfoPlugin` diff --git a/packages/device_info/device_info/pubspec.yaml b/packages/device_info/device_info/pubspec.yaml index f041e3e6374d..5b00750fcbbc 100644 --- a/packages/device_info/device_info/pubspec.yaml +++ b/packages/device_info/device_info/pubspec.yaml @@ -2,10 +2,7 @@ name: device_info description: Flutter plugin providing detailed information about the device (make, model, etc.), and Android or iOS version the app is running on. homepage: https://github.com/flutter/plugins/tree/master/packages/device_info -# 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.2+10 +version: 1.0.0 flutter: plugin: diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 4ccedf17823a..080a6c01e143 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0 + +* Announce 1.0.0. + ## 0.11.1+5 * Update Dart SDK constraint in example. @@ -7,6 +11,7 @@ ## 0.11.1+4 * Add `toString()` to `Caption`. +* Fix a bug on Android when loading videos from assets would crash. ## 0.11.1+3 diff --git a/packages/video_player/video_player/README.md b/packages/video_player/video_player/README.md index 9c0e6b1abb28..5eff770b87a2 100644 --- a/packages/video_player/video_player/README.md +++ b/packages/video_player/video_player/README.md @@ -4,13 +4,6 @@ A Flutter plugin for iOS, Android and Web for playing back video on a Widget surface. -**Please set your constraint to `video_player: '>=0.10.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.10.y+z`. -Please use `video_player: '>=0.10.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ![The example app running in iOS](https://github.com/flutter/plugins/blob/master/packages/video_player/video_player/doc/demo_ipod.gif?raw=true) *Note*: This plugin is still under development, and some APIs might not be available yet. diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index c12df3fe1194..72fbedc7ecf6 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,10 +1,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -# 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.11.1+5 +version: 1.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: From 6fe38b6914a16b11538cb8f527d96a946d597318 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 3 Nov 2020 17:12:16 -0800 Subject: [PATCH 006/924] Update contribution guide for xcuitests (#3237) --- CONTRIBUTING.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f58dfea6a065..b278b43e524f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,6 +40,28 @@ USB and debugging enabled on that device. * `cd packages/battery/example` * `flutter run` +## Setting up XCUITests + +Sometimes, XCUITests are useful when integration testing a plugin that has native UI on iOS (e.g image_picker, in_app_purchase, camera, share, local_auth etc). Most of the time, XCUITests are not necessary, consider using [integration_test](https://pub.dev/packages/integration_test) if the tests are not focused on iOS system UI. + +If XCUITests has always been set up for the plugin, a RunnerUITests folder under `/example/ios` directory can be found. +If XCUITests has not been set up for the plugin, follow these steps to set it up: + +1. Open /example/ios/Runner.xcworkspace using XCode. +1. Create a new "UI Testing Bundle". +1. In the target options window, populate details as following, then click on "Finish". + * In the "product name" field, type in "RunnerUITests" (this is the test target name our CI looks for.). + * In the "Team" field, select "None". + * In the Organization Name field, type in "Flutter". This should usually be pre-populated. + * In the organization identifer field, type in "com.google". This should usually be pre-populated. + * In the Language field, select "Objective-C". + * In the Project field, select the xcodeproj "Runner" (blue color). + * In the Target to be Tested, select xcworkspace "Runner" (white color). +1. A RunnerUITests folder should be created and you can start hacking in `RunnerUITests.m`. +1. To enable the test on CI, the plugin needs to be removed from the "skip" list: + * Open `./cirrus.yml` and find PLUGINS_TO_SKIP_XCTESTS. + * Remove the plugin name from the list. + ## Running the tests ### Integration tests @@ -84,6 +106,26 @@ cd android ./gradlew test ``` +### XCTests (iOS) + +XCUnitTests are typically configured to run with cocoapods in this repo. To run all the XCUnitTests for a plugin: + +```console +cd ios +pod lib lint --allow-warnings +``` + +XCUITests aren't usually configured with cocoapods in this repo. They are configured in a xcode workspace target named RunnerUITests. +To run all the XCUITests in a plugin, follow the steps in a regular iOS development workflow [here](https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/testing_with_xcode/chapters/05-running_tests.html) + +For convenience, a [flutter_plugin_tools](https://pub.dev/packages/flutter_plugin_tools) command `xctest` could also be used to run all the XCUITests in the repo: + +```console +pub global activate flutter_plugin_tools +cd /packages +pub global run flutter_plugin_tools xctest --target RunnerUITests --skip +``` + ## Contributing code We gladly accept contributions via GitHub pull requests. From c7062dc74a92175fb4f806e2ee443a54794257a2 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 4 Nov 2020 10:39:36 -0800 Subject: [PATCH 007/924] [webview_flutter] iOS: Make `webViewWebContentProcessDidTerminate` invoke `onWebResourceError` (#3212) --- packages/webview_flutter/CHANGELOG.md | 4 ++ .../ios/Runner.xcodeproj/project.pbxproj | 7 ++++ .../ios/Classes/FLTWKNavigationDelegate.m | 9 ++++ .../ios/Tests/FLTWKNavigationDelegateTests.m | 41 +++++++++++++++++++ packages/webview_flutter/pubspec.yaml | 2 +- 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 29c3cd8dc6b3..4aa559ea4feb 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.6 + +* Invoke the WebView.onWebResourceError on iOS when the webview content process crashes. + ## 1.0.5 * Fix example in the readme. diff --git a/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj index ef6bc3e620ce..33e9d9745bba 100644 --- a/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 686B4BF92548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 686B4BF82548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m */; }; 68BDCAF623C3F97800D9C032 /* FLTWebViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68BDCAF523C3F97800D9C032 /* FLTWebViewTests.m */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; @@ -46,6 +47,7 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 686B4BF82548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLTWKNavigationDelegateTests.m; path = ../../../ios/Tests/FLTWKNavigationDelegateTests.m; sourceTree = ""; }; 68BDCAE923C3F7CB00D9C032 /* webview_flutter_exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = webview_flutter_exampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68BDCAED23C3F7CB00D9C032 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 68BDCAF523C3F97800D9C032 /* FLTWebViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLTWebViewTests.m; path = ../../../ios/Tests/FLTWebViewTests.m; sourceTree = ""; }; @@ -86,6 +88,7 @@ 68BDCAEA23C3F7CB00D9C032 /* webview_flutter_exampleTests */ = { isa = PBXGroup; children = ( + 686B4BF82548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m */, 68BDCAF523C3F97800D9C032 /* FLTWebViewTests.m */, 68BDCAED23C3F7CB00D9C032 /* Info.plist */, ); @@ -218,6 +221,9 @@ LastUpgradeCheck = 1030; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { + 68BDCAE823C3F7CB00D9C032 = { + ProvisioningStyle = Automatic; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; }; @@ -336,6 +342,7 @@ buildActionMask = 2147483647; files = ( 68BDCAF623C3F97800D9C032 /* FLTWebViewTests.m in Sources */, + 686B4BF92548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m index dd9608d57ac0..7eb08daea40e 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m +++ b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m @@ -104,4 +104,13 @@ - (void)webView:(WKWebView *)webView withError:(NSError *)error { [self onWebResourceError:error]; } + +- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView { + NSError *contentProcessTerminatedError = + [[NSError alloc] initWithDomain:WKErrorDomain + code:WKErrorWebContentProcessTerminated + userInfo:nil]; + [self onWebResourceError:contentProcessTerminatedError]; +} + @end diff --git a/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m b/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m new file mode 100644 index 000000000000..b22f9aa9d642 --- /dev/null +++ b/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m @@ -0,0 +1,41 @@ +// Copyright 2019 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 Flutter; +@import XCTest; +@import webview_flutter; + +// OCMock library doesn't generate a valid modulemap. +#import + +@interface FLTWKNavigationDelegateTests : XCTestCase + +@property(strong, nonatomic) FlutterMethodChannel *mockMethodChannel; +@property(strong, nonatomic) FLTWKNavigationDelegate *navigationDelegate; + +@end + +@implementation FLTWKNavigationDelegateTests + +- (void)setUp { + self.mockMethodChannel = OCMClassMock(FlutterMethodChannel.class); + self.navigationDelegate = + [[FLTWKNavigationDelegate alloc] initWithChannel:self.mockMethodChannel]; +} + +- (void)testWebViewWebContentProcessDidTerminateCallsRecourseErrorChannel { + if (@available(iOS 9.0, *)) { + // `webViewWebContentProcessDidTerminate` is only available on iOS 9.0 and above. + WKWebView *webview = OCMClassMock(WKWebView.class); + [self.navigationDelegate webViewWebContentProcessDidTerminate:webview]; + OCMVerify([self.mockMethodChannel + invokeMethod:@"onWebResourceError" + arguments:[OCMArg checkWithBlock:^BOOL(NSDictionary *args) { + XCTAssertEqualObjects(args[@"errorType"], @"webContentProcessTerminated"); + return true; + }]]); + } +} + +@end diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 504e2ce97247..27190da60c57 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 1.0.5 +version: 1.0.6 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: From 27f5cbafa4fb8667233903916795be3ed7871ca4 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Wed, 4 Nov 2020 15:12:01 -0800 Subject: [PATCH 008/924] [multiple] Remove custom analysis_options.yaml from web plugins. (#3238) Substitute `undefined_prefixed_name: ignore` custom analyzer setting by a `dart:ui` shim with conditional exports for the following plugins: * video_player_web * google_maps_flutter_web * url_launcher_web Remove these plugins from the CUSTOM_ANALYSIS_PLUGINS list in `script/incremental_build.sh` --- .../google_maps_flutter_web/CHANGELOG.md | 4 +++ .../analysis_options.yaml | 10 ------- .../lib/google_maps_flutter_web.dart | 2 +- .../lib/src/shims/dart_ui.dart | 10 +++++++ .../lib/src/shims/dart_ui_fake.dart | 28 +++++++++++++++++++ .../lib/src/shims/dart_ui_real.dart | 5 ++++ .../google_maps_flutter_web/pubspec.yaml | 2 +- .../url_launcher_web/CHANGELOG.md | 4 +++ .../url_launcher_web/analysis_options.yaml | 10 ------- .../lib/src/shims/dart_ui.dart | 10 +++++++ .../lib/src/shims/dart_ui_fake.dart | 28 +++++++++++++++++++ .../lib/src/shims/dart_ui_real.dart | 5 ++++ .../lib/url_launcher_web.dart | 3 +- .../url_launcher_web/pubspec.yaml | 2 +- .../video_player_web/CHANGELOG.md | 4 +++ .../video_player_web/analysis_options.yaml | 10 ------- .../lib/src/shims/dart_ui.dart | 10 +++++++ .../lib/src/shims/dart_ui_fake.dart | 28 +++++++++++++++++++ .../lib/src/shims/dart_ui_real.dart | 5 ++++ .../lib/video_player_web.dart | 5 +--- .../video_player_web/pubspec.yaml | 2 +- script/incremental_build.sh | 3 -- 22 files changed, 147 insertions(+), 43 deletions(-) delete mode 100644 packages/google_maps_flutter/google_maps_flutter_web/analysis_options.yaml create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart delete mode 100644 packages/url_launcher/url_launcher_web/analysis_options.yaml create mode 100644 packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart create mode 100644 packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart create mode 100644 packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart delete mode 100644 packages/video_player/video_player_web/analysis_options.yaml create mode 100644 packages/video_player/video_player_web/lib/src/shims/dart_ui.dart create mode 100644 packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart create mode 100644 packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 9307affdf945..07700151a2d1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0+7 + +* Substitute `undefined_prefixed_name: ignore` analyzer setting by a `dart:ui` shim with conditional exports. [Issue](https://github.com/flutter/flutter/issues/69309). + ## 0.1.0+6 * Ensure a single `InfoWindow` is shown at a time. [Issue](https://github.com/flutter/flutter/issues/67380). diff --git a/packages/google_maps_flutter/google_maps_flutter_web/analysis_options.yaml b/packages/google_maps_flutter/google_maps_flutter_web/analysis_options.yaml deleted file mode 100644 index 443b16551ec9..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_web/analysis_options.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# This is a temporary file to allow us to unblock the flutter/plugins repo CI. -# It disables some of lints that were disabled inline. Disabling lints inline -# is no longer possible, so this file is required. -# TODO(ditman) https://github.com/flutter/flutter/issues/55000 (clean this up) - -include: ../../../analysis_options.yaml - -analyzer: - errors: - undefined_prefixed_name: ignore diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart index cf133fb9e533..2ce3923c7ea9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart @@ -6,7 +6,7 @@ library google_maps_flutter_web; import 'dart:async'; import 'dart:html'; -import 'dart:ui' as ui; +import 'src/shims/dart_ui.dart' as ui; // Conditionally imports dart:ui in web import 'dart:convert'; import 'package:flutter/rendering.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart new file mode 100644 index 000000000000..27d39b528e51 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart @@ -0,0 +1,10 @@ +// 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. + +/// This file shims dart:ui in web-only scenarios, getting rid of the need to +/// suppress analyzer warnings. + +// TODO(flutter/flutter#55000) Remove this file once web-only dart:ui APIs +// are exposed from a dedicated place. +export 'dart_ui_fake.dart' if (dart.library.html) 'dart_ui_real.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart new file mode 100644 index 000000000000..7f8c2b2c0796 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart @@ -0,0 +1,28 @@ +// 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:html' as html; + +// Fake interface for the logic that this package needs from (web-only) dart:ui. +// This is conditionally exported so the analyzer sees these methods as available. + +/// Shim for web_ui engine.PlatformViewRegistry +/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/ui.dart#L62 +class platformViewRegistry { + /// Shim for registerViewFactory + /// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/ui.dart#L72 + static registerViewFactory( + String viewTypeId, html.Element Function(int viewId) viewFactory) {} +} + +/// Shim for web_ui engine.AssetManager. +/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/assets.dart#L12 +class webOnlyAssetManager { + /// Shim for getAssetUrl. + /// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/assets.dart#L45 + static getAssetUrl(String asset) {} +} + +/// Signature of callbacks that have no arguments and return no data. +typedef VoidCallback = void Function(); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart new file mode 100644 index 000000000000..16654a0fa967 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart @@ -0,0 +1,5 @@ +// 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. + +export 'dart:ui'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index 9f88ff16ea4c..bbbfcfa79472 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.1.0+6 +version: 0.1.0+7 flutter: plugin: diff --git a/packages/url_launcher/url_launcher_web/CHANGELOG.md b/packages/url_launcher/url_launcher_web/CHANGELOG.md index e7abd1301c88..093029104f8f 100644 --- a/packages/url_launcher/url_launcher_web/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.1.5+1 + +- Substitute `undefined_prefixed_name: ignore` analyzer setting by a `dart:ui` shim with conditional exports. [Issue](https://github.com/flutter/flutter/issues/69309). + # 0.1.5 - Added the web implementation of the Link widget. diff --git a/packages/url_launcher/url_launcher_web/analysis_options.yaml b/packages/url_launcher/url_launcher_web/analysis_options.yaml deleted file mode 100644 index 443b16551ec9..000000000000 --- a/packages/url_launcher/url_launcher_web/analysis_options.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# This is a temporary file to allow us to unblock the flutter/plugins repo CI. -# It disables some of lints that were disabled inline. Disabling lints inline -# is no longer possible, so this file is required. -# TODO(ditman) https://github.com/flutter/flutter/issues/55000 (clean this up) - -include: ../../../analysis_options.yaml - -analyzer: - errors: - undefined_prefixed_name: ignore diff --git a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart new file mode 100644 index 000000000000..27d39b528e51 --- /dev/null +++ b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart @@ -0,0 +1,10 @@ +// 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. + +/// This file shims dart:ui in web-only scenarios, getting rid of the need to +/// suppress analyzer warnings. + +// TODO(flutter/flutter#55000) Remove this file once web-only dart:ui APIs +// are exposed from a dedicated place. +export 'dart_ui_fake.dart' if (dart.library.html) 'dart_ui_real.dart'; diff --git a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart new file mode 100644 index 000000000000..7f8c2b2c0796 --- /dev/null +++ b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart @@ -0,0 +1,28 @@ +// 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:html' as html; + +// Fake interface for the logic that this package needs from (web-only) dart:ui. +// This is conditionally exported so the analyzer sees these methods as available. + +/// Shim for web_ui engine.PlatformViewRegistry +/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/ui.dart#L62 +class platformViewRegistry { + /// Shim for registerViewFactory + /// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/ui.dart#L72 + static registerViewFactory( + String viewTypeId, html.Element Function(int viewId) viewFactory) {} +} + +/// Shim for web_ui engine.AssetManager. +/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/assets.dart#L12 +class webOnlyAssetManager { + /// Shim for getAssetUrl. + /// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/assets.dart#L45 + static getAssetUrl(String asset) {} +} + +/// Signature of callbacks that have no arguments and return no data. +typedef VoidCallback = void Function(); diff --git a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart new file mode 100644 index 000000000000..16654a0fa967 --- /dev/null +++ b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart @@ -0,0 +1,5 @@ +// 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. + +export 'dart:ui'; diff --git a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart index e7367b3a2f6d..969cfbaa2dfd 100644 --- a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart +++ b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart @@ -4,8 +4,7 @@ import 'dart:async'; import 'dart:html' as html; -// ignore: undefined_shown_name -import 'dart:ui' as ui show platformViewRegistry; +import 'src/shims/dart_ui.dart' as ui; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:meta/meta.dart'; diff --git a/packages/url_launcher/url_launcher_web/pubspec.yaml b/packages/url_launcher/url_launcher_web/pubspec.yaml index 7ae84cdfb07e..b40a8ea236cc 100644 --- a/packages/url_launcher/url_launcher_web/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/u # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.5 +version: 0.1.5+1 flutter: plugin: diff --git a/packages/video_player/video_player_web/CHANGELOG.md b/packages/video_player/video_player_web/CHANGELOG.md index d18504913d89..d8bebd3ae4b6 100644 --- a/packages/video_player/video_player_web/CHANGELOG.md +++ b/packages/video_player/video_player_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.4+1 + +* Substitute `undefined_prefixed_name: ignore` analyzer setting by a `dart:ui` shim with conditional exports. [Issue](https://github.com/flutter/flutter/issues/69309). + ## 0.1.4 * Added option to set the video playback speed on the video controller. diff --git a/packages/video_player/video_player_web/analysis_options.yaml b/packages/video_player/video_player_web/analysis_options.yaml deleted file mode 100644 index 443b16551ec9..000000000000 --- a/packages/video_player/video_player_web/analysis_options.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# This is a temporary file to allow us to unblock the flutter/plugins repo CI. -# It disables some of lints that were disabled inline. Disabling lints inline -# is no longer possible, so this file is required. -# TODO(ditman) https://github.com/flutter/flutter/issues/55000 (clean this up) - -include: ../../../analysis_options.yaml - -analyzer: - errors: - undefined_prefixed_name: ignore diff --git a/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart b/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart new file mode 100644 index 000000000000..27d39b528e51 --- /dev/null +++ b/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart @@ -0,0 +1,10 @@ +// 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. + +/// This file shims dart:ui in web-only scenarios, getting rid of the need to +/// suppress analyzer warnings. + +// TODO(flutter/flutter#55000) Remove this file once web-only dart:ui APIs +// are exposed from a dedicated place. +export 'dart_ui_fake.dart' if (dart.library.html) 'dart_ui_real.dart'; diff --git a/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart b/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart new file mode 100644 index 000000000000..7f8c2b2c0796 --- /dev/null +++ b/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart @@ -0,0 +1,28 @@ +// 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:html' as html; + +// Fake interface for the logic that this package needs from (web-only) dart:ui. +// This is conditionally exported so the analyzer sees these methods as available. + +/// Shim for web_ui engine.PlatformViewRegistry +/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/ui.dart#L62 +class platformViewRegistry { + /// Shim for registerViewFactory + /// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/ui.dart#L72 + static registerViewFactory( + String viewTypeId, html.Element Function(int viewId) viewFactory) {} +} + +/// Shim for web_ui engine.AssetManager. +/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/assets.dart#L12 +class webOnlyAssetManager { + /// Shim for getAssetUrl. + /// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/assets.dart#L45 + static getAssetUrl(String asset) {} +} + +/// Signature of callbacks that have no arguments and return no data. +typedef VoidCallback = void Function(); diff --git a/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart b/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart new file mode 100644 index 000000000000..16654a0fa967 --- /dev/null +++ b/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart @@ -0,0 +1,5 @@ +// 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. + +export 'dart:ui'; diff --git a/packages/video_player/video_player_web/lib/video_player_web.dart b/packages/video_player/video_player_web/lib/video_player_web.dart index 251da3779e7f..6715d5aca53b 100644 --- a/packages/video_player/video_player_web/lib/video_player_web.dart +++ b/packages/video_player/video_player_web/lib/video_player_web.dart @@ -1,6 +1,6 @@ import 'dart:async'; import 'dart:html'; -import 'dart:ui' as ui; +import 'src/shims/dart_ui.dart' as ui; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -78,8 +78,6 @@ class VideoPlayerPlugin extends VideoPlayerPlatform { if (dataSource.package != null && dataSource.package.isNotEmpty) { assetUrl = 'packages/${dataSource.package}/$assetUrl'; } - // 'webOnlyAssetManager' is only in the web version of dart:ui - // ignore: undefined_prefixed_name assetUrl = ui.webOnlyAssetManager.getAssetUrl(assetUrl); uri = assetUrl; break; @@ -170,7 +168,6 @@ class _VideoPlayer { videoElement.setAttribute('playsinline', 'true'); // TODO(hterkelsen): Use initialization parameters once they are available - // ignore: undefined_prefixed_name ui.platformViewRegistry.registerViewFactory( 'videoPlayer-$textureId', (int viewId) => videoElement); diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml index 98191bf6ba85..ae05bfbcf910 100644 --- a/packages/video_player/video_player_web/pubspec.yaml +++ b/packages/video_player/video_player_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/v # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.4 +version: 0.1.4+1 flutter: plugin: diff --git a/script/incremental_build.sh b/script/incremental_build.sh index 550413abff56..f89bc1d0e5c9 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -20,9 +20,6 @@ fi # # TODO(mklim): Remove everything from this list. https://github.com/flutter/flutter/issues/45440 CUSTOM_ANALYSIS_PLUGINS=( - "video_player/video_player_web" - "google_maps_flutter/google_maps_flutter_web" - "url_launcher/url_launcher_web" ) # Comma-separated string of the list above readonly CUSTOM_FLAG=$(IFS=, ; echo "${CUSTOM_ANALYSIS_PLUGINS[*]}") From b597aba597e511afad7ff5f34e981cf15e331232 Mon Sep 17 00:00:00 2001 From: Hamdi Kahloun <32666446+hamdikahloun@users.noreply.github.com> Date: Thu, 5 Nov 2020 18:05:03 +0100 Subject: [PATCH 009/924] [video_player] Android: Dispose video players when app is closed (#3245) --- .../video_player/video_player/CHANGELOG.md | 4 ++ .../videoplayer/VideoPlayerPlugin.java | 3 +- .../example/android/app/build.gradle | 2 + .../FlutterActivityTest.java | 46 +++++++++++++++++++ .../video_player/video_player/pubspec.yaml | 2 +- 5 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 080a6c01e143..90082d8358e3 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.1 + +* Android: Dispose video players when app is closed. + ## 1.0.0 * Announce 1.0.0. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java index b17509d27d27..0c5854f4bc83 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java @@ -6,9 +6,9 @@ import android.content.Context; import android.os.Build; -import android.util.Log; import android.util.LongSparseArray; import io.flutter.FlutterInjector; +import io.flutter.Log; import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.EventChannel; @@ -92,6 +92,7 @@ public void onDetachedFromEngine(FlutterPluginBinding binding) { } flutterState.stopListening(binding.getBinaryMessenger()); flutterState = null; + initialize(); } private void disposeAllPlayers() { diff --git a/packages/video_player/video_player/example/android/app/build.gradle b/packages/video_player/video_player/example/android/app/build.gradle index 13fabc7554e9..fc0673ad1bd8 100644 --- a/packages/video_player/video_player/example/android/app/build.gradle +++ b/packages/video_player/video_player/example/android/app/build.gradle @@ -64,4 +64,6 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + testImplementation 'org.robolectric:robolectric:3.8' + testImplementation 'org.mockito:mockito-core:3.5.13' } diff --git a/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java b/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java new file mode 100644 index 000000000000..0286237cf7ea --- /dev/null +++ b/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java @@ -0,0 +1,46 @@ +package io.flutter.plugins.videoplayerexample; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.embedding.engine.FlutterEngineCache; +import io.flutter.embedding.engine.FlutterJNI; +import io.flutter.embedding.engine.loader.FlutterLoader; +import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.plugins.videoplayer.VideoPlayerPlugin; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class FlutterActivityTest { + + @Test + public void disposeAllPlayers() { + VideoPlayerPlugin videoPlayerPlugin = spy(new VideoPlayerPlugin()); + FlutterLoader flutterLoader = mock(FlutterLoader.class); + FlutterJNI flutterJNI = mock(FlutterJNI.class); + ArgumentCaptor pluginBindingCaptor = + ArgumentCaptor.forClass(FlutterPlugin.FlutterPluginBinding.class); + + when(flutterJNI.isAttached()).thenReturn(true); + FlutterEngine engine = + spy(new FlutterEngine(RuntimeEnvironment.application, flutterLoader, flutterJNI)); + FlutterEngineCache.getInstance().put("my_flutter_engine", engine); + + engine.getPlugins().add(videoPlayerPlugin); + verify(videoPlayerPlugin, times(1)).onAttachedToEngine(pluginBindingCaptor.capture()); + + engine.destroy(); + verify(videoPlayerPlugin, times(1)).onDetachedFromEngine(pluginBindingCaptor.capture()); + verify(videoPlayerPlugin, times(1)).initialize(); + } +} diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 72fbedc7ecf6..69be8b24100b 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -version: 1.0.0 +version: 1.0.1 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: From da36984614e3e1c4e1ec76e80a6f1a2c55e9a4b4 Mon Sep 17 00:00:00 2001 From: Hamdi Kahloun <32666446+hamdikahloun@users.noreply.github.com> Date: Fri, 6 Nov 2020 20:20:02 +0100 Subject: [PATCH 010/924] [connectivity] Fix IllegalArgumentException (#3235) * IllegalArgumentException * IllegalArgumentException * Update ConnectivityBroadcastReceiver.java * Add onConnectivityChanged Test * Format * Format * Test registerDefaultNetworkCallback * Format * Format * null != networkCallback --- .../connectivity/connectivity/CHANGELOG.md | 5 ++ .../connectivity/android/build.gradle | 2 +- .../plugins/connectivity/Connectivity.java | 4 +- .../ConnectivityBroadcastReceiver.java | 39 +++++++------- .../example/android/app/build.gradle | 4 +- .../connectivityexample/ActivityTest.java | 53 +++++++++++++++++++ .../connectivity/example/android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../connectivity/connectivity/pubspec.yaml | 2 +- 9 files changed, 88 insertions(+), 25 deletions(-) create mode 100644 packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index c159f9ed0792..72b6d9b6513a 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.2 + +* Android: Fix IllegalArgumentException. +* Android: Update Example project. + ## 2.0.1 * Remove unused `test` dependency. diff --git a/packages/connectivity/connectivity/android/build.gradle b/packages/connectivity/connectivity/android/build.gradle index e1982a03cf09..30ab4789d312 100644 --- a/packages/connectivity/connectivity/android/build.gradle +++ b/packages/connectivity/connectivity/android/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.5.0' } } diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java index 0a3a6bac0914..a8902fa62ef9 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java @@ -10,10 +10,10 @@ import android.os.Build; /** Reports connectivity related information such as connectivity type and wifi information. */ -class Connectivity { +public class Connectivity { private ConnectivityManager connectivityManager; - Connectivity(ConnectivityManager connectivityManager) { + public Connectivity(ConnectivityManager connectivityManager) { this.connectivityManager = connectivityManager; } diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java index 0c6554c0a5f7..ca3ccff82d2d 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java @@ -13,7 +13,6 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; -import androidx.annotation.RequiresApi; import io.flutter.plugin.common.EventChannel; /** @@ -24,15 +23,16 @@ * io.flutter.plugin.common.EventChannel#setStreamHandler(io.flutter.plugin.common.EventChannel.StreamHandler)} * to set up the receiver. */ -class ConnectivityBroadcastReceiver extends BroadcastReceiver +public class ConnectivityBroadcastReceiver extends BroadcastReceiver implements EventChannel.StreamHandler { private Context context; private Connectivity connectivity; private EventChannel.EventSink events; private Handler mainHandler = new Handler(Looper.getMainLooper()); + private ConnectivityManager.NetworkCallback networkCallback; public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; - ConnectivityBroadcastReceiver(Context context, Connectivity connectivity) { + public ConnectivityBroadcastReceiver(Context context, Connectivity connectivity) { this.context = context; this.connectivity = connectivity; } @@ -41,7 +41,19 @@ class ConnectivityBroadcastReceiver extends BroadcastReceiver public void onListen(Object arguments, EventChannel.EventSink events) { this.events = events; if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - connectivity.getConnectivityManager().registerDefaultNetworkCallback(getNetworkCallback()); + networkCallback = + new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(Network network) { + sendEvent(); + } + + @Override + public void onLost(Network network) { + sendEvent(); + } + }; + connectivity.getConnectivityManager().registerDefaultNetworkCallback(networkCallback); } else { context.registerReceiver(this, new IntentFilter(CONNECTIVITY_ACTION)); } @@ -50,7 +62,9 @@ public void onListen(Object arguments, EventChannel.EventSink events) { @Override public void onCancel(Object arguments) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - connectivity.getConnectivityManager().unregisterNetworkCallback(getNetworkCallback()); + if (networkCallback != null) { + connectivity.getConnectivityManager().unregisterNetworkCallback(networkCallback); + } } else { context.unregisterReceiver(this); } @@ -63,19 +77,8 @@ public void onReceive(Context context, Intent intent) { } } - @RequiresApi(api = Build.VERSION_CODES.N) - ConnectivityManager.NetworkCallback getNetworkCallback() { - return new ConnectivityManager.NetworkCallback() { - @Override - public void onAvailable(Network network) { - sendEvent(); - } - - @Override - public void onLost(Network network) { - sendEvent(); - } - }; + public ConnectivityManager.NetworkCallback getNetworkCallback() { + return networkCallback; } private void sendEvent() { diff --git a/packages/connectivity/connectivity/example/android/app/build.gradle b/packages/connectivity/connectivity/example/android/app/build.gradle index bacbc2f6f4c2..64f3d0626bf4 100644 --- a/packages/connectivity/connectivity/example/android/app/build.gradle +++ b/packages/connectivity/connectivity/example/android/app/build.gradle @@ -34,7 +34,7 @@ android { defaultConfig { applicationId "io.flutter.plugins.connectivityexample" minSdkVersion 16 - targetSdkVersion 28 + targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -55,4 +55,6 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + testImplementation 'org.robolectric:robolectric:3.8' + testImplementation 'org.mockito:mockito-core:3.5.13' } diff --git a/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java b/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java new file mode 100644 index 000000000000..f8f4247a7ef5 --- /dev/null +++ b/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java @@ -0,0 +1,53 @@ +package io.flutter.plugins.connectivityexample; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.spy; + +import android.content.Context; +import android.net.ConnectivityManager; +import io.flutter.plugins.connectivity.Connectivity; +import io.flutter.plugins.connectivity.ConnectivityBroadcastReceiver; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +public class ActivityTest { + private ConnectivityManager connectivityManager; + + @Before + public void setUp() { + connectivityManager = + (ConnectivityManager) + RuntimeEnvironment.application.getSystemService(Context.CONNECTIVITY_SERVICE); + } + + @Test + @Config(sdk = 24, manifest = Config.NONE) + public void networkCallbackNewApi() { + Context context = RuntimeEnvironment.application; + Connectivity connectivity = spy(new Connectivity(connectivityManager)); + ConnectivityBroadcastReceiver broadcastReceiver = + spy(new ConnectivityBroadcastReceiver(context, connectivity)); + + broadcastReceiver.onListen(any(), any()); + assertNotNull(broadcastReceiver.getNetworkCallback()); + } + + @Test + @Config(sdk = 23, manifest = Config.NONE) + public void networkCallbackLowApi() { + Context context = RuntimeEnvironment.application; + Connectivity connectivity = spy(new Connectivity(connectivityManager)); + ConnectivityBroadcastReceiver broadcastReceiver = + spy(new ConnectivityBroadcastReceiver(context, connectivity)); + + broadcastReceiver.onListen(any(), any()); + assertNull(broadcastReceiver.getNetworkCallback()); + } +} diff --git a/packages/connectivity/connectivity/example/android/build.gradle b/packages/connectivity/connectivity/example/android/build.gradle index 541636cc492a..e0d7ae2c11af 100644 --- a/packages/connectivity/connectivity/example/android/build.gradle +++ b/packages/connectivity/connectivity/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.5.0' } } diff --git a/packages/connectivity/connectivity/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/connectivity/connectivity/example/android/gradle/wrapper/gradle-wrapper.properties index 019065d1d650..01a286e96a21 100644 --- a/packages/connectivity/connectivity/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/connectivity/connectivity/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index d856d1069913..91d06373ab83 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -2,7 +2,7 @@ name: connectivity description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity -version: 2.0.1 +version: 2.0.2 flutter: plugin: From 4e8f8ed338bef287405db20683f1c51412204c50 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 9 Nov 2020 13:01:22 -0800 Subject: [PATCH 011/924] [image_picker] Set up XCUITests (#3254) --- .cirrus.yml | 2 +- .../image_picker/image_picker/CHANGELOG.md | 4 + .../ios/Runner.xcodeproj/project.pbxproj | 131 ++++++++++++- .../ImagePickerFromGalleryUITests.m | 174 ++++++++++++++++++ .../example/ios/RunnerUITests/Info.plist | 22 +++ .../image_picker/example/lib/main.dart | 23 ++- .../image_picker/image_picker/pubspec.yaml | 2 +- 7 files changed, 345 insertions(+), 13 deletions(-) create mode 100644 packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m create mode 100644 packages/image_picker/image_picker/example/ios/RunnerUITests/Info.plist diff --git a/.cirrus.yml b/.cirrus.yml index 8c632a076522..685dacae8f17 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -163,7 +163,7 @@ task: - name: build-ipas+drive-examples env: PATH: $PATH:/usr/local/bin - PLUGINS_TO_SKIP_XCTESTS: "battery/battery,camera,connectivity/connectivity,device_info/device_info,espresso,google_maps_flutter/google_maps_flutter,google_sign_in/google_sign_in,image_picker/image_picker,in_app_purchase,integration_test,ios_platform_images,local_auth,package_info,path_provider/path_provider,quick_actions,sensors,shared_preferences/shared_preferences,url_launcher/url_launcher,video_player/video_player,webview_flutter,wifi_info_flutter/wifi_info_flutter" + PLUGINS_TO_SKIP_XCTESTS: "battery/battery,camera,connectivity/connectivity,device_info/device_info,espresso,google_maps_flutter/google_maps_flutter,google_sign_in/google_sign_in,in_app_purchase,integration_test,ios_platform_images,local_auth,package_info,path_provider/path_provider,quick_actions,sensors,shared_preferences/shared_preferences,url_launcher/url_launcher,video_player/video_player,webview_flutter,wifi_info_flutter/wifi_info_flutter" matrix: PLUGIN_SHARDING: "--shardIndex 0 --shardCount 4" PLUGIN_SHARDING: "--shardIndex 1 --shardCount 4" diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 0fb0ce46b4c5..26e8b100cd20 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+14 + +* Set up XCUITests. + ## 0.6.7+13 * Update documentation of `getImage()` about HEIC images. diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj index 106d49cad0c7..be3d55f406bf 100644 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 680049272280D79A006DD6AB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 680049382280F2B9006DD6AB /* pngImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 680049352280F2B8006DD6AB /* pngImage.png */; }; 680049392280F2B9006DD6AB /* jpgImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 680049362280F2B8006DD6AB /* jpgImage.jpg */; }; + 6801C8392555D726009DAF8D /* ImagePickerFromGalleryUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6801C8382555D726009DAF8D /* ImagePickerFromGalleryUITests.m */; }; 68B9AF72243E4B3F00927CE4 /* ImagePickerPluginTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */; }; 68F4B464228B3AB500C25614 /* PhotoAssetUtilTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68F4B463228B3AB500C25614 /* PhotoAssetUtilTests.m */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; @@ -34,6 +35,13 @@ remoteGlobalIDString = 97C146ED1CF9000F007C117D; remoteInfo = Runner; }; + 6801C83B2555D726009DAF8D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -60,6 +68,9 @@ 680049352280F2B8006DD6AB /* pngImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = pngImage.png; sourceTree = ""; }; 680049362280F2B8006DD6AB /* jpgImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = jpgImage.jpg; sourceTree = ""; }; 6801632E632668F4349764C9 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 6801C8362555D726009DAF8D /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 6801C8382555D726009DAF8D /* ImagePickerFromGalleryUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImagePickerFromGalleryUITests.m; sourceTree = ""; }; + 6801C83A2555D726009DAF8D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ImagePickerPluginTests.m; path = ../../../ios/Tests/ImagePickerPluginTests.m; sourceTree = ""; }; 68F4B463228B3AB500C25614 /* PhotoAssetUtilTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = PhotoAssetUtilTests.m; path = ../../../ios/Tests/PhotoAssetUtilTests.m; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -88,6 +99,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 6801C8332555D726009DAF8D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -123,6 +141,15 @@ path = TestImages; sourceTree = ""; }; + 6801C8372555D726009DAF8D /* RunnerUITests */ = { + isa = PBXGroup; + children = ( + 6801C8382555D726009DAF8D /* ImagePickerFromGalleryUITests.m */, + 6801C83A2555D726009DAF8D /* Info.plist */, + ); + path = RunnerUITests; + sourceTree = ""; + }; 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { isa = PBXGroup; children = ( @@ -150,6 +177,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 680049182280D368006DD6AB /* image_picker_exampleTests */, + 6801C8372555D726009DAF8D /* RunnerUITests */, 97C146EF1CF9000F007C117D /* Products */, 840012C8B5EDBCF56B0E4AC1 /* Pods */, CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, @@ -161,6 +189,7 @@ children = ( 97C146EE1CF9000F007C117D /* Runner.app */, 680049172280D368006DD6AB /* image_picker_exampleTests.xctest */, + 6801C8362555D726009DAF8D /* RunnerUITests.xctest */, ); name = Products; sourceTree = ""; @@ -218,6 +247,24 @@ productReference = 680049172280D368006DD6AB /* image_picker_exampleTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 6801C8352555D726009DAF8D /* RunnerUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6801C83F2555D726009DAF8D /* Build configuration list for PBXNativeTarget "RunnerUITests" */; + buildPhases = ( + 6801C8322555D726009DAF8D /* Sources */, + 6801C8332555D726009DAF8D /* Frameworks */, + 6801C8342555D726009DAF8D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 6801C83C2555D726009DAF8D /* PBXTargetDependency */, + ); + name = RunnerUITests; + productName = RunnerUITests; + productReference = 6801C8362555D726009DAF8D /* RunnerUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -255,6 +302,11 @@ ProvisioningStyle = Automatic; TestTargetID = 97C146ED1CF9000F007C117D; }; + 6801C8352555D726009DAF8D = { + CreatedOnToolsVersion = 11.7; + ProvisioningStyle = Automatic; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; SystemCapabilities = { @@ -280,6 +332,7 @@ targets = ( 97C146ED1CF9000F007C117D /* Runner */, 680049162280D368006DD6AB /* image_picker_exampleTests */, + 6801C8352555D726009DAF8D /* RunnerUITests */, ); }; /* End PBXProject section */ @@ -296,6 +349,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 6801C8342555D726009DAF8D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -389,6 +449,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 6801C8322555D726009DAF8D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6801C8392555D726009DAF8D /* ImagePickerFromGalleryUITests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -407,6 +475,11 @@ target = 97C146ED1CF9000F007C117D /* Runner */; targetProxy = 6800491C2280D368006DD6AB /* PBXContainerItemProxy */; }; + 6801C83C2555D726009DAF8D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 6801C83B2555D726009DAF8D /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -480,9 +553,55 @@ }; name = Release; }; + 6801C83D2555D726009DAF8D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = RunnerUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.google.RunnerUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Runner; + }; + name = Debug; + }; + 6801C83E2555D726009DAF8D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = RunnerUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.google.RunnerUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Runner; + }; + name = Release; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -539,7 +658,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -644,6 +762,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 6801C83F2555D726009DAF8D /* Build configuration list for PBXNativeTarget "RunnerUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6801C83D2555D726009DAF8D /* Debug */, + 6801C83E2555D726009DAF8D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m new file mode 100644 index 000000000000..1ba8457c9709 --- /dev/null +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m @@ -0,0 +1,174 @@ +// Copyright 2019 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 +#import + +const int kElementWaitingTime = 30; + +@interface ImagePickerFromGalleryUITests : XCTestCase + +@property(nonatomic, strong) XCUIApplication* app; + +@end + +@implementation ImagePickerFromGalleryUITests + +- (void)setUp { + // Delete the app if already exists, to test permission popups + + self.continueAfterFailure = NO; + self.app = [[XCUIApplication alloc] init]; + [self.app launch]; + [self addUIInterruptionMonitorWithDescription:@"Permission popups" + handler:^BOOL(XCUIElement* _Nonnull interruptingElement) { + XCUIElement* ok = interruptingElement.buttons[@"OK"]; + if (ok.exists) { + [ok tap]; + } + // iOS 14. + XCUIElement* allPhotoPermission = + interruptingElement + .buttons[@"Allow Access to All Photos"]; + if (allPhotoPermission.exists) { + [allPhotoPermission tap]; + } + return YES; + }]; +} + +- (void)testPickingFromGallery { + [self launchPickerAndCancel]; + [self launchPickerAndPick]; +} + +- (void)launchPickerAndCancel { + // Find and tap on the pick from gallery button. + NSPredicate* predicateToFindImageFromGalleryButton = + [NSPredicate predicateWithFormat:@"label == %@", @"image_picker_example_from_gallery"]; + + XCUIElement* imageFromGalleryButton = + [self.app.otherElements elementMatchingPredicate:predicateToFindImageFromGalleryButton]; + if (![imageFromGalleryButton waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find image from gallery button with %@ seconds", + @(kElementWaitingTime)); + } + + XCTAssertTrue(imageFromGalleryButton.exists); + [imageFromGalleryButton tap]; + + // Find and tap on the `pick` button. + NSPredicate* predicateToFindPickButton = + [NSPredicate predicateWithFormat:@"label == %@", @"PICK"]; + + XCUIElement* pickButton = [self.app.buttons elementMatchingPredicate:predicateToFindPickButton]; + if (![pickButton waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find pick button with %@ seconds", @(kElementWaitingTime)); + } + + XCTAssertTrue(pickButton.exists); + [pickButton tap]; + + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + [self.app tap]; + + // Find and tap on the `Cancel` button. + NSPredicate* predicateToFindCancelButton = + [NSPredicate predicateWithFormat:@"label == %@", @"Cancel"]; + + XCUIElement* cancelButton = + [self.app.buttons elementMatchingPredicate:predicateToFindCancelButton]; + if (![cancelButton waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find Cancel button with %@ seconds", + @(kElementWaitingTime)); + } + + XCTAssertTrue(cancelButton.exists); + [cancelButton tap]; + + // Find the "not picked image text". + XCUIElement* imageNotPickedText = [self.app.otherElements + elementMatchingPredicate:[NSPredicate + predicateWithFormat:@"label == %@", + @"You have not yet picked an image."]]; + if (![imageNotPickedText waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find imageNotPickedText with %@ seconds", + @(kElementWaitingTime)); + } + + XCTAssertTrue(imageNotPickedText.exists); +} + +- (void)launchPickerAndPick { + // Find and tap on the pick from gallery button. + NSPredicate* predicateToFindImageFromGalleryButton = + [NSPredicate predicateWithFormat:@"label == %@", @"image_picker_example_from_gallery"]; + + XCUIElement* imageFromGalleryButton = + [self.app.otherElements elementMatchingPredicate:predicateToFindImageFromGalleryButton]; + if (![imageFromGalleryButton waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find image from gallery button with %@ seconds", + @(kElementWaitingTime)); + } + + XCTAssertTrue(imageFromGalleryButton.exists); + [imageFromGalleryButton tap]; + + // Find and tap on the `pick` button. + NSPredicate* predicateToFindPickButton = + [NSPredicate predicateWithFormat:@"label == %@", @"PICK"]; + + XCUIElement* pickButton = [self.app.buttons elementMatchingPredicate:predicateToFindPickButton]; + if (![pickButton waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find pick button with %@ seconds", @(kElementWaitingTime)); + } + + XCTAssertTrue(pickButton.exists); + [pickButton tap]; + + // Find an image and tap on it. (IOS 14 UI, images are showing directly) + XCUIElement* aImage; + if (@available(iOS 14, *)) { + aImage = self.app.scrollViews.firstMatch.images.firstMatch; + } else { + XCUIElement* allPhotosCell = [self.app.cells + elementMatchingPredicate:[NSPredicate predicateWithFormat:@"label == %@", @"All Photos"]]; + if (![allPhotosCell waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find \"All Photos\" cell with %@ seconds", + @(kElementWaitingTime)); + } + [allPhotosCell tap]; + aImage = [self.app.collectionViews elementMatchingType:XCUIElementTypeCollectionView + identifier:@"PhotosGridView"] + .cells.firstMatch; + } + if (![aImage waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find an image with %@ seconds", @(kElementWaitingTime)); + } + XCTAssertTrue(aImage.exists); + [aImage tap]; + + // Find the picked image. + NSPredicate* predicateToFindPickedImage = + [NSPredicate predicateWithFormat:@"label == %@", @"image_picker_example_picked_image"]; + + XCUIElement* pickedImage = [self.app.images elementMatchingPredicate:predicateToFindPickedImage]; + if (![pickedImage waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find pickedImage with %@ seconds", @(kElementWaitingTime)); + } + + XCTAssertTrue(pickedImage.exists); +} + +@end diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/Info.plist b/packages/image_picker/image_picker/example/ios/RunnerUITests/Info.plist new file mode 100644 index 000000000000..64d65ca49577 --- /dev/null +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/packages/image_picker/image_picker/example/lib/main.dart b/packages/image_picker/image_picker/example/lib/main.dart index ece8c45d9c8e..3047ac13f235 100755 --- a/packages/image_picker/image_picker/example/lib/main.dart +++ b/packages/image_picker/image_picker/example/lib/main.dart @@ -156,7 +156,9 @@ class _MyHomePageState extends State { // See https://pub.dev/packages/image_picker#getting-ready-for-the-web-platform return Image.network(_imageFile.path); } else { - return Image.file(File(_imageFile.path)); + return Semantics( + child: Image.file(File(_imageFile.path)), + label: 'image_picker_example_picked_image'); } } else if (_pickImageError != null) { return Text( @@ -231,14 +233,17 @@ class _MyHomePageState extends State { floatingActionButton: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ - FloatingActionButton( - onPressed: () { - isVideo = false; - _onImageButtonPressed(ImageSource.gallery, context: context); - }, - heroTag: 'image0', - tooltip: 'Pick Image from gallery', - child: const Icon(Icons.photo_library), + Semantics( + label: 'image_picker_example_from_gallery', + child: FloatingActionButton( + onPressed: () { + isVideo = false; + _onImageButtonPressed(ImageSource.gallery, context: context); + }, + heroTag: 'image0', + tooltip: 'Pick Image from gallery', + child: const Icon(Icons.photo_library), + ), ), Padding( padding: const EdgeInsets.only(top: 16.0), diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 711d2db1ba0f..2dcd7c137b7d 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+13 +version: 0.6.7+14 flutter: plugin: From d256f56779b292f978f6b4e543fe039cc187a479 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 9 Nov 2020 17:19:38 -0800 Subject: [PATCH 012/924] [webview_flutter] update documentation to indicate gesture handling issues on iOS 13.4 and 13.5 (#3259) --- packages/webview_flutter/CHANGELOG.md | 5 +++++ packages/webview_flutter/lib/webview_flutter.dart | 4 ++++ packages/webview_flutter/pubspec.yaml | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 4aa559ea4feb..8f1e238f6919 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.0.7 + +* Minor documentation update to indicate known issue on iOS 13.4 and 13.5. + * See: https://github.com/flutter/flutter/issues/53490 + ## 1.0.6 * Invoke the WebView.onWebResourceError on iOS when the webview content process crashes. diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 5e2bffd6539d..2fdf639180a7 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -196,6 +196,10 @@ class JavascriptChannel { } /// A web view widget for showing html content. +/// +/// There is a known issue that on iOS 13.4 and 13.5, other flutter widgets covering +/// the `WebView` is not able to block the `WebView` from receiving touch events. +/// See https://github.com/flutter/flutter/issues/53490. class WebView extends StatefulWidget { /// Creates a new web view. /// diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 27190da60c57..e4627a4f9f65 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 1.0.6 +version: 1.0.7 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: From ee1dbfa4fc2ab69941d0337e8e83ce0d4ea0bdf1 Mon Sep 17 00:00:00 2001 From: Sempakonka <47318358+Sempakonka@users.noreply.github.com> Date: Tue, 10 Nov 2020 07:50:28 +0100 Subject: [PATCH 013/924] [Camera] Made CameraController.isDisposed publicly accessible. Added unit Tests for the new implementation. (#3193) * Update feedback from Flutter team * Removed obsolete dependency on mockito * Apply feedback on pull request * Bump version number * Update CHANGELOG description to reflect changes * Fix formatting * Refactor try..catch to returnsNormally * Fix formatting issues Co-authored-by: Maurits van Beusekom --- packages/camera/CHANGELOG.md | 4 +++ packages/camera/lib/camera.dart | 7 +++++ packages/camera/pubspec.yaml | 2 +- packages/camera/test/camera_test.dart | 44 +++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 packages/camera/test/camera_test.dart diff --git a/packages/camera/CHANGELOG.md b/packages/camera/CHANGELOG.md index f6ff34d9db9e..61a420ae9ddb 100644 --- a/packages/camera/CHANGELOG.md +++ b/packages/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.8+15 + +* Added the `debugCheckIsDisposed` method which can be used in debug mode to validate if the `CameraController` class has been disposed. + ## 0.5.8+14 * Changed the order of the setters for `mediaRecorder` in `MediaRecorderBuilder.java` to make it more readable. diff --git a/packages/camera/lib/camera.dart b/packages/camera/lib/camera.dart index 91c6525072e1..3b2cd77c5757 100644 --- a/packages/camera/lib/camera.dart +++ b/packages/camera/lib/camera.dart @@ -307,6 +307,13 @@ class CameraController extends ValueNotifier { StreamSubscription _imageStreamSubscription; Completer _creatingCompleter; + /// Checks whether [CameraController.dispose] has completed successfully. + /// + /// This is a no-op when asserts are disabled. + void debugCheckIsDisposed() { + assert(_isDisposed); + } + /// Initializes the camera on the device. /// /// Throws a [CameraException] if the initialization fails. diff --git a/packages/camera/pubspec.yaml b/packages/camera/pubspec.yaml index de7d8b56d035..eede48d57654 100644 --- a/packages/camera/pubspec.yaml +++ b/packages/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.5.8+14 +version: 0.5.8+15 homepage: https://github.com/flutter/plugins/tree/master/packages/camera dependencies: diff --git a/packages/camera/test/camera_test.dart b/packages/camera/test/camera_test.dart new file mode 100644 index 000000000000..cc33b369f000 --- /dev/null +++ b/packages/camera/test/camera_test.dart @@ -0,0 +1,44 @@ +// 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 'package:camera/camera.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('camera', () { + test('debugCheckIsDisposed should not throw assertion error when disposed', + () { + final MockCameraDescription description = MockCameraDescription(); + final CameraController controller = CameraController( + description, + ResolutionPreset.low, + ); + + controller.dispose(); + + expect(controller.debugCheckIsDisposed, returnsNormally); + }); + + test('debugCheckIsDisposed should throw assertion error when not disposed', + () { + final MockCameraDescription description = MockCameraDescription(); + final CameraController controller = CameraController( + description, + ResolutionPreset.low, + ); + + expect( + () => controller.debugCheckIsDisposed(), + throwsAssertionError, + ); + }); + }); +} + +class MockCameraDescription extends CameraDescription { + @override + CameraLensDirection get lensDirection => CameraLensDirection.back; + + @override + String get name => 'back'; +} From 97d36e755dc282d4ee96820f7d3c032ef4e1b6f6 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 10 Nov 2020 22:56:04 +0100 Subject: [PATCH 014/924] [camera] Move camera to camera/camera (#3258) * Move camera to camera/camera * Fix relative path after move * Rebased with master and update version * Update homepage * Skip XCTESTS for the camera/camera plugin --- .cirrus.yml | 2 +- packages/camera/{ => camera}/CHANGELOG.md | 4 ++++ packages/camera/{ => camera}/LICENSE | 0 packages/camera/{ => camera}/README.md | 0 packages/camera/{ => camera}/android/build.gradle | 0 .../camera/{ => camera}/android/gradle.properties | 0 .../camera/{ => camera}/android/settings.gradle | 0 .../android/src/main/AndroidManifest.xml | 0 .../main/java/io/flutter/plugins/camera/Camera.java | 0 .../flutter/plugins/camera/CameraPermissions.java | 0 .../io/flutter/plugins/camera/CameraPlugin.java | 0 .../java/io/flutter/plugins/camera/CameraUtils.java | 0 .../io/flutter/plugins/camera/DartMessenger.java | 0 .../plugins/camera/MethodCallHandlerImpl.java | 0 .../plugins/camera/media/MediaRecorderBuilder.java | 0 .../plugins/camera/CameraPermissionsTest.java | 0 .../flutter/plugins/camera/DartMessengerTest.java | 0 .../camera/media/MediaRecorderBuilderTest.java | 0 packages/camera/{ => camera}/camera_android.iml | 0 packages/camera/{ => camera}/example/android.iml | 0 .../{ => camera}/example/android/app/build.gradle | 0 .../app/gradle/wrapper/gradle-wrapper.properties | 0 .../cameraexample/EmbeddingV1ActivityTest.java | 0 .../plugins/cameraexample/FlutterActivityTest.java | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../plugins/cameraexample/EmbeddingV1Activity.java | 0 .../app/src/main/res/drawable/launch_background.xml | 0 .../app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../app/src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../app/src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../android/app/src/main/res/values/styles.xml | 0 .../{ => camera}/example/android/build.gradle | 0 .../{ => camera}/example/android/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../{ => camera}/example/android/settings.gradle | 0 .../camera/{ => camera}/example/camera_example.iml | 0 .../{ => camera}/example/camera_example_android.iml | 0 .../example/integration_test/camera_test.dart | 0 .../example/ios/Flutter/AppFrameworkInfo.plist | 0 .../{ => camera}/example/ios/Flutter/Debug.xcconfig | 0 .../example/ios/Flutter/Release.xcconfig | 0 .../example/ios/Runner.xcodeproj/project.pbxproj | 0 .../project.xcworkspace/contents.xcworkspacedata | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../ios/Runner.xcworkspace/contents.xcworkspacedata | 0 .../{ => camera}/example/ios/Runner/AppDelegate.h | 0 .../{ => camera}/example/ios/Runner/AppDelegate.m | 0 .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../AppIcon.appiconset/Icon-App-83.5x83.5@2x.png | Bin .../LaunchImage.imageset/Contents.json | 0 .../LaunchImage.imageset/LaunchImage.png | Bin .../LaunchImage.imageset/LaunchImage@2x.png | Bin .../LaunchImage.imageset/LaunchImage@3x.png | Bin .../Assets.xcassets/LaunchImage.imageset/README.md | 0 .../ios/Runner/Base.lproj/LaunchScreen.storyboard | 0 .../example/ios/Runner/Base.lproj/Main.storyboard | 0 .../{ => camera}/example/ios/Runner/Info.plist | 0 .../camera/{ => camera}/example/ios/Runner/main.m | 0 packages/camera/{ => camera}/example/lib/main.dart | 0 packages/camera/{ => camera}/example/pubspec.yaml | 2 +- .../example/test_driver/integration_test.dart | 0 packages/camera/{ => camera}/ios/Assets/.gitkeep | 0 .../camera/{ => camera}/ios/Classes/CameraPlugin.h | 0 .../camera/{ => camera}/ios/Classes/CameraPlugin.m | 0 .../{ => camera}/ios/Tests/CameraPluginTests.m | 0 packages/camera/{ => camera}/ios/camera.podspec | 0 packages/camera/{ => camera}/lib/camera.dart | 0 packages/camera/{ => camera}/lib/camera_image.dart | 0 packages/camera/{ => camera}/pubspec.yaml | 4 ++-- packages/camera/{ => camera}/test/camera_test.dart | 0 85 files changed, 8 insertions(+), 4 deletions(-) rename packages/camera/{ => camera}/CHANGELOG.md (98%) rename packages/camera/{ => camera}/LICENSE (100%) rename packages/camera/{ => camera}/README.md (100%) rename packages/camera/{ => camera}/android/build.gradle (100%) rename packages/camera/{ => camera}/android/gradle.properties (100%) rename packages/camera/{ => camera}/android/settings.gradle (100%) rename packages/camera/{ => camera}/android/src/main/AndroidManifest.xml (100%) rename packages/camera/{ => camera}/android/src/main/java/io/flutter/plugins/camera/Camera.java (100%) rename packages/camera/{ => camera}/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java (100%) rename packages/camera/{ => camera}/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java (100%) rename packages/camera/{ => camera}/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java (100%) rename packages/camera/{ => camera}/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java (100%) rename packages/camera/{ => camera}/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java (100%) rename packages/camera/{ => camera}/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java (100%) rename packages/camera/{ => camera}/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java (100%) rename packages/camera/{ => camera}/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java (100%) rename packages/camera/{ => camera}/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java (100%) rename packages/camera/{ => camera}/camera_android.iml (100%) rename packages/camera/{ => camera}/example/android.iml (100%) rename packages/camera/{ => camera}/example/android/app/build.gradle (100%) rename packages/camera/{ => camera}/example/android/app/gradle/wrapper/gradle-wrapper.properties (100%) rename packages/camera/{ => camera}/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java (100%) rename packages/camera/{ => camera}/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java (100%) rename packages/camera/{ => camera}/example/android/app/src/main/AndroidManifest.xml (100%) rename packages/camera/{ => camera}/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java (100%) rename packages/camera/{ => camera}/example/android/app/src/main/res/drawable/launch_background.xml (100%) rename packages/camera/{ => camera}/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename packages/camera/{ => camera}/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename packages/camera/{ => camera}/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename packages/camera/{ => camera}/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename packages/camera/{ => camera}/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename packages/camera/{ => camera}/example/android/app/src/main/res/values/styles.xml (100%) rename packages/camera/{ => camera}/example/android/build.gradle (100%) rename packages/camera/{ => camera}/example/android/gradle.properties (100%) rename packages/camera/{ => camera}/example/android/gradle/wrapper/gradle-wrapper.properties (100%) rename packages/camera/{ => camera}/example/android/settings.gradle (100%) rename packages/camera/{ => camera}/example/camera_example.iml (100%) rename packages/camera/{ => camera}/example/camera_example_android.iml (100%) rename packages/camera/{ => camera}/example/integration_test/camera_test.dart (100%) rename packages/camera/{ => camera}/example/ios/Flutter/AppFrameworkInfo.plist (100%) rename packages/camera/{ => camera}/example/ios/Flutter/Debug.xcconfig (100%) rename packages/camera/{ => camera}/example/ios/Flutter/Release.xcconfig (100%) rename packages/camera/{ => camera}/example/ios/Runner.xcodeproj/project.pbxproj (100%) rename packages/camera/{ => camera}/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename packages/camera/{ => camera}/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename packages/camera/{ => camera}/example/ios/Runner.xcworkspace/contents.xcworkspacedata (100%) rename packages/camera/{ => camera}/example/ios/Runner/AppDelegate.h (100%) rename packages/camera/{ => camera}/example/ios/Runner/AppDelegate.m (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%) rename packages/camera/{ => camera}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%) rename packages/camera/{ => camera}/example/ios/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename packages/camera/{ => camera}/example/ios/Runner/Base.lproj/Main.storyboard (100%) rename packages/camera/{ => camera}/example/ios/Runner/Info.plist (100%) rename packages/camera/{ => camera}/example/ios/Runner/main.m (100%) rename packages/camera/{ => camera}/example/lib/main.dart (100%) rename packages/camera/{ => camera}/example/pubspec.yaml (92%) rename packages/camera/{ => camera}/example/test_driver/integration_test.dart (100%) rename packages/camera/{ => camera}/ios/Assets/.gitkeep (100%) rename packages/camera/{ => camera}/ios/Classes/CameraPlugin.h (100%) rename packages/camera/{ => camera}/ios/Classes/CameraPlugin.m (100%) rename packages/camera/{ => camera}/ios/Tests/CameraPluginTests.m (100%) rename packages/camera/{ => camera}/ios/camera.podspec (100%) rename packages/camera/{ => camera}/lib/camera.dart (100%) rename packages/camera/{ => camera}/lib/camera_image.dart (100%) rename packages/camera/{ => camera}/pubspec.yaml (95%) rename packages/camera/{ => camera}/test/camera_test.dart (100%) diff --git a/.cirrus.yml b/.cirrus.yml index 685dacae8f17..98cd6276e0e6 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -163,7 +163,7 @@ task: - name: build-ipas+drive-examples env: PATH: $PATH:/usr/local/bin - PLUGINS_TO_SKIP_XCTESTS: "battery/battery,camera,connectivity/connectivity,device_info/device_info,espresso,google_maps_flutter/google_maps_flutter,google_sign_in/google_sign_in,in_app_purchase,integration_test,ios_platform_images,local_auth,package_info,path_provider/path_provider,quick_actions,sensors,shared_preferences/shared_preferences,url_launcher/url_launcher,video_player/video_player,webview_flutter,wifi_info_flutter/wifi_info_flutter" + PLUGINS_TO_SKIP_XCTESTS: "battery/battery,camera/camera,connectivity/connectivity,device_info/device_info,espresso,google_maps_flutter/google_maps_flutter,google_sign_in/google_sign_in,in_app_purchase,integration_test,ios_platform_images,local_auth,package_info,path_provider/path_provider,quick_actions,sensors,shared_preferences/shared_preferences,url_launcher/url_launcher,video_player/video_player,webview_flutter,wifi_info_flutter/wifi_info_flutter" matrix: PLUGIN_SHARDING: "--shardIndex 0 --shardCount 4" PLUGIN_SHARDING: "--shardIndex 1 --shardCount 4" diff --git a/packages/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md similarity index 98% rename from packages/camera/CHANGELOG.md rename to packages/camera/camera/CHANGELOG.md index 61a420ae9ddb..c9f9dd0f8c58 100644 --- a/packages/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.8+16 + +* Moved package to camera/camera subdir, to allow for federated implementations. + ## 0.5.8+15 * Added the `debugCheckIsDisposed` method which can be used in debug mode to validate if the `CameraController` class has been disposed. diff --git a/packages/camera/LICENSE b/packages/camera/camera/LICENSE similarity index 100% rename from packages/camera/LICENSE rename to packages/camera/camera/LICENSE diff --git a/packages/camera/README.md b/packages/camera/camera/README.md similarity index 100% rename from packages/camera/README.md rename to packages/camera/camera/README.md diff --git a/packages/camera/android/build.gradle b/packages/camera/camera/android/build.gradle similarity index 100% rename from packages/camera/android/build.gradle rename to packages/camera/camera/android/build.gradle diff --git a/packages/camera/android/gradle.properties b/packages/camera/camera/android/gradle.properties similarity index 100% rename from packages/camera/android/gradle.properties rename to packages/camera/camera/android/gradle.properties diff --git a/packages/camera/android/settings.gradle b/packages/camera/camera/android/settings.gradle similarity index 100% rename from packages/camera/android/settings.gradle rename to packages/camera/camera/android/settings.gradle diff --git a/packages/camera/android/src/main/AndroidManifest.xml b/packages/camera/camera/android/src/main/AndroidManifest.xml similarity index 100% rename from packages/camera/android/src/main/AndroidManifest.xml rename to packages/camera/camera/android/src/main/AndroidManifest.xml diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java similarity index 100% rename from packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java rename to packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java similarity index 100% rename from packages/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java rename to packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java similarity index 100% rename from packages/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java rename to packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java similarity index 100% rename from packages/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java rename to packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java similarity index 100% rename from packages/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java rename to packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java similarity index 100% rename from packages/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java rename to packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java similarity index 100% rename from packages/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java rename to packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java diff --git a/packages/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java similarity index 100% rename from packages/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java rename to packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java diff --git a/packages/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java similarity index 100% rename from packages/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java rename to packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java diff --git a/packages/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java similarity index 100% rename from packages/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java rename to packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java diff --git a/packages/camera/camera_android.iml b/packages/camera/camera/camera_android.iml similarity index 100% rename from packages/camera/camera_android.iml rename to packages/camera/camera/camera_android.iml diff --git a/packages/camera/example/android.iml b/packages/camera/camera/example/android.iml similarity index 100% rename from packages/camera/example/android.iml rename to packages/camera/camera/example/android.iml diff --git a/packages/camera/example/android/app/build.gradle b/packages/camera/camera/example/android/app/build.gradle similarity index 100% rename from packages/camera/example/android/app/build.gradle rename to packages/camera/camera/example/android/app/build.gradle diff --git a/packages/camera/example/android/app/gradle/wrapper/gradle-wrapper.properties b/packages/camera/camera/example/android/app/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/camera/example/android/app/gradle/wrapper/gradle-wrapper.properties rename to packages/camera/camera/example/android/app/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java b/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java similarity index 100% rename from packages/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java rename to packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java diff --git a/packages/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java b/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java similarity index 100% rename from packages/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java rename to packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java diff --git a/packages/camera/example/android/app/src/main/AndroidManifest.xml b/packages/camera/camera/example/android/app/src/main/AndroidManifest.xml similarity index 100% rename from packages/camera/example/android/app/src/main/AndroidManifest.xml rename to packages/camera/camera/example/android/app/src/main/AndroidManifest.xml diff --git a/packages/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java b/packages/camera/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java similarity index 100% rename from packages/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java rename to packages/camera/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java diff --git a/packages/camera/example/android/app/src/main/res/drawable/launch_background.xml b/packages/camera/camera/example/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from packages/camera/example/android/app/src/main/res/drawable/launch_background.xml rename to packages/camera/camera/example/android/app/src/main/res/drawable/launch_background.xml diff --git a/packages/camera/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/camera/camera/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from packages/camera/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to packages/camera/camera/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/packages/camera/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/camera/camera/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from packages/camera/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to packages/camera/camera/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/packages/camera/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/camera/camera/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from packages/camera/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to packages/camera/camera/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/packages/camera/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/camera/camera/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from packages/camera/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to packages/camera/camera/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/packages/camera/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/camera/camera/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from packages/camera/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to packages/camera/camera/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/packages/camera/example/android/app/src/main/res/values/styles.xml b/packages/camera/camera/example/android/app/src/main/res/values/styles.xml similarity index 100% rename from packages/camera/example/android/app/src/main/res/values/styles.xml rename to packages/camera/camera/example/android/app/src/main/res/values/styles.xml diff --git a/packages/camera/example/android/build.gradle b/packages/camera/camera/example/android/build.gradle similarity index 100% rename from packages/camera/example/android/build.gradle rename to packages/camera/camera/example/android/build.gradle diff --git a/packages/camera/example/android/gradle.properties b/packages/camera/camera/example/android/gradle.properties similarity index 100% rename from packages/camera/example/android/gradle.properties rename to packages/camera/camera/example/android/gradle.properties diff --git a/packages/camera/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/camera/camera/example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/camera/example/android/gradle/wrapper/gradle-wrapper.properties rename to packages/camera/camera/example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/camera/example/android/settings.gradle b/packages/camera/camera/example/android/settings.gradle similarity index 100% rename from packages/camera/example/android/settings.gradle rename to packages/camera/camera/example/android/settings.gradle diff --git a/packages/camera/example/camera_example.iml b/packages/camera/camera/example/camera_example.iml similarity index 100% rename from packages/camera/example/camera_example.iml rename to packages/camera/camera/example/camera_example.iml diff --git a/packages/camera/example/camera_example_android.iml b/packages/camera/camera/example/camera_example_android.iml similarity index 100% rename from packages/camera/example/camera_example_android.iml rename to packages/camera/camera/example/camera_example_android.iml diff --git a/packages/camera/example/integration_test/camera_test.dart b/packages/camera/camera/example/integration_test/camera_test.dart similarity index 100% rename from packages/camera/example/integration_test/camera_test.dart rename to packages/camera/camera/example/integration_test/camera_test.dart diff --git a/packages/camera/example/ios/Flutter/AppFrameworkInfo.plist b/packages/camera/camera/example/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from packages/camera/example/ios/Flutter/AppFrameworkInfo.plist rename to packages/camera/camera/example/ios/Flutter/AppFrameworkInfo.plist diff --git a/packages/camera/example/ios/Flutter/Debug.xcconfig b/packages/camera/camera/example/ios/Flutter/Debug.xcconfig similarity index 100% rename from packages/camera/example/ios/Flutter/Debug.xcconfig rename to packages/camera/camera/example/ios/Flutter/Debug.xcconfig diff --git a/packages/camera/example/ios/Flutter/Release.xcconfig b/packages/camera/camera/example/ios/Flutter/Release.xcconfig similarity index 100% rename from packages/camera/example/ios/Flutter/Release.xcconfig rename to packages/camera/camera/example/ios/Flutter/Release.xcconfig diff --git a/packages/camera/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from packages/camera/example/ios/Runner.xcodeproj/project.pbxproj rename to packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj diff --git a/packages/camera/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/camera/camera/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/camera/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to packages/camera/camera/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/packages/camera/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/camera/camera/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from packages/camera/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/camera/camera/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/packages/camera/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/camera/camera/example/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/camera/example/ios/Runner.xcworkspace/contents.xcworkspacedata rename to packages/camera/camera/example/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/packages/camera/example/ios/Runner/AppDelegate.h b/packages/camera/camera/example/ios/Runner/AppDelegate.h similarity index 100% rename from packages/camera/example/ios/Runner/AppDelegate.h rename to packages/camera/camera/example/ios/Runner/AppDelegate.h diff --git a/packages/camera/example/ios/Runner/AppDelegate.m b/packages/camera/camera/example/ios/Runner/AppDelegate.m similarity index 100% rename from packages/camera/example/ios/Runner/AppDelegate.m rename to packages/camera/camera/example/ios/Runner/AppDelegate.m diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/camera/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/camera/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/packages/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/camera/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from packages/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to packages/camera/camera/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/packages/camera/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/camera/camera/example/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from packages/camera/example/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to packages/camera/camera/example/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/packages/camera/example/ios/Runner/Base.lproj/Main.storyboard b/packages/camera/camera/example/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from packages/camera/example/ios/Runner/Base.lproj/Main.storyboard rename to packages/camera/camera/example/ios/Runner/Base.lproj/Main.storyboard diff --git a/packages/camera/example/ios/Runner/Info.plist b/packages/camera/camera/example/ios/Runner/Info.plist similarity index 100% rename from packages/camera/example/ios/Runner/Info.plist rename to packages/camera/camera/example/ios/Runner/Info.plist diff --git a/packages/camera/example/ios/Runner/main.m b/packages/camera/camera/example/ios/Runner/main.m similarity index 100% rename from packages/camera/example/ios/Runner/main.m rename to packages/camera/camera/example/ios/Runner/main.m diff --git a/packages/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart similarity index 100% rename from packages/camera/example/lib/main.dart rename to packages/camera/camera/example/lib/main.dart diff --git a/packages/camera/example/pubspec.yaml b/packages/camera/camera/example/pubspec.yaml similarity index 92% rename from packages/camera/example/pubspec.yaml rename to packages/camera/camera/example/pubspec.yaml index bc33087a5877..0d1f03bef437 100644 --- a/packages/camera/example/pubspec.yaml +++ b/packages/camera/camera/example/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: sdk: flutter video_player: ^0.10.0 integration_test: - path: ../../integration_test + path: ../../../integration_test dev_dependencies: flutter_test: diff --git a/packages/camera/example/test_driver/integration_test.dart b/packages/camera/camera/example/test_driver/integration_test.dart similarity index 100% rename from packages/camera/example/test_driver/integration_test.dart rename to packages/camera/camera/example/test_driver/integration_test.dart diff --git a/packages/camera/ios/Assets/.gitkeep b/packages/camera/camera/ios/Assets/.gitkeep similarity index 100% rename from packages/camera/ios/Assets/.gitkeep rename to packages/camera/camera/ios/Assets/.gitkeep diff --git a/packages/camera/ios/Classes/CameraPlugin.h b/packages/camera/camera/ios/Classes/CameraPlugin.h similarity index 100% rename from packages/camera/ios/Classes/CameraPlugin.h rename to packages/camera/camera/ios/Classes/CameraPlugin.h diff --git a/packages/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m similarity index 100% rename from packages/camera/ios/Classes/CameraPlugin.m rename to packages/camera/camera/ios/Classes/CameraPlugin.m diff --git a/packages/camera/ios/Tests/CameraPluginTests.m b/packages/camera/camera/ios/Tests/CameraPluginTests.m similarity index 100% rename from packages/camera/ios/Tests/CameraPluginTests.m rename to packages/camera/camera/ios/Tests/CameraPluginTests.m diff --git a/packages/camera/ios/camera.podspec b/packages/camera/camera/ios/camera.podspec similarity index 100% rename from packages/camera/ios/camera.podspec rename to packages/camera/camera/ios/camera.podspec diff --git a/packages/camera/lib/camera.dart b/packages/camera/camera/lib/camera.dart similarity index 100% rename from packages/camera/lib/camera.dart rename to packages/camera/camera/lib/camera.dart diff --git a/packages/camera/lib/camera_image.dart b/packages/camera/camera/lib/camera_image.dart similarity index 100% rename from packages/camera/lib/camera_image.dart rename to packages/camera/camera/lib/camera_image.dart diff --git a/packages/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml similarity index 95% rename from packages/camera/pubspec.yaml rename to packages/camera/camera/pubspec.yaml index eede48d57654..7088faf227aa 100644 --- a/packages/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,8 +2,8 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.5.8+15 -homepage: https://github.com/flutter/plugins/tree/master/packages/camera +version: 0.5.8+16 +homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: flutter: diff --git a/packages/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart similarity index 100% rename from packages/camera/test/camera_test.dart rename to packages/camera/camera/test/camera_test.dart From 06530f9d3da4e80a818c3d3c0ec34fe2084b4abf Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 10 Nov 2020 16:25:16 -0800 Subject: [PATCH 015/924] [file_selector] Allow empty type groups (#3261) This was restricted under the assumption that there was no reason for an empty group to exist, but that's not actually true; on platforms with selectable groups in the native UI, it may be useful to provide specific options as well as a fallback option (e.g., "Text files" and "All files"). --- .../CHANGELOG.md | 4 ++++ .../lib/src/types/x_type_group/x_type_group.dart | 10 ++++------ .../pubspec.yaml | 2 +- .../test/x_type_group_test.dart | 16 ++++++++++++---- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md index 0d8803f93540..3663064a069f 100644 --- a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md +++ b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.1 + +* Allow type groups that allow any file. + ## 1.0.0 * Initial release. diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart index a7d52a766498..fb591f2b248a 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart @@ -5,18 +5,16 @@ /// A set of allowed XTypes class XTypeGroup { /// Creates a new group with the given label and file extensions. + /// + /// A group with none of the type options provided indicates that any type is + /// allowed. XTypeGroup({ this.label, this.extensions, this.mimeTypes, this.macUTIs, this.webWildCards, - }) : assert( - !((extensions == null || extensions.isEmpty) && - (mimeTypes == null || mimeTypes.isEmpty) && - (macUTIs == null || macUTIs.isEmpty) && - (webWildCards == null || webWildCards.isEmpty)), - "At least one type must be provided for an XTypeGroup."); + }); /// The 'name' or reference to this group of types final String label; diff --git a/packages/file_selector/file_selector_platform_interface/pubspec.yaml b/packages/file_selector/file_selector_platform_interface/pubspec.yaml index 015762a8f5a1..ca5c2bd189ae 100644 --- a/packages/file_selector/file_selector_platform_interface/pubspec.yaml +++ b/packages/file_selector/file_selector_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the file_selector plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_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.0.0 +version: 1.0.1 dependencies: flutter: diff --git a/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart b/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart index 877e530cb342..bde89f46405d 100644 --- a/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart +++ b/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart @@ -7,10 +7,6 @@ import 'package:file_selector_platform_interface/file_selector_platform_interfac void main() { group('XTypeGroup', () { - test('fails assertion with no parameters set', () { - expect(() => XTypeGroup(), throwsAssertionError); - }); - test('toJSON() creates correct map', () { final label = 'test group'; final extensions = ['.txt', '.jpg']; @@ -33,5 +29,17 @@ void main() { expect(jsonMap['macUTIs'], macUTIs); expect(jsonMap['webWildCards'], webWildCards); }); + + test('A wildcard group can be created', () { + final group = XTypeGroup( + label: 'Any', + ); + + final jsonMap = group.toJSON(); + expect(jsonMap['extensions'], null); + expect(jsonMap['mimeTypes'], null); + expect(jsonMap['macUTIs'], null); + expect(jsonMap['webWildCards'], null); + }); }); } From 63b3e7e1b212b261040851bc686c883f4184c005 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 17 Nov 2020 10:25:56 -0800 Subject: [PATCH 016/924] [google_maps_flutter_platform_interface] Add BitmapDescriptor.fromJson constructor. (#3263) This is required so serialized descriptors can be synchronously re-hydrated in the Web implementation. This will be removed/deprecated once the buildWidget API gets refactored. --- .../CHANGELOG.md | 4 + .../lib/src/types/bitmap.dart | 69 +++++++- .../pubspec.yaml | 2 +- .../test/types/bitmap_test.dart | 167 ++++++++++++++++++ 4 files changed, 234 insertions(+), 8 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index dc8eddf8b557..0586ac414d97 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.5 + +* Temporarily add a `fromJson` constructor to `BitmapDescriptor` so serialized descriptors can be synchronously re-hydrated. This will be removed when a fix for [this issue](https://github.com/flutter/flutter/issues/70330) lands. + ## 1.0.4 * Add a `dispose` method to the interface, so implementations may cleanup resources acquired on `init`. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart index a6fdcc1b7e33..e10481e321f5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart @@ -17,6 +17,18 @@ import 'package:flutter/foundation.dart' show kIsWeb; class BitmapDescriptor { const BitmapDescriptor._(this._json); + static const String _defaultMarker = 'defaultMarker'; + static const String _fromAsset = 'fromAsset'; + static const String _fromAssetImage = 'fromAssetImage'; + static const String _fromBytes = 'fromBytes'; + + static const Set _validTypes = { + _defaultMarker, + _fromAsset, + _fromAssetImage, + _fromBytes, + }; + /// Convenience hue value representing red. static const double hueRed = 0.0; @@ -49,14 +61,14 @@ class BitmapDescriptor { /// Creates a BitmapDescriptor that refers to the default marker image. static const BitmapDescriptor defaultMarker = - BitmapDescriptor._(['defaultMarker']); + BitmapDescriptor._([_defaultMarker]); /// Creates a BitmapDescriptor that refers to a colorization of the default /// marker image. For convenience, there is a predefined set of hue values. /// See e.g. [hueYellow]. static BitmapDescriptor defaultMarkerWithHue(double hue) { assert(0.0 <= hue && hue < 360.0); - return BitmapDescriptor._(['defaultMarker', hue]); + return BitmapDescriptor._([_defaultMarker, hue]); } /// Creates a BitmapDescriptor using the name of a bitmap image in the assets @@ -67,9 +79,9 @@ class BitmapDescriptor { @Deprecated("Use fromAssetImage instead") static BitmapDescriptor fromAsset(String assetName, {String package}) { if (package == null) { - return BitmapDescriptor._(['fromAsset', assetName]); + return BitmapDescriptor._([_fromAsset, assetName]); } else { - return BitmapDescriptor._(['fromAsset', assetName, package]); + return BitmapDescriptor._([_fromAsset, assetName, package]); } } @@ -89,7 +101,7 @@ class BitmapDescriptor { }) async { if (!mipmaps && configuration.devicePixelRatio != null) { return BitmapDescriptor._([ - 'fromAssetImage', + _fromAssetImage, assetName, configuration.devicePixelRatio, ]); @@ -99,7 +111,7 @@ class BitmapDescriptor { final AssetBundleImageKey assetBundleImageKey = await assetImage.obtainKey(configuration); return BitmapDescriptor._([ - 'fromAssetImage', + _fromAssetImage, assetBundleImageKey.name, assetBundleImageKey.scale, if (kIsWeb && configuration?.size != null) @@ -113,7 +125,50 @@ class BitmapDescriptor { /// Creates a BitmapDescriptor using an array of bytes that must be encoded /// as PNG. static BitmapDescriptor fromBytes(Uint8List byteData) { - return BitmapDescriptor._(['fromBytes', byteData]); + return BitmapDescriptor._([_fromBytes, byteData]); + } + + /// The inverse of .toJson. + // This is needed in Web to re-hydrate BitmapDescriptors that have been + // transformed to JSON for transport. + // TODO(https://github.com/flutter/flutter/issues/70330): Clean this up. + BitmapDescriptor.fromJson(dynamic json) : _json = json { + assert(_validTypes.contains(_json[0])); + switch (_json[0]) { + case _defaultMarker: + assert(_json.length <= 2); + if (_json.length == 2) { + assert(_json[1] is num); + assert(0 <= _json[1] && _json[1] < 360); + } + break; + case _fromBytes: + assert(_json.length == 2); + assert(_json[1] != null && _json[1] is List); + assert((_json[1] as List).isNotEmpty); + break; + case _fromAsset: + assert(_json.length <= 3); + assert(_json[1] != null && _json[1] is String); + assert((_json[1] as String).isNotEmpty); + if (_json.length == 3) { + assert(_json[2] != null && _json[2] is String); + assert((_json[2] as String).isNotEmpty); + } + break; + case _fromAssetImage: + assert(_json.length <= 4); + assert(_json[1] != null && _json[1] is String); + assert((_json[1] as String).isNotEmpty); + assert(_json[2] != null && _json[2] is double); + if (_json.length == 4) { + assert(_json[3] != null && _json[3] is List); + assert((_json[3] as List).length == 2); + } + break; + default: + break; + } } final dynamic _json; diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index fd3a1c434960..a2b5ff56fee1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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.0.4 +version: 1.0.5 dependencies: flutter: diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart new file mode 100644 index 000000000000..afcf57debef1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart @@ -0,0 +1,167 @@ +// 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:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$BitmapDescriptor', () { + test('toJson / fromJson', () { + final descriptor = + BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueCyan); + final json = descriptor.toJson(); + + // Rehydrate a new bitmap descriptor... + // ignore: deprecated_member_use_from_same_package + final descriptorFromJson = BitmapDescriptor.fromJson(json); + + expect(descriptorFromJson, isNot(descriptor)); // New instance + expect(identical(descriptorFromJson.toJson(), json), isTrue); // Same JSON + }); + + group('fromJson validation', () { + group('type validation', () { + test('correct type', () { + expect(BitmapDescriptor.fromJson(['defaultMarker']), + isA()); + }); + test('wrong type', () { + expect(() { + BitmapDescriptor.fromJson(['bogusType']); + }, throwsAssertionError); + }); + }); + group('defaultMarker', () { + test('hue is null', () { + expect(BitmapDescriptor.fromJson(['defaultMarker']), + isA()); + }); + test('hue is number', () { + expect(BitmapDescriptor.fromJson(['defaultMarker', 158]), + isA()); + }); + test('hue is not number', () { + expect(() { + BitmapDescriptor.fromJson(['defaultMarker', 'nope']); + }, throwsAssertionError); + }); + test('hue is out of range', () { + expect(() { + BitmapDescriptor.fromJson(['defaultMarker', -1]); + }, throwsAssertionError); + expect(() { + BitmapDescriptor.fromJson(['defaultMarker', 361]); + }, throwsAssertionError); + }); + }); + group('fromBytes', () { + test('with bytes', () { + expect( + BitmapDescriptor.fromJson([ + 'fromBytes', + Uint8List.fromList([1, 2, 3]) + ]), + isA()); + }); + test('without bytes', () { + expect(() { + BitmapDescriptor.fromJson(['fromBytes', null]); + }, throwsAssertionError); + expect(() { + BitmapDescriptor.fromJson(['fromBytes', []]); + }, throwsAssertionError); + }); + }); + group('fromAsset', () { + test('name is passed', () { + expect(BitmapDescriptor.fromJson(['fromAsset', 'some/path.png']), + isA()); + }); + test('name cannot be null or empty', () { + expect(() { + BitmapDescriptor.fromJson(['fromAsset', null]); + }, throwsAssertionError); + expect(() { + BitmapDescriptor.fromJson(['fromAsset', '']); + }, throwsAssertionError); + }); + test('package is passed', () { + expect( + BitmapDescriptor.fromJson( + ['fromAsset', 'some/path.png', 'some_package']), + isA()); + }); + test('package cannot be null or empty', () { + expect(() { + BitmapDescriptor.fromJson(['fromAsset', 'some/path.png', null]); + }, throwsAssertionError); + expect(() { + BitmapDescriptor.fromJson(['fromAsset', 'some/path.png', '']); + }, throwsAssertionError); + }); + }); + group('fromAssetImage', () { + test('name and dpi passed', () { + expect( + BitmapDescriptor.fromJson( + ['fromAssetImage', 'some/path.png', 1.0]), + isA()); + }); + test('name cannot be null or empty', () { + expect(() { + BitmapDescriptor.fromJson(['fromAssetImage', null, 1.0]); + }, throwsAssertionError); + expect(() { + BitmapDescriptor.fromJson(['fromAssetImage', '', 1.0]); + }, throwsAssertionError); + }); + test('dpi must be number', () { + expect(() { + BitmapDescriptor.fromJson( + ['fromAssetImage', 'some/path.png', null]); + }, throwsAssertionError); + expect(() { + BitmapDescriptor.fromJson( + ['fromAssetImage', 'some/path.png', 'one']); + }, throwsAssertionError); + }); + test('with optional [width, height] List', () { + expect( + BitmapDescriptor.fromJson([ + 'fromAssetImage', + 'some/path.png', + 1.0, + [640, 480] + ]), + isA()); + }); + test( + 'optional [width, height] List cannot be null or not contain 2 elements', + () { + expect(() { + BitmapDescriptor.fromJson( + ['fromAssetImage', 'some/path.png', 1.0, null]); + }, throwsAssertionError); + expect(() { + BitmapDescriptor.fromJson( + ['fromAssetImage', 'some/path.png', 1.0, []]); + }, throwsAssertionError); + expect(() { + BitmapDescriptor.fromJson([ + 'fromAssetImage', + 'some/path.png', + 1.0, + [640, 480, 1024] + ]); + }, throwsAssertionError); + }); + }); + }); + }); +} From 05067420ed247e43153489fa38ab617342973862 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Wed, 18 Nov 2020 09:04:06 +0100 Subject: [PATCH 017/924] [cross_file] An abstraction to allow working with files across multiple platforms. (#3260) * Initial version of x_file package * Renamed from x_file to cross_file * Add back x_file type to file_selector * Fix formatting issues * Update homepage and version * Added README.md * Added missing copyright * Revert "Added missing copyright" This reverts commit cf7e8d5f3810ae646669f584738502a8cc3c5ca1. * Add missing copyright Co-Authored-By: Jason Panelli <38673809+jasonpanelli@users.noreply.github.com> * Renamed class implementation back to XFile * Fix formatting issues * Rename to cross_file * Added code owners for cross_file package Co-authored-by: Jason Panelli <38673809+jasonpanelli@users.noreply.github.com> --- CODEOWNERS | 1 + packages/cross_file/CHANGELOG.md | 3 + packages/cross_file/LICENSE | 25 ++++ packages/cross_file/README.md | 34 +++++ packages/cross_file/lib/cross_file.dart | 5 + packages/cross_file/lib/src/types/base.dart | 86 +++++++++++ packages/cross_file/lib/src/types/html.dart | 136 ++++++++++++++++++ .../cross_file/lib/src/types/interface.dart | 58 ++++++++ packages/cross_file/lib/src/types/io.dart | 115 +++++++++++++++ .../lib/src/web_helpers/web_helpers.dart | 38 +++++ packages/cross_file/lib/src/x_file.dart | 7 + packages/cross_file/pubspec.yaml | 20 +++ packages/cross_file/test/assets/hello.txt | 1 + .../cross_file/test/x_file_html_test.dart | 108 ++++++++++++++ packages/cross_file/test/x_file_io_test.dart | 99 +++++++++++++ 15 files changed, 736 insertions(+) create mode 100644 packages/cross_file/CHANGELOG.md create mode 100644 packages/cross_file/LICENSE create mode 100644 packages/cross_file/README.md create mode 100644 packages/cross_file/lib/cross_file.dart create mode 100644 packages/cross_file/lib/src/types/base.dart create mode 100644 packages/cross_file/lib/src/types/html.dart create mode 100644 packages/cross_file/lib/src/types/interface.dart create mode 100644 packages/cross_file/lib/src/types/io.dart create mode 100644 packages/cross_file/lib/src/web_helpers/web_helpers.dart create mode 100644 packages/cross_file/lib/src/x_file.dart create mode 100644 packages/cross_file/pubspec.yaml create mode 100644 packages/cross_file/test/assets/hello.txt create mode 100644 packages/cross_file/test/x_file_html_test.dart create mode 100644 packages/cross_file/test/x_file_io_test.dart diff --git a/CODEOWNERS b/CODEOWNERS index 160c0d5a3d10..5f6d83c209ac 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -9,6 +9,7 @@ packages/android_intent/** @mklim @matthew-carroll packages/battery/** @amirh @matthew-carroll packages/camera/** @bparrishMines packages/connectivity/** @cyanglaz @matthew-carroll +packages/cross_file/** @ditman @mvanbeusekom packages/device_info/** @matthew-carroll packages/espresso/** @collinjackson @adazh packages/file_selector/** @ditman diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md new file mode 100644 index 000000000000..3b5ae7756a98 --- /dev/null +++ b/packages/cross_file/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.1.0 + +- Initial open-source release \ No newline at end of file diff --git a/packages/cross_file/LICENSE b/packages/cross_file/LICENSE new file mode 100644 index 000000000000..2c91f1438173 --- /dev/null +++ b/packages/cross_file/LICENSE @@ -0,0 +1,25 @@ +Copyright 2020 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/packages/cross_file/README.md b/packages/cross_file/README.md new file mode 100644 index 000000000000..f1ab89bc52f1 --- /dev/null +++ b/packages/cross_file/README.md @@ -0,0 +1,34 @@ +# cross_file + +An abstraction to allow working with files across multiple platforms. + +# Usage + +Import `package:cross/cross_info.dart`, instantiate a `CrossFile` +using a path or byte array and use its methods and properties to +access the file and its metadata. + +Example: + +```dart +import 'package:cross_file/cross_file.dart'; + +final file = CrossFile('assets/hello.txt'); + +print('File information:'); +print('- Path: ${file.path}'); +print('- Name: ${file.name}'); +print('- MIME type: ${file.mimeType}'); + +final fileContent = await file.readAsString(); +print('Content of the file: ${fileContent}'); // e.g. "Moto G (4)" +``` + +You will find links to the API docs on the [pub page](https://pub.dartlang.org/packages/cross_file). + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](http://flutter.io/). + +For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). \ No newline at end of file diff --git a/packages/cross_file/lib/cross_file.dart b/packages/cross_file/lib/cross_file.dart new file mode 100644 index 000000000000..a3e2873e670d --- /dev/null +++ b/packages/cross_file/lib/cross_file.dart @@ -0,0 +1,5 @@ +// Copyright 2018 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. + +export 'src/x_file.dart'; diff --git a/packages/cross_file/lib/src/types/base.dart b/packages/cross_file/lib/src/types/base.dart new file mode 100644 index 000000000000..6dc2d51b08b1 --- /dev/null +++ b/packages/cross_file/lib/src/types/base.dart @@ -0,0 +1,86 @@ +// Copyright 2018 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:convert'; +import 'dart:typed_data'; + +/// The interface for a CrossFile. +/// +/// A CrossFile is a container that wraps the path of a selected +/// file by the user and (in some platforms, like web) the bytes +/// with the contents of the file. +/// +/// This class is a very limited subset of dart:io [File], so all +/// the methods should seem familiar. +abstract class XFileBase { + /// Construct a CrossFile + XFileBase(String path); + + /// Save the CrossFile at the indicated file path. + void saveTo(String path) async { + throw UnimplementedError('saveTo has not been implemented.'); + } + + /// Get the path of the picked file. + /// + /// This should only be used as a backwards-compatibility clutch + /// for mobile apps, or cosmetic reasons only (to show the user + /// the path they've picked). + /// + /// Accessing the data contained in the picked file by its path + /// is platform-dependant (and won't work on web), so use the + /// byte getters in the CrossFile instance instead. + String get path { + throw UnimplementedError('.path has not been implemented.'); + } + + /// The name of the file as it was selected by the user in their device. + /// + /// Use only for cosmetic reasons, do not try to use this as a path. + String get name { + throw UnimplementedError('.name has not been implemented.'); + } + + /// For web, it may be necessary for a file to know its MIME type. + String get mimeType { + throw UnimplementedError('.mimeType has not been implemented.'); + } + + /// Get the length of the file. Returns a `Future` that completes with the length in bytes. + Future length() { + throw UnimplementedError('.length() has not been implemented.'); + } + + /// Synchronously read the entire file contents as a string using the given [Encoding]. + /// + /// By default, `encoding` is [utf8]. + /// + /// Throws Exception if the operation fails. + Future readAsString({Encoding encoding = utf8}) { + throw UnimplementedError('readAsString() has not been implemented.'); + } + + /// Synchronously read the entire file contents as a list of bytes. + /// + /// Throws Exception if the operation fails. + Future readAsBytes() { + throw UnimplementedError('readAsBytes() has not been implemented.'); + } + + /// Create a new independent [Stream] for the contents of this file. + /// + /// If `start` is present, the file will be read from byte-offset `start`. Otherwise from the beginning (index 0). + /// + /// 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 openRead([int start, int end]) { + throw UnimplementedError('openRead() has not been implemented.'); + } + + /// Get the last-modified time for the CrossFile + Future lastModified() { + throw UnimplementedError('openRead() has not been implemented.'); + } +} diff --git a/packages/cross_file/lib/src/types/html.dart b/packages/cross_file/lib/src/types/html.dart new file mode 100644 index 000000000000..269f2a8d9412 --- /dev/null +++ b/packages/cross_file/lib/src/types/html.dart @@ -0,0 +1,136 @@ +// Copyright 2018 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:convert'; +import 'dart:typed_data'; + +import 'package:http/http.dart' as http show readBytes; +import 'package:meta/meta.dart'; +import 'dart:html'; + +import '../web_helpers/web_helpers.dart'; +import './base.dart'; + +/// A CrossFile that works on web. +/// +/// It wraps the bytes of a selected file. +class XFile extends XFileBase { + String path; + + final String mimeType; + final Uint8List _data; + final int _length; + final String name; + final DateTime _lastModified; + Element _target; + + final CrossFileTestOverrides _overrides; + + bool get _hasTestOverrides => _overrides != null; + + /// Construct a CrossFile object from its ObjectUrl. + /// + /// Optionally, this can be initialized with `bytes` and `length` + /// so no http requests are performed to retrieve files later. + /// + /// `name` needs to be passed from the outside, since we only have + /// access to it while we create the ObjectUrl. + XFile( + this.path, { + this.mimeType, + this.name, + int length, + Uint8List bytes, + DateTime lastModified, + @visibleForTesting CrossFileTestOverrides overrides, + }) : _data = bytes, + _length = length, + _overrides = overrides, + _lastModified = lastModified, + super(path); + + /// Construct an CrossFile from its data + XFile.fromData( + Uint8List bytes, { + this.mimeType, + this.name, + int length, + DateTime lastModified, + this.path, + @visibleForTesting CrossFileTestOverrides overrides, + }) : _data = bytes, + _length = length, + _overrides = overrides, + _lastModified = lastModified, + super(path) { + if (path == null) { + final blob = (mimeType == null) ? Blob([bytes]) : Blob([bytes], mimeType); + this.path = Url.createObjectUrl(blob); + } + } + + @override + Future lastModified() async { + if (_lastModified != null) { + return Future.value(_lastModified); + } + return null; + } + + Future get _bytes async { + if (_data != null) { + return Future.value(UnmodifiableUint8ListView(_data)); + } + return http.readBytes(path); + } + + @override + Future length() async { + return _length ?? (await _bytes).length; + } + + @override + Future readAsString({Encoding encoding = utf8}) async { + return encoding.decode(await _bytes); + } + + @override + Future readAsBytes() async { + return Future.value(await _bytes); + } + + @override + Stream openRead([int start, int end]) async* { + final bytes = await _bytes; + yield bytes.sublist(start ?? 0, end ?? bytes.length); + } + + /// Saves the data of this CrossFile at the location indicated by path. + /// For the web implementation, the path variable is ignored. + void saveTo(String path) async { + // Create a DOM container where we can host the anchor. + _target = ensureInitialized('__x_file_dom_element'); + + // Create an tag with the appropriate download attributes and click it + // May be overridden with CrossFileTestOverrides + final AnchorElement element = + (_hasTestOverrides && _overrides.createAnchorElement != null) + ? _overrides.createAnchorElement(this.path, this.name) + : createAnchorElement(this.path, this.name); + + // Clear the children in our container so we can add an element to click + _target.children.clear(); + addElementToContainerAndClick(_target, element); + } +} + +/// Overrides some functions to allow testing +@visibleForTesting +class CrossFileTestOverrides { + /// For overriding the creation of the file input element. + Element Function(String href, String suggestedName) createAnchorElement; + + /// Default constructor for overrides + CrossFileTestOverrides({this.createAnchorElement}); +} diff --git a/packages/cross_file/lib/src/types/interface.dart b/packages/cross_file/lib/src/types/interface.dart new file mode 100644 index 000000000000..e30bc63b4c92 --- /dev/null +++ b/packages/cross_file/lib/src/types/interface.dart @@ -0,0 +1,58 @@ +// Copyright 2018 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:typed_data'; +import 'package:meta/meta.dart'; + +import './base.dart'; + +/// A CrossFile is a cross-platform, simplified File abstraction. +/// +/// It wraps the bytes of a selected file, and its (platform-dependant) path. +class XFile extends XFileBase { + /// Construct a CrossFile object from its path. + /// + /// Optionally, this can be initialized with `bytes` and `length` + /// so no http requests are performed to retrieve data later. + /// + /// `name` may be passed from the outside, for those cases where the effective + /// `path` of the file doesn't match what the user sees when selecting it + /// (like in web) + XFile( + String path, { + String mimeType, + String name, + int length, + Uint8List bytes, + DateTime lastModified, + @visibleForTesting CrossFileTestOverrides overrides, + }) : super(path) { + throw UnimplementedError( + 'CrossFile is not available in your current platform.'); + } + + /// Construct a CrossFile object from its data + XFile.fromData( + Uint8List bytes, { + String mimeType, + String name, + int length, + DateTime lastModified, + String path, + @visibleForTesting CrossFileTestOverrides overrides, + }) : super(path) { + throw UnimplementedError( + 'CrossFile is not available in your current platform.'); + } +} + +/// Overrides some functions of CrossFile for testing purposes +@visibleForTesting +class CrossFileTestOverrides { + /// For overriding the creation of the file input element. + dynamic Function(String href, String suggestedName) createAnchorElement; + + /// Default constructor for overrides + CrossFileTestOverrides({this.createAnchorElement}); +} diff --git a/packages/cross_file/lib/src/types/io.dart b/packages/cross_file/lib/src/types/io.dart new file mode 100644 index 000000000000..81b8cdd84d67 --- /dev/null +++ b/packages/cross_file/lib/src/types/io.dart @@ -0,0 +1,115 @@ +// Copyright 2018 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:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import './base.dart'; + +/// A CrossFile backed by a dart:io File. +class XFile extends XFileBase { + final File _file; + final String mimeType; + final DateTime _lastModified; + int _length; + + final Uint8List _bytes; + + /// Construct a CrossFile object backed by a dart:io File. + XFile( + String path, { + this.mimeType, + String name, + int length, + Uint8List bytes, + DateTime lastModified, + }) : _file = File(path), + _bytes = null, + _lastModified = lastModified, + super(path); + + /// Construct an CrossFile from its data + XFile.fromData( + Uint8List bytes, { + this.mimeType, + String path, + String name, + int length, + DateTime lastModified, + }) : _bytes = bytes, + _file = File(path ?? ''), + _length = length, + _lastModified = lastModified, + super(path) { + if (length == null) { + _length = bytes.length; + } + } + + @override + Future lastModified() { + if (_lastModified != null) { + return Future.value(_lastModified); + } + return _file.lastModified(); + } + + @override + void saveTo(String path) async { + File fileToSave = File(path); + await fileToSave.writeAsBytes(_bytes ?? (await readAsBytes())); + await fileToSave.create(); + } + + @override + String get path { + return _file.path; + } + + @override + String get name { + return _file.path.split(Platform.pathSeparator).last; + } + + @override + Future length() { + if (_length != null) { + return Future.value(_length); + } + return _file.length(); + } + + @override + Future readAsString({Encoding encoding = utf8}) { + if (_bytes != null) { + return Future.value(String.fromCharCodes(_bytes)); + } + return _file.readAsString(encoding: encoding); + } + + @override + Future readAsBytes() { + if (_bytes != null) { + return Future.value(_bytes); + } + return _file.readAsBytes(); + } + + Stream _getBytes(int start, int end) async* { + final bytes = _bytes; + yield bytes.sublist(start ?? 0, end ?? bytes.length); + } + + @override + Stream openRead([int start, int end]) { + if (_bytes != null) { + return _getBytes(start, end); + } else { + return _file + .openRead(start ?? 0, end) + .map((chunk) => Uint8List.fromList(chunk)); + } + } +} diff --git a/packages/cross_file/lib/src/web_helpers/web_helpers.dart b/packages/cross_file/lib/src/web_helpers/web_helpers.dart new file mode 100644 index 000000000000..813f5f975561 --- /dev/null +++ b/packages/cross_file/lib/src/web_helpers/web_helpers.dart @@ -0,0 +1,38 @@ +// Copyright 2018 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:html'; + +/// Create anchor element with download attribute +AnchorElement createAnchorElement(String href, String suggestedName) { + final element = AnchorElement(href: href); + + if (suggestedName == null) { + element.download = 'download'; + } else { + element.download = suggestedName; + } + + return element; +} + +/// Add an element to a container and click it +void addElementToContainerAndClick(Element container, Element element) { + // Add the element and click it + // All previous elements will be removed before adding the new one + container.children.add(element); + element.click(); +} + +/// Initializes a DOM container where we can host elements. +Element ensureInitialized(String id) { + var target = querySelector('#${id}'); + if (target == null) { + final Element targetElement = Element.tag('flt-x-file')..id = id; + + querySelector('body').children.add(targetElement); + target = targetElement; + } + return target; +} diff --git a/packages/cross_file/lib/src/x_file.dart b/packages/cross_file/lib/src/x_file.dart new file mode 100644 index 000000000000..6136bff39f36 --- /dev/null +++ b/packages/cross_file/lib/src/x_file.dart @@ -0,0 +1,7 @@ +// Copyright 2018 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. + +export 'types/interface.dart' + if (dart.library.html) 'types/html.dart' + if (dart.library.io) 'types/io.dart'; diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml new file mode 100644 index 000000000000..40084d3d1ea0 --- /dev/null +++ b/packages/cross_file/pubspec.yaml @@ -0,0 +1,20 @@ + +name: cross_file +description: An abstraction to allow working with files across multiple platforms. +homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file +version: 0.1.0 + +dependencies: + flutter: + sdk: flutter + http: ^0.12.0+1 + meta: ^1.0.5 + +dev_dependencies: + flutter_test: + sdk: flutter + pedantic: ^1.8.0 + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.22.0 <2.0.0" \ No newline at end of file diff --git a/packages/cross_file/test/assets/hello.txt b/packages/cross_file/test/assets/hello.txt new file mode 100644 index 000000000000..5dd01c177f5d --- /dev/null +++ b/packages/cross_file/test/assets/hello.txt @@ -0,0 +1 @@ +Hello, world! \ No newline at end of file diff --git a/packages/cross_file/test/x_file_html_test.dart b/packages/cross_file/test/x_file_html_test.dart new file mode 100644 index 000000000000..fadba96b3c6c --- /dev/null +++ b/packages/cross_file/test/x_file_html_test.dart @@ -0,0 +1,108 @@ +// Copyright 2020 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. + +@TestOn('chrome') // Uses web-only Flutter SDK + +import 'dart:convert'; +import 'dart:html' as html; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:cross_file/cross_file.dart'; + +import 'dart:html'; + +final String expectedStringContents = 'Hello, world!'; +final Uint8List bytes = utf8.encode(expectedStringContents); +final html.File textFile = html.File([bytes], 'hello.txt'); +final String textFileUrl = html.Url.createObjectUrl(textFile); + +void main() { + group('Create with an objectUrl', () { + final file = XFile(textFileUrl); + + test('Can be read as a string', () async { + expect(await file.readAsString(), equals(expectedStringContents)); + }); + test('Can be read as bytes', () async { + expect(await file.readAsBytes(), equals(bytes)); + }); + + test('Can be read as a stream', () async { + expect(await file.openRead().first, equals(bytes)); + }); + + test('Stream can be sliced', () async { + expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); + }); + }); + + group('Create from data', () { + final file = XFile.fromData(bytes); + + test('Can be read as a string', () async { + expect(await file.readAsString(), equals(expectedStringContents)); + }); + test('Can be read as bytes', () async { + expect(await file.readAsBytes(), equals(bytes)); + }); + + test('Can be read as a stream', () async { + expect(await file.openRead().first, equals(bytes)); + }); + + test('Stream can be sliced', () async { + expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); + }); + }); + + group('saveTo(..)', () { + final String CrossFileDomElementId = '__x_file_dom_element'; + + group('CrossFile saveTo(..)', () { + test('creates a DOM container', () async { + XFile file = XFile.fromData(bytes); + + await file.saveTo(''); + + final container = querySelector('#${CrossFileDomElementId}'); + + expect(container, isNotNull); + }); + + test('create anchor element', () async { + XFile file = XFile.fromData(bytes, name: textFile.name); + + await file.saveTo('path'); + + final container = querySelector('#${CrossFileDomElementId}'); + final AnchorElement element = container?.children?.firstWhere( + (element) => element.tagName == 'A', + orElse: () => null); + + expect(element, isNotNull); + expect(element.href, file.path); + expect(element.download, file.name); + }); + + test('anchor element is clicked', () async { + final mockAnchor = AnchorElement(); + + CrossFileTestOverrides overrides = CrossFileTestOverrides( + createAnchorElement: (_, __) => mockAnchor, + ); + + XFile file = + XFile.fromData(bytes, name: textFile.name, overrides: overrides); + + bool clicked = false; + mockAnchor.onClick.listen((event) => clicked = true); + + await file.saveTo('path'); + + expect(clicked, true); + }); + }); + }); +} diff --git a/packages/cross_file/test/x_file_io_test.dart b/packages/cross_file/test/x_file_io_test.dart new file mode 100644 index 000000000000..65edea1ea45d --- /dev/null +++ b/packages/cross_file/test/x_file_io_test.dart @@ -0,0 +1,99 @@ +// Copyright 2020 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. + +@TestOn('vm') // Uses dart:io + +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:cross_file/cross_file.dart'; + +// Please note that executing this test with command +// `flutter test test/x_file_io_test.dart` will set the directory +// to ./file_selector_platform_interface. +// +// This will cause our hello.txt file to be not be found. Please +// execute this test with `flutter test` or change the path prefix +// to ./test/assets/ +// +// https://github.com/flutter/flutter/issues/20907 + +final pathPrefix = './assets/'; +final path = pathPrefix + 'hello.txt'; +final String expectedStringContents = 'Hello, world!'; +final Uint8List bytes = utf8.encode(expectedStringContents); +final File textFile = File(path); +final String textFilePath = textFile.path; + +void main() { + group('Create with a path', () { + final file = XFile(textFilePath); + + test('Can be read as a string', () async { + expect(await file.readAsString(), equals(expectedStringContents)); + }); + test('Can be read as bytes', () async { + expect(await file.readAsBytes(), equals(bytes)); + }); + + test('Can be read as a stream', () async { + expect(await file.openRead().first, equals(bytes)); + }); + + test('Stream can be sliced', () async { + expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); + }); + + test('saveTo(..) creates file', () async { + File removeBeforeTest = File(pathPrefix + 'newFilePath.txt'); + if (removeBeforeTest.existsSync()) { + await removeBeforeTest.delete(); + } + + await file.saveTo(pathPrefix + 'newFilePath.txt'); + File newFile = File(pathPrefix + 'newFilePath.txt'); + + expect(newFile.existsSync(), isTrue); + expect(newFile.readAsStringSync(), 'Hello, world!'); + + await newFile.delete(); + }); + }); + + group('Create with data', () { + final file = XFile.fromData(bytes); + + test('Can be read as a string', () async { + expect(await file.readAsString(), equals(expectedStringContents)); + }); + test('Can be read as bytes', () async { + expect(await file.readAsBytes(), equals(bytes)); + }); + + test('Can be read as a stream', () async { + expect(await file.openRead().first, equals(bytes)); + }); + + test('Stream can be sliced', () async { + expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); + }); + + test('Function saveTo(..) creates file', () async { + File removeBeforeTest = File(pathPrefix + 'newFileData.txt'); + if (removeBeforeTest.existsSync()) { + await removeBeforeTest.delete(); + } + + await file.saveTo(pathPrefix + 'newFileData.txt'); + File newFile = File(pathPrefix + 'newFileData.txt'); + + expect(newFile.existsSync(), isTrue); + expect(newFile.readAsStringSync(), 'Hello, world!'); + + await newFile.delete(); + }); + }); +} From 869f21113f8eefcb2daf2b3bc11ef13416928cf3 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Wed, 18 Nov 2020 11:42:09 -0800 Subject: [PATCH 018/924] [google_maps_flutter_web] Render custom Marker icons. (#3273) * Render markers fromBytes. Ensure initial icon is also preserved. Add test. * Opt-out tests from null-safety until plugin is migrated. --- .../google_maps_flutter_web/CHANGELOG.md | 5 ++++ .../lib/src/convert.dart | 12 ++++++-- .../google_maps_flutter_web/pubspec.yaml | 5 ++-- .../google_maps_controller_integration.dart | 2 ++ .../google_maps_plugin_integration.dart | 2 ++ .../test/test_driver/marker_integration.dart | 2 ++ .../test/test_driver/markers_integration.dart | 30 +++++++++++++++++++ .../resources/icon_image_base64.dart | 24 +++++++++++++++ .../test/test_driver/shape_integration.dart | 2 ++ .../test/test_driver/shapes_integration.dart | 2 ++ 10 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/resources/icon_image_base64.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 07700151a2d1..dcafa12a2c13 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.1.0+8 + +* Update `package:google_maps_flutter_platform_interface` to `^1.0.5`. +* Add support for `fromBitmap` BitmapDescriptors. [Issue](https://github.com/flutter/flutter/issues/66622). + ## 0.1.0+7 * Substitute `undefined_prefixed_name: ignore` analyzer setting by a `dart:ui` shim with conditional exports. [Issue](https://github.com/flutter/flutter/issues/69309). diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index e8847fdd7b84..551c1572b1bb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -264,6 +264,7 @@ Set _rawOptionsToInitialMarkers(Map rawOptions) { Offset offset; LatLng position; InfoWindow infoWindow; + BitmapDescriptor icon; if (rawMarker['anchor'] != null) { offset = Offset((rawMarker['anchor'][0]), (rawMarker['anchor'][1])); } @@ -280,6 +281,9 @@ Set _rawOptionsToInitialMarkers(Map rawOptions) { ); } } + if (rawMarker['icon'] != null) { + icon = BitmapDescriptor.fromJson(rawMarker['icon']); + } return Marker( markerId: MarkerId(rawMarker['markerId']), alpha: rawMarker['alpha'], @@ -287,8 +291,7 @@ Set _rawOptionsToInitialMarkers(Map rawOptions) { consumeTapEvents: rawMarker['consumeTapEvents'], draggable: rawMarker['draggable'], flat: rawMarker['flat'], - // TODO: Doesn't this support custom icons? - icon: BitmapDescriptor.defaultMarker, + icon: icon, infoWindow: infoWindow, position: position ?? _nullLatLng, rotation: rawMarker['rotation'], @@ -432,6 +435,11 @@ gmaps.MarkerOptions _markerOptionsFromMarker( ..size = size ..scaledSize = size; } + } else if (iconConfig[0] == 'fromBytes') { + // Grab the bytes, and put them into a blob + List bytes = iconConfig[1]; + final blob = Blob([bytes]); // Let the browser figure out the encoding + icon = gmaps.Icon()..url = Url.createObjectUrlFromBlob(blob); } } return gmaps.MarkerOptions() diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index bbbfcfa79472..237415318aac 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.1.0+7 +version: 0.1.0+8 flutter: plugin: @@ -16,7 +16,7 @@ dependencies: flutter_web_plugins: sdk: flutter meta: ^1.1.7 - google_maps_flutter_platform_interface: ^1.0.4 + google_maps_flutter_platform_interface: ^1.0.5 google_maps: ^3.4.5 stream_transform: ^1.2.0 sanitize_html: ^1.4.1 @@ -24,6 +24,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + http: ^0.12.2 url_launcher: ^5.2.5 pedantic: ^1.8.0 mockito: ^4.1.1 diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart index dfd01c6faf55..70d4452e411f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart index 59b5de42400f..6276d26753a4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/marker_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/marker_integration.dart index 1cada32104af..c83e92dbb79d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/marker_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/marker_integration.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart index cad8cd8acfed..9c3ed8ea3860 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart @@ -2,14 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; +import 'dart:convert'; import 'dart:html'; +import 'package:http/http.dart' as http; import 'package:integration_test/integration_test.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'resources/icon_image_base64.dart'; + void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); @@ -141,6 +147,30 @@ void main() { expect(controller.markers[MarkerId('1')].marker.icon, isNull); }); + // + testWidgets('markers with custom bitmap icon work', + (WidgetTester tester) async { + final bytes = Base64Decoder().convert(iconImageBase64); + final markers = { + Marker( + markerId: MarkerId('1'), icon: BitmapDescriptor.fromBytes(bytes)), + }; + + controller.addMarkers(markers); + + expect(controller.markers.length, 1); + expect(controller.markers[MarkerId('1')].marker.icon, isNotNull); + expect(controller.markers[MarkerId('1')].marker.icon.url, + startsWith('blob:')); + + final blobUrl = controller.markers[MarkerId('1')].marker.icon.url; + final response = await http.get(blobUrl); + + expect(response.bodyBytes, bytes, + reason: + 'Bytes from the Icon blob must match bytes used to create Marker'); + }); + // https://github.com/flutter/flutter/issues/67854 testWidgets('InfoWindow snippet can have links', (WidgetTester tester) async { diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/resources/icon_image_base64.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/resources/icon_image_base64.dart new file mode 100644 index 000000000000..aa4a80baddbb --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/resources/icon_image_base64.dart @@ -0,0 +1,24 @@ +final iconImageBase64 = + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAIRlWElmTU' + '0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIA' + 'AIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQ' + 'AAABCgAwAEAAAAAQAAABAAAAAAx28c8QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1M' + 'OmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIH' + 'g6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8v' + 'd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcm' + 'lwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFk' + 'b2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk' + '9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6' + 'eG1wbWV0YT4KTMInWQAAAplJREFUOBF1k01ME1EQx2fe7tIPoGgTE6AJgQQSPaiH9oAtkFbsgX' + 'jygFcT0XjSkxcTDxtPJh6MR28ePMHBBA8cNLSIony0oBhEMVETP058tE132+7uG3cW24DAXN57' + '2fn9/zPz3iIcEdEl0nIxtNLr1IlVeoMadkubKmoL+u2SzAV8IjV5Ekt4GN+A8+VOUPwLarOI2G' + 'Vpqq0i4JQorwQxPtWHVZ1IKP8LNGDXGaSyqARFxDGo7MJBy4XVf3AyQ+qTHnTEXoF9cFUy3OkY' + '0oWxmWFtD5xNoc1sQ6AOn1+hCNTkkhKow8KFZV77tVs2O9dhFvBm0IA/U0RhZ7/ocEx23oUDlh' + 'h8HkNjZIN8Lb3gOU8gOp7AKJHCB2/aNZkTftHumNzzbtl2CBPZHqxw8mHhVZBeoz6w5DvhE2FZ' + 'lQYPjKdd2/qRyKZ6KsPv7TEk7EYEk0A0EUmJduHRy1i4oLKqgmC59ZggAdwrC9pFuWy1iUT2rA' + 'uv0h2UdNtNqxCBBkgqorjOMOgksN7CxQ90vEb00U3c3LIwyo9o8FXxQVNr8Coqyk+S5EPBXnjt' + 'xRmc4TegI7qWbvBkeeUbGMnTCd4nZnYeDOWIEtlC6cKK/JJepY3hZSvN33jovO6L0XFqPKqBTO' + 'FuapUoPr1lxDM7cmC2TAOz25cYSGa++feBew/cjpc0V+mNT29/HZp3KDFTNLvuTRPEHy5065lj' + 'Xn4y41XM+wP/AlcycRmdc3MUhvLm/J/ceu/3qUVT62oP2EZpjSylHybHSpDUVcjq9gEBVo0+Xt' + 'JyN2IWRO+3QUforRoKnZLVsglaMECW+YmMSj9M3SrC6Lg71CMiqWfUrJ6ywzefhnZ+G69BaKdB' + 'WhXQAn6wzDUpfUPw7MrmX/WhbfmKblw+AAAAAElFTkSuQmCC'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shape_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shape_integration.dart index a05d704850e6..b1a691d18def 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shape_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shape_integration.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart index 4345843eb537..0c92c6a924e7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'dart:ui'; From e4a06425e92e29845617e3e3997600d61b97d025 Mon Sep 17 00:00:00 2001 From: Jia Hao Date: Fri, 20 Nov 2020 07:32:27 +0800 Subject: [PATCH 019/924] [path_provider] Log errors in the linux example (#3146) --- .../path_provider/path_provider_linux/CHANGELOG.md | 5 ++++- .../path_provider_linux/example/lib/main.dart | 12 ++++++++---- .../path_provider/path_provider_linux/pubspec.yaml | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/path_provider/path_provider_linux/CHANGELOG.md b/packages/path_provider/path_provider_linux/CHANGELOG.md index 21f336c5f0f2..bf043c6e6954 100644 --- a/packages/path_provider/path_provider_linux/CHANGELOG.md +++ b/packages/path_provider/path_provider_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.1+2 + +* Log errors in the example when calls to the `path_provider` fail. + ## 0.1.1+1 * Check in linux/ directory for example/ @@ -19,4 +23,3 @@ ## 0.0.1 * The initial implementation of path_provider for Linux * Implements getApplicationSupportPath, getApplicationDocumentsPath, getDownloadsPath, and getTemporaryPath - diff --git a/packages/path_provider/path_provider_linux/example/lib/main.dart b/packages/path_provider/path_provider_linux/example/lib/main.dart index edba63482ad5..6dc364b77f2a 100644 --- a/packages/path_provider/path_provider_linux/example/lib/main.dart +++ b/packages/path_provider/path_provider_linux/example/lib/main.dart @@ -35,25 +35,29 @@ class _MyAppState extends State { // Platform messages may fail, so we use a try/catch PlatformException. try { tempDirectory = (await getTemporaryDirectory()).path; - } on PlatformException { + } on PlatformException catch (e, stackTrace) { tempDirectory = 'Failed to get temp directory.'; + print('$tempDirectory $e $stackTrace'); } try { downloadsDirectory = (await getDownloadsDirectory()).path; - } on PlatformException { + } on PlatformException catch (e, stackTrace) { downloadsDirectory = 'Failed to get downloads directory.'; + print('$downloadsDirectory $e $stackTrace'); } try { documentsDirectory = (await getApplicationDocumentsDirectory()).path; - } on PlatformException { + } on PlatformException catch (e, stackTrace) { documentsDirectory = 'Failed to get documents directory.'; + print('$documentsDirectory $e $stackTrace'); } try { appSupportDirectory = (await getApplicationSupportDirectory()).path; - } on PlatformException { + } on PlatformException catch (e, stackTrace) { appSupportDirectory = 'Failed to get documents directory.'; + print('$appSupportDirectory $e $stackTrace'); } // If the widget was removed from the tree while the asynchronous platform // message was in flight, we want to discard the reply rather than calling diff --git a/packages/path_provider/path_provider_linux/pubspec.yaml b/packages/path_provider/path_provider_linux/pubspec.yaml index feac1a6ec2f7..fac82d24829f 100644 --- a/packages/path_provider/path_provider_linux/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: path_provider_linux description: linux implementation of the path_provider plugin -version: 0.1.1+1 +version: 0.1.1+2 homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_linux flutter: From f15a800258408b090b55ba7f5ace305752c7831e Mon Sep 17 00:00:00 2001 From: Hamdi Kahloun <32666446+hamdikahloun@users.noreply.github.com> Date: Fri, 20 Nov 2020 09:42:46 +0100 Subject: [PATCH 020/924] [google_maps_flutter] Android Code Inspection and Clean up (#3112) * Android Code Inspection and Clean up * Android Code Inspection and Clean up * Android Code Inspection and Clean up * Android Code Inspection and Clean up * Android Code Inspection and Clean up * Android Code Inspection and Clean up * Import PluginRegistry * Import PluginRegistry * Update GoogleMapController.java * google_maps_flutter * Update build.gradle * Update Convert.java * Update Convert.java Add TODO comment * Update Convert.java --- .../google_maps_flutter/CHANGELOG.md | 4 ++ .../flutter/plugins/googlemaps/Convert.java | 22 ++++++- .../googlemaps/GoogleMapController.java | 60 ++++++++++--------- .../google_maps_flutter/pubspec.yaml | 2 +- 4 files changed, 56 insertions(+), 32 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index 4a7026f01ccd..12e9ab4b55f7 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.7 + +* Android: Handle deprecation & unchecked warning as error. + ## 1.0.6 * Update Dart SDK constraint in example. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 5ef7b26a4a2c..7222511a2a3b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -33,6 +33,9 @@ /** Conversions between JSON-like values and GoogleMaps data types. */ class Convert { + // TODO(hamdikahloun): FlutterMain has been deprecated and should be replaced with FlutterLoader + // when it's available in Stable channel: https://github.com/flutter/flutter/issues/70923. + @SuppressWarnings("deprecation") private static BitmapDescriptor toBitmapDescriptor(Object o) { final List data = toList(o); switch (toString(data.get(0))) { @@ -207,8 +210,9 @@ static LatLng toLatLng(Object o) { } static Point toPoint(Object o) { - Map screenCoordinate = (Map) o; - return new Point(screenCoordinate.get("x"), screenCoordinate.get("y")); + Object x = toMap(o).get("x"); + Object y = toMap(o).get("y"); + return new Point((int) x, (int) y); } static Map pointToJson(Point point) { @@ -234,6 +238,18 @@ private static List toList(Object o) { return (Map) o; } + private static Map toObjectMap(Object o) { + Map hashMap = new HashMap<>(); + Map map = (Map) o; + for (Object key : map.keySet()) { + Object object = map.get(key); + if (object != null) { + hashMap.put((String) key, object); + } + } + return hashMap; + } + private static float toFractionalPixels(Object o, float density) { return toFloat(o) * density; } @@ -377,7 +393,7 @@ static String interpretMarkerOptions(Object o, MarkerOptionsSink sink) { final Object infoWindow = data.get("infoWindow"); if (infoWindow != null) { - interpretInfoWindowOptions(sink, (Map) infoWindow); + interpretInfoWindowOptions(sink, toObjectMap(infoWindow)); } final Object position = data.get("position"); if (position != null) { diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index 33cacffc88d4..f6b8c3fe1fd1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -239,12 +239,12 @@ public void onSnapshotReady(Bitmap bitmap) { } case "markers#update": { - Object markersToAdd = call.argument("markersToAdd"); - markersController.addMarkers((List) markersToAdd); - Object markersToChange = call.argument("markersToChange"); - markersController.changeMarkers((List) markersToChange); - Object markerIdsToRemove = call.argument("markerIdsToRemove"); - markersController.removeMarkers((List) markerIdsToRemove); + List markersToAdd = call.argument("markersToAdd"); + markersController.addMarkers(markersToAdd); + List markersToChange = call.argument("markersToChange"); + markersController.changeMarkers(markersToChange); + List markerIdsToRemove = call.argument("markerIdsToRemove"); + markersController.removeMarkers(markerIdsToRemove); result.success(null); break; } @@ -268,34 +268,34 @@ public void onSnapshotReady(Bitmap bitmap) { } case "polygons#update": { - Object polygonsToAdd = call.argument("polygonsToAdd"); - polygonsController.addPolygons((List) polygonsToAdd); - Object polygonsToChange = call.argument("polygonsToChange"); - polygonsController.changePolygons((List) polygonsToChange); - Object polygonIdsToRemove = call.argument("polygonIdsToRemove"); - polygonsController.removePolygons((List) polygonIdsToRemove); + List polygonsToAdd = call.argument("polygonsToAdd"); + polygonsController.addPolygons(polygonsToAdd); + List polygonsToChange = call.argument("polygonsToChange"); + polygonsController.changePolygons(polygonsToChange); + List polygonIdsToRemove = call.argument("polygonIdsToRemove"); + polygonsController.removePolygons(polygonIdsToRemove); result.success(null); break; } case "polylines#update": { - Object polylinesToAdd = call.argument("polylinesToAdd"); - polylinesController.addPolylines((List) polylinesToAdd); - Object polylinesToChange = call.argument("polylinesToChange"); - polylinesController.changePolylines((List) polylinesToChange); - Object polylineIdsToRemove = call.argument("polylineIdsToRemove"); - polylinesController.removePolylines((List) polylineIdsToRemove); + List polylinesToAdd = call.argument("polylinesToAdd"); + polylinesController.addPolylines(polylinesToAdd); + List polylinesToChange = call.argument("polylinesToChange"); + polylinesController.changePolylines(polylinesToChange); + List polylineIdsToRemove = call.argument("polylineIdsToRemove"); + polylinesController.removePolylines(polylineIdsToRemove); result.success(null); break; } case "circles#update": { - Object circlesToAdd = call.argument("circlesToAdd"); - circlesController.addCircles((List) circlesToAdd); - Object circlesToChange = call.argument("circlesToChange"); - circlesController.changeCircles((List) circlesToChange); - Object circleIdsToRemove = call.argument("circleIdsToRemove"); - circlesController.removeCircles((List) circleIdsToRemove); + List circlesToAdd = call.argument("circlesToAdd"); + circlesController.addCircles(circlesToAdd); + List circlesToChange = call.argument("circlesToChange"); + circlesController.changeCircles(circlesToChange); + List circleIdsToRemove = call.argument("circleIdsToRemove"); + circlesController.removeCircles(circleIdsToRemove); result.success(null); break; } @@ -682,7 +682,8 @@ public void setZoomControlsEnabled(boolean zoomControlsEnabled) { @Override public void setInitialMarkers(Object initialMarkers) { - this.initialMarkers = (List) initialMarkers; + ArrayList markers = (ArrayList) initialMarkers; + this.initialMarkers = markers != null ? new ArrayList<>(markers) : null; if (googleMap != null) { updateInitialMarkers(); } @@ -694,7 +695,8 @@ private void updateInitialMarkers() { @Override public void setInitialPolygons(Object initialPolygons) { - this.initialPolygons = (List) initialPolygons; + ArrayList polygons = (ArrayList) initialPolygons; + this.initialPolygons = polygons != null ? new ArrayList<>(polygons) : null; if (googleMap != null) { updateInitialPolygons(); } @@ -706,7 +708,8 @@ private void updateInitialPolygons() { @Override public void setInitialPolylines(Object initialPolylines) { - this.initialPolylines = (List) initialPolylines; + ArrayList polylines = (ArrayList) initialPolylines; + this.initialPolylines = polylines != null ? new ArrayList<>(polylines) : null; if (googleMap != null) { updateInitialPolylines(); } @@ -718,7 +721,8 @@ private void updateInitialPolylines() { @Override public void setInitialCircles(Object initialCircles) { - this.initialCircles = (List) initialCircles; + ArrayList circles = (ArrayList) initialCircles; + this.initialCircles = circles != null ? new ArrayList<>(circles) : null; if (googleMap != null) { updateInitialCircles(); } diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 2e4ae9dca5d1..06d5fb2f4257 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 1.0.6 +version: 1.0.7 dependencies: flutter: From 576f04abdc21f392987131accdefd271de8885bb Mon Sep 17 00:00:00 2001 From: Juanjo Tugores Date: Fri, 20 Nov 2020 15:49:10 -0600 Subject: [PATCH 021/924] [file_selector] Initial implementation (#3140) Co-authored-by: Jason Panelli --- .../file_selector/file_selector/CHANGELOG.md | 3 + packages/file_selector/file_selector/LICENSE | 25 ++ .../file_selector/file_selector/README.md | 36 +++ .../file_selector/example/.gitignore | 48 ++++ .../file_selector/example/.metadata | 10 + .../file_selector/example/README.md | 8 + .../example/lib/get_directory_page.dart | 65 +++++ .../file_selector/example/lib/home_page.dart | 54 ++++ .../file_selector/example/lib/main.dart | 33 +++ .../example/lib/open_image_page.dart | 75 ++++++ .../lib/open_multiple_images_page.dart | 86 ++++++ .../example/lib/open_text_page.dart | 72 +++++ .../example/lib/save_text_page.dart | 65 +++++ .../file_selector/example/pubspec.yaml | 78 ++++++ .../file_selector/example/web/favicon.png | Bin 0 -> 917 bytes .../example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../file_selector/example/web/index.html | 33 +++ .../file_selector/example/web/manifest.json | 23 ++ .../file_selector/lib/file_selector.dart | 57 ++++ .../file_selector/file_selector/pubspec.yaml | 21 ++ .../test/file_selector_test.dart | 246 ++++++++++++++++++ 22 files changed, 1038 insertions(+) create mode 100644 packages/file_selector/file_selector/CHANGELOG.md create mode 100644 packages/file_selector/file_selector/LICENSE create mode 100644 packages/file_selector/file_selector/README.md create mode 100644 packages/file_selector/file_selector/example/.gitignore create mode 100644 packages/file_selector/file_selector/example/.metadata create mode 100644 packages/file_selector/file_selector/example/README.md create mode 100644 packages/file_selector/file_selector/example/lib/get_directory_page.dart create mode 100644 packages/file_selector/file_selector/example/lib/home_page.dart create mode 100644 packages/file_selector/file_selector/example/lib/main.dart create mode 100644 packages/file_selector/file_selector/example/lib/open_image_page.dart create mode 100644 packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart create mode 100644 packages/file_selector/file_selector/example/lib/open_text_page.dart create mode 100644 packages/file_selector/file_selector/example/lib/save_text_page.dart create mode 100644 packages/file_selector/file_selector/example/pubspec.yaml create mode 100644 packages/file_selector/file_selector/example/web/favicon.png create mode 100644 packages/file_selector/file_selector/example/web/icons/Icon-192.png create mode 100644 packages/file_selector/file_selector/example/web/icons/Icon-512.png create mode 100644 packages/file_selector/file_selector/example/web/index.html create mode 100644 packages/file_selector/file_selector/example/web/manifest.json create mode 100644 packages/file_selector/file_selector/lib/file_selector.dart create mode 100644 packages/file_selector/file_selector/pubspec.yaml create mode 100644 packages/file_selector/file_selector/test/file_selector_test.dart diff --git a/packages/file_selector/file_selector/CHANGELOG.md b/packages/file_selector/file_selector/CHANGELOG.md new file mode 100644 index 000000000000..8dab88a33cef --- /dev/null +++ b/packages/file_selector/file_selector/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.7.0 + +* Initial Open Source release. diff --git a/packages/file_selector/file_selector/LICENSE b/packages/file_selector/file_selector/LICENSE new file mode 100644 index 000000000000..2c91f1438173 --- /dev/null +++ b/packages/file_selector/file_selector/LICENSE @@ -0,0 +1,25 @@ +Copyright 2020 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/packages/file_selector/file_selector/README.md b/packages/file_selector/file_selector/README.md new file mode 100644 index 000000000000..22ae7073ca2d --- /dev/null +++ b/packages/file_selector/file_selector/README.md @@ -0,0 +1,36 @@ +# file_selector + +[![pub package](https://img.shields.io/pub/v/file_selector.svg)](https://pub.dartlang.org/packages/file_selector) + +A Flutter plugin that manages files and interactions with file dialogs. + +## Usage +To use this plugin, add `file_selector` as a [dependency in your pubspec.yaml file](https://flutter.dev/platform-plugins/). + +### Examples +Here are small examples that show you how to use the API. +Please also take a look at our [example][example] app. + +#### Open a single file +``` dart +final typeGroup = XTypeGroup(label: 'images', extensions: ['jpg', 'png']); +final file = await openFile(acceptedTypeGroups: [typeGroup]); +``` + +#### Open multiple files at once +``` dart +final typeGroup = XTypeGroup(label: 'images', extensions: ['jpg', 'png']); +final files = await openFiles(acceptedTypeGroups: [typeGroup]); +``` + +#### Saving a file +```dart +final path = await getSavePath(); +final name = "hello_file_selector.txt"; +final data = Uint8List.fromList("Hello World!".codeUnits); +final mimeType = "text/plain"; +final file = XFile.fromData(data, name: name, mimeType: mimeType); +await file.saveTo(path); +``` + +[example]:./example diff --git a/packages/file_selector/file_selector/example/.gitignore b/packages/file_selector/file_selector/example/.gitignore new file mode 100644 index 000000000000..7abd0753cfc3 --- /dev/null +++ b/packages/file_selector/file_selector/example/.gitignore @@ -0,0 +1,48 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Currently only web supported +android/ +ios/ + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/packages/file_selector/file_selector/example/.metadata b/packages/file_selector/file_selector/example/.metadata new file mode 100644 index 000000000000..897381f2373f --- /dev/null +++ b/packages/file_selector/file_selector/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 7736f3bc90270dcb0480db2ccffbf1d13c28db85 + channel: dev + +project_type: app diff --git a/packages/file_selector/file_selector/example/README.md b/packages/file_selector/file_selector/example/README.md new file mode 100644 index 000000000000..93260dc716b2 --- /dev/null +++ b/packages/file_selector/file_selector/example/README.md @@ -0,0 +1,8 @@ +# file_selector_example + +Demonstrates how to use the file_selector plugin. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](https://flutter.dev/). diff --git a/packages/file_selector/file_selector/example/lib/get_directory_page.dart b/packages/file_selector/file_selector/example/lib/get_directory_page.dart new file mode 100644 index 000000000000..2afc58f246a4 --- /dev/null +++ b/packages/file_selector/file_selector/example/lib/get_directory_page.dart @@ -0,0 +1,65 @@ +import 'package:file_selector/file_selector.dart'; +import 'package:flutter/material.dart'; + +/// Screen that shows an example of getDirectoryPath +class GetDirectoryPage extends StatelessWidget { + void _getDirectoryPath(BuildContext context) async { + final String confirmButtonText = 'Choose'; + final String directoryPath = await getDirectoryPath( + confirmButtonText: confirmButtonText, + ); + await showDialog( + context: context, + builder: (context) => TextDisplay(directoryPath), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Open a text file"), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RaisedButton( + color: Colors.blue, + textColor: Colors.white, + child: Text('Press to ask user to choose a directory'), + onPressed: () => _getDirectoryPath(context), + ), + ], + ), + ), + ); + } +} + +/// Widget that displays a text file in a dialog +class TextDisplay extends StatelessWidget { + /// Directory path + final String directoryPath; + + /// Default Constructor + TextDisplay(this.directoryPath); + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text('Selected Directory'), + content: Scrollbar( + child: SingleChildScrollView( + child: Text(directoryPath), + ), + ), + actions: [ + FlatButton( + child: const Text('Close'), + onPressed: () => Navigator.pop(context), + ), + ], + ); + } +} diff --git a/packages/file_selector/file_selector/example/lib/home_page.dart b/packages/file_selector/file_selector/example/lib/home_page.dart new file mode 100644 index 000000000000..c37d90170f6e --- /dev/null +++ b/packages/file_selector/file_selector/example/lib/home_page.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; + +/// Home Page of the application +class HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('File Selector Demo Home Page'), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RaisedButton( + color: Colors.blue, + textColor: Colors.white, + child: Text('Open a text file'), + onPressed: () => Navigator.pushNamed(context, '/open/text'), + ), + SizedBox(height: 10), + RaisedButton( + color: Colors.blue, + textColor: Colors.white, + child: Text('Open an image'), + onPressed: () => Navigator.pushNamed(context, '/open/image'), + ), + SizedBox(height: 10), + RaisedButton( + color: Colors.blue, + textColor: Colors.white, + child: Text('Open multiple images'), + onPressed: () => Navigator.pushNamed(context, '/open/images'), + ), + SizedBox(height: 10), + RaisedButton( + color: Colors.blue, + textColor: Colors.white, + child: Text('Save a file'), + onPressed: () => Navigator.pushNamed(context, '/save/text'), + ), + SizedBox(height: 10), + RaisedButton( + color: Colors.blue, + textColor: Colors.white, + child: Text('Open a get directory dialog'), + onPressed: () => Navigator.pushNamed(context, '/directory'), + ), + ], + ), + ), + ); + } +} diff --git a/packages/file_selector/file_selector/example/lib/main.dart b/packages/file_selector/file_selector/example/lib/main.dart new file mode 100644 index 000000000000..bb34918e36a3 --- /dev/null +++ b/packages/file_selector/file_selector/example/lib/main.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:example/home_page.dart'; +import 'package:example/get_directory_page.dart'; +import 'package:example/open_text_page.dart'; +import 'package:example/open_image_page.dart'; +import 'package:example/open_multiple_images_page.dart'; +import 'package:example/save_text_page.dart'; + +void main() { + runApp(MyApp()); +} + +/// MyApp is the Main Application +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'File Selector Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: HomePage(), + routes: { + '/open/image': (context) => OpenImagePage(), + '/open/images': (context) => OpenMultipleImagesPage(), + '/open/text': (context) => OpenTextPage(), + '/save/text': (context) => SaveTextPage(), + '/directory': (context) => GetDirectoryPage(), + }, + ); + } +} diff --git a/packages/file_selector/file_selector/example/lib/open_image_page.dart b/packages/file_selector/file_selector/example/lib/open_image_page.dart new file mode 100644 index 000000000000..2821635fb30b --- /dev/null +++ b/packages/file_selector/file_selector/example/lib/open_image_page.dart @@ -0,0 +1,75 @@ +import 'dart:io'; +import 'package:flutter/foundation.dart'; +import 'package:file_selector/file_selector.dart'; +import 'package:flutter/material.dart'; + +/// Screen that shows an example of openFiles +class OpenImagePage extends StatelessWidget { + void _openImageFile(BuildContext context) async { + final XTypeGroup typeGroup = XTypeGroup( + label: 'images', + extensions: ['jpg', 'png'], + ); + final List files = await openFiles(acceptedTypeGroups: [typeGroup]); + final XFile file = files[0]; + final String fileName = file.name; + final String filePath = file.path; + + await showDialog( + context: context, + builder: (context) => ImageDisplay(fileName, filePath), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Open an image"), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RaisedButton( + color: Colors.blue, + textColor: Colors.white, + child: Text('Press to open an image file(png, jpg)'), + onPressed: () => _openImageFile(context), + ), + ], + ), + ), + ); + } +} + +/// Widget that displays a text file in a dialog +class ImageDisplay extends StatelessWidget { + /// Image's name + final String fileName; + + /// Image's path + final String filePath; + + /// Default Constructor + ImageDisplay(this.fileName, this.filePath); + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text(fileName), + // On web the filePath is a blob url + // while on other platforms it is a system path. + content: kIsWeb ? Image.network(filePath) : Image.file(File(filePath)), + actions: [ + FlatButton( + child: const Text('Close'), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ); + } +} diff --git a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart new file mode 100644 index 000000000000..7a27a0c0715f --- /dev/null +++ b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart @@ -0,0 +1,86 @@ +import 'dart:io'; +import 'package:flutter/foundation.dart'; +import 'package:file_selector/file_selector.dart'; +import 'package:flutter/material.dart'; + +/// Screen that shows an example of openFiles +class OpenMultipleImagesPage extends StatelessWidget { + void _openImageFile(BuildContext context) async { + final XTypeGroup jpgsTypeGroup = XTypeGroup( + label: 'JPEGs', + extensions: ['jpg', 'jpeg'], + ); + final XTypeGroup pngTypeGroup = XTypeGroup( + label: 'PNGs', + extensions: ['png'], + ); + final List files = await openFiles(acceptedTypeGroups: [ + jpgsTypeGroup, + pngTypeGroup, + ]); + await showDialog( + context: context, + builder: (context) => MultipleImagesDisplay(files), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Open multiple images"), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RaisedButton( + color: Colors.blue, + textColor: Colors.white, + child: Text('Press to open multiple images (png, jpg)'), + onPressed: () => _openImageFile(context), + ), + ], + ), + ), + ); + } +} + +/// Widget that displays a text file in a dialog +class MultipleImagesDisplay extends StatelessWidget { + /// The files containing the images + final List files; + + /// Default Constructor + MultipleImagesDisplay(this.files); + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text('Gallery'), + // On web the filePath is a blob url + // while on other platforms it is a system path. + content: Center( + child: Row( + children: [ + ...files.map( + (file) => Flexible( + child: kIsWeb + ? Image.network(file.path) + : Image.file(File(file.path))), + ) + ], + ), + ), + actions: [ + FlatButton( + child: const Text('Close'), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ); + } +} diff --git a/packages/file_selector/file_selector/example/lib/open_text_page.dart b/packages/file_selector/file_selector/example/lib/open_text_page.dart new file mode 100644 index 000000000000..4cb3064046fd --- /dev/null +++ b/packages/file_selector/file_selector/example/lib/open_text_page.dart @@ -0,0 +1,72 @@ +import 'package:file_selector/file_selector.dart'; +import 'package:flutter/material.dart'; + +/// Screen that shows an example of openFile +class OpenTextPage extends StatelessWidget { + void _openTextFile(BuildContext context) async { + final XTypeGroup typeGroup = XTypeGroup( + label: 'text', + extensions: ['txt', 'json'], + ); + final XFile file = await openFile(acceptedTypeGroups: [typeGroup]); + final String fileName = file.name; + final String fileContent = await file.readAsString(); + + await showDialog( + context: context, + builder: (context) => TextDisplay(fileName, fileContent), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Open a text file"), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RaisedButton( + color: Colors.blue, + textColor: Colors.white, + child: Text('Press to open a text file (json, txt)'), + onPressed: () => _openTextFile(context), + ), + ], + ), + ), + ); + } +} + +/// Widget that displays a text file in a dialog +class TextDisplay extends StatelessWidget { + /// File's name + final String fileName; + + /// File to display + final String fileContent; + + /// Default Constructor + TextDisplay(this.fileName, this.fileContent); + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text(fileName), + content: Scrollbar( + child: SingleChildScrollView( + child: Text(fileContent), + ), + ), + actions: [ + FlatButton( + child: const Text('Close'), + onPressed: () => Navigator.pop(context), + ), + ], + ); + } +} diff --git a/packages/file_selector/file_selector/example/lib/save_text_page.dart b/packages/file_selector/file_selector/example/lib/save_text_page.dart new file mode 100644 index 000000000000..b70231f5a410 --- /dev/null +++ b/packages/file_selector/file_selector/example/lib/save_text_page.dart @@ -0,0 +1,65 @@ +import 'dart:typed_data'; +import 'package:file_selector/file_selector.dart'; +import 'package:flutter/material.dart'; + +/// Page for showing an example of saving with file_selector +class SaveTextPage extends StatelessWidget { + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _contentController = TextEditingController(); + + void _saveFile() async { + final String path = await getSavePath(); + final String text = _contentController.text; + final String fileName = _nameController.text; + final Uint8List fileData = Uint8List.fromList(text.codeUnits); + final String fileMimeType = 'text/plain'; + final XFile textFile = + XFile.fromData(fileData, mimeType: fileMimeType, name: fileName); + await textFile.saveTo(path); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Save text into a file"), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 300, + child: TextField( + minLines: 1, + maxLines: 12, + controller: _nameController, + decoration: InputDecoration( + hintText: '(Optional) Suggest File Name', + ), + ), + ), + Container( + width: 300, + child: TextField( + minLines: 1, + maxLines: 12, + controller: _contentController, + decoration: InputDecoration( + hintText: 'Enter File Contents', + ), + ), + ), + SizedBox(height: 10), + RaisedButton( + color: Colors.blue, + textColor: Colors.white, + child: Text('Press to save a text file'), + onPressed: () => _saveFile(), + ), + ], + ), + ), + ); + } +} diff --git a/packages/file_selector/file_selector/example/pubspec.yaml b/packages/file_selector/file_selector/example/pubspec.yaml new file mode 100644 index 000000000000..58f0abbf2658 --- /dev/null +++ b/packages/file_selector/file_selector/example/pubspec.yaml @@ -0,0 +1,78 @@ +name: example +description: A new Flutter project. + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + + file_selector: + path: ../ + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^0.1.3 + +dev_dependencies: + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/file_selector/file_selector/example/web/favicon.png b/packages/file_selector/file_selector/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/packages/file_selector/file_selector/example/web/icons/Icon-192.png b/packages/file_selector/file_selector/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/packages/file_selector/file_selector/example/web/icons/Icon-512.png b/packages/file_selector/file_selector/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/packages/file_selector/file_selector/example/web/index.html b/packages/file_selector/file_selector/example/web/index.html new file mode 100644 index 000000000000..9b7a438f823a --- /dev/null +++ b/packages/file_selector/file_selector/example/web/index.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + example + + + + + + + + diff --git a/packages/file_selector/file_selector/example/web/manifest.json b/packages/file_selector/file_selector/example/web/manifest.json new file mode 100644 index 000000000000..8c012917dab7 --- /dev/null +++ b/packages/file_selector/file_selector/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/packages/file_selector/file_selector/lib/file_selector.dart b/packages/file_selector/file_selector/lib/file_selector.dart new file mode 100644 index 000000000000..080eac4460ac --- /dev/null +++ b/packages/file_selector/file_selector/lib/file_selector.dart @@ -0,0 +1,57 @@ +// Copyright 2020 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 'dart:async'; + +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; + +export 'package:file_selector_platform_interface/file_selector_platform_interface.dart' + show XFile, XTypeGroup; + +/// Open file dialog for loading files and return a file path +Future openFile({ + List acceptedTypeGroups, + String initialDirectory, + String confirmButtonText, +}) { + return FileSelectorPlatform.instance.openFile( + acceptedTypeGroups: acceptedTypeGroups, + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText); +} + +/// Open file dialog for loading files and return a list of file paths +Future> openFiles({ + List acceptedTypeGroups, + String initialDirectory, + String confirmButtonText, +}) { + return FileSelectorPlatform.instance.openFiles( + acceptedTypeGroups: acceptedTypeGroups, + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText); +} + +/// Saves File to user's file system +Future getSavePath({ + List acceptedTypeGroups, + String initialDirectory, + String suggestedName, + String confirmButtonText, +}) async { + return FileSelectorPlatform.instance.getSavePath( + acceptedTypeGroups: acceptedTypeGroups, + initialDirectory: initialDirectory, + suggestedName: suggestedName, + confirmButtonText: confirmButtonText); +} + +/// Gets a directory path from a user's file system +Future getDirectoryPath({ + String initialDirectory, + String confirmButtonText, +}) async { + return FileSelectorPlatform.instance.getDirectoryPath( + initialDirectory: initialDirectory, confirmButtonText: confirmButtonText); +} diff --git a/packages/file_selector/file_selector/pubspec.yaml b/packages/file_selector/file_selector/pubspec.yaml new file mode 100644 index 000000000000..5a90f048c314 --- /dev/null +++ b/packages/file_selector/file_selector/pubspec.yaml @@ -0,0 +1,21 @@ +name: file_selector +description: Flutter plugin for opening and saving files. +homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector +version: 0.7.0 + +dependencies: + flutter: + sdk: flutter + file_selector_platform_interface: ^1.0.0 + +dev_dependencies: + flutter_test: + sdk: flutter + test: ^1.3.0 + mockito: ^4.1.1 + plugin_platform_interface: ^1.0.0 + pedantic: ^1.8.0 + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/file_selector/file_selector/test/file_selector_test.dart b/packages/file_selector/file_selector/test/file_selector_test.dart new file mode 100644 index 000000000000..15756cc2b622 --- /dev/null +++ b/packages/file_selector/file_selector/test/file_selector_test.dart @@ -0,0 +1,246 @@ +// Copyright 2020 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_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:file_selector/file_selector.dart'; +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; + +void main() { + MockFileSelector mock; + final initialDirectory = '/home/flutteruser'; + final confirmButtonText = 'Use this profile picture'; + final suggestedName = 'suggested_name'; + final acceptedTypeGroups = [ + XTypeGroup(label: 'documents', mimeTypes: [ + 'application/msword', + 'application/vnd.openxmlformats-officedocument.wordprocessing', + ]), + XTypeGroup(label: 'images', extensions: [ + 'jpg', + 'png', + ]), + ]; + + setUp(() { + mock = MockFileSelector(); + FileSelectorPlatform.instance = mock; + }); + + group('openFile', () { + final expectedFile = XFile('path'); + + test('works', () async { + when(mock.openFile( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + acceptedTypeGroups: acceptedTypeGroups, + )).thenAnswer((_) => Future.value(expectedFile)); + + final file = await openFile( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + acceptedTypeGroups: acceptedTypeGroups, + ); + + expect(file, expectedFile); + }); + + test('works with no arguments', () async { + when(mock.openFile()).thenAnswer((_) => Future.value(expectedFile)); + + final file = await openFile(); + + expect(file, expectedFile); + }); + + test('sets the initial directory', () async { + when(mock.openFile(initialDirectory: initialDirectory)) + .thenAnswer((_) => Future.value(expectedFile)); + + final file = await openFile(initialDirectory: initialDirectory); + expect(file, expectedFile); + }); + + test('sets the button confirmation label', () async { + when(mock.openFile(confirmButtonText: confirmButtonText)) + .thenAnswer((_) => Future.value(expectedFile)); + + final file = await openFile(confirmButtonText: confirmButtonText); + expect(file, expectedFile); + }); + + test('sets the accepted type groups', () async { + when(mock.openFile(acceptedTypeGroups: acceptedTypeGroups)) + .thenAnswer((_) => Future.value(expectedFile)); + + final file = await openFile(acceptedTypeGroups: acceptedTypeGroups); + expect(file, expectedFile); + }); + }); + + group('openFiles', () { + final expectedFiles = [XFile('path')]; + + test('works', () async { + when(mock.openFiles( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + acceptedTypeGroups: acceptedTypeGroups, + )).thenAnswer((_) => Future.value(expectedFiles)); + + final file = await openFiles( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + acceptedTypeGroups: acceptedTypeGroups, + ); + + expect(file, expectedFiles); + }); + + test('works with no arguments', () async { + when(mock.openFiles()).thenAnswer((_) => Future.value(expectedFiles)); + + final files = await openFiles(); + + expect(files, expectedFiles); + }); + + test('sets the initial directory', () async { + when(mock.openFiles(initialDirectory: initialDirectory)) + .thenAnswer((_) => Future.value(expectedFiles)); + + final files = await openFiles(initialDirectory: initialDirectory); + expect(files, expectedFiles); + }); + + test('sets the button confirmation label', () async { + when(mock.openFiles(confirmButtonText: confirmButtonText)) + .thenAnswer((_) => Future.value(expectedFiles)); + + final files = await openFiles(confirmButtonText: confirmButtonText); + expect(files, expectedFiles); + }); + + test('sets the accepted type groups', () async { + when(mock.openFiles(acceptedTypeGroups: acceptedTypeGroups)) + .thenAnswer((_) => Future.value(expectedFiles)); + + final files = await openFiles(acceptedTypeGroups: acceptedTypeGroups); + expect(files, expectedFiles); + }); + }); + + group('getSavePath', () { + final expectedSavePath = '/example/path'; + + test('works', () async { + when(mock.getSavePath( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + acceptedTypeGroups: acceptedTypeGroups, + suggestedName: suggestedName, + )).thenAnswer((_) => Future.value(expectedSavePath)); + + final savePath = await getSavePath( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + acceptedTypeGroups: acceptedTypeGroups, + suggestedName: suggestedName, + ); + + expect(savePath, expectedSavePath); + }); + + test('works with no arguments', () async { + when(mock.getSavePath()) + .thenAnswer((_) => Future.value(expectedSavePath)); + + final savePath = await getSavePath(); + expect(savePath, expectedSavePath); + }); + + test('sets the initial directory', () async { + when(mock.getSavePath(initialDirectory: initialDirectory)) + .thenAnswer((_) => Future.value(expectedSavePath)); + + final savePath = await getSavePath(initialDirectory: initialDirectory); + expect(savePath, expectedSavePath); + }); + + test('sets the button confirmation label', () async { + when(mock.getSavePath(confirmButtonText: confirmButtonText)) + .thenAnswer((_) => Future.value(expectedSavePath)); + + final savePath = await getSavePath(confirmButtonText: confirmButtonText); + expect(savePath, expectedSavePath); + }); + + test('sets the accepted type groups', () async { + when(mock.getSavePath(acceptedTypeGroups: acceptedTypeGroups)) + .thenAnswer((_) => Future.value(expectedSavePath)); + + final savePath = + await getSavePath(acceptedTypeGroups: acceptedTypeGroups); + expect(savePath, expectedSavePath); + }); + + test('sets the suggested name', () async { + when(mock.getSavePath(suggestedName: suggestedName)) + .thenAnswer((_) => Future.value(expectedSavePath)); + + final savePath = await getSavePath(suggestedName: suggestedName); + expect(savePath, expectedSavePath); + }); + }); + + group('getDirectoryPath', () { + final expectedDirectoryPath = '/example/path'; + + test('works', () async { + when(mock.getDirectoryPath( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + )).thenAnswer((_) => Future.value(expectedDirectoryPath)); + + final directoryPath = await getDirectoryPath( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + ); + + expect(directoryPath, expectedDirectoryPath); + }); + + test('works with no arguments', () async { + when(mock.getDirectoryPath()) + .thenAnswer((_) => Future.value(expectedDirectoryPath)); + + final directoryPath = await getDirectoryPath(); + expect(directoryPath, expectedDirectoryPath); + }); + + test('sets the initial directory', () async { + when(mock.getDirectoryPath(initialDirectory: initialDirectory)) + .thenAnswer((_) => Future.value(expectedDirectoryPath)); + + final directoryPath = + await getDirectoryPath(initialDirectory: initialDirectory); + expect(directoryPath, expectedDirectoryPath); + }); + + test('sets the button confirmation label', () async { + when(mock.getDirectoryPath(confirmButtonText: confirmButtonText)) + .thenAnswer((_) => Future.value(expectedDirectoryPath)); + + final directoryPath = + await getDirectoryPath(confirmButtonText: confirmButtonText); + expect(directoryPath, expectedDirectoryPath); + }); + }); +} + +class MockFileSelector extends Mock + with MockPlatformInterfaceMixin + implements FileSelectorPlatform {} From 592b5b27431689336fa4c721a099eedf787aeb56 Mon Sep 17 00:00:00 2001 From: John Ryan Date: Fri, 20 Nov 2020 15:00:15 -0800 Subject: [PATCH 022/924] Fix broken link (#3280) --- packages/integration_test/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/integration_test/README.md b/packages/integration_test/README.md index be08a722bc75..e94cb1e01854 100644 --- a/packages/integration_test/README.md +++ b/packages/integration_test/README.md @@ -42,7 +42,7 @@ Future main() => integrationDriver(); You can also use different driver scripts to customize the behavior of the app under test. For example, `FlutterDriver` can also be parameterized with different [options](https://api.flutter.dev/flutter/flutter_driver/FlutterDriver/connect.html). -See the [extended driver](https://github.com/flutter/plugins/tree/master/packages/integration_test/example/test_driver/integration_test_extended_driver.dart) for an example. +See the [extended driver](https://github.com/flutter/plugins/blob/master/packages/integration_test/example/test_driver/extended_integration_test.dart) for an example. ### Package Structure From 862a551d9895ef9179b9fb7506b89e8f2ea6a918 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Wed, 25 Nov 2020 00:18:06 +0100 Subject: [PATCH 023/924] [file_selector_platform_interface] Migrate to cross_file package (#3286) --- .../CHANGELOG.md | 4 + .../method_channel_file_selector.dart | 1 + .../file_selector_interface.dart | 1 + .../lib/src/types/types.dart | 3 +- .../lib/src/types/x_file/base.dart | 82 ----------- .../lib/src/types/x_file/html.dart | 132 ------------------ .../lib/src/types/x_file/interface.dart | 54 ------- .../lib/src/types/x_file/io.dart | 111 --------------- .../lib/src/types/x_file/x_file.dart | 3 - .../pubspec.yaml | 3 +- .../test/assets/hello.txt | 1 - .../test/x_file_html_test.dart | 108 -------------- .../test/x_file_io_test.dart | 99 ------------- 13 files changed, 9 insertions(+), 593 deletions(-) delete mode 100644 packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/base.dart delete mode 100644 packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/html.dart delete mode 100644 packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/interface.dart delete mode 100644 packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/io.dart delete mode 100644 packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/x_file.dart delete mode 100644 packages/file_selector/file_selector_platform_interface/test/assets/hello.txt delete mode 100644 packages/file_selector/file_selector_platform_interface/test/x_file_html_test.dart delete mode 100644 packages/file_selector/file_selector_platform_interface/test/x_file_io_test.dart diff --git a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md index 3663064a069f..7f1d5732ec9b 100644 --- a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md +++ b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2 + +* Replace locally defined `XFile` types with the versions from the [cross_file](https://pub.dev/packages/cross_file) package. + ## 1.0.1 * Allow type groups that allow any file. diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart b/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart index 8681a1dbffa6..586b1abcae1e 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:cross_file/cross_file.dart'; import 'package:flutter/services.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart b/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart index cf23d5f01eab..e7b32631a58b 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart @@ -4,6 +4,7 @@ import 'dart:async'; +import 'package:cross_file/cross_file.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart index 8848c6751ba3..88dc3c2a5f83 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart @@ -1,3 +1,2 @@ -export 'x_file/x_file.dart'; - +export 'package:cross_file/cross_file.dart'; export 'x_type_group/x_type_group.dart'; diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/base.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/base.dart deleted file mode 100644 index 7ea050ff28db..000000000000 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/base.dart +++ /dev/null @@ -1,82 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -/// The interface for a XFile. -/// -/// A XFile is a container that wraps the path of a selected -/// file by the user and (in some platforms, like web) the bytes -/// with the contents of the file. -/// -/// This class is a very limited subset of dart:io [File], so all -/// the methods should seem familiar. -abstract class XFileBase { - /// Construct a XFile - XFileBase(String path); - - /// Save the XFile at the indicated file path. - void saveTo(String path) async { - throw UnimplementedError('saveTo has not been implemented.'); - } - - /// Get the path of the picked file. - /// - /// This should only be used as a backwards-compatibility clutch - /// for mobile apps, or cosmetic reasons only (to show the user - /// the path they've picked). - /// - /// Accessing the data contained in the picked file by its path - /// is platform-dependant (and won't work on web), so use the - /// byte getters in the XFile instance instead. - String get path { - throw UnimplementedError('.path has not been implemented.'); - } - - /// The name of the file as it was selected by the user in their device. - /// - /// Use only for cosmetic reasons, do not try to use this as a path. - String get name { - throw UnimplementedError('.name has not been implemented.'); - } - - /// For web, it may be necessary for a file to know its MIME type. - String get mimeType { - throw UnimplementedError('.mimeType has not been implemented.'); - } - - /// Get the length of the file. Returns a `Future` that completes with the length in bytes. - Future length() { - throw UnimplementedError('.length() has not been implemented.'); - } - - /// Synchronously read the entire file contents as a string using the given [Encoding]. - /// - /// By default, `encoding` is [utf8]. - /// - /// Throws Exception if the operation fails. - Future readAsString({Encoding encoding = utf8}) { - throw UnimplementedError('readAsString() has not been implemented.'); - } - - /// Synchronously read the entire file contents as a list of bytes. - /// - /// Throws Exception if the operation fails. - Future readAsBytes() { - throw UnimplementedError('readAsBytes() has not been implemented.'); - } - - /// Create a new independent [Stream] for the contents of this file. - /// - /// If `start` is present, the file will be read from byte-offset `start`. Otherwise from the beginning (index 0). - /// - /// 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 openRead([int start, int end]) { - throw UnimplementedError('openRead() has not been implemented.'); - } - - /// Get the last-modified time for the XFile - Future lastModified() { - throw UnimplementedError('openRead() has not been implemented.'); - } -} diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/html.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/html.dart deleted file mode 100644 index fe898eb4ca62..000000000000 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/html.dart +++ /dev/null @@ -1,132 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:http/http.dart' as http show readBytes; -import 'package:meta/meta.dart'; -import 'dart:html'; - -import '../../web_helpers/web_helpers.dart'; -import './base.dart'; - -/// A XFile that works on web. -/// -/// It wraps the bytes of a selected file. -class XFile extends XFileBase { - String path; - - final String mimeType; - final Uint8List _data; - final int _length; - final String name; - final DateTime _lastModified; - Element _target; - - final XFileTestOverrides _overrides; - - bool get _hasTestOverrides => _overrides != null; - - /// Construct a XFile object from its ObjectUrl. - /// - /// Optionally, this can be initialized with `bytes` and `length` - /// so no http requests are performed to retrieve files later. - /// - /// `name` needs to be passed from the outside, since we only have - /// access to it while we create the ObjectUrl. - XFile( - this.path, { - this.mimeType, - this.name, - int length, - Uint8List bytes, - DateTime lastModified, - @visibleForTesting XFileTestOverrides overrides, - }) : _data = bytes, - _length = length, - _overrides = overrides, - _lastModified = lastModified, - super(path); - - /// Construct an XFile from its data - XFile.fromData( - Uint8List bytes, { - this.mimeType, - this.name, - int length, - DateTime lastModified, - this.path, - @visibleForTesting XFileTestOverrides overrides, - }) : _data = bytes, - _length = length, - _overrides = overrides, - _lastModified = lastModified, - super(path) { - if (path == null) { - final blob = (mimeType == null) ? Blob([bytes]) : Blob([bytes], mimeType); - this.path = Url.createObjectUrl(blob); - } - } - - @override - Future lastModified() async { - if (_lastModified != null) { - return Future.value(_lastModified); - } - return null; - } - - Future get _bytes async { - if (_data != null) { - return Future.value(UnmodifiableUint8ListView(_data)); - } - return http.readBytes(path); - } - - @override - Future length() async { - return _length ?? (await _bytes).length; - } - - @override - Future readAsString({Encoding encoding = utf8}) async { - return encoding.decode(await _bytes); - } - - @override - Future readAsBytes() async { - return Future.value(await _bytes); - } - - @override - Stream openRead([int start, int end]) async* { - final bytes = await _bytes; - yield bytes.sublist(start ?? 0, end ?? bytes.length); - } - - /// Saves the data of this XFile at the location indicated by path. - /// For the web implementation, the path variable is ignored. - void saveTo(String path) async { - // Create a DOM container where we can host the anchor. - _target = ensureInitialized('__x_file_dom_element'); - - // Create an tag with the appropriate download attributes and click it - // May be overridden with XFileTestOverrides - final AnchorElement element = - (_hasTestOverrides && _overrides.createAnchorElement != null) - ? _overrides.createAnchorElement(this.path, this.name) - : createAnchorElement(this.path, this.name); - - // Clear the children in our container so we can add an element to click - _target.children.clear(); - addElementToContainerAndClick(_target, element); - } -} - -/// Overrides some functions to allow testing -@visibleForTesting -class XFileTestOverrides { - /// For overriding the creation of the file input element. - Element Function(String href, String suggestedName) createAnchorElement; - - /// Default constructor for overrides - XFileTestOverrides({this.createAnchorElement}); -} diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/interface.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/interface.dart deleted file mode 100644 index f5fe388e0899..000000000000 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/interface.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'dart:typed_data'; -import 'package:meta/meta.dart'; - -import './base.dart'; - -/// A XFile is a cross-platform, simplified File abstraction. -/// -/// It wraps the bytes of a selected file, and its (platform-dependant) path. -class XFile extends XFileBase { - /// Construct a XFile object from its path. - /// - /// Optionally, this can be initialized with `bytes` and `length` - /// so no http requests are performed to retrieve data later. - /// - /// `name` may be passed from the outside, for those cases where the effective - /// `path` of the file doesn't match what the user sees when selecting it - /// (like in web) - XFile( - String path, { - String mimeType, - String name, - int length, - Uint8List bytes, - DateTime lastModified, - @visibleForTesting XFileTestOverrides overrides, - }) : super(path) { - throw UnimplementedError( - 'XFile is not available in your current platform.'); - } - - /// Construct a XFile object from its data - XFile.fromData( - Uint8List bytes, { - String mimeType, - String name, - int length, - DateTime lastModified, - String path, - @visibleForTesting XFileTestOverrides overrides, - }) : super(path) { - throw UnimplementedError( - 'XFile is not available in your current platform.'); - } -} - -/// Overrides some functions of XFile for testing purposes -@visibleForTesting -class XFileTestOverrides { - /// For overriding the creation of the file input element. - dynamic Function(String href, String suggestedName) createAnchorElement; - - /// Default constructor for overrides - XFileTestOverrides({this.createAnchorElement}); -} diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/io.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/io.dart deleted file mode 100644 index 753732df2811..000000000000 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/io.dart +++ /dev/null @@ -1,111 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; - -import './base.dart'; - -/// A XFile backed by a dart:io File. -class XFile extends XFileBase { - final File _file; - final String mimeType; - final DateTime _lastModified; - int _length; - - final Uint8List _bytes; - - /// Construct a XFile object backed by a dart:io File. - XFile( - String path, { - this.mimeType, - String name, - int length, - Uint8List bytes, - DateTime lastModified, - }) : _file = File(path), - _bytes = null, - _lastModified = lastModified, - super(path); - - /// Construct an XFile from its data - XFile.fromData( - Uint8List bytes, { - this.mimeType, - String path, - String name, - int length, - DateTime lastModified, - }) : _bytes = bytes, - _file = File(path ?? ''), - _length = length, - _lastModified = lastModified, - super(path) { - if (length == null) { - _length = bytes.length; - } - } - - @override - Future lastModified() { - if (_lastModified != null) { - return Future.value(_lastModified); - } - return _file.lastModified(); - } - - @override - void saveTo(String path) async { - File fileToSave = File(path); - await fileToSave.writeAsBytes(_bytes ?? (await readAsBytes())); - await fileToSave.create(); - } - - @override - String get path { - return _file.path; - } - - @override - String get name { - return _file.path.split(Platform.pathSeparator).last; - } - - @override - Future length() { - if (_length != null) { - return Future.value(_length); - } - return _file.length(); - } - - @override - Future readAsString({Encoding encoding = utf8}) { - if (_bytes != null) { - return Future.value(String.fromCharCodes(_bytes)); - } - return _file.readAsString(encoding: encoding); - } - - @override - Future readAsBytes() { - if (_bytes != null) { - return Future.value(_bytes); - } - return _file.readAsBytes(); - } - - Stream _getBytes(int start, int end) async* { - final bytes = _bytes; - yield bytes.sublist(start ?? 0, end ?? bytes.length); - } - - @override - Stream openRead([int start, int end]) { - if (_bytes != null) { - return _getBytes(start, end); - } else { - return _file - .openRead(start ?? 0, end) - .map((chunk) => Uint8List.fromList(chunk)); - } - } -} diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/x_file.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/x_file.dart deleted file mode 100644 index 4545c605875a..000000000000 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_file/x_file.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'interface.dart' - if (dart.library.html) 'html.dart' - if (dart.library.io) 'io.dart'; diff --git a/packages/file_selector/file_selector_platform_interface/pubspec.yaml b/packages/file_selector/file_selector_platform_interface/pubspec.yaml index ca5c2bd189ae..a0a3d28922fe 100644 --- a/packages/file_selector/file_selector_platform_interface/pubspec.yaml +++ b/packages/file_selector/file_selector_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the file_selector plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_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.0.1 +version: 1.0.2 dependencies: flutter: @@ -11,6 +11,7 @@ dependencies: meta: ^1.0.5 http: ^0.12.0+1 plugin_platform_interface: ^1.0.1 + cross_file: ^0.1.0 dev_dependencies: test: ^1.15.0 diff --git a/packages/file_selector/file_selector_platform_interface/test/assets/hello.txt b/packages/file_selector/file_selector_platform_interface/test/assets/hello.txt deleted file mode 100644 index 5dd01c177f5d..000000000000 --- a/packages/file_selector/file_selector_platform_interface/test/assets/hello.txt +++ /dev/null @@ -1 +0,0 @@ -Hello, world! \ No newline at end of file diff --git a/packages/file_selector/file_selector_platform_interface/test/x_file_html_test.dart b/packages/file_selector/file_selector_platform_interface/test/x_file_html_test.dart deleted file mode 100644 index f888a0486ca7..000000000000 --- a/packages/file_selector/file_selector_platform_interface/test/x_file_html_test.dart +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2020 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. - -@TestOn('chrome') // Uses web-only Flutter SDK - -import 'dart:convert'; -import 'dart:html' as html; -import 'dart:typed_data'; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; - -import 'dart:html'; - -final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = utf8.encode(expectedStringContents); -final html.File textFile = html.File([bytes], 'hello.txt'); -final String textFileUrl = html.Url.createObjectUrl(textFile); - -void main() { - group('Create with an objectUrl', () { - final file = XFile(textFileUrl); - - test('Can be read as a string', () async { - expect(await file.readAsString(), equals(expectedStringContents)); - }); - test('Can be read as bytes', () async { - expect(await file.readAsBytes(), equals(bytes)); - }); - - test('Can be read as a stream', () async { - expect(await file.openRead().first, equals(bytes)); - }); - - test('Stream can be sliced', () async { - expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); - }); - }); - - group('Create from data', () { - final file = XFile.fromData(bytes); - - test('Can be read as a string', () async { - expect(await file.readAsString(), equals(expectedStringContents)); - }); - test('Can be read as bytes', () async { - expect(await file.readAsBytes(), equals(bytes)); - }); - - test('Can be read as a stream', () async { - expect(await file.openRead().first, equals(bytes)); - }); - - test('Stream can be sliced', () async { - expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); - }); - }); - - group('saveTo(..)', () { - final String xFileDomElementId = '__x_file_dom_element'; - - group('XFile saveTo(..)', () { - test('creates a DOM container', () async { - XFile file = XFile.fromData(bytes); - - await file.saveTo(''); - - final container = querySelector('#${xFileDomElementId}'); - - expect(container, isNotNull); - }); - - test('create anchor element', () async { - XFile file = XFile.fromData(bytes, name: textFile.name); - - await file.saveTo('path'); - - final container = querySelector('#${xFileDomElementId}'); - final AnchorElement element = container?.children?.firstWhere( - (element) => element.tagName == 'A', - orElse: () => null); - - expect(element, isNotNull); - expect(element.href, file.path); - expect(element.download, file.name); - }); - - test('anchor element is clicked', () async { - final mockAnchor = AnchorElement(); - - XFileTestOverrides overrides = XFileTestOverrides( - createAnchorElement: (_, __) => mockAnchor, - ); - - XFile file = - XFile.fromData(bytes, name: textFile.name, overrides: overrides); - - bool clicked = false; - mockAnchor.onClick.listen((event) => clicked = true); - - await file.saveTo('path'); - - expect(clicked, true); - }); - }); - }); -} diff --git a/packages/file_selector/file_selector_platform_interface/test/x_file_io_test.dart b/packages/file_selector/file_selector_platform_interface/test/x_file_io_test.dart deleted file mode 100644 index b669324462b2..000000000000 --- a/packages/file_selector/file_selector_platform_interface/test/x_file_io_test.dart +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2020 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. - -@TestOn('vm') // Uses dart:io - -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; - -// Please note that executing this test with command -// `flutter test test/x_file_io_test.dart` will set the directory -// to ./file_selector_platform_interface. -// -// This will cause our hello.txt file to be not be found. Please -// execute this test with `flutter test` or change the path prefix -// to ./test/assets/ -// -// https://github.com/flutter/flutter/issues/20907 - -final pathPrefix = './assets/'; -final path = pathPrefix + 'hello.txt'; -final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = utf8.encode(expectedStringContents); -final File textFile = File(path); -final String textFilePath = textFile.path; - -void main() { - group('Create with a path', () { - final file = XFile(textFilePath); - - test('Can be read as a string', () async { - expect(await file.readAsString(), equals(expectedStringContents)); - }); - test('Can be read as bytes', () async { - expect(await file.readAsBytes(), equals(bytes)); - }); - - test('Can be read as a stream', () async { - expect(await file.openRead().first, equals(bytes)); - }); - - test('Stream can be sliced', () async { - expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); - }); - - test('saveTo(..) creates file', () async { - File removeBeforeTest = File(pathPrefix + 'newFilePath.txt'); - if (removeBeforeTest.existsSync()) { - await removeBeforeTest.delete(); - } - - await file.saveTo(pathPrefix + 'newFilePath.txt'); - File newFile = File(pathPrefix + 'newFilePath.txt'); - - expect(newFile.existsSync(), isTrue); - expect(newFile.readAsStringSync(), 'Hello, world!'); - - await newFile.delete(); - }); - }); - - group('Create with data', () { - final file = XFile.fromData(bytes); - - test('Can be read as a string', () async { - expect(await file.readAsString(), equals(expectedStringContents)); - }); - test('Can be read as bytes', () async { - expect(await file.readAsBytes(), equals(bytes)); - }); - - test('Can be read as a stream', () async { - expect(await file.openRead().first, equals(bytes)); - }); - - test('Stream can be sliced', () async { - expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); - }); - - test('Function saveTo(..) creates file', () async { - File removeBeforeTest = File(pathPrefix + 'newFileData.txt'); - if (removeBeforeTest.existsSync()) { - await removeBeforeTest.delete(); - } - - await file.saveTo(pathPrefix + 'newFileData.txt'); - File newFile = File(pathPrefix + 'newFileData.txt'); - - expect(newFile.existsSync(), isTrue); - expect(newFile.readAsStringSync(), 'Hello, world!'); - - await newFile.delete(); - }); - }); -} From ba035e9e58bea8e5eaf0a15726a00a5fa4618fda Mon Sep 17 00:00:00 2001 From: Jia Hao Date: Wed, 25 Nov 2020 08:53:05 +0800 Subject: [PATCH 024/924] Use testWidgets instead of test to fix failures not surfacing on CI (#3279) --- packages/integration_test/CHANGELOG.md | 4 ++++ packages/integration_test/README.md | 2 ++ packages/integration_test/pubspec.yaml | 2 +- .../shared_preferences/shared_preferences/CHANGELOG.md | 4 ++++ .../example/integration_test/shared_preferences_test.dart | 8 ++++---- .../shared_preferences/shared_preferences/pubspec.yaml | 2 +- .../shared_preferences_linux/CHANGELOG.md | 4 ++++ .../example/integration_test/shared_preferences_test.dart | 8 ++++---- .../shared_preferences_linux/pubspec.yaml | 2 +- .../shared_preferences_windows/CHANGELOG.md | 4 ++++ .../example/integration_test/shared_preferences_test.dart | 8 ++++---- .../shared_preferences_windows/pubspec.yaml | 2 +- packages/url_launcher/url_launcher/CHANGELOG.md | 4 ++++ .../example/integration_test/url_launcher_test.dart | 2 +- packages/url_launcher/url_launcher/pubspec.yaml | 2 +- packages/url_launcher/url_launcher_linux/CHANGELOG.md | 4 ++++ .../example/integration_test/url_launcher_test.dart | 2 +- packages/url_launcher/url_launcher_linux/pubspec.yaml | 2 +- packages/url_launcher/url_launcher_macos/CHANGELOG.md | 4 ++++ .../example/integration_test/url_launcher_test.dart | 2 +- packages/url_launcher/url_launcher_macos/pubspec.yaml | 2 +- packages/url_launcher/url_launcher_windows/CHANGELOG.md | 4 ++++ .../example/integration_test/url_launcher_test.dart | 2 +- packages/url_launcher/url_launcher_windows/pubspec.yaml | 2 +- 24 files changed, 58 insertions(+), 24 deletions(-) diff --git a/packages/integration_test/CHANGELOG.md b/packages/integration_test/CHANGELOG.md index 534d7063db6c..a46fd4eab8b2 100644 --- a/packages/integration_test/CHANGELOG.md +++ b/packages/integration_test/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.3 + +* Update README to mention that only `testWidgets` is supported for declaring tests. + ## 0.9.2+2 * Broaden the constraint on vm_service. diff --git a/packages/integration_test/README.md b/packages/integration_test/README.md index e94cb1e01854..676041eefae5 100644 --- a/packages/integration_test/README.md +++ b/packages/integration_test/README.md @@ -14,6 +14,8 @@ Create a `integration_test/` directory for your package. In this directory, create a `_test.dart`, using the following as a starting point to make assertions. +Note: You should only use `testWidgets` to declare your tests, or errors will not be reported correctly. + ```dart import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index 337fc55b11bf..94839dbcbb9a 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -1,6 +1,6 @@ name: integration_test description: Runs tests that use the flutter_test API as integration tests. -version: 0.9.2+2 +version: 0.9.3 homepage: https://github.com/flutter/plugins/tree/master/packages/integration_test environment: diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 64a74e4ac684..d86588b33098 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.13 + +* Update integration test examples to use `testWidgets` instead of `test`. + ## 0.5.12+4 * Remove unused `test` dependency. diff --git a/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart index 0d49ed95dd2d..e43d4e3ae0c2 100644 --- a/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart @@ -33,7 +33,7 @@ void main() { preferences.clear(); }); - test('reading', () async { + testWidgets('reading', (WidgetTester _) async { expect(preferences.get('String'), isNull); expect(preferences.get('bool'), isNull); expect(preferences.get('int'), isNull); @@ -46,7 +46,7 @@ void main() { expect(preferences.getStringList('List'), isNull); }); - test('writing', () async { + testWidgets('writing', (WidgetTester _) async { await Future.wait(>[ preferences.setString('String', kTestValues2['flutter.String']), preferences.setBool('bool', kTestValues2['flutter.bool']), @@ -61,7 +61,7 @@ void main() { expect(preferences.getStringList('List'), kTestValues2['flutter.List']); }); - test('removing', () async { + testWidgets('removing', (WidgetTester _) async { const String key = 'testKey'; await preferences.setString(key, kTestValues['flutter.String']); await preferences.setBool(key, kTestValues['flutter.bool']); @@ -72,7 +72,7 @@ void main() { expect(preferences.get('testKey'), isNull); }); - test('clearing', () async { + testWidgets('clearing', (WidgetTester _) async { await preferences.setString('String', kTestValues['flutter.String']); await preferences.setBool('bool', kTestValues['flutter.bool']); await preferences.setInt('int', kTestValues['flutter.int']); diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index c09e2c64d7f9..8897ee7c78fe 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/shared_prefere # 0.5.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.5.12+4 +version: 0.5.13 flutter: plugin: diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md index dd67393b07b0..6a0a0414086b 100644 --- a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.3 + +* Update integration test examples to use `testWidgets` instead of `test`. + ## 0.0.2+4 * Remove unused `test` dependency. diff --git a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart index 0d49ed95dd2d..e43d4e3ae0c2 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart @@ -33,7 +33,7 @@ void main() { preferences.clear(); }); - test('reading', () async { + testWidgets('reading', (WidgetTester _) async { expect(preferences.get('String'), isNull); expect(preferences.get('bool'), isNull); expect(preferences.get('int'), isNull); @@ -46,7 +46,7 @@ void main() { expect(preferences.getStringList('List'), isNull); }); - test('writing', () async { + testWidgets('writing', (WidgetTester _) async { await Future.wait(>[ preferences.setString('String', kTestValues2['flutter.String']), preferences.setBool('bool', kTestValues2['flutter.bool']), @@ -61,7 +61,7 @@ void main() { expect(preferences.getStringList('List'), kTestValues2['flutter.List']); }); - test('removing', () async { + testWidgets('removing', (WidgetTester _) async { const String key = 'testKey'; await preferences.setString(key, kTestValues['flutter.String']); await preferences.setBool(key, kTestValues['flutter.bool']); @@ -72,7 +72,7 @@ void main() { expect(preferences.get('testKey'), isNull); }); - test('clearing', () async { + testWidgets('clearing', (WidgetTester _) async { await preferences.setString('String', kTestValues['flutter.String']); await preferences.setBool('bool', kTestValues['flutter.bool']); await preferences.setInt('int', kTestValues['flutter.int']); diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml index 380cee9efb1c..2548ca1f7965 100644 --- a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: shared_preferences_linux description: Linux implementation of the shared_preferences plugin -version: 0.0.2+4 +version: 0.0.3 homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux flutter: diff --git a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md index 8604db297ca6..ee7b36884237 100644 --- a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2 + +* Update integration test examples to use `testWidgets` instead of `test`. + ## 0.0.1+3 * Remove unused `test` dependency. diff --git a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart index 44c8129e9405..016a21f70fe3 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart @@ -37,7 +37,7 @@ void main() { preferences.clear(); }); - test('reading', () async { + testWidgets('reading', (WidgetTester _) async { final Map values = await preferences.getAll(); expect(values['String'], isNull); expect(values['bool'], isNull); @@ -46,7 +46,7 @@ void main() { expect(values['List'], isNull); }); - test('writing', () async { + testWidgets('writing', (WidgetTester _) async { await Future.wait(>[ preferences.setValue( 'String', 'String', kTestValues2['flutter.String']), @@ -64,7 +64,7 @@ void main() { expect(values['List'], kTestValues2['flutter.List']); }); - test('removing', () async { + testWidgets('removing', (WidgetTester _) async { const String key = 'testKey'; await preferences.setValue('String', key, kTestValues['flutter.String']); await preferences.setValue('Bool', key, kTestValues['flutter.bool']); @@ -77,7 +77,7 @@ void main() { expect(values[key], isNull); }); - test('clearing', () async { + testWidgets('clearing', (WidgetTester _) async { await preferences.setValue( 'String', 'String', kTestValues['flutter.String']); await preferences.setValue('Bool', 'bool', kTestValues['flutter.bool']); diff --git a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml index 0de70737bc19..32d4cb5c242c 100644 --- a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: shared_preferences_windows description: Windows implementation of shared_preferences homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_windows -version: 0.0.1+3 +version: 0.0.2 flutter: plugin: diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 832c0c62f553..72a0cc92e37a 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.7.11 + +* Update integration test examples to use `testWidgets` instead of `test`. + ## 5.7.10 * Update Dart SDK constraint in example. diff --git a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart index 9fb5eaa34b4c..4c0f5031ee6b 100644 --- a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart @@ -12,7 +12,7 @@ import 'package:url_launcher/url_launcher.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - test('canLaunch', () async { + testWidgets('canLaunch', (WidgetTester _) async { expect(await canLaunch('randomstring'), false); // Generally all devices should have some default browser. diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 7fa97388ef91..4d5e3a7cb0bd 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 5.7.10 +version: 5.7.11 flutter: plugin: diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md index e0a01ec629f5..1b4041fe4c73 100644 --- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2 + +* Update integration test examples to use `testWidgets` instead of `test`. + ## 0.0.1+4 * Update Dart SDK constraint in example. diff --git a/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart index 0b25516c2a29..d11ddb49966b 100644 --- a/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart @@ -9,7 +9,7 @@ import 'package:url_launcher/url_launcher.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - test('canLaunch', () async { + testWidgets('canLaunch', (WidgetTester _) async { expect(await canLaunch('randomstring'), false); // Generally all devices should have some default browser. diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml index 16448e4020e5..d231bf98476f 100644 --- a/packages/url_launcher/url_launcher_linux/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: url_launcher_linux description: Linux implementation of the url_launcher plugin. -version: 0.0.1+4 +version: 0.0.2 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux flutter: diff --git a/packages/url_launcher/url_launcher_macos/CHANGELOG.md b/packages/url_launcher/url_launcher_macos/CHANGELOG.md index 190aa2887353..9462960ad45e 100644 --- a/packages/url_launcher/url_launcher_macos/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2 + +* Update integration test examples to use `testWidgets` instead of `test`. + # 0.0.1+9 * Update Dart SDK constraint in example. diff --git a/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart index 676b78c3bbfb..3e8d34c0b258 100644 --- a/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart @@ -9,7 +9,7 @@ import 'package:url_launcher/url_launcher.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - test('canLaunch', () async { + testWidgets('canLaunch', (WidgetTester _) async { expect(await canLaunch('randomstring'), false); // Generally all devices should have some default browser. diff --git a/packages/url_launcher/url_launcher_macos/pubspec.yaml b/packages/url_launcher/url_launcher_macos/pubspec.yaml index 1a77bc7aeab3..1a14e6bc9bb9 100644 --- a/packages/url_launcher/url_launcher_macos/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the url_launcher plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.1+9 +version: 0.0.2 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos flutter: diff --git a/packages/url_launcher/url_launcher_windows/CHANGELOG.md b/packages/url_launcher/url_launcher_windows/CHANGELOG.md index 3bf040f964e6..ca4718813608 100644 --- a/packages/url_launcher/url_launcher_windows/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2 + +* Update integration test examples to use `testWidgets` instead of `test`. + ## 0.0.1+3 * Update Dart SDK constraint in example. diff --git a/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart index 7a33e00fec0a..2617150348ee 100644 --- a/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart @@ -9,7 +9,7 @@ import 'package:url_launcher_platform_interface/url_launcher_platform_interface. void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - test('canLaunch', () async { + testWidgets('canLaunch', (WidgetTester _) async { UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; expect(await launcher.canLaunch('randomstring'), false); diff --git a/packages/url_launcher/url_launcher_windows/pubspec.yaml b/packages/url_launcher/url_launcher_windows/pubspec.yaml index dd7423d017f8..f543e7aea2fd 100644 --- a/packages/url_launcher/url_launcher_windows/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/pubspec.yaml @@ -3,7 +3,7 @@ description: Windows implementation of the url_launcher plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.1+3 +version: 0.0.2 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows flutter: From 488b94684dbf87523a47ce7a392e2f97bf63e721 Mon Sep 17 00:00:00 2001 From: rh-id <58564005+rh-id@users.noreply.github.com> Date: Tue, 1 Dec 2020 00:50:08 +0700 Subject: [PATCH 025/924] [android_alarm_manager] fix AndroidManifest.xml for android lint issue "XML tag has empty body" (#3288) --- packages/android_alarm_manager/README.md | 2 +- .../example/android/app/src/main/AndroidManifest.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/android_alarm_manager/README.md b/packages/android_alarm_manager/README.md index e7c7f6ee2713..9d245e5edc20 100644 --- a/packages/android_alarm_manager/README.md +++ b/packages/android_alarm_manager/README.md @@ -36,7 +36,7 @@ Next, within the `` tags, add: android:name="io.flutter.plugins.androidalarmmanager.RebootBroadcastReceiver" android:enabled="false"> - + diff --git a/packages/android_alarm_manager/example/android/app/src/main/AndroidManifest.xml b/packages/android_alarm_manager/example/android/app/src/main/AndroidManifest.xml index 356c10f45651..2a9dc331ebf1 100644 --- a/packages/android_alarm_manager/example/android/app/src/main/AndroidManifest.xml +++ b/packages/android_alarm_manager/example/android/app/src/main/AndroidManifest.xml @@ -41,7 +41,7 @@ android:name="io.flutter.plugins.androidalarmmanager.RebootBroadcastReceiver" android:enabled="false"> - + Date: Wed, 2 Dec 2020 09:28:13 -0800 Subject: [PATCH 026/924] bump integration test to 1.0.0 (#3295) --- packages/integration_test/CHANGELOG.md | 4 ++++ packages/integration_test/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/integration_test/CHANGELOG.md b/packages/integration_test/CHANGELOG.md index a46fd4eab8b2..8c6f7abefca5 100644 --- a/packages/integration_test/CHANGELOG.md +++ b/packages/integration_test/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0 + +* Public stable release of plugin. + ## 0.9.3 * Update README to mention that only `testWidgets` is supported for declaring tests. diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index 94839dbcbb9a..2daf3e543827 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -1,6 +1,6 @@ name: integration_test description: Runs tests that use the flutter_test API as integration tests. -version: 0.9.3 +version: 1.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/integration_test environment: From b3e6d1d38a7c7b6b9e0b78337a5ad54536a89af6 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 3 Dec 2020 12:18:30 -0800 Subject: [PATCH 027/924] [camera] Support Android 30 (#3299) --- packages/camera/camera/CHANGELOG.md | 4 ++ .../io/flutter/plugins/camera/Camera.java | 46 +++++++++++++++++-- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index c9f9dd0f8c58..b07e3b86244d 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.8+17 + +* Added Android 30 support. + ## 0.5.8+16 * Moved package to camera/camera subdir, to allow for federated implementations. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 2384393c7d2b..9cf111b9ee69 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -4,6 +4,7 @@ import static io.flutter.plugins.camera.CameraUtils.computeBestPreviewSize; import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.graphics.ImageFormat; @@ -16,12 +17,16 @@ import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.OutputConfiguration; +import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.CamcorderProfile; import android.media.Image; import android.media.ImageReader; import android.media.MediaRecorder; import android.os.Build; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; import android.util.Size; import android.view.OrientationEventListener; import android.view.Surface; @@ -39,6 +44,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Executors; public class Camera { private final SurfaceTextureEntry flutterTexture; @@ -325,12 +331,42 @@ public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession } }; - // Collect all surfaces we want to render to. - List surfaceList = new ArrayList<>(); - surfaceList.add(flutterSurface); - surfaceList.addAll(remainingSurfaces); // Start the session - cameraDevice.createCaptureSession(surfaceList, callback, null); + if (VERSION.SDK_INT >= VERSION_CODES.P) { + // Collect all surfaces we want to render to. + List configs = new ArrayList<>(); + configs.add(new OutputConfiguration(flutterSurface)); + for (Surface surface : remainingSurfaces) { + configs.add(new OutputConfiguration(surface)); + } + createCaptureSessionWithSessionConfig(configs, callback); + } else { + // Collect all surfaces we want to render to. + List surfaceList = new ArrayList<>(); + surfaceList.add(flutterSurface); + surfaceList.addAll(remainingSurfaces); + createCaptureSession(surfaceList, callback); + } + } + + @TargetApi(VERSION_CODES.P) + private void createCaptureSessionWithSessionConfig( + List outputConfigs, CameraCaptureSession.StateCallback callback) + throws CameraAccessException { + cameraDevice.createCaptureSession( + new SessionConfiguration( + SessionConfiguration.SESSION_REGULAR, + outputConfigs, + Executors.newSingleThreadExecutor(), + callback)); + } + + @TargetApi(VERSION_CODES.LOLLIPOP) + @SuppressWarnings("deprecation") + private void createCaptureSession( + List surfaces, CameraCaptureSession.StateCallback callback) + throws CameraAccessException { + cameraDevice.createCaptureSession(surfaces, callback, null); } public void startVideoRecording(String filePath, Result result) { diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 7088faf227aa..f2151fc21c73 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.5.8+16 +version: 0.5.8+17 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 9fef1c7f289caa81d683cdb5c7a5fb006fc840e5 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Fri, 4 Dec 2020 08:50:27 +0100 Subject: [PATCH 028/924] [camera] Add `camera_platform_interface` package (#3253) * Make sure only camera_platform_interface has updates * add dev dependency to async package * refactored import to package import * Fix formatting issues --- .../camera_platform_interface/CHANGELOG.md | 3 + .../camera/camera_platform_interface/LICENSE | 25 + .../camera_platform_interface/README.md | 26 + .../lib/camera_platform_interface.dart | 10 + .../lib/src/events/camera_event.dart | 198 +++++++ .../method_channel/method_channel_camera.dart | 239 +++++++++ .../platform_interface/camera_platform.dart | 120 +++++ .../lib/src/types/camera_description.dart | 52 ++ .../lib/src/types/camera_exception.dart | 20 + .../lib/src/types/resolution_preset.dart | 26 + .../lib/src/types/types.dart | 7 + .../lib/src/utils/utils.dart | 14 + .../camera_platform_interface/pubspec.yaml | 25 + .../test/camera_platform_interface_test.dart | 229 ++++++++ .../test/events/camera_event_test.dart | 252 +++++++++ .../method_channel_camera_test.dart | 491 ++++++++++++++++++ .../test/types/camera_description_test.dart | 113 ++++ .../test/types/camera_exception_test.dart | 28 + .../test/types/resolution_preset_test.dart | 25 + .../test/utils/method_channel_mock.dart | 38 ++ .../test/utils/utils_test.dart | 33 ++ 21 files changed, 1974 insertions(+) create mode 100644 packages/camera/camera_platform_interface/CHANGELOG.md create mode 100644 packages/camera/camera_platform_interface/LICENSE create mode 100644 packages/camera/camera_platform_interface/README.md create mode 100644 packages/camera/camera_platform_interface/lib/camera_platform_interface.dart create mode 100644 packages/camera/camera_platform_interface/lib/src/events/camera_event.dart create mode 100644 packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart create mode 100644 packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart create mode 100644 packages/camera/camera_platform_interface/lib/src/types/camera_description.dart create mode 100644 packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart create mode 100644 packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart create mode 100644 packages/camera/camera_platform_interface/lib/src/types/types.dart create mode 100644 packages/camera/camera_platform_interface/lib/src/utils/utils.dart create mode 100644 packages/camera/camera_platform_interface/pubspec.yaml create mode 100644 packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart create mode 100644 packages/camera/camera_platform_interface/test/events/camera_event_test.dart create mode 100644 packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart create mode 100644 packages/camera/camera_platform_interface/test/types/camera_description_test.dart create mode 100644 packages/camera/camera_platform_interface/test/types/camera_exception_test.dart create mode 100644 packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart create mode 100644 packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart create mode 100644 packages/camera/camera_platform_interface/test/utils/utils_test.dart diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md new file mode 100644 index 000000000000..75d169ea1d6a --- /dev/null +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial open-source release diff --git a/packages/camera/camera_platform_interface/LICENSE b/packages/camera/camera_platform_interface/LICENSE new file mode 100644 index 000000000000..a6d6c0749818 --- /dev/null +++ b/packages/camera/camera_platform_interface/LICENSE @@ -0,0 +1,25 @@ +Copyright 2017 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/camera/camera_platform_interface/README.md b/packages/camera/camera_platform_interface/README.md new file mode 100644 index 000000000000..43be651935b5 --- /dev/null +++ b/packages/camera/camera_platform_interface/README.md @@ -0,0 +1,26 @@ +# camera_platform_interface + +A common platform interface for the [`camera`][1] plugin. + +This interface allows platform-specific implementations of the `camera` +plugin, as well as the plugin itself, to ensure they are supporting the +same interface. + +# Usage + +To implement a new platform-specific implementation of `camera`, extend +[`CameraPlatform`][2] with an implementation that performs the +platform-specific behavior, and when you register your plugin, set the default +`CameraPlatform` by calling +`CameraPlatform.instance = MyPlatformCamera()`. + +# Note on breaking changes + +Strongly prefer non-breaking changes (such as adding a method to the interface) +over breaking changes for this package. + +See https://flutter.dev/go/platform-interface-breaking-changes for a discussion +on why a less-clean interface is preferable to a breaking change. + +[1]: ../camera +[2]: lib/camera_platform_interface.dart diff --git a/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart b/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart new file mode 100644 index 000000000000..eaa14da45a5e --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart @@ -0,0 +1,10 @@ +// Copyright 2018 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. + +export 'src/events/camera_event.dart'; +export 'src/platform_interface/camera_platform.dart'; +export 'src/types/types.dart'; + +/// Expose XFile +export 'package:cross_file/cross_file.dart'; diff --git a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart new file mode 100644 index 000000000000..ab3d45545f23 --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart @@ -0,0 +1,198 @@ +// Copyright 2019 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. + +/// Generic Event coming from the native side of Camera. +/// +/// All [CameraEvent]s contain the `cameraId` that originated the event. This +/// should never be `null`. +/// +/// This class is used as a base class for all the events that might be +/// triggered from a Camera, but it is never used directly as an event type. +/// +/// Do NOT instantiate new events like `CameraEvent(cameraId)` directly, +/// use a specific class instead: +/// +/// Do `class NewEvent extend CameraEvent` when creating your own events. +/// See below for examples: `CameraClosingEvent`, `CameraErrorEvent`... +/// These events are more semantic and more pleasant to use than raw generics. +/// They can be (and in fact, are) filtered by the `instanceof`-operator. +abstract class CameraEvent { + /// The ID of the Camera this event is associated to. + final int cameraId; + + /// Build a Camera Event, that relates a `cameraId`. + /// + /// The `cameraId` is the ID of the camera that triggered the event. + CameraEvent(this.cameraId) : assert(cameraId != null); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is CameraEvent && + runtimeType == other.runtimeType && + cameraId == other.cameraId; + + @override + int get hashCode => cameraId.hashCode; +} + +/// An event fired when the camera has finished initializing. +class CameraInitializedEvent extends CameraEvent { + /// The width of the preview in pixels. + final double previewWidth; + + /// The height of the preview in pixels. + final double previewHeight; + + /// Build a CameraInitialized event triggered from the camera represented by + /// `cameraId`. + /// + /// The `previewWidth` represents the width of the generated preview in pixels. + /// The `previewHeight` represents the height of the generated preview in pixels. + CameraInitializedEvent( + int cameraId, + this.previewWidth, + this.previewHeight, + ) : super(cameraId); + + /// Converts the supplied [Map] to an instance of the [CameraInitializedEvent] + /// class. + CameraInitializedEvent.fromJson(Map json) + : previewWidth = json['previewWidth'], + previewHeight = json['previewHeight'], + super(json['cameraId']); + + /// Converts the [CameraInitializedEvent] instance into a [Map] instance that + /// can be serialized to JSON. + Map toJson() => { + 'cameraId': cameraId, + 'previewWidth': previewWidth, + 'previewHeight': previewHeight, + }; + + @override + bool operator ==(Object other) => + identical(this, other) || + super == other && + other is CameraInitializedEvent && + runtimeType == other.runtimeType && + previewWidth == other.previewWidth && + previewHeight == other.previewHeight; + + @override + int get hashCode => + super.hashCode ^ previewWidth.hashCode ^ previewHeight.hashCode; +} + +/// An event fired when the resolution preset of the camera has changed. +class CameraResolutionChangedEvent extends CameraEvent { + /// The capture width in pixels. + final double captureWidth; + + /// The capture height in pixels. + final double captureHeight; + + /// Build a CameraResolutionChanged event triggered from the camera + /// represented by `cameraId`. + /// + /// The `captureWidth` represents the width of the resulting image in pixels. + /// The `captureHeight` represents the height of the resulting image in pixels. + CameraResolutionChangedEvent( + int cameraId, + this.captureWidth, + this.captureHeight, + ) : super(cameraId); + + /// Converts the supplied [Map] to an instance of the + /// [CameraResolutionChangedEvent] class. + CameraResolutionChangedEvent.fromJson(Map json) + : captureWidth = json['captureWidth'], + captureHeight = json['captureHeight'], + super(json['cameraId']); + + /// Converts the [CameraResolutionChangedEvent] instance into a [Map] instance + /// that can be serialized to JSON. + Map toJson() => { + 'cameraId': cameraId, + 'captureWidth': captureWidth, + 'captureHeight': captureHeight, + }; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is CameraResolutionChangedEvent && + super == (other) && + runtimeType == other.runtimeType && + captureWidth == other.captureWidth && + captureHeight == other.captureHeight; + + @override + int get hashCode => + super.hashCode ^ captureWidth.hashCode ^ captureHeight.hashCode; +} + +/// An event fired when the camera is going to close. +class CameraClosingEvent extends CameraEvent { + /// Build a CameraClosing event triggered from the camera represented by + /// `cameraId`. + CameraClosingEvent(int cameraId) : super(cameraId); + + /// Converts the supplied [Map] to an instance of the [CameraClosingEvent] + /// class. + CameraClosingEvent.fromJson(Map json) + : super(json['cameraId']); + + /// Converts the [CameraClosingEvent] instance into a [Map] instance that can + /// be serialized to JSON. + Map toJson() => { + 'cameraId': cameraId, + }; + + @override + bool operator ==(Object other) => + identical(this, other) || + super == (other) && + other is CameraClosingEvent && + runtimeType == other.runtimeType; + + @override + int get hashCode => super.hashCode; +} + +/// An event fired when an error occured while operating the camera. +class CameraErrorEvent extends CameraEvent { + /// Description of the error. + final String description; + + /// Build a CameraError event triggered from the camera represented by + /// `cameraId`. + /// + /// The `description` represents the error occured on the camera. + CameraErrorEvent(int cameraId, this.description) : super(cameraId); + + /// Converts the supplied [Map] to an instance of the [CameraErrorEvent] + /// class. + CameraErrorEvent.fromJson(Map json) + : description = json['description'], + super(json['cameraId']); + + /// Converts the [CameraErrorEvent] instance into a [Map] instance that can be + /// serialized to JSON. + Map toJson() => { + 'cameraId': cameraId, + 'description': description, + }; + + @override + bool operator ==(Object other) => + identical(this, other) || + super == (other) && + other is CameraErrorEvent && + runtimeType == other.runtimeType && + description == other.description; + + @override + int get hashCode => super.hashCode ^ description.hashCode; +} diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart new file mode 100644 index 000000000000..c649a41f5e9f --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -0,0 +1,239 @@ +// Copyright 2018 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:async'; + +import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/utils/utils.dart'; +import 'package:cross_file/cross_file.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:meta/meta.dart'; +import 'package:stream_transform/stream_transform.dart'; + +const MethodChannel _channel = MethodChannel('plugins.flutter.io/camera'); + +/// An implementation of [CameraPlatform] that uses method channels. +class MethodChannelCamera extends CameraPlatform { + final Map _channels = {}; + + /// The controller we need to broadcast the different events coming + /// from handleMethodCall. + /// + /// It is a `broadcast` because multiple controllers will connect to + /// different stream views of this Controller. + /// This is only exposed for test purposes. It shouldn't be used by clients of + /// the plugin as it may break or change at any time. + @visibleForTesting + final StreamController cameraEventStreamController = + StreamController.broadcast(); + + Stream _events(int cameraId) => + cameraEventStreamController.stream + .where((event) => event.cameraId == cameraId); + + @override + Future> availableCameras() async { + try { + final List> cameras = await _channel + .invokeListMethod>('availableCameras'); + return cameras.map((Map camera) { + return CameraDescription( + name: camera['name'], + lensDirection: parseCameraLensDirection(camera['lensFacing']), + sensorOrientation: camera['sensorOrientation'], + ); + }).toList(); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + @override + Future createCamera( + CameraDescription cameraDescription, + ResolutionPreset resolutionPreset, { + bool enableAudio, + }) async { + try { + final Map reply = + await _channel.invokeMapMethod( + 'create', + { + 'cameraName': cameraDescription.name, + 'resolutionPreset': resolutionPreset != null + ? _serializeResolutionPreset(resolutionPreset) + : null, + 'enableAudio': enableAudio, + }, + ); + return reply['cameraId']; + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + @override + Future initializeCamera(int cameraId) { + _channels.putIfAbsent(cameraId, () { + final channel = MethodChannel('flutter.io/cameraPlugin/camera$cameraId'); + channel.setMethodCallHandler( + (MethodCall call) => handleMethodCall(call, cameraId)); + return channel; + }); + + Completer _completer = Completer(); + + onCameraInitialized(cameraId).first.then((value) { + _completer.complete(); + }); + + _channel.invokeMapMethod( + 'initialize', + { + 'cameraId': cameraId, + }, + ); + + return _completer.future; + } + + @override + Future dispose(int cameraId) async { + await _channel.invokeMethod( + 'dispose', + {'cameraId': cameraId}, + ); + + if (_channels.containsKey(cameraId)) { + _channels[cameraId].setMethodCallHandler(null); + _channels.remove(cameraId); + } + } + + @override + Stream onCameraInitialized(int cameraId) { + return _events(cameraId).whereType(); + } + + @override + Stream onCameraResolutionChanged(int cameraId) { + return _events(cameraId).whereType(); + } + + @override + Stream onCameraClosing(int cameraId) { + return _events(cameraId).whereType(); + } + + @override + Stream onCameraError(int cameraId) { + return _events(cameraId).whereType(); + } + + @override + Future takePicture(int cameraId) async { + String path = await _channel.invokeMethod( + 'takePicture', + {'cameraId': cameraId}, + ); + return XFile(path); + } + + @override + Future prepareForVideoRecording() => + _channel.invokeMethod('prepareForVideoRecording'); + + @override + Future startVideoRecording(int cameraId) async { + await _channel.invokeMethod( + 'startVideoRecording', + {'cameraId': cameraId}, + ); + } + + @override + Future stopVideoRecording(int cameraId) async { + String path = await _channel.invokeMethod( + 'stopVideoRecording', + {'cameraId': cameraId}, + ); + return XFile(path); + } + + @override + Future pauseVideoRecording(int cameraId) => _channel.invokeMethod( + 'pauseVideoRecording', + {'cameraId': cameraId}, + ); + + @override + Future resumeVideoRecording(int cameraId) => + _channel.invokeMethod( + 'resumeVideoRecording', + {'cameraId': cameraId}, + ); + + @override + Widget buildPreview(int cameraId) { + return Texture(textureId: cameraId); + } + + /// Returns the resolution preset as a String. + String _serializeResolutionPreset(ResolutionPreset resolutionPreset) { + switch (resolutionPreset) { + case ResolutionPreset.max: + return 'max'; + case ResolutionPreset.ultraHigh: + return 'ultraHigh'; + case ResolutionPreset.veryHigh: + return 'veryHigh'; + case ResolutionPreset.high: + return 'high'; + case ResolutionPreset.medium: + return 'medium'; + case ResolutionPreset.low: + return 'low'; + default: + throw ArgumentError('Unknown ResolutionPreset value'); + } + } + + /// Converts messages received from the native platform into events. + /// + /// This is only exposed for test purposes. It shouldn't be used by clients of + /// the plugin as it may break or change at any time. + @visibleForTesting + Future handleMethodCall(MethodCall call, int cameraId) async { + switch (call.method) { + case 'initialized': + cameraEventStreamController.add(CameraInitializedEvent( + cameraId, + call.arguments['previewWidth'], + call.arguments['previewHeight'], + )); + break; + case 'resolution_changed': + cameraEventStreamController.add(CameraResolutionChangedEvent( + cameraId, + call.arguments['captureWidth'], + call.arguments['captureHeight'], + )); + break; + case 'camera_closing': + cameraEventStreamController.add(CameraClosingEvent( + cameraId, + )); + break; + case 'error': + cameraEventStreamController.add(CameraErrorEvent( + cameraId, + call.arguments['description'], + )); + break; + default: + throw MissingPluginException(); + } + } +} diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart new file mode 100644 index 000000000000..5281a423459a --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -0,0 +1,120 @@ +// Copyright 2018 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:async'; + +import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; +import 'package:cross_file/cross_file.dart'; +import 'package:flutter/widgets.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +/// The interface that implementations of camera must implement. +/// +/// Platform implementations should extend this class rather than implement it as `camera` +/// does not consider newly added methods to be breaking changes. Extending this class +/// (using `extends`) ensures that the subclass will get the default implementation, while +/// platform implementations that `implements` this interface will be broken by newly added +/// [CameraPlatform] methods. +abstract class CameraPlatform extends PlatformInterface { + /// Constructs a CameraPlatform. + CameraPlatform() : super(token: _token); + + static final Object _token = Object(); + + static CameraPlatform _instance = MethodChannelCamera(); + + /// The default instance of [CameraPlatform] to use. + /// + /// Defaults to [MethodChannelCamera]. + static CameraPlatform get instance => _instance; + + /// Platform-specific plugins should set this with their own platform-specific + /// class that extends [CameraPlatform] when they register themselves. + static set instance(CameraPlatform instance) { + PlatformInterface.verifyToken(instance, _token); + _instance = instance; + } + + /// Completes with a list of available cameras. + Future> availableCameras() { + throw UnimplementedError('availableCameras() is not implemented.'); + } + + /// Creates an uninitialized camera instance and returns the cameraId. + Future createCamera( + CameraDescription cameraDescription, + ResolutionPreset resolutionPreset, { + bool enableAudio, + }) { + throw UnimplementedError('createCamera() is not implemented.'); + } + + /// Initializes the camera on the device. + Future initializeCamera(int cameraId) { + throw UnimplementedError('initializeCamera() is not implemented.'); + } + + /// The camera has been initialized + Stream onCameraInitialized(int cameraId) { + throw UnimplementedError('onCameraInitialized() is not implemented.'); + } + + /// The camera's resolution has changed + Stream onCameraResolutionChanged(int cameraId) { + throw UnimplementedError('onResolutionChanged() is not implemented.'); + } + + /// The camera started to close. + Stream onCameraClosing(int cameraId) { + throw UnimplementedError('onCameraClosing() is not implemented.'); + } + + /// The camera experienced an error. + Stream onCameraError(int cameraId) { + throw UnimplementedError('onCameraError() is not implemented.'); + } + + /// Captures an image and returns the file where it was saved. + Future takePicture(int cameraId) { + throw UnimplementedError('takePicture() is not implemented.'); + } + + /// Prepare the capture session for video recording. + Future prepareForVideoRecording() { + throw UnimplementedError('prepareForVideoRecording() is not implemented.'); + } + + /// Starts a video recording. + /// + /// The video is returned as a [XFile] after calling [stopVideoRecording]. + Future startVideoRecording(int cameraId) { + throw UnimplementedError('startVideoRecording() is not implemented.'); + } + + /// Stops the video recording and returns the file where it was saved. + Future stopVideoRecording(int cameraId) { + throw UnimplementedError('stopVideoRecording() is not implemented.'); + } + + /// Pause video recording. + Future pauseVideoRecording(int cameraId) { + throw UnimplementedError('pauseVideoRecording() is not implemented.'); + } + + /// Resume video recording after pausing. + Future resumeVideoRecording(int cameraId) { + throw UnimplementedError('resumeVideoRecording() is not implemented.'); + } + + /// Returns a widget showing a live camera preview. + Widget buildPreview(int cameraId) { + throw UnimplementedError('buildView() has not been implemented.'); + } + + /// Releases the resources of this camera. + Future dispose(int cameraId) { + throw UnimplementedError('dispose() is not implemented.'); + } +} diff --git a/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart b/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart new file mode 100644 index 000000000000..c19af1f50d1c --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart @@ -0,0 +1,52 @@ +// Copyright 2018 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. + +/// The direction the camera is facing. +enum CameraLensDirection { + /// Front facing camera (a user looking at the screen is seen by the camera). + front, + + /// Back facing camera (a user looking at the screen is not seen by the camera). + back, + + /// External camera which may not be mounted to the device. + external, +} + +/// Properties of a camera device. +class CameraDescription { + /// Creates a new camera description with the given properties. + CameraDescription({this.name, this.lensDirection, this.sensorOrientation}); + + /// The name of the camera device. + final String name; + + /// The direction the camera is facing. + final CameraLensDirection lensDirection; + + /// Clockwise angle through which the output image needs to be rotated to be upright on the device screen in its native orientation. + /// + /// **Range of valid values:** + /// 0, 90, 180, 270 + /// + /// On Android, also defines the direction of rolling shutter readout, which + /// is from top to bottom in the sensor's coordinate system. + final int sensorOrientation; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is CameraDescription && + runtimeType == other.runtimeType && + name == other.name && + lensDirection == other.lensDirection; + + @override + int get hashCode => name.hashCode ^ lensDirection.hashCode; + + @override + String toString() { + return '$runtimeType($name, $lensDirection, $sensorOrientation)'; + } +} diff --git a/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart b/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart new file mode 100644 index 000000000000..3da659f7021d --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart @@ -0,0 +1,20 @@ +// Copyright 2018 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. + +/// This is thrown when the plugin reports an error. +class CameraException implements Exception { + /// Creates a new camera exception with the given error code and description. + CameraException(this.code, this.description); + + /// Error code. + // TODO(bparrishMines): Document possible error codes. + // https://github.com/flutter/flutter/issues/69298 + String code; + + /// Textual description of the error. + String description; + + @override + String toString() => 'CameraException($code, $description)'; +} diff --git a/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart b/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart new file mode 100644 index 000000000000..ead592364131 --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart @@ -0,0 +1,26 @@ +// Copyright 2019 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. + +/// Affect the quality of video recording and image capture: +/// +/// If a preset is not available on the camera being used a preset of lower quality will be selected automatically. +enum ResolutionPreset { + /// 352x288 on iOS, 240p (320x240) on Android + low, + + /// 480p (640x480 on iOS, 720x480 on Android) + medium, + + /// 720p (1280x720) + high, + + /// 1080p (1920x1080) + veryHigh, + + /// 2160p (3840x2160) + ultraHigh, + + /// The highest resolution available. + max, +} diff --git a/packages/camera/camera_platform_interface/lib/src/types/types.dart b/packages/camera/camera_platform_interface/lib/src/types/types.dart new file mode 100644 index 000000000000..71e7a97ef49a --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/types/types.dart @@ -0,0 +1,7 @@ +// Copyright 2018 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. + +export 'camera_description.dart'; +export 'resolution_preset.dart'; +export 'camera_exception.dart'; diff --git a/packages/camera/camera_platform_interface/lib/src/utils/utils.dart b/packages/camera/camera_platform_interface/lib/src/utils/utils.dart new file mode 100644 index 000000000000..f94d8e69c07e --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/utils/utils.dart @@ -0,0 +1,14 @@ +import 'package:camera_platform_interface/camera_platform_interface.dart'; + +/// Parses a string into a corresponding CameraLensDirection. +CameraLensDirection parseCameraLensDirection(String string) { + switch (string) { + case 'front': + return CameraLensDirection.front; + case 'back': + return CameraLensDirection.back; + case 'external': + return CameraLensDirection.external; + } + throw ArgumentError('Unknown CameraLensDirection value'); +} diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml new file mode 100644 index 000000000000..c2bb6fcc5963 --- /dev/null +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -0,0 +1,25 @@ +name: camera_platform_interface +description: A common platform interface for the camera plugin. +homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.0.0 + +dependencies: + flutter: + sdk: flutter + meta: ^1.0.5 + plugin_platform_interface: ^1.0.1 + cross_file: ^0.1.0 + stream_transform: ^1.2.0 + +dev_dependencies: + flutter_test: + sdk: flutter + async: ^2.4.2 + mockito: ^4.1.1 + pedantic: ^1.8.0 + +environment: + sdk: ">=2.1.0 <3.0.0" + flutter: ">=1.22.0 <2.0.0" diff --git a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart new file mode 100644 index 000000000000..2bc35bf4055c --- /dev/null +++ b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart @@ -0,0 +1,229 @@ +// Copyright 2019 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 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$CameraPlatform', () { + test('$MethodChannelCamera is the default instance', () { + expect(CameraPlatform.instance, isA()); + }); + + test('Cannot be implemented with `implements`', () { + expect(() { + CameraPlatform.instance = ImplementsCameraPlatform(); + }, throwsNoSuchMethodError); + }); + + test('Can be extended', () { + CameraPlatform.instance = ExtendsCameraPlatform(); + }); + + test('Can be mocked with `implements`', () { + final mock = MockCameraPlatform(); + CameraPlatform.instance = mock; + }); + + test( + 'Default implementation of availableCameras() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.availableCameras(), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of onCameraInitialized() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.onCameraInitialized(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of onResolutionChanged() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.onCameraResolutionChanged(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of onCameraClosing() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.onCameraClosing(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of onCameraError() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.onCameraError(1), + throwsUnimplementedError, + ); + }); + + test('Default implementation of dispose() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.dispose(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of createCamera() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.createCamera(null, null), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of initializeCamera() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.initializeCamera(null), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of pauseVideoRecording() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.pauseVideoRecording(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of prepareForVideoRecording() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.prepareForVideoRecording(), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of resumeVideoRecording() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.resumeVideoRecording(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of startVideoRecording() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.startVideoRecording(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of stopVideoRecording() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.stopVideoRecording(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of takePicture() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.takePicture(1), + throwsUnimplementedError, + ); + }); + }); +} + +class ImplementsCameraPlatform implements CameraPlatform { + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +class MockCameraPlatform extends Mock + with + // ignore: prefer_mixin + MockPlatformInterfaceMixin + implements + CameraPlatform {} + +class ExtendsCameraPlatform extends CameraPlatform {} diff --git a/packages/camera/camera_platform_interface/test/events/camera_event_test.dart b/packages/camera/camera_platform_interface/test/events/camera_event_test.dart new file mode 100644 index 000000000000..01b03b8e93a0 --- /dev/null +++ b/packages/camera/camera_platform_interface/test/events/camera_event_test.dart @@ -0,0 +1,252 @@ +// Copyright 2019 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 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('CameraInitializedEvent tests', () { + test('Constructor should initialize all properties', () { + final event = CameraInitializedEvent(1, 1024, 640); + + expect(event.cameraId, 1); + expect(event.previewWidth, 1024); + expect(event.previewHeight, 640); + }); + + test('fromJson should initialize all properties', () { + final event = CameraInitializedEvent.fromJson({ + 'cameraId': 1, + 'previewWidth': 1024.0, + 'previewHeight': 640.0, + }); + + expect(event.cameraId, 1); + expect(event.previewWidth, 1024); + expect(event.previewHeight, 640); + }); + + test('toJson should return a map with all fields', () { + final event = CameraInitializedEvent(1, 1024, 640); + + final jsonMap = event.toJson(); + + expect(jsonMap.length, 3); + expect(jsonMap['cameraId'], 1); + expect(jsonMap['previewWidth'], 1024); + expect(jsonMap['previewHeight'], 640); + }); + + test('equals should return true if objects are the same', () { + final firstEvent = CameraInitializedEvent(1, 1024, 640); + final secondEvent = CameraInitializedEvent(1, 1024, 640); + + expect(firstEvent == secondEvent, true); + }); + + test('equals should return false if cameraId is different', () { + final firstEvent = CameraInitializedEvent(1, 1024, 640); + final secondEvent = CameraInitializedEvent(2, 1024, 640); + + expect(firstEvent == secondEvent, false); + }); + + test('equals should return false if previewWidth is different', () { + final firstEvent = CameraInitializedEvent(1, 1024, 640); + final secondEvent = CameraInitializedEvent(1, 2048, 640); + + expect(firstEvent == secondEvent, false); + }); + + test('equals should return false if previewHeight is different', () { + final firstEvent = CameraInitializedEvent(1, 1024, 640); + final secondEvent = CameraInitializedEvent(1, 1024, 980); + + expect(firstEvent == secondEvent, false); + }); + + test('hashCode should match hashCode of all properties', () { + final event = CameraInitializedEvent(1, 1024, 640); + final expectedHashCode = event.cameraId.hashCode ^ + event.previewWidth.hashCode ^ + event.previewHeight.hashCode; + + expect(event.hashCode, expectedHashCode); + }); + }); + + group('CameraResolutionChangesEvent tests', () { + test('Constructor should initialize all properties', () { + final event = CameraResolutionChangedEvent(1, 1024, 640); + + expect(event.cameraId, 1); + expect(event.captureWidth, 1024); + expect(event.captureHeight, 640); + }); + + test('fromJson should initialize all properties', () { + final event = CameraResolutionChangedEvent.fromJson({ + 'cameraId': 1, + 'captureWidth': 1024.0, + 'captureHeight': 640.0, + }); + + expect(event.cameraId, 1); + expect(event.captureWidth, 1024); + expect(event.captureHeight, 640); + }); + + test('toJson should return a map with all fields', () { + final event = CameraResolutionChangedEvent(1, 1024, 640); + + final jsonMap = event.toJson(); + + expect(jsonMap.length, 3); + expect(jsonMap['cameraId'], 1); + expect(jsonMap['captureWidth'], 1024); + expect(jsonMap['captureHeight'], 640); + }); + + test('equals should return true if objects are the same', () { + final firstEvent = CameraResolutionChangedEvent(1, 1024, 640); + final secondEvent = CameraResolutionChangedEvent(1, 1024, 640); + + expect(firstEvent == secondEvent, true); + }); + + test('equals should return false if cameraId is different', () { + final firstEvent = CameraResolutionChangedEvent(1, 1024, 640); + final secondEvent = CameraResolutionChangedEvent(2, 1024, 640); + + expect(firstEvent == secondEvent, false); + }); + + test('equals should return false if captureWidth is different', () { + final firstEvent = CameraResolutionChangedEvent(1, 1024, 640); + final secondEvent = CameraResolutionChangedEvent(1, 2048, 640); + + expect(firstEvent == secondEvent, false); + }); + + test('equals should return false if captureHeight is different', () { + final firstEvent = CameraResolutionChangedEvent(1, 1024, 640); + final secondEvent = CameraResolutionChangedEvent(1, 1024, 980); + + expect(firstEvent == secondEvent, false); + }); + + test('hashCode should match hashCode of all properties', () { + final event = CameraResolutionChangedEvent(1, 1024, 640); + final expectedHashCode = event.cameraId.hashCode ^ + event.captureWidth.hashCode ^ + event.captureHeight.hashCode; + + expect(event.hashCode, expectedHashCode); + }); + }); + + group('CameraClosingEvent tests', () { + test('Constructor should initialize all properties', () { + final event = CameraClosingEvent(1); + + expect(event.cameraId, 1); + }); + + test('fromJson should initialize all properties', () { + final event = CameraClosingEvent.fromJson({ + 'cameraId': 1, + }); + + expect(event.cameraId, 1); + }); + + test('toJson should return a map with all fields', () { + final event = CameraClosingEvent(1); + + final jsonMap = event.toJson(); + + expect(jsonMap.length, 1); + expect(jsonMap['cameraId'], 1); + }); + + test('equals should return true if objects are the same', () { + final firstEvent = CameraClosingEvent(1); + final secondEvent = CameraClosingEvent(1); + + expect(firstEvent == secondEvent, true); + }); + + test('equals should return false if cameraId is different', () { + final firstEvent = CameraClosingEvent(1); + final secondEvent = CameraClosingEvent(2); + + expect(firstEvent == secondEvent, false); + }); + + test('hashCode should match hashCode of all properties', () { + final event = CameraClosingEvent(1); + final expectedHashCode = event.cameraId.hashCode; + + expect(event.hashCode, expectedHashCode); + }); + }); + + group('CameraErrorEvent tests', () { + test('Constructor should initialize all properties', () { + final event = CameraErrorEvent(1, 'Error'); + + expect(event.cameraId, 1); + expect(event.description, 'Error'); + }); + + test('fromJson should initialize all properties', () { + final event = CameraErrorEvent.fromJson( + {'cameraId': 1, 'description': 'Error'}); + + expect(event.cameraId, 1); + expect(event.description, 'Error'); + }); + + test('toJson should return a map with all fields', () { + final event = CameraErrorEvent(1, 'Error'); + + final jsonMap = event.toJson(); + + expect(jsonMap.length, 2); + expect(jsonMap['cameraId'], 1); + expect(jsonMap['description'], 'Error'); + }); + + test('equals should return true if objects are the same', () { + final firstEvent = CameraErrorEvent(1, 'Error'); + final secondEvent = CameraErrorEvent(1, 'Error'); + + expect(firstEvent == secondEvent, true); + }); + + test('equals should return false if cameraId is different', () { + final firstEvent = CameraErrorEvent(1, 'Error'); + final secondEvent = CameraErrorEvent(2, 'Error'); + + expect(firstEvent == secondEvent, false); + }); + + test('equals should return false if description is different', () { + final firstEvent = CameraErrorEvent(1, 'Error'); + final secondEvent = CameraErrorEvent(1, 'Ooops'); + + expect(firstEvent == secondEvent, false); + }); + + test('hashCode should match hashCode of all properties', () { + final event = CameraErrorEvent(1, 'Error'); + final expectedHashCode = + event.cameraId.hashCode ^ event.description.hashCode; + + expect(event.hashCode, expectedHashCode); + }); + }); +} diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart new file mode 100644 index 000000000000..952a78e3408b --- /dev/null +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -0,0 +1,491 @@ +// Copyright 2019 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:async'; + +import 'package:async/async.dart'; +import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; +import 'package:camera_platform_interface/src/utils/utils.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../utils/method_channel_mock.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$MethodChannelCamera', () { + group('Creation, Initialization & Disposal Tests', () { + test('Should send creation data and receive back a camera id', () async { + // Arrange + MethodChannelMock cameraMockChannel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: { + 'create': {'cameraId': 1} + }); + final camera = MethodChannelCamera(); + + // Act + final cameraId = await camera.createCamera( + CameraDescription(name: 'Test'), + ResolutionPreset.high, + ); + + // Assert + expect(cameraMockChannel.log, [ + isMethodCall( + 'create', + arguments: { + 'cameraName': 'Test', + 'resolutionPreset': 'high', + 'enableAudio': null + }, + ), + ]); + expect(cameraId, 1); + }); + + test( + 'Should throw CameraException when create throws a PlatformException', + () { + // Arrange + MethodChannelMock(channelName: 'plugins.flutter.io/camera', methods: { + 'create': PlatformException( + code: 'TESTING_ERROR_CODE', + message: 'Mock error message used during testing.', + ) + }); + final camera = MethodChannelCamera(); + + // Act + expect( + () => camera.createCamera( + CameraDescription(name: 'Test'), + ResolutionPreset.high, + ), + throwsA( + isA() + .having((e) => e.code, 'code', 'TESTING_ERROR_CODE') + .having((e) => e.description, 'description', + 'Mock error message used during testing.'), + ), + ); + }); + + test( + 'Should throw CameraException when create throws a PlatformException', + () { + // Arrange + MethodChannelMock(channelName: 'plugins.flutter.io/camera', methods: { + 'create': PlatformException( + code: 'TESTING_ERROR_CODE', + message: 'Mock error message used during testing.', + ) + }); + final camera = MethodChannelCamera(); + + // Act + expect( + () => camera.createCamera( + CameraDescription(name: 'Test'), + ResolutionPreset.high, + ), + throwsA( + isA() + .having((e) => e.code, 'code', 'TESTING_ERROR_CODE') + .having((e) => e.description, 'description', + 'Mock error message used during testing.'), + ), + ); + }); + + test('Should send initialization data', () async { + // Arrange + MethodChannelMock cameraMockChannel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: { + 'create': {'cameraId': 1}, + 'initialize': null + }); + final camera = MethodChannelCamera(); + final cameraId = await camera.createCamera( + CameraDescription(name: 'Test'), + ResolutionPreset.high, + ); + + // Act + Future initializeFuture = camera.initializeCamera(cameraId); + camera.cameraEventStreamController + .add(CameraInitializedEvent(cameraId, 1920, 1080)); + await initializeFuture; + + // Assert + expect(cameraId, 1); + expect(cameraMockChannel.log, [ + anything, + isMethodCall( + 'initialize', + arguments: { + 'cameraId': 1, + }, + ), + ]); + }); + + test('Should send a disposal call on dispose', () async { + // Arrange + MethodChannelMock cameraMockChannel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: { + 'create': {'cameraId': 1}, + 'initialize': null, + 'dispose': {'cameraId': 1} + }); + + final camera = MethodChannelCamera(); + final cameraId = await camera.createCamera( + CameraDescription(name: 'Test'), + ResolutionPreset.high, + ); + Future initializeFuture = camera.initializeCamera(cameraId); + camera.cameraEventStreamController + .add(CameraInitializedEvent(cameraId, 1920, 1080)); + await initializeFuture; + + // Act + await camera.dispose(cameraId); + + // Assert + expect(cameraId, 1); + expect(cameraMockChannel.log, [ + anything, + anything, + isMethodCall( + 'dispose', + arguments: {'cameraId': 1}, + ), + ]); + }); + }); + + group('Event Tests', () { + MethodChannelCamera camera; + int cameraId; + setUp(() async { + MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: { + 'create': {'cameraId': 1}, + 'initialize': null + }, + ); + camera = MethodChannelCamera(); + cameraId = await camera.createCamera( + CameraDescription(name: 'Test'), + ResolutionPreset.high, + ); + Future initializeFuture = camera.initializeCamera(cameraId); + camera.cameraEventStreamController + .add(CameraInitializedEvent(cameraId, 1920, 1080)); + await initializeFuture; + }); + + test('Should receive initialized event', () async { + // Act + final Stream eventStream = + camera.onCameraInitialized(cameraId); + final streamQueue = StreamQueue(eventStream); + + // Emit test events + final event = CameraInitializedEvent(cameraId, 3840, 2160); + await camera.handleMethodCall( + MethodCall('initialized', event.toJson()), cameraId); + + // Assert + expect(await streamQueue.next, event); + + // Clean up + await streamQueue.cancel(); + }); + + test('Should receive resolution changes', () async { + // Act + final Stream resolutionStream = + camera.onCameraResolutionChanged(cameraId); + final streamQueue = StreamQueue(resolutionStream); + + // Emit test events + final fhdEvent = CameraResolutionChangedEvent(cameraId, 1920, 1080); + final uhdEvent = CameraResolutionChangedEvent(cameraId, 3840, 2160); + await camera.handleMethodCall( + MethodCall('resolution_changed', fhdEvent.toJson()), cameraId); + await camera.handleMethodCall( + MethodCall('resolution_changed', uhdEvent.toJson()), cameraId); + await camera.handleMethodCall( + MethodCall('resolution_changed', fhdEvent.toJson()), cameraId); + await camera.handleMethodCall( + MethodCall('resolution_changed', uhdEvent.toJson()), cameraId); + + // Assert + expect(await streamQueue.next, fhdEvent); + expect(await streamQueue.next, uhdEvent); + expect(await streamQueue.next, fhdEvent); + expect(await streamQueue.next, uhdEvent); + + // Clean up + await streamQueue.cancel(); + }); + + test('Should receive camera closing events', () async { + // Act + final Stream eventStream = + camera.onCameraClosing(cameraId); + final streamQueue = StreamQueue(eventStream); + + // Emit test events + final event = CameraClosingEvent(cameraId); + await camera.handleMethodCall( + MethodCall('camera_closing', event.toJson()), cameraId); + await camera.handleMethodCall( + MethodCall('camera_closing', event.toJson()), cameraId); + await camera.handleMethodCall( + MethodCall('camera_closing', event.toJson()), cameraId); + + // Assert + expect(await streamQueue.next, event); + expect(await streamQueue.next, event); + expect(await streamQueue.next, event); + + // Clean up + await streamQueue.cancel(); + }); + + test('Should receive camera error events', () async { + // Act + final errorStream = camera.onCameraError(cameraId); + final streamQueue = StreamQueue(errorStream); + + // Emit test events + final event = CameraErrorEvent(cameraId, 'Error Description'); + await camera.handleMethodCall( + MethodCall('error', event.toJson()), cameraId); + await camera.handleMethodCall( + MethodCall('error', event.toJson()), cameraId); + await camera.handleMethodCall( + MethodCall('error', event.toJson()), cameraId); + + // Assert + expect(await streamQueue.next, event); + expect(await streamQueue.next, event); + expect(await streamQueue.next, event); + + // Clean up + await streamQueue.cancel(); + }); + }); + + group('Function Tests', () { + MethodChannelCamera camera; + int cameraId; + setUp(() async { + MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: { + 'create': {'cameraId': 1}, + 'initialize': null + }, + ); + camera = MethodChannelCamera(); + cameraId = await camera.createCamera( + CameraDescription(name: 'Test'), + ResolutionPreset.high, + ); + Future initializeFuture = camera.initializeCamera(cameraId); + camera.cameraEventStreamController + .add(CameraInitializedEvent(cameraId, 1920, 1080)); + await initializeFuture; + }); + + test('Should fetch CameraDescription instances for available cameras', + () async { + // Arrange + List> returnData = [ + {'name': 'Test 1', 'lensFacing': 'front', 'sensorOrientation': 1}, + {'name': 'Test 2', 'lensFacing': 'back', 'sensorOrientation': 2} + ]; + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'availableCameras': returnData}, + ); + + // Act + List cameras = await camera.availableCameras(); + + // Assert + expect(channel.log, [ + isMethodCall('availableCameras', arguments: null), + ]); + expect(cameras.length, returnData.length); + for (int i = 0; i < returnData.length; i++) { + CameraDescription cameraDescription = CameraDescription( + name: returnData[i]['name'], + lensDirection: + parseCameraLensDirection(returnData[i]['lensFacing']), + sensorOrientation: returnData[i]['sensorOrientation'], + ); + expect(cameras[i], cameraDescription); + } + }); + + test( + 'Should throw CameraException when availableCameras throws a PlatformException', + () { + // Arrange + MethodChannelMock(channelName: 'plugins.flutter.io/camera', methods: { + 'availableCameras': PlatformException( + code: 'TESTING_ERROR_CODE', + message: 'Mock error message used during testing.', + ) + }); + + // Act + expect( + camera.availableCameras, + throwsA( + isA() + .having((e) => e.code, 'code', 'TESTING_ERROR_CODE') + .having((e) => e.description, 'description', + 'Mock error message used during testing.'), + ), + ); + }); + + test('Should take a picture and return an XFile instance', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'takePicture': '/test/path.jpg'}); + + // Act + XFile file = await camera.takePicture(cameraId); + + // Assert + expect(channel.log, [ + isMethodCall('takePicture', arguments: { + 'cameraId': cameraId, + }), + ]); + expect(file.path, '/test/path.jpg'); + }); + + test('Should prepare for video recording', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'prepareForVideoRecording': null}, + ); + + // Act + await camera.prepareForVideoRecording(); + + // Assert + expect(channel.log, [ + isMethodCall('prepareForVideoRecording', arguments: null), + ]); + }); + + test('Should start recording a video', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'startVideoRecording': null}, + ); + + // Act + await camera.startVideoRecording(cameraId); + + // Assert + expect(channel.log, [ + isMethodCall('startVideoRecording', arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test('Should stop a video recording and return the file', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'stopVideoRecording': '/test/path.mp4'}, + ); + + // Act + XFile file = await camera.stopVideoRecording(cameraId); + + // Assert + expect(channel.log, [ + isMethodCall('stopVideoRecording', arguments: { + 'cameraId': cameraId, + }), + ]); + expect(file.path, '/test/path.mp4'); + }); + + test('Should pause a video recording', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'pauseVideoRecording': null}, + ); + + // Act + await camera.pauseVideoRecording(cameraId); + + // Assert + expect(channel.log, [ + isMethodCall('pauseVideoRecording', arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test('Should resume a video recording', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'resumeVideoRecording': null}, + ); + + // Act + await camera.resumeVideoRecording(cameraId); + + // Assert + expect(channel.log, [ + isMethodCall('resumeVideoRecording', arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test('Should build a texture widget as preview widget', () async { + // Act + Widget widget = camera.buildPreview(cameraId); + + // Act + expect(widget is Texture, isTrue); + expect((widget as Texture).textureId, cameraId); + }); + + test('Should throw MissingPluginException when handling unknown method', + () { + final camera = MethodChannelCamera(); + + expect(() => camera.handleMethodCall(MethodCall('unknown_method'), 1), + throwsA(isA())); + }); + }); + }); +} diff --git a/packages/camera/camera_platform_interface/test/types/camera_description_test.dart b/packages/camera/camera_platform_interface/test/types/camera_description_test.dart new file mode 100644 index 000000000000..03909dbafb97 --- /dev/null +++ b/packages/camera/camera_platform_interface/test/types/camera_description_test.dart @@ -0,0 +1,113 @@ +// Copyright 2019 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 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('CameraLensDirection tests', () { + test('CameraLensDirection should contain 3 options', () { + final values = CameraLensDirection.values; + + expect(values.length, 3); + }); + + test("CameraLensDirection enum should have items in correct index", () { + final values = CameraLensDirection.values; + + expect(values[0], CameraLensDirection.front); + expect(values[1], CameraLensDirection.back); + expect(values[2], CameraLensDirection.external); + }); + }); + + group('CameraDescription tests', () { + test('Constructor should initialize all properties', () { + final description = CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.front, + sensorOrientation: 90, + ); + + expect(description.name, 'Test'); + expect(description.lensDirection, CameraLensDirection.front); + expect(description.sensorOrientation, 90); + }); + + test('equals should return true if objects are the same', () { + final firstDescription = CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.front, + sensorOrientation: 90, + ); + final secondDescription = CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.front, + sensorOrientation: 90, + ); + + expect(firstDescription == secondDescription, true); + }); + + test('equals should return false if name is different', () { + final firstDescription = CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.front, + sensorOrientation: 90, + ); + final secondDescription = CameraDescription( + name: 'Testing', + lensDirection: CameraLensDirection.front, + sensorOrientation: 90, + ); + + expect(firstDescription == secondDescription, false); + }); + + test('equals should return false if lens direction is different', () { + final firstDescription = CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.front, + sensorOrientation: 90, + ); + final secondDescription = CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90, + ); + + expect(firstDescription == secondDescription, false); + }); + + test('equals should return true if sensor orientation is different', () { + final firstDescription = CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.front, + sensorOrientation: 0, + ); + final secondDescription = CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.front, + sensorOrientation: 90, + ); + + expect(firstDescription == secondDescription, true); + }); + + test('hashCode should match hashCode of all properties', () { + final description = CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.front, + sensorOrientation: 0, + ); + final expectedHashCode = description.name.hashCode ^ + description.lensDirection.hashCode ^ + description.sensorOrientation.hashCode; + + expect(description.hashCode, expectedHashCode); + }); + }); +} diff --git a/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart b/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart new file mode 100644 index 000000000000..17370e4561f5 --- /dev/null +++ b/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart @@ -0,0 +1,28 @@ +// Copyright 2019 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 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('constructor should initialize properties', () { + final code = 'TEST_ERROR'; + final description = 'This is a test error'; + final exception = CameraException(code, description); + + expect(exception.code, code); + expect(exception.description, description); + }); + + test('toString: Should return a description of the exception', () { + final code = 'TEST_ERROR'; + final description = 'This is a test error'; + final expected = 'CameraException($code, $description)'; + final exception = CameraException(code, description); + + final actual = exception.toString(); + + expect(actual, expected); + }); +} diff --git a/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart b/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart new file mode 100644 index 000000000000..aadf589f87c4 --- /dev/null +++ b/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart @@ -0,0 +1,25 @@ +// Copyright 2019 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 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('ResolutionPreset should contain 6 options', () { + final values = ResolutionPreset.values; + + expect(values.length, 6); + }); + + test("ResolutionPreset enum should have items in correct index", () { + final values = ResolutionPreset.values; + + expect(values[0], ResolutionPreset.low); + expect(values[1], ResolutionPreset.medium); + expect(values[2], ResolutionPreset.high); + expect(values[3], ResolutionPreset.veryHigh); + expect(values[4], ResolutionPreset.ultraHigh); + expect(values[5], ResolutionPreset.max); + }); +} diff --git a/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart b/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart new file mode 100644 index 000000000000..cdf393f82b5f --- /dev/null +++ b/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart @@ -0,0 +1,38 @@ +// Copyright 2019 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 'package:flutter/services.dart'; + +class MethodChannelMock { + final Duration delay; + final MethodChannel methodChannel; + final Map methods; + final log = []; + + MethodChannelMock({ + String channelName, + this.delay, + this.methods, + }) : methodChannel = MethodChannel(channelName) { + methodChannel.setMockMethodCallHandler(_handler); + } + + Future _handler(MethodCall methodCall) async { + log.add(methodCall); + + if (!methods.containsKey(methodCall.method)) { + throw MissingPluginException('No implementation found for method ' + '${methodCall.method} on channel ${methodChannel.name}'); + } + + return Future.delayed(delay ?? Duration.zero, () { + final result = methods[methodCall.method]; + if (result is Exception) { + throw result; + } + + return Future.value(result); + }); + } +} diff --git a/packages/camera/camera_platform_interface/test/utils/utils_test.dart b/packages/camera/camera_platform_interface/test/utils/utils_test.dart new file mode 100644 index 000000000000..dccb30754f14 --- /dev/null +++ b/packages/camera/camera_platform_interface/test/utils/utils_test.dart @@ -0,0 +1,33 @@ +import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/utils/utils.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('Utility methods', () { + test( + 'Should return CameraLensDirection when valid value is supplied when parsing camera lens direction', + () { + expect( + parseCameraLensDirection('back'), + CameraLensDirection.back, + ); + expect( + parseCameraLensDirection('front'), + CameraLensDirection.front, + ); + expect( + parseCameraLensDirection('external'), + CameraLensDirection.external, + ); + }); + + test( + 'Should throw ArgumentException when invalid value is supplied when parsing camera lens direction', + () { + expect( + () => parseCameraLensDirection('test'), + throwsA(isArgumentError), + ); + }); + }); +} From f9d5525308ad193abaf803eb4adbf7d0408f82ff Mon Sep 17 00:00:00 2001 From: Hamdi Kahloun <32666446+hamdikahloun@users.noreply.github.com> Date: Fri, 4 Dec 2020 18:38:12 +0100 Subject: [PATCH 029/924] [Espresso] Android Code Inspection and Clean up (#3111) * Remove unchecked && deprecated Warnings * Remove settings_aar.gradle * Update CHANGELOG.md * Fix Format * Fix Format * espresso * Format * SuppressWarnings --- packages/espresso/CHANGELOG.md | 4 ++++ .../androidx/test/espresso/flutter/EspressoFlutter.java | 1 + .../test/espresso/flutter/action/FlutterViewAction.java | 5 +++-- .../flutter/internal/protocol/impl/DartVmService.java | 8 +++----- .../flutter/internal/protocol/impl/DartVmServiceUtil.java | 1 + .../test/espresso/flutter/matcher/FlutterMatchers.java | 1 + packages/espresso/example/android/app/build.gradle | 2 +- packages/espresso/pubspec.yaml | 2 +- 8 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/espresso/CHANGELOG.md b/packages/espresso/CHANGELOG.md index a9d61f1178c2..0ab068056df9 100644 --- a/packages/espresso/CHANGELOG.md +++ b/packages/espresso/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.1+8 + +* Android: Handle deprecation & unchecked warning as error. + ## 0.0.1+7 * Update android compileSdkVersion to 29. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java index 106436f2b9ce..6730a66a5406 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java @@ -130,6 +130,7 @@ public WidgetInteraction check(@Nonnull WidgetAssertion assertion) { return this; } + @SuppressWarnings("unchecked") private T performInternal(FlutterAction flutterAction) { checkNotNull( flutterAction, diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java index 7864b43d9ec0..fc554d761db5 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java @@ -32,7 +32,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import io.flutter.embedding.android.FlutterView; -import io.flutter.view.FlutterNativeView; +import io.flutter.embedding.engine.FlutterJNI; import java.net.URI; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -105,7 +105,7 @@ public void perform(UiController uiController, View flutterView) { // The url {@code FlutterNativeView} returns is the http url that the Dart VM Observatory http // server serves at. Need to convert to the one that the WebSocket uses. URI dartVmServiceProtocolUrl = - DartVmServiceUtil.getServiceProtocolUri(FlutterNativeView.getObservatoryUri()); + DartVmServiceUtil.getServiceProtocolUri(FlutterJNI.getObservatoryUri()); String isolateId = DartVmServiceUtil.getDartIsolateId(flutterView); final FlutterTestingProtocol flutterTestingProtocol = new DartVmService( @@ -199,6 +199,7 @@ public String getName() { return FlutterViewRenderedIdlingResource.class.getSimpleName(); } + @SuppressWarnings("deprecation") @Override public boolean isIdleNow() { boolean isIdle = false; diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java index da11fcc8c8b6..c6ec0e08b03a 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java @@ -30,7 +30,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -360,10 +359,9 @@ boolean isTestingApiRegistered(JsonRpcResponse isolateInfoResp) { isolateId, isolateInfoResp.getError())); return false; } - Iterator extensions = - isolateInfoResp.getResult().get(EXTENSION_RPCS_TAG).getAsJsonArray().iterator(); - while (extensions.hasNext()) { - String extensionApi = extensions.next().getAsString(); + for (JsonElement jsonElement : + isolateInfoResp.getResult().get(EXTENSION_RPCS_TAG).getAsJsonArray()) { + String extensionApi = jsonElement.getAsString(); if (TESTING_EXTENSION_METHOD.equals(extensionApi)) { Log.d( TAG, diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java index 2cf41f1f87a7..a943194e348e 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java @@ -71,6 +71,7 @@ public static String getDartIsolateId(View flutterView) { } /** Gets the Dart executor for the given {@code flutterView}. */ + @SuppressWarnings("deprecation") public static DartExecutor getDartExecutor(View flutterView) { checkNotNull(flutterView, "The Flutter View instance cannot be null."); // Flutter's embedding is in the phase of rewriting/refactoring. Let's be compatible with both diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java index 5a272f24bdc0..f867b7dcbed4 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java @@ -96,6 +96,7 @@ public void describeTo(Description description) { description.appendText("is a FlutterView"); } + @SuppressWarnings("deprecation") @Override public boolean matchesSafely(View flutterView) { return flutterView instanceof FlutterView diff --git a/packages/espresso/example/android/app/build.gradle b/packages/espresso/example/android/app/build.gradle index 45fe0e173fe1..6def13f65898 100644 --- a/packages/espresso/example/android/app/build.gradle +++ b/packages/espresso/example/android/app/build.gradle @@ -35,7 +35,7 @@ android { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.espresso_example" minSdkVersion 16 - targetSdkVersion 28 + targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/packages/espresso/pubspec.yaml b/packages/espresso/pubspec.yaml index fe284260b73c..39b88cb98940 100644 --- a/packages/espresso/pubspec.yaml +++ b/packages/espresso/pubspec.yaml @@ -1,6 +1,6 @@ name: espresso description: Java classes for testing Flutter apps using Espresso. -version: 0.0.1+7 +version: 0.0.1+8 homepage: https://github.com/flutter/plugins/espresso environment: From a7c492933c7abc6e372a3bb81671aeecca0c157d Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Thu, 10 Dec 2020 14:44:03 +0100 Subject: [PATCH 030/924] [camera] Expanded platform interface to support setting flash mode (#3313) * Expanded platform interface so support setting flash mode * Formatted dart code * Manually serialize flash mode enum rather than relying on stringification. * Add default to flash mode serialization --- .../camera_platform_interface/CHANGELOG.md | 4 ++++ .../method_channel/method_channel_camera.dart | 24 +++++++++++++++++++ .../platform_interface/camera_platform.dart | 5 ++++ .../lib/src/types/flash_mode.dart | 15 ++++++++++++ .../lib/src/types/types.dart | 1 + .../camera_platform_interface/pubspec.yaml | 2 +- .../test/camera_platform_interface_test.dart | 13 ++++++++++ .../method_channel_camera_test.dart | 23 ++++++++++++++++++ .../test/types/flash_mode_test.dart | 22 +++++++++++++++++ 9 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart create mode 100644 packages/camera/camera_platform_interface/test/types/flash_mode_test.dart diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index 75d169ea1d6a..22efaaa3f85b 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.1 + +- Added interface methods for setting flash mode. + ## 1.0.0 - Initial open-source release diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index c649a41f5e9f..3086ae018d57 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -175,11 +175,35 @@ class MethodChannelCamera extends CameraPlatform { {'cameraId': cameraId}, ); + @override + Future setFlashMode(int cameraId, FlashMode mode) => + _channel.invokeMethod( + 'setFlashMode', + { + 'cameraId': cameraId, + 'mode': _serializeFlashMode(mode), + }, + ); + @override Widget buildPreview(int cameraId) { return Texture(textureId: cameraId); } + /// Returns the flash mode as a String. + String _serializeFlashMode(FlashMode flashMode) { + switch (flashMode) { + case FlashMode.off: + return 'off'; + case FlashMode.auto: + return 'auto'; + case FlashMode.always: + return 'always'; + default: + throw ArgumentError('Unknown FlashMode value'); + } + } + /// Returns the resolution preset as a String. String _serializeResolutionPreset(ResolutionPreset resolutionPreset) { switch (resolutionPreset) { diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 5281a423459a..5a1568b45a43 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -108,6 +108,11 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('resumeVideoRecording() is not implemented.'); } + /// Sets the flash mode for taking pictures. + Future setFlashMode(int cameraId, FlashMode mode) { + throw UnimplementedError('setFlashMode() is not implemented.'); + } + /// Returns a widget showing a live camera preview. Widget buildPreview(int cameraId) { throw UnimplementedError('buildView() has not been implemented.'); diff --git a/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart new file mode 100644 index 000000000000..6ed92e4801eb --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart @@ -0,0 +1,15 @@ +// Copyright 2019 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. + +/// The possible flash modes that can be set for a camera +enum FlashMode { + /// Do not use the flash when taking a picture. + off, + + /// Let the device decide whether to flash the camera when taking a picture. + auto, + + /// Always use the flash when taking a picture. + always, +} diff --git a/packages/camera/camera_platform_interface/lib/src/types/types.dart b/packages/camera/camera_platform_interface/lib/src/types/types.dart index 71e7a97ef49a..3a89a1021e95 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/types.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/types.dart @@ -5,3 +5,4 @@ export 'camera_description.dart'; export 'resolution_preset.dart'; export 'camera_exception.dart'; +export 'flash_mode.dart'; diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index c2bb6fcc5963..e29f7979f8b3 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.0.0 +version: 1.0.1 dependencies: flutter: diff --git a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart index 2bc35bf4055c..52b1b3ea34c4 100644 --- a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart +++ b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart @@ -173,6 +173,19 @@ void main() { ); }); + test( + 'Default implementation of setFlashMode() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.setFlashMode(1, null), + throwsUnimplementedError, + ); + }); + test( 'Default implementation of startVideoRecording() should throw unimplemented error', () { diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index 952a78e3408b..a42d9ab9769c 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -470,6 +470,29 @@ void main() { ]); }); + test('Should set the flash mode', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'setFlashMode': null}, + ); + + // Act + await camera.setFlashMode(cameraId, FlashMode.always); + await camera.setFlashMode(cameraId, FlashMode.auto); + await camera.setFlashMode(cameraId, FlashMode.off); + + // Assert + expect(channel.log, [ + isMethodCall('setFlashMode', + arguments: {'cameraId': cameraId, 'mode': 'always'}), + isMethodCall('setFlashMode', + arguments: {'cameraId': cameraId, 'mode': 'auto'}), + isMethodCall('setFlashMode', + arguments: {'cameraId': cameraId, 'mode': 'off'}), + ]); + }); + test('Should build a texture widget as preview widget', () async { // Act Widget widget = camera.buildPreview(cameraId); diff --git a/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart b/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart new file mode 100644 index 000000000000..59726acf7873 --- /dev/null +++ b/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart @@ -0,0 +1,22 @@ +// Copyright 2019 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 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('FlashMode should contain 3 options', () { + final values = FlashMode.values; + + expect(values.length, 3); + }); + + test("FlashMode enum should have items in correct index", () { + final values = FlashMode.values; + + expect(values[0], FlashMode.off); + expect(values[1], FlashMode.auto); + expect(values[2], FlashMode.always); + }); +} From a35f830382861f539d73300b4829e5b96452202a Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 10 Dec 2020 11:29:43 -0800 Subject: [PATCH 031/924] [image_picker] [integration_test] Fixes to make the tree green (#3317) --- .../image_picker/image_picker/CHANGELOG.md | 6 +++ .../ImagePickerFromGalleryUITests.m | 46 +++++++++++++++---- .../image_picker/image_picker/pubspec.yaml | 2 +- packages/integration_test/CHANGELOG.md | 4 ++ packages/integration_test/lib/common.dart | 4 +- packages/integration_test/pubspec.yaml | 2 +- 6 files changed, 50 insertions(+), 14 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 26e8b100cd20..970ddf1ed7ed 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.6.7+15 + +* Fix element type in XCUITests to look for staticText type when searching for texts. + * See https://github.com/flutter/flutter/issues/71927 +* Minor update in XCUITests to search for different elements on iOS 14 and above. + ## 0.6.7+14 * Set up XCUITests. diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m index 1ba8457c9709..74df795a3df3 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m @@ -21,18 +21,33 @@ - (void)setUp { self.continueAfterFailure = NO; self.app = [[XCUIApplication alloc] init]; [self.app launch]; + __weak typeof(self) weakSelf = self; [self addUIInterruptionMonitorWithDescription:@"Permission popups" handler:^BOOL(XCUIElement* _Nonnull interruptingElement) { - XCUIElement* ok = interruptingElement.buttons[@"OK"]; - if (ok.exists) { - [ok tap]; - } - // iOS 14. - XCUIElement* allPhotoPermission = - interruptingElement - .buttons[@"Allow Access to All Photos"]; - if (allPhotoPermission.exists) { + if (@available(iOS 14, *)) { + XCUIElement* allPhotoPermission = + interruptingElement + .buttons[@"Allow Access to All Photos"]; + if (![allPhotoPermission waitForExistenceWithTimeout: + kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", + self.app.debugDescription); + XCTFail(@"Failed due to not able to find " + @"allPhotoPermission button with %@ seconds", + @(kElementWaitingTime)); + } [allPhotoPermission tap]; + } else { + XCUIElement* ok = interruptingElement.buttons[@"OK"]; + if (![ok waitForExistenceWithTimeout: + kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", + self.app.debugDescription); + XCTFail(@"Failed due to not able to find ok button " + @"with %@ seconds", + @(kElementWaitingTime)); + } + [ok tap]; } return YES; }]; @@ -92,10 +107,21 @@ - (void)launchPickerAndCancel { [cancelButton tap]; // Find the "not picked image text". - XCUIElement* imageNotPickedText = [self.app.otherElements + XCUIElement* imageNotPickedText = [self.app.staticTexts elementMatchingPredicate:[NSPredicate predicateWithFormat:@"label == %@", @"You have not yet picked an image."]]; + if (![imageNotPickedText waitForExistenceWithTimeout:kElementWaitingTime]) { + // Before https://github.com/flutter/engine/pull/22811 the label's a11y type was otherElements. + // TODO(cyanglaz): Remove this after + // https://github.com/flutter/flutter/commit/057e8230743ec96f33b73948ccd6b80081e3615e rolled to + // stable. + // https://github.com/flutter/flutter/issues/71927 + imageNotPickedText = [self.app.otherElements + elementMatchingPredicate:[NSPredicate + predicateWithFormat:@"label == %@", + @"You have not yet picked an image."]]; + } if (![imageNotPickedText waitForExistenceWithTimeout:kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); XCTFail(@"Failed due to not able to find imageNotPickedText with %@ seconds", diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 2dcd7c137b7d..226602a99403 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+14 +version: 0.6.7+15 flutter: plugin: diff --git a/packages/integration_test/CHANGELOG.md b/packages/integration_test/CHANGELOG.md index 8c6f7abefca5..912e7404e906 100644 --- a/packages/integration_test/CHANGELOG.md +++ b/packages/integration_test/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.1 + +* Remove usages of deprecated `List` constructor. + ## 1.0.0 * Public stable release of plugin. diff --git a/packages/integration_test/lib/common.dart b/packages/integration_test/lib/common.dart index 53714a8e97ee..da93b3b51450 100644 --- a/packages/integration_test/lib/common.dart +++ b/packages/integration_test/lib/common.dart @@ -86,7 +86,7 @@ class Response { /// Create a list of Strings from [_failureDetails]. List _failureDetailsAsString() { - final List list = List(); + final List list = []; if (_failureDetails == null || _failureDetails.isEmpty) { return list; } @@ -100,7 +100,7 @@ class Response { /// Creates a [Failure] list using a json response. static List _failureDetailsFromJson(List list) { - final List failureList = List(); + final List failureList = []; list.forEach((s) { final String failure = s as String; failureList.add(Failure.fromJsonString(failure)); diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index 2daf3e543827..bef1ceb0a2e6 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -1,6 +1,6 @@ name: integration_test description: Runs tests that use the flutter_test API as integration tests. -version: 1.0.0 +version: 1.0.1 homepage: https://github.com/flutter/plugins/tree/master/packages/integration_test environment: From 284ad5de663c984c14dd00d70f09e53aa9d2e223 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 10 Dec 2020 20:38:07 +0100 Subject: [PATCH 032/924] [camera] Suppress unchecked cast warning in java test (#3316) * Suppress unchecked cast warning in java test * Bumped version number --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../java/io/flutter/plugins/camera/DartMessengerTest.java | 2 +- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index b07e3b86244d..0a6c050844fa 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.8+18 + +* Suppress unchecked warning in Android tests which prevented the tests to compile. + ## 0.5.8+17 * Added Android 30 support. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java index c5ea83aa058a..5a5358229c15 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java @@ -93,9 +93,9 @@ public void sendCameraClosingEvent() { assertNull(event.get("errorDescription")); } + @SuppressWarnings("unchecked") private Map decodeSentMessage(ByteBuffer sentMessage) { sentMessage.position(0); - //noinspection unchecked return (Map) StandardMethodCodec.INSTANCE.decodeEnvelope(sentMessage); } diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index f2151fc21c73..af8979d0df03 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.5.8+17 +version: 0.5.8+18 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 2f708d7a738c2f7ee58d1766310f794c71a17b16 Mon Sep 17 00:00:00 2001 From: Amir Hardon Date: Thu, 10 Dec 2020 15:59:23 -0800 Subject: [PATCH 033/924] update analysis options for nnbd (#3319) With NNBD assert(foo != null) for a non nullable foo generates an analysis error. However as long as we support mixed-mode we want these asserts it, so disabling the check. --- analysis_options.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/analysis_options.yaml b/analysis_options.yaml index b1261f36fac9..47cdbd2f98dc 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -4,6 +4,9 @@ analyzer: # Ignore generated files - '**/*.g.dart' - 'lib/src/generated/*.dart' + errors: + always_require_non_null_named_parameters: false # not needed with nnbd + unnecessary_null_comparison: false # Turned as long as nnbd mix-mode is supported. linter: rules: - public_member_api_docs From 7d392476ac20569c8afd9ebc5f0328d383fdc7c5 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Fri, 11 Dec 2020 09:33:30 +0100 Subject: [PATCH 034/924] [camera] Add zoom support to platform interface (#3312) * Add zoom support to platform interface * Added method to retrieve min supported zoom level * Bumped version to 1.0.2 * Fixed small typo --- .../camera_platform_interface/CHANGELOG.md | 4 + .../method_channel/method_channel_camera.dart | 27 +++++++ .../platform_interface/camera_platform.dart | 19 +++++ .../camera_platform_interface/pubspec.yaml | 2 +- .../test/camera_platform_interface_test.dart | 39 ++++++++++ .../method_channel_camera_test.dart | 78 +++++++++++++++++++ 6 files changed, 168 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index 22efaaa3f85b..ac0dce2cb4ea 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2 + +- Added interface methods to support zoom features. + ## 1.0.1 - Added interface methods for setting flash mode. diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index 3086ae018d57..bc836b0ac98e 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -185,6 +185,33 @@ class MethodChannelCamera extends CameraPlatform { }, ); + @override + Future getMaxZoomLevel(int cameraId) => _channel.invokeMethod( + 'getMaxZoomLevel', + {'cameraId': cameraId}, + ); + + @override + Future getMinZoomLevel(int cameraId) => _channel.invokeMethod( + 'getMinZoomLevel', + {'cameraId': cameraId}, + ); + + @override + Future setZoomLevel(int cameraId, double zoom) async { + try { + await _channel.invokeMethod( + 'setZoomLevel', + { + 'cameraId': cameraId, + 'zoom': zoom, + }, + ); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + @override Widget buildPreview(int cameraId) { return Texture(textureId: cameraId); diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 5a1568b45a43..c398e9e9ef17 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -113,6 +113,25 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('setFlashMode() is not implemented.'); } + /// Gets the maximum supported zoom level for the selected camera. + Future getMaxZoomLevel(int cameraId) { + throw UnimplementedError('getMaxZoomLevel() is not implemented.'); + } + + /// Gets the minimum supported zoom level for the selected camera. + Future getMinZoomLevel(int cameraId) { + throw UnimplementedError('getMinZoomLevel() is not implemented.'); + } + + /// Set the zoom level for the selected camera. + /// + /// The supplied [zoom] value should be between 1.0 and the maximum supported + /// zoom level returned by the `getMaxZoomLevel`. Throws an `CameraException` + /// when an illegal zoom level is supplied. + Future setZoomLevel(int cameraId, double zoom) { + throw UnimplementedError('setZoomLevel() is not implemented.'); + } + /// Returns a widget showing a live camera preview. Widget buildPreview(int cameraId) { throw UnimplementedError('buildView() has not been implemented.'); diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index e29f7979f8b3..1d1a7ec4565b 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.0.1 +version: 1.0.2 dependencies: flutter: diff --git a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart index 52b1b3ea34c4..7a6fc344503f 100644 --- a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart +++ b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart @@ -224,6 +224,45 @@ void main() { throwsUnimplementedError, ); }); + + test( + 'Default implementation of getMaxZoomLevel() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.getMaxZoomLevel(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of getMinZoomLevel() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.getMinZoomLevel(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of setZoomLevel() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.setZoomLevel(1, 1.0), + throwsUnimplementedError, + ); + }); }); } diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index a42d9ab9769c..c461b1fd583c 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -509,6 +509,84 @@ void main() { expect(() => camera.handleMethodCall(MethodCall('unknown_method'), 1), throwsA(isA())); }); + + test('Should get the max zoom level', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'getMaxZoomLevel': 10.0}, + ); + + // Act + final maxZoomLevel = await camera.getMaxZoomLevel(cameraId); + + // Assert + expect(maxZoomLevel, 10.0); + expect(channel.log, [ + isMethodCall('getMaxZoomLevel', arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test('Should get the min zoom level', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'getMinZoomLevel': 1.0}, + ); + + // Act + final maxZoomLevel = await camera.getMinZoomLevel(cameraId); + + // Assert + expect(maxZoomLevel, 1.0); + expect(channel.log, [ + isMethodCall('getMinZoomLevel', arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test('Should set the zoom level', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'setZoomLevel': null}, + ); + + // Act + await camera.setZoomLevel(cameraId, 2.0); + + // Assert + expect(channel.log, [ + isMethodCall('setZoomLevel', + arguments: {'cameraId': cameraId, 'zoom': 2.0}), + ]); + }); + + test('Should throw CameraException when illegal zoom level is supplied', + () async { + // Arrange + MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: { + 'setZoomLevel': PlatformException( + code: 'ZOOM_ERROR', + message: 'Illegal zoom error', + details: null, + ) + }, + ); + + // Act & assert + expect( + () => camera.setZoomLevel(cameraId, -1.0), + throwsA(isA() + .having((e) => e.code, 'code', 'ZOOM_ERROR') + .having((e) => e.description, 'description', + 'Illegal zoom error'))); + }); }); }); } From 298fb23e2d33ad260a3741d05f6113f955b45ce0 Mon Sep 17 00:00:00 2001 From: Francesco Iapicca Date: Fri, 11 Dec 2020 22:26:08 +0200 Subject: [PATCH 035/924] [documentation] [url_launcher] fix for readme code sample (#3308) * code sample fixed * updated CHANGELOG.md and pubspec.yaml --- .../url_launcher/url_launcher/CHANGELOG.md | 4 +++ packages/url_launcher/url_launcher/README.md | 33 +++++++++---------- .../url_launcher/url_launcher/pubspec.yaml | 2 +- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 72a0cc92e37a..c92c4f5784aa 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.7.12 + +* Updated code sample in `README.md` + ## 5.7.11 * Update integration test examples to use `testWidgets` instead of `test`. diff --git a/packages/url_launcher/url_launcher/README.md b/packages/url_launcher/url_launcher/README.md index 811dcd5b4ea1..f29b5327a611 100644 --- a/packages/url_launcher/url_launcher/README.md +++ b/packages/url_launcher/url_launcher/README.md @@ -14,26 +14,23 @@ To use this plugin, add `url_launcher` as a [dependency in your pubspec.yaml fil import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; -void main() { - runApp(Scaffold( - body: Center( - child: RaisedButton( - onPressed: _launchURL, - child: Text('Show Flutter homepage'), +const _url = 'https://flutter.dev'; + +void main() => runApp( + const MaterialApp( + home: Material( + child: Center( + child: RaisedButton( + onPressed: _launchURL, + child: Text('Show Flutter homepage'), + ), + ), + ), ), - ), - )); -} - -_launchURL() async { - const url = 'https://flutter.dev'; - if (await canLaunch(url)) { - await launch(url); - } else { - throw 'Could not launch $url'; - } -} + ); +void _launchURL() async => + await canLaunch(_url) ? await launch(_url) : throw 'Could not launch $_url'; ``` ## Supported URL schemes diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 4d5e3a7cb0bd..e4fc0f1d654c 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 5.7.11 +version: 5.7.12 flutter: plugin: From 6870b08bd56a94bd52ca95b62cdbf39253dd0698 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Fri, 11 Dec 2020 14:26:17 -0800 Subject: [PATCH 036/924] Exclude null-safe plugins from testing on stable (#3318) --- script/build_all_plugins_app.sh | 12 +++++++++++- script/incremental_build.sh | 15 ++++++++++++--- script/nnbd_plugins.sh | 11 +++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 script/nnbd_plugins.sh diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index f1f68ddbe985..f2897f8aa9a2 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -8,6 +8,8 @@ readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd)" readonly REPO_DIR="$(dirname "$SCRIPT_DIR")" source "$SCRIPT_DIR/common.sh" +source "$SCRIPT_DIR/nnbd_plugins.sh" + check_changed_packages > /dev/null readonly EXCLUDED_PLUGINS_LIST=( @@ -42,7 +44,15 @@ readonly EXCLUDED_PLUGINS_LIST=( # Comma-separated string of the list above readonly EXCLUDED=$(IFS=, ; echo "${EXCLUDED_PLUGINS_LIST[*]}") -(cd "$REPO_DIR" && pub global run flutter_plugin_tools all-plugins-app --exclude $EXCLUDED) +ALL_EXCLUDED=($EXCLUDED) +# Exclude nnbd plugins from stable. +if [[ "$CHANNEL" -eq "stable" ]]; then + ALL_EXCLUDED=("$EXCLUDED,$EXCLUDED_PLUGINS_FROM_STABLE") +fi + +echo "Excluding the following plugins: $ALL_EXCLUDED" + +(cd "$REPO_DIR" && pub global run flutter_plugin_tools all-plugins-app --exclude $ALL_EXCLUDED) function error() { echo "$@" 1>&2 diff --git a/script/incremental_build.sh b/script/incremental_build.sh index f89bc1d0e5c9..671ce66a086f 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -5,6 +5,7 @@ readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" readonly REPO_DIR="$(dirname "$SCRIPT_DIR")" source "$SCRIPT_DIR/common.sh" +source "$SCRIPT_DIR/nnbd_plugins.sh" if [ "$(expr substr $(uname -s) 1 5)" == "MINGW" ]; then PUB=pub.bat @@ -12,6 +13,14 @@ else PUB=pub fi +# Plugins that are excluded from this task. +ALL_EXCLUDED=("") +# Exclude nnbd plugins from stable. +if [[ "$CHANNEL" -eq "stable" ]]; then + ALL_EXCLUDED=($EXCLUDED_PLUGINS_FROM_STABLE) + echo "Excluding the following plugins: $ALL_EXCLUDED" +fi + # Plugins that deliberately use their own analysis_options.yaml. # # This list should only be deleted from, never added to. This only exists @@ -39,7 +48,7 @@ PLUGIN_SHARDING=($PLUGIN_SHARDING) if [[ "${BRANCH_NAME}" == "master" ]]; then echo "Running for all packages" - (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" ${PLUGIN_SHARDING[@]}) + (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) else # Sets CHANGED_PACKAGES check_changed_packages @@ -47,10 +56,10 @@ else if [[ "$CHANGED_PACKAGES" == "" ]]; then echo "No changes detected in packages." echo "Running for all packages" - (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" ${PLUGIN_SHARDING[@]}) + (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) else echo running "${ACTIONS[@]}" - (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" --plugins="$CHANGED_PACKAGES" ${PLUGIN_SHARDING[@]}) + (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" --plugins="$CHANGED_PACKAGES" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) echo "Running version check for changed packages" (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools version-check --base_sha="$(get_branch_base_sha)") fi diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh new file mode 100644 index 000000000000..5d167d7b5da6 --- /dev/null +++ b/script/nnbd_plugins.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# This script contains the list of plugins migrated to nnbd +# that should be excluded from testing on Flutter stable until +# null-safe is available on stable. + +readonly NNBD_PLUGINS_LIST=( + "flutter_webview" +) + +export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}") From 163e7c2a1e8b2f63518e8a3eadb748ffc167d586 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Fri, 11 Dec 2020 15:44:46 -0800 Subject: [PATCH 037/924] [image_picker_platform_interface] Pass Uri to package:http APIs (#3309) This is in preparation for https://github.com/dart-lang/http/issues/375 --- .../image_picker/image_picker_platform_interface/CHANGELOG.md | 4 ++++ .../lib/src/types/picked_file/html.dart | 2 +- .../image_picker/image_picker_platform_interface/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index 1ed45028f513..a7da543bd7f9 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.4 + +* Pass `Uri`s to `package:http` methods, instead of strings, in preparation for a major version update in `http`. + ## 1.1.3 * Update documentation of `pickImage()` regarding HEIC images. 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 0faf531f3f75..ee5145009dc7 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 @@ -24,7 +24,7 @@ class PickedFile extends PickedFileBase { if (_initBytes != null) { return Future.value(UnmodifiableUint8ListView(_initBytes)); } - return http.readBytes(path); + return http.readBytes(Uri.parse(path)); } @override diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 39a65284e247..2ada3b66d700 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the image_picker plugin. 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.3 +version: 1.1.4 dependencies: flutter: From 6473b5c0ee0a597ae470e32f53f043e805d7d218 Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Sat, 12 Dec 2020 00:45:41 +0100 Subject: [PATCH 038/924] [a-c] Update Flutter SDK constraint (#3320) Update Flutter SDK constraint to match templates. --- packages/android_alarm_manager/CHANGELOG.md | 4 ++++ packages/android_alarm_manager/pubspec.yaml | 4 ++-- packages/android_intent/CHANGELOG.md | 4 ++++ packages/android_intent/pubspec.yaml | 4 ++-- packages/battery/battery/CHANGELOG.md | 4 ++++ packages/battery/battery/pubspec.yaml | 4 ++-- packages/battery/battery_platform_interface/CHANGELOG.md | 4 ++++ packages/battery/battery_platform_interface/pubspec.yaml | 4 ++-- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/pubspec.yaml | 4 ++-- packages/camera/camera_platform_interface/CHANGELOG.md | 4 ++++ packages/camera/camera_platform_interface/pubspec.yaml | 4 ++-- packages/connectivity/connectivity/CHANGELOG.md | 4 ++++ packages/connectivity/connectivity/pubspec.yaml | 4 ++-- packages/connectivity/connectivity_macos/CHANGELOG.md | 4 ++++ packages/connectivity/connectivity_macos/pubspec.yaml | 4 ++-- .../connectivity_platform_interface/CHANGELOG.md | 4 ++++ .../connectivity_platform_interface/pubspec.yaml | 4 ++-- packages/cross_file/CHANGELOG.md | 4 ++++ packages/cross_file/pubspec.yaml | 5 ++--- 20 files changed, 60 insertions(+), 21 deletions(-) diff --git a/packages/android_alarm_manager/CHANGELOG.md b/packages/android_alarm_manager/CHANGELOG.md index 023a140fbcc9..e0c436d79eea 100644 --- a/packages/android_alarm_manager/CHANGELOG.md +++ b/packages/android_alarm_manager/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.5+18 + +* Update Flutter SDK constraint. + ## 0.4.5+17 * Update Dart SDK constraint in example. diff --git a/packages/android_alarm_manager/pubspec.yaml b/packages/android_alarm_manager/pubspec.yaml index 9de2d8308419..5b6780b4b14a 100644 --- a/packages/android_alarm_manager/pubspec.yaml +++ b/packages/android_alarm_manager/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for accessing the Android AlarmManager service, and # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.5+17 +version: 0.4.5+18 homepage: https://github.com/flutter/plugins/tree/master/packages/android_alarm_manager dependencies: @@ -25,4 +25,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/android_intent/CHANGELOG.md b/packages/android_intent/CHANGELOG.md index 5a3ba03b33eb..f3534982a971 100644 --- a/packages/android_intent/CHANGELOG.md +++ b/packages/android_intent/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.7+8 + +* Update Flutter SDK constraint. + ## 0.3.7+7 * Update Dart SDK constraint in example. diff --git a/packages/android_intent/pubspec.yaml b/packages/android_intent/pubspec.yaml index 8d41d5165c68..1b63371e488c 100644 --- a/packages/android_intent/pubspec.yaml +++ b/packages/android_intent/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/android_intent # 0.3.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.3.7+7 +version: 0.3.7+8 flutter: plugin: @@ -27,4 +27,4 @@ dev_dependencies: environment: sdk: ">=2.3.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/battery/battery/CHANGELOG.md b/packages/battery/battery/CHANGELOG.md index 260f3efeb8ad..c9bf41a81baf 100644 --- a/packages/battery/battery/CHANGELOG.md +++ b/packages/battery/battery/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.9 + +* Update Flutter SDK constraint. + ## 1.0.8 * Update Dart SDK constraint in example. diff --git a/packages/battery/battery/pubspec.yaml b/packages/battery/battery/pubspec.yaml index ec747190ac69..c7d4f0a9f5c2 100644 --- a/packages/battery/battery/pubspec.yaml +++ b/packages/battery/battery/pubspec.yaml @@ -2,7 +2,7 @@ name: battery description: Flutter plugin for accessing information about the battery state (full, charging, discharging) on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/battery/battery -version: 1.0.8 +version: 1.0.9 flutter: plugin: @@ -32,4 +32,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/battery/battery_platform_interface/CHANGELOG.md b/packages/battery/battery_platform_interface/CHANGELOG.md index 6fadda91b380..09ac38cc5b4b 100644 --- a/packages/battery/battery_platform_interface/CHANGELOG.md +++ b/packages/battery/battery_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.1 + +- Update Flutter SDK constraint. + ## 1.0.0 - Initial open-source release. diff --git a/packages/battery/battery_platform_interface/pubspec.yaml b/packages/battery/battery_platform_interface/pubspec.yaml index 6c571debc7b0..e88ef378be6e 100644 --- a/packages/battery/battery_platform_interface/pubspec.yaml +++ b/packages/battery/battery_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the battery plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/battery # 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.0.0 +version: 1.0.1 dependencies: flutter: @@ -19,4 +19,4 @@ dev_dependencies: environment: sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.9.1+hotfix.4 <2.0.0" + flutter: ">=1.9.1+hotfix.4" diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 0a6c050844fa..d1d11c4d8877 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.8+19 + +* Update Flutter SDK constraint. + ## 0.5.8+18 * Suppress unchecked warning in Android tests which prevented the tests to compile. diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index af8979d0df03..146219d8366f 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.5.8+18 +version: 0.5.8+19 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: @@ -29,4 +29,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index ac0dce2cb4ea..500e8d67a6e4 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.3 + +- Update Flutter SDK constraint. + ## 1.0.2 - Added interface methods to support zoom features. diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index 1d1a7ec4565b..9349c5536ff2 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.0.2 +version: 1.0.3 dependencies: flutter: @@ -22,4 +22,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.22.0 <2.0.0" + flutter: ">=1.22.0" diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index 72b6d9b6513a..b993bf15dc8b 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.3 + +* Update Flutter SDK constraint. + ## 2.0.2 * Android: Fix IllegalArgumentException. diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index 91d06373ab83..1a53f42fa3cb 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -2,7 +2,7 @@ name: connectivity description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity -version: 2.0.2 +version: 2.0.3 flutter: plugin: @@ -38,4 +38,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/connectivity/connectivity_macos/CHANGELOG.md b/packages/connectivity/connectivity_macos/CHANGELOG.md index 87910374bb8b..f7c893e6fdb4 100644 --- a/packages/connectivity/connectivity_macos/CHANGELOG.md +++ b/packages/connectivity/connectivity_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0+8 + +* Update Flutter SDK constraint. + ## 0.1.0+7 * Remove unused `test` dependency. diff --git a/packages/connectivity/connectivity_macos/pubspec.yaml b/packages/connectivity/connectivity_macos/pubspec.yaml index 2ab493072f8c..acd608fa2505 100644 --- a/packages/connectivity/connectivity_macos/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the connectivity plugin. # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.0+7 +version: 0.1.0+8 homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_macos flutter: @@ -14,7 +14,7 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" dependencies: flutter: diff --git a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md index e45f8f7e4d99..2a16860c3cc4 100644 --- a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md +++ b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.7 + +* Update Flutter SDK constraint. + ## 1.0.6 * Update lower bound of dart dependency to 2.1.0. diff --git a/packages/connectivity/connectivity_platform_interface/pubspec.yaml b/packages/connectivity/connectivity_platform_interface/pubspec.yaml index 5bafcf9b806b..7aa415c9d36f 100644 --- a/packages/connectivity/connectivity_platform_interface/pubspec.yaml +++ b/packages/connectivity/connectivity_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the connectivity plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_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.0.6 +version: 1.0.7 dependencies: flutter: @@ -18,4 +18,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md index 3b5ae7756a98..b5d8a5695c5e 100644 --- a/packages/cross_file/CHANGELOG.md +++ b/packages/cross_file/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0+1 + +- Update Flutter SDK constraint. + ## 0.1.0 - Initial open-source release \ No newline at end of file diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml index 40084d3d1ea0..495a0ced5eee 100644 --- a/packages/cross_file/pubspec.yaml +++ b/packages/cross_file/pubspec.yaml @@ -1,8 +1,7 @@ - name: cross_file description: An abstraction to allow working with files across multiple platforms. homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file -version: 0.1.0 +version: 0.1.0+1 dependencies: flutter: @@ -17,4 +16,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.22.0 <2.0.0" \ No newline at end of file + flutter: ">=1.22.0" From af9d38b1830d2d5326bee52da4803cad70159173 Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Sat, 12 Dec 2020 00:46:35 +0100 Subject: [PATCH 039/924] [d-g] Update Flutter SDK constraint (#3321) Update Flutter SDK constraint to match templates. --- packages/device_info/device_info/CHANGELOG.md | 4 ++++ packages/device_info/device_info/pubspec.yaml | 4 ++-- .../device_info/device_info_platform_interface/CHANGELOG.md | 4 ++++ .../device_info/device_info_platform_interface/pubspec.yaml | 4 ++-- packages/espresso/CHANGELOG.md | 4 ++++ packages/espresso/pubspec.yaml | 4 ++-- packages/file_selector/file_selector/CHANGELOG.md | 4 ++++ packages/file_selector/file_selector/pubspec.yaml | 4 ++-- .../file_selector_platform_interface/CHANGELOG.md | 4 ++++ .../file_selector_platform_interface/pubspec.yaml | 4 ++-- packages/flutter_plugin_android_lifecycle/CHANGELOG.md | 4 ++++ packages/flutter_plugin_android_lifecycle/pubspec.yaml | 4 ++-- packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md | 4 ++++ packages/google_maps_flutter/google_maps_flutter/pubspec.yaml | 4 ++-- .../google_maps_flutter_platform_interface/CHANGELOG.md | 4 ++++ .../google_maps_flutter_platform_interface/pubspec.yaml | 4 ++-- .../google_maps_flutter/google_maps_flutter_web/CHANGELOG.md | 4 ++++ .../google_maps_flutter/google_maps_flutter_web/pubspec.yaml | 4 ++-- .../extension_google_sign_in_as_googleapis_auth/CHANGELOG.md | 4 ++++ .../extension_google_sign_in_as_googleapis_auth/pubspec.yaml | 4 ++-- packages/google_sign_in/google_sign_in/CHANGELOG.md | 4 ++++ packages/google_sign_in/google_sign_in/pubspec.yaml | 4 ++-- .../google_sign_in_platform_interface/CHANGELOG.md | 4 ++++ .../google_sign_in_platform_interface/pubspec.yaml | 4 ++-- packages/google_sign_in/google_sign_in_web/CHANGELOG.md | 4 ++++ packages/google_sign_in/google_sign_in_web/pubspec.yaml | 4 ++-- 26 files changed, 78 insertions(+), 26 deletions(-) diff --git a/packages/device_info/device_info/CHANGELOG.md b/packages/device_info/device_info/CHANGELOG.md index 06b327f4a198..29382c1ccb61 100644 --- a/packages/device_info/device_info/CHANGELOG.md +++ b/packages/device_info/device_info/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.1 + +* Update Flutter SDK constraint. + ## 1.0.0 * Announce 1.0.0. diff --git a/packages/device_info/device_info/pubspec.yaml b/packages/device_info/device_info/pubspec.yaml index 5b00750fcbbc..0f31234414f5 100644 --- a/packages/device_info/device_info/pubspec.yaml +++ b/packages/device_info/device_info/pubspec.yaml @@ -2,7 +2,7 @@ name: device_info description: Flutter plugin providing detailed information about the device (make, model, etc.), and Android or iOS version the app is running on. homepage: https://github.com/flutter/plugins/tree/master/packages/device_info -version: 1.0.0 +version: 1.0.1 flutter: plugin: @@ -26,4 +26,4 @@ dev_dependencies: environment: sdk: ">=2.1.0<3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/device_info/device_info_platform_interface/CHANGELOG.md b/packages/device_info/device_info_platform_interface/CHANGELOG.md index 8a7eb6c46be3..e513c662bef7 100644 --- a/packages/device_info/device_info_platform_interface/CHANGELOG.md +++ b/packages/device_info/device_info_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2 + +- Update Flutter SDK constraint. + ## 1.0.1 - Documentation typo fixed. diff --git a/packages/device_info/device_info_platform_interface/pubspec.yaml b/packages/device_info/device_info_platform_interface/pubspec.yaml index 656e5b24c373..fedaba6c6522 100644 --- a/packages/device_info/device_info_platform_interface/pubspec.yaml +++ b/packages/device_info/device_info_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the device_info plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/device_info # 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.0.1 +version: 1.0.2 dependencies: flutter: @@ -19,4 +19,4 @@ dev_dependencies: environment: sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.9.1+hotfix.4 <2.0.0" + flutter: ">=1.9.1+hotfix.4" diff --git a/packages/espresso/CHANGELOG.md b/packages/espresso/CHANGELOG.md index 0ab068056df9..fe43202b7654 100644 --- a/packages/espresso/CHANGELOG.md +++ b/packages/espresso/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.1+9 + +* Update Flutter SDK constraint. + ## 0.0.1+8 * Android: Handle deprecation & unchecked warning as error. diff --git a/packages/espresso/pubspec.yaml b/packages/espresso/pubspec.yaml index 39b88cb98940..e7e1f6691ed3 100644 --- a/packages/espresso/pubspec.yaml +++ b/packages/espresso/pubspec.yaml @@ -1,11 +1,11 @@ name: espresso description: Java classes for testing Flutter apps using Espresso. -version: 0.0.1+8 +version: 0.0.1+9 homepage: https://github.com/flutter/plugins/espresso environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" dependencies: flutter: diff --git a/packages/file_selector/file_selector/CHANGELOG.md b/packages/file_selector/file_selector/CHANGELOG.md index 8dab88a33cef..92136485a447 100644 --- a/packages/file_selector/file_selector/CHANGELOG.md +++ b/packages/file_selector/file_selector/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+1 + +* Update Flutter SDK constraint. + ## 0.7.0 * Initial Open Source release. diff --git a/packages/file_selector/file_selector/pubspec.yaml b/packages/file_selector/file_selector/pubspec.yaml index 5a90f048c314..f095ba1f6a36 100644 --- a/packages/file_selector/file_selector/pubspec.yaml +++ b/packages/file_selector/file_selector/pubspec.yaml @@ -1,7 +1,7 @@ name: file_selector description: Flutter plugin for opening and saving files. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector -version: 0.7.0 +version: 0.7.0+1 dependencies: flutter: @@ -18,4 +18,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md index 7f1d5732ec9b..0d6d6d08c298 100644 --- a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md +++ b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.3 + +* Update Flutter SDK constraint. + ## 1.0.2 * Replace locally defined `XFile` types with the versions from the [cross_file](https://pub.dev/packages/cross_file) package. diff --git a/packages/file_selector/file_selector_platform_interface/pubspec.yaml b/packages/file_selector/file_selector_platform_interface/pubspec.yaml index a0a3d28922fe..2d0b7c954ece 100644 --- a/packages/file_selector/file_selector_platform_interface/pubspec.yaml +++ b/packages/file_selector/file_selector_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the file_selector plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_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.0.2 +version: 1.0.3 dependencies: flutter: @@ -22,4 +22,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.9.1+hotfix.4 <2.0.0" + flutter: ">=1.9.1+hotfix.4" diff --git a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md index 401be5f5278a..43797321f614 100644 --- a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md +++ b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.12 + +* Update Flutter SDK constraint. + ## 1.0.11 * Keep handling deprecated Android v1 classes for backward compatibility. diff --git a/packages/flutter_plugin_android_lifecycle/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/pubspec.yaml index a671381b3f47..57441d08de7a 100644 --- a/packages/flutter_plugin_android_lifecycle/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/pubspec.yaml @@ -1,11 +1,11 @@ name: flutter_plugin_android_lifecycle description: Flutter plugin for accessing an Android Lifecycle within other plugins. -version: 1.0.11 +version: 1.0.12 homepage: https://github.com/flutter/plugins/tree/master/packages/flutter_plugin_android_lifecycle environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13 <2.0.0" + flutter: ">=1.12.13" dependencies: flutter: diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index 12e9ab4b55f7..75788a5d97fe 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.8 + +* Update Flutter SDK constraint. + ## 1.0.7 * Android: Handle deprecation & unchecked warning as error. diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 06d5fb2f4257..b2f23805d863 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 1.0.7 +version: 1.0.8 dependencies: flutter: @@ -33,4 +33,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.22.0 <2.0.0" + flutter: ">=1.22.0" diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index 0586ac414d97..b40fc9d40e5b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.6 + +* Update Flutter SDK constraint. + ## 1.0.5 * Temporarily add a `fromJson` constructor to `BitmapDescriptor` so serialized descriptors can be synchronously re-hydrated. This will be removed when a fix for [this issue](https://github.com/flutter/flutter/issues/70330) lands. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index a2b5ff56fee1..633478c5d636 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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.0.5 +version: 1.0.6 dependencies: flutter: @@ -20,4 +20,4 @@ dev_dependencies: environment: sdk: ">=2.3.0 <3.0.0" - flutter: ">=1.9.1+hotfix.4 <2.0.0" + flutter: ">=1.9.1+hotfix.4" diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index dcafa12a2c13..2d03ab254bc0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0+9 + +* Update Flutter SDK constraint. + ## 0.1.0+8 * Update `package:google_maps_flutter_platform_interface` to `^1.0.5`. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index 237415318aac..b41e24c25357 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.1.0+8 +version: 0.1.0+9 flutter: plugin: @@ -33,4 +33,4 @@ dev_dependencies: environment: sdk: ">=2.3.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md index 3425ff6c34b0..b2e5e7920db3 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2 + +* Update Flutter SDK constraint. + ## 1.0.1 * Update android compileSdkVersion to 29. diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml index c978ce446714..39243e719b8a 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml @@ -6,7 +6,7 @@ name: extension_google_sign_in_as_googleapis_auth description: A bridge package between google_sign_in and googleapis_auth, to create Authenticated Clients from google_sign_in user credentials. -version: 1.0.1 +version: 1.0.2 homepage: https://github.com/flutter/plugins/google_sign_in/extension_google_sign_in_as_googleapis_auth dependencies: @@ -25,4 +25,4 @@ dev_dependencies: environment: sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4 <2.0.0" + flutter: ">=1.12.13+hotfix.4" diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md index 7f4bfddfa45a..3c9605eb9752 100644 --- a/packages/google_sign_in/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.5.7 + +* Update Flutter SDK constraint. + ## 4.5.6 * Fix deprecated member warning in tests. diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index a63091b945b2..ea1218543d83 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in -version: 4.5.6 +version: 4.5.7 flutter: plugin: @@ -39,4 +39,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4 <2.0.0" + flutter: ">=1.12.13+hotfix.4" diff --git a/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md b/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md index aa8ad2cff80f..e69e912195bf 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.3 + +* Update Flutter SDK constraint. + ## 1.1.2 * Update lower bound of dart dependency to 2.1.0. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml b/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml index 7bc63d84110c..8edeba0072a8 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_sign_in plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in_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.2 +version: 1.1.3 dependencies: flutter: @@ -19,4 +19,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md index d71badc53bfc..d1353f723fd5 100644 --- a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.2+1 + +* Update Flutter SDK constraint. + ## 0.9.2 * Throw PlatformExceptions from where the GMaps SDK may throw exceptions: `init()` and `signIn()`. diff --git a/packages/google_sign_in/google_sign_in_web/pubspec.yaml b/packages/google_sign_in/google_sign_in_web/pubspec.yaml index 70758ac6830d..ac9d36bd15be 100644 --- a/packages/google_sign_in/google_sign_in_web/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_web/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_web description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android, iOS and Web. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in_web -version: 0.9.2 +version: 0.9.2+1 flutter: plugin: @@ -31,4 +31,4 @@ dev_dependencies: environment: sdk: ">=2.6.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4 <2.0.0" + flutter: ">=1.12.13+hotfix.4" From 2cca4fed7696b729afe659b574684627063e0266 Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Sat, 12 Dec 2020 00:54:58 +0100 Subject: [PATCH 040/924] [i-p] Update Flutter SDK constraint (#3322) Update Flutter SDK constraint to match templates. --- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ packages/image_picker/image_picker/pubspec.yaml | 4 ++-- packages/image_picker/image_picker_for_web/CHANGELOG.md | 4 ++++ packages/image_picker/image_picker_for_web/pubspec.yaml | 4 ++-- .../image_picker_platform_interface/CHANGELOG.md | 4 ++++ .../image_picker_platform_interface/pubspec.yaml | 4 ++-- packages/in_app_purchase/CHANGELOG.md | 4 ++++ packages/in_app_purchase/pubspec.yaml | 4 ++-- packages/integration_test/CHANGELOG.md | 4 ++++ packages/integration_test/pubspec.yaml | 4 ++-- packages/ios_platform_images/CHANGELOG.md | 4 ++++ packages/ios_platform_images/pubspec.yaml | 6 ++---- packages/local_auth/CHANGELOG.md | 4 ++++ packages/local_auth/pubspec.yaml | 4 ++-- packages/package_info/CHANGELOG.md | 4 ++++ packages/package_info/pubspec.yaml | 4 ++-- packages/path_provider/path_provider/CHANGELOG.md | 4 ++++ packages/path_provider/path_provider/pubspec.yaml | 4 ++-- packages/path_provider/path_provider_linux/CHANGELOG.md | 4 ++++ packages/path_provider/path_provider_linux/pubspec.yaml | 4 ++-- packages/path_provider/path_provider_macos/CHANGELOG.md | 4 ++++ packages/path_provider/path_provider_macos/pubspec.yaml | 4 ++-- .../path_provider_platform_interface/CHANGELOG.md | 4 ++++ .../path_provider_platform_interface/pubspec.yaml | 4 ++-- packages/path_provider/path_provider_windows/CHANGELOG.md | 4 ++++ packages/path_provider/path_provider_windows/pubspec.yaml | 4 ++-- 26 files changed, 78 insertions(+), 28 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 970ddf1ed7ed..70a1cb21b354 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+16 + +* Update Flutter SDK constraint. + ## 0.6.7+15 * Fix element type in XCUITests to look for staticText type when searching for texts. diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 226602a99403..4eb16beec641 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+15 +version: 0.6.7+16 flutter: plugin: @@ -29,4 +29,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md index 604314240a1e..4c452ee78de9 100644 --- a/packages/image_picker/image_picker_for_web/CHANGELOG.md +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.1.0+3 + +* Update Flutter SDK constraint. + # 0.1.0+2 * Adds Video MIME Types for the safari browser for acception diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index 32e89437415e..b7e079b39ce0 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/i # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.0+2 +version: 0.1.0+3 flutter: plugin: @@ -29,4 +29,4 @@ dev_dependencies: environment: sdk: ">=2.5.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index a7da543bd7f9..efcef0146cdc 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.5 + +* Update Flutter SDK constraint. + ## 1.1.4 * Pass `Uri`s to `package:http` methods, instead of strings, in preparation for a major version update in `http`. diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 2ada3b66d700..7943a2a3eccd 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the image_picker plugin. 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.4 +version: 1.1.5 dependencies: flutter: @@ -20,4 +20,4 @@ dev_dependencies: environment: sdk: ">=2.5.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index 6207da9b403c..7b3301cf41cf 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.4+17 + +* Update Flutter SDK constraint. + ## 0.3.4+16 * Add Dartdocs to all public APIs. diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index eda865e487f7..4b009b1383fd 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.3.4+16 +version: 0.3.4+17 dependencies: async: ^2.0.8 @@ -37,4 +37,4 @@ flutter: environment: sdk: ">=2.3.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/integration_test/CHANGELOG.md b/packages/integration_test/CHANGELOG.md index 912e7404e906..4bbfe591d6cc 100644 --- a/packages/integration_test/CHANGELOG.md +++ b/packages/integration_test/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2 + +* Update Flutter SDK constraint. + ## 1.0.1 * Remove usages of deprecated `List` constructor. diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index bef1ceb0a2e6..997faa79e1ca 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -1,11 +1,11 @@ name: integration_test description: Runs tests that use the flutter_test API as integration tests. -version: 1.0.1 +version: 1.0.2 homepage: https://github.com/flutter/plugins/tree/master/packages/integration_test environment: sdk: ">=2.2.2 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" dependencies: flutter: diff --git a/packages/ios_platform_images/CHANGELOG.md b/packages/ios_platform_images/CHANGELOG.md index a83f22ec7571..4b11b40f5510 100644 --- a/packages/ios_platform_images/CHANGELOG.md +++ b/packages/ios_platform_images/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.2+4 + +* Update Flutter SDK constraint. + ## 0.1.2+3 * Remove no-op android folder in the example app. diff --git a/packages/ios_platform_images/pubspec.yaml b/packages/ios_platform_images/pubspec.yaml index 482097a515b8..7049b62cf00a 100644 --- a/packages/ios_platform_images/pubspec.yaml +++ b/packages/ios_platform_images/pubspec.yaml @@ -1,11 +1,11 @@ name: ios_platform_images description: A plugin to share images between Flutter and iOS in add-to-app setups. -version: 0.1.2+3 +version: 0.1.2+4 homepage: https://github.com/flutter/plugins/tree/master/packages/ios_platform_images/ios_platform_images environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" dependencies: flutter: @@ -29,7 +29,6 @@ flutter: platforms: ios: pluginClass: IosPlatformImagesPlugin - # To add assets to your plugin package, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg @@ -40,7 +39,6 @@ flutter: # # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. - # To add custom fonts to your plugin package, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index 96388a76ab4f..0ea59f37bf45 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.3+5 + +* Update Flutter SDK constraint. + ## 0.6.3+4 * Update Dart SDK constraint in example. diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 6ba77aca6679..834980b7131d 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth description: Flutter plugin for Android and iOS device authentication sensors such as Fingerprint Reader and Touch ID. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 0.6.3+4 +version: 0.6.3+5 flutter: plugin: @@ -32,4 +32,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/package_info/CHANGELOG.md b/packages/package_info/CHANGELOG.md index 21319fe4fbf1..ebb95c1da17e 100644 --- a/packages/package_info/CHANGELOG.md +++ b/packages/package_info/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.3+3 + +* Update Flutter SDK constraint. + ## 0.4.3+2 * Remove unused `test` dependency. diff --git a/packages/package_info/pubspec.yaml b/packages/package_info/pubspec.yaml index cb46ca66b9a4..884a71659a48 100644 --- a/packages/package_info/pubspec.yaml +++ b/packages/package_info/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/package_info # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.3+2 +version: 0.4.3+3 flutter: plugin: @@ -33,4 +33,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index 646a2e36bc9e..551e040f0488 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.25 + +* Update Flutter SDK constraint. + ## 1.6.24 * Remove unused `test` dependency. diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index b3960941acff..4be15fad09ff 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 1.6.24 +version: 1.6.25 flutter: plugin: @@ -40,4 +40,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/path_provider/path_provider_linux/CHANGELOG.md b/packages/path_provider/path_provider_linux/CHANGELOG.md index bf043c6e6954..ee382b04710b 100644 --- a/packages/path_provider/path_provider_linux/CHANGELOG.md +++ b/packages/path_provider/path_provider_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.1+3 + +* Update Flutter SDK constraint. + ## 0.1.1+2 * Log errors in the example when calls to the `path_provider` fail. diff --git a/packages/path_provider/path_provider_linux/pubspec.yaml b/packages/path_provider/path_provider_linux/pubspec.yaml index fac82d24829f..adabbdd45246 100644 --- a/packages/path_provider/path_provider_linux/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: path_provider_linux description: linux implementation of the path_provider plugin -version: 0.1.1+2 +version: 0.1.1+3 homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_linux flutter: @@ -12,7 +12,7 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" dependencies: path: ^1.6.4 diff --git a/packages/path_provider/path_provider_macos/CHANGELOG.md b/packages/path_provider/path_provider_macos/CHANGELOG.md index ba2a38e563d6..d9be6859e125 100644 --- a/packages/path_provider/path_provider_macos/CHANGELOG.md +++ b/packages/path_provider/path_provider_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.4+7 + +* Update Flutter SDK constraint. + ## 0.0.4+6 * Remove unused `test` dependency. diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index 69241491d29d..05f03a7930ba 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the path_provider plugin # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.4+6 +version: 0.0.4+7 homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_macos flutter: @@ -14,7 +14,7 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" dependencies: flutter: diff --git a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md index 744764c3215a..47e4fee3f13b 100644 --- a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md +++ b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.5 + +* Update Flutter SDK constraint. + ## 1.0.4 * Remove unused `test` dependency. diff --git a/packages/path_provider/path_provider_platform_interface/pubspec.yaml b/packages/path_provider/path_provider_platform_interface/pubspec.yaml index 36b539ba1077..fc3d4696b51c 100644 --- a/packages/path_provider/path_provider_platform_interface/pubspec.yaml +++ b/packages/path_provider/path_provider_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the path_provider plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_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.0.4 +version: 1.0.5 dependencies: flutter: @@ -19,4 +19,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index bdb0ae5b2d9f..ef1f5043a2b7 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.4+4 + +* Update Flutter SDK constraint. + ## 0.0.4+3 * Remove unused `test` dependency. diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index 342774680dc4..62185f42e765 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_windows -version: 0.0.4+3 +version: 0.0.4+4 flutter: plugin: @@ -26,4 +26,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4 <2.0.0" + flutter: ">=1.12.13+hotfix.4" From 0251017cc973924ee40aebf5c2e338c82299f536 Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Sat, 12 Dec 2020 00:55:37 +0100 Subject: [PATCH 041/924] [q-w] Update Flutter SDK constraint (#3323) Update Flutter SDK constraint to match templates. --- packages/quick_actions/CHANGELOG.md | 4 ++++ packages/quick_actions/pubspec.yaml | 4 ++-- packages/sensors/CHANGELOG.md | 4 ++++ packages/sensors/pubspec.yaml | 4 ++-- packages/share/CHANGELOG.md | 4 ++++ packages/share/pubspec.yaml | 4 ++-- packages/shared_preferences/shared_preferences/CHANGELOG.md | 4 ++++ packages/shared_preferences/shared_preferences/pubspec.yaml | 4 ++-- .../shared_preferences_linux/CHANGELOG.md | 4 ++++ .../shared_preferences_linux/pubspec.yaml | 4 ++-- .../shared_preferences_macos/CHANGELOG.md | 4 ++++ .../shared_preferences_macos/pubspec.yaml | 4 ++-- .../shared_preferences_platform_interface/CHANGELOG.md | 4 ++++ .../shared_preferences_platform_interface/pubspec.yaml | 4 ++-- .../shared_preferences/shared_preferences_web/CHANGELOG.md | 4 ++++ .../shared_preferences/shared_preferences_web/pubspec.yaml | 4 ++-- .../shared_preferences_windows/CHANGELOG.md | 4 ++++ .../shared_preferences_windows/pubspec.yaml | 4 ++-- packages/url_launcher/url_launcher/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher/pubspec.yaml | 4 ++-- packages/url_launcher/url_launcher_linux/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher_linux/pubspec.yaml | 4 ++-- packages/url_launcher/url_launcher_macos/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher_macos/pubspec.yaml | 4 ++-- .../url_launcher_platform_interface/CHANGELOG.md | 4 ++++ .../url_launcher_platform_interface/pubspec.yaml | 4 ++-- packages/url_launcher/url_launcher_web/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher_web/pubspec.yaml | 4 ++-- packages/url_launcher/url_launcher_windows/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher_windows/pubspec.yaml | 4 ++-- packages/video_player/video_player/CHANGELOG.md | 4 ++++ packages/video_player/video_player/pubspec.yaml | 6 +++--- .../video_player_platform_interface/CHANGELOG.md | 4 ++++ .../video_player_platform_interface/pubspec.yaml | 4 ++-- packages/video_player/video_player_web/CHANGELOG.md | 4 ++++ packages/video_player/video_player_web/pubspec.yaml | 4 ++-- packages/webview_flutter/CHANGELOG.md | 4 ++++ packages/webview_flutter/pubspec.yaml | 4 ++-- packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md | 4 ++++ packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml | 4 ++-- .../wifi_info_flutter_platform_interface/CHANGELOG.md | 4 ++++ .../wifi_info_flutter_platform_interface/pubspec.yaml | 4 ++-- 42 files changed, 127 insertions(+), 43 deletions(-) diff --git a/packages/quick_actions/CHANGELOG.md b/packages/quick_actions/CHANGELOG.md index 0742d73f500a..8126f08ae3a8 100644 --- a/packages/quick_actions/CHANGELOG.md +++ b/packages/quick_actions/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.0+11 + +* Update Flutter SDK constraint. + ## 0.4.0+10 * Update android compileSdkVersion to 29. diff --git a/packages/quick_actions/pubspec.yaml b/packages/quick_actions/pubspec.yaml index 187c5707ddea..ea363e842f08 100644 --- a/packages/quick_actions/pubspec.yaml +++ b/packages/quick_actions/pubspec.yaml @@ -2,7 +2,7 @@ name: quick_actions description: Flutter plugin for creating shortcuts on home screen, also known as Quick Actions on iOS and App Shortcuts on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/quick_actions -version: 0.4.0+10 +version: 0.4.0+11 flutter: plugin: @@ -29,4 +29,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/sensors/CHANGELOG.md b/packages/sensors/CHANGELOG.md index a2693dd7ed0b..82500ae4edda 100644 --- a/packages/sensors/CHANGELOG.md +++ b/packages/sensors/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.2+7 + +* Update Flutter SDK constraint. + ## 0.4.2+6 * Update android compileSdkVersion to 29. diff --git a/packages/sensors/pubspec.yaml b/packages/sensors/pubspec.yaml index 4e830d9d0480..e1abc05a8496 100644 --- a/packages/sensors/pubspec.yaml +++ b/packages/sensors/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/sensors # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.2+6 +version: 0.4.2+7 flutter: plugin: @@ -31,4 +31,4 @@ dev_dependencies: environment: sdk: ">=2.1.0<3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/share/CHANGELOG.md b/packages/share/CHANGELOG.md index 883cd340ecfb..8a3806209c1c 100644 --- a/packages/share/CHANGELOG.md +++ b/packages/share/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.5+5 + +* Update Flutter SDK constraint. + ## 0.6.5+4 * Fix iPad share window not showing when `origin` is null. diff --git a/packages/share/pubspec.yaml b/packages/share/pubspec.yaml index 5bd79effe4a7..23644d290473 100644 --- a/packages/share/pubspec.yaml +++ b/packages/share/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/share # 0.6.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.6.5+4 +version: 0.6.5+5 flutter: plugin: @@ -33,4 +33,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index d86588b33098..407cf0ccdda4 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.13+1 + +* Update Flutter SDK constraint. + ## 0.5.13 * Update integration test examples to use `testWidgets` instead of `test`. diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 8897ee7c78fe..492027ac0e42 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/shared_prefere # 0.5.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.5.13 +version: 0.5.13+1 flutter: plugin: @@ -48,4 +48,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md index 6a0a0414086b..9821b79c5cc2 100644 --- a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.3+1 + +* Update Flutter SDK constraint. + ## 0.0.3 * Update integration test examples to use `testWidgets` instead of `test`. diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml index 2548ca1f7965..50709aac5f8a 100644 --- a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: shared_preferences_linux description: Linux implementation of the shared_preferences plugin -version: 0.0.3 +version: 0.0.3+1 homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux flutter: @@ -12,7 +12,7 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" dependencies: file: ">=5.1.0 <7.0.0" diff --git a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md index 177f1f2e02e2..3eff6db6949e 100644 --- a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.1+12 + +* Update Flutter SDK constraint. + ## 0.0.1+11 * Remove unused `test` dependency. diff --git a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml index b161327e3f3d..afc5b9ec0b4e 100644 --- a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the shared_preferences plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.1+11 +version: 0.0.1+12 homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_macos flutter: @@ -14,7 +14,7 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" dependencies: shared_preferences_platform_interface: ^1.0.0 diff --git a/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md b/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md index 5fe7b18160ba..88d3a9ac5f00 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.5 + +* Update Flutter SDK constraint. + ## 1.0.4 * Update lower bound of dart dependency to 2.1.0. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml b/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml index 3b8f2bfcada4..da31497df1c6 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml @@ -1,7 +1,7 @@ name: shared_preferences_platform_interface description: A common platform interface for the shared_preferences plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_platform_interface -version: 1.0.4 +version: 1.0.5 dependencies: meta: ^1.0.4 @@ -15,4 +15,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" diff --git a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md index b2076dd8c17e..2ba877856da6 100644 --- a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.2+8 + +* Update Flutter SDK constraint. + ## 0.1.2+7 * Removed Android folder from `shared_preferences_web`. diff --git a/packages/shared_preferences/shared_preferences_web/pubspec.yaml b/packages/shared_preferences/shared_preferences_web/pubspec.yaml index a153135b6da7..d657b2300727 100644 --- a/packages/shared_preferences/shared_preferences_web/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/shared_prefere # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.2+7 +version: 0.1.2+8 flutter: plugin: @@ -28,4 +28,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4 <2.0.0" + flutter: ">=1.12.13+hotfix.4" diff --git a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md index ee7b36884237..ecc790ef9bab 100644 --- a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2+1 + +* Update Flutter SDK constraint. + ## 0.0.2 * Update integration test examples to use `testWidgets` instead of `test`. diff --git a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml index 32d4cb5c242c..ce559d5ea3fb 100644 --- a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: shared_preferences_windows description: Windows implementation of shared_preferences homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_windows -version: 0.0.2 +version: 0.0.2+1 flutter: plugin: @@ -12,7 +12,7 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" dependencies: shared_preferences_platform_interface: ^1.0.0 diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index c92c4f5784aa..9c2d8ce19672 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.7.13 + +* Update Flutter SDK constraint. + ## 5.7.12 * Updated code sample in `README.md` diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index e4fc0f1d654c..8b731faa1a96 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 5.7.12 +version: 5.7.13 flutter: plugin: @@ -45,4 +45,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md index 1b4041fe4c73..57da89f50785 100644 --- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2+1 + +* Update Flutter SDK constraint. + ## 0.0.2 * Update integration test examples to use `testWidgets` instead of `test`. diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml index d231bf98476f..65e10e05e166 100644 --- a/packages/url_launcher/url_launcher_linux/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: url_launcher_linux description: Linux implementation of the url_launcher plugin. -version: 0.0.2 +version: 0.0.2+1 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux flutter: @@ -11,7 +11,7 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" dependencies: flutter: diff --git a/packages/url_launcher/url_launcher_macos/CHANGELOG.md b/packages/url_launcher/url_launcher_macos/CHANGELOG.md index 9462960ad45e..ab132757bbf2 100644 --- a/packages/url_launcher/url_launcher_macos/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2+1 + +* Update Flutter SDK constraint. + ## 0.0.2 * Update integration test examples to use `testWidgets` instead of `test`. diff --git a/packages/url_launcher/url_launcher_macos/pubspec.yaml b/packages/url_launcher/url_launcher_macos/pubspec.yaml index 1a14e6bc9bb9..12ce6a0b0907 100644 --- a/packages/url_launcher/url_launcher_macos/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the url_launcher plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.2 +version: 0.0.2+1 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos flutter: @@ -15,7 +15,7 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" dependencies: flutter: diff --git a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md index 10057e147adf..26047c748ae6 100644 --- a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.10 + +* Update Flutter SDK constraint. + ## 1.0.9 * Laid the groundwork for introducing a Link widget. diff --git a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml index ce0fdd936c9a..b8b05b8ec837 100644 --- a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml +++ b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the url_launcher plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_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.0.9 +version: 1.0.10 dependencies: flutter: @@ -19,4 +19,4 @@ dev_dependencies: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.22.0 <2.0.0" + flutter: ">=1.22.0" diff --git a/packages/url_launcher/url_launcher_web/CHANGELOG.md b/packages/url_launcher/url_launcher_web/CHANGELOG.md index 093029104f8f..e8db0e49aeb7 100644 --- a/packages/url_launcher/url_launcher_web/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.1.5+2 + +- Update Flutter SDK constraint. + # 0.1.5+1 - Substitute `undefined_prefixed_name: ignore` analyzer setting by a `dart:ui` shim with conditional exports. [Issue](https://github.com/flutter/flutter/issues/69309). diff --git a/packages/url_launcher/url_launcher_web/pubspec.yaml b/packages/url_launcher/url_launcher_web/pubspec.yaml index b40a8ea236cc..049c4bb44544 100644 --- a/packages/url_launcher/url_launcher_web/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/u # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.5+1 +version: 0.1.5+2 flutter: plugin: @@ -32,4 +32,4 @@ dev_dependencies: environment: sdk: ">=2.2.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/url_launcher/url_launcher_windows/CHANGELOG.md b/packages/url_launcher/url_launcher_windows/CHANGELOG.md index ca4718813608..fb1a83f0190d 100644 --- a/packages/url_launcher/url_launcher_windows/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2+1 + +* Update Flutter SDK constraint. + ## 0.0.2 * Update integration test examples to use `testWidgets` instead of `test`. diff --git a/packages/url_launcher/url_launcher_windows/pubspec.yaml b/packages/url_launcher/url_launcher_windows/pubspec.yaml index f543e7aea2fd..8db8d94fc411 100644 --- a/packages/url_launcher/url_launcher_windows/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/pubspec.yaml @@ -3,7 +3,7 @@ description: Windows implementation of the url_launcher plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.2 +version: 0.0.2+1 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows flutter: @@ -14,7 +14,7 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" dependencies: flutter: diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 90082d8358e3..32614b43d261 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2 + +* Update Flutter SDK constraint. + ## 1.0.1 * Android: Dispose video players when app is closed. diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 69be8b24100b..fa55ba43b945 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -version: 1.0.1 +version: 1.0.2 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: @@ -24,7 +24,7 @@ dependencies: # validation, so we set a ^ constraint. # TODO(amirh): Revisit this (either update this part in the design or the pub tool). # https://github.com/flutter/flutter/issues/46264 - video_player_web: '>=0.1.4 <2.0.0' + video_player_web: ">=0.1.4 <2.0.0" flutter: sdk: flutter @@ -37,4 +37,4 @@ dev_dependencies: environment: sdk: ">=2.8.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/video_player/video_player_platform_interface/CHANGELOG.md b/packages/video_player/video_player_platform_interface/CHANGELOG.md index 8af22f783675..fea2357a7ea2 100644 --- a/packages/video_player/video_player_platform_interface/CHANGELOG.md +++ b/packages/video_player/video_player_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.2.1 + +* Update Flutter SDK constraint. + ## 2.2.0 * Added option to set the video playback speed on the video controller. diff --git a/packages/video_player/video_player_platform_interface/pubspec.yaml b/packages/video_player/video_player_platform_interface/pubspec.yaml index cc3cd79f1f33..0c1dcad32648 100644 --- a/packages/video_player/video_player_platform_interface/pubspec.yaml +++ b/packages/video_player/video_player_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the video_player plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_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: 2.2.0 +version: 2.2.1 dependencies: flutter: @@ -18,4 +18,4 @@ dev_dependencies: environment: sdk: ">=2.8.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/video_player/video_player_web/CHANGELOG.md b/packages/video_player/video_player_web/CHANGELOG.md index d8bebd3ae4b6..cbb07e8b9295 100644 --- a/packages/video_player/video_player_web/CHANGELOG.md +++ b/packages/video_player/video_player_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.4+2 + +* Update Flutter SDK constraint. + ## 0.1.4+1 * Substitute `undefined_prefixed_name: ignore` analyzer setting by a `dart:ui` shim with conditional exports. [Issue](https://github.com/flutter/flutter/issues/69309). diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml index ae05bfbcf910..37cadbd3a1b3 100644 --- a/packages/video_player/video_player_web/pubspec.yaml +++ b/packages/video_player/video_player_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/v # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.4+1 +version: 0.1.4+2 flutter: plugin: @@ -30,4 +30,4 @@ dev_dependencies: environment: sdk: ">=2.8.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 8f1e238f6919..447e263e54ff 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.8 + +* Update Flutter SDK constraint. + ## 1.0.7 * Minor documentation update to indicate known issue on iOS 13.4 and 13.5. diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index e4627a4f9f65..de99c4b7cdb8 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,11 +1,11 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 1.0.7 +version: 1.0.8 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.22.0 <2.0.0" + flutter: ">=1.22.0" dependencies: flutter: diff --git a/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md b/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md index 37711dcac49c..9073486aa601 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md +++ b/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2 + +* Update Flutter SDK constraint. + ## 1.0.1 * Fixed method channel name in android implementation. [Issue](https://github.com/flutter/flutter/issues/69073). diff --git a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml index 74ee9f074cb5..09dff3a48104 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml @@ -1,11 +1,11 @@ name: wifi_info_flutter description: A new flutter plugin project. -version: 1.0.1 +version: 1.0.2 homepage: https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter/wifi_info_flutter environment: sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.20.0 <2.0.0" + flutter: ">=1.20.0" dependencies: flutter: diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md index a845f1956ab4..951f8f5f5ae0 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.1 + +* Update Flutter SDK constraint. + ## 1.0.0 * Initial release of package. Includes support for retrieving wifi name, wifi BSSID, wifi ip address diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml index 68d516d515a8..62bffd0eeeb3 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml @@ -1,13 +1,13 @@ name: wifi_info_flutter_platform_interface description: A common platform interface for the wifi_info_flutter plugin. -version: 1.0.0 +version: 1.0.1 # 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 homepage: https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter/wifi_info_flutter_platform_interface environment: sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.17.0 <2.0.0" + flutter: ">=1.17.0" dependencies: plugin_platform_interface: ^1.0.3 From 0b158bd73e9924a4c57c9b3cea0e450ba5533ce0 Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Sat, 12 Dec 2020 18:15:59 +0100 Subject: [PATCH 042/924] [camera] Add implementations for `camera_platform_interface` package. (#3302) * First suggestion for camera platform interface * Remove test coverage folder * Renamed onLatestImageAvailableHandler definition * Split CameraEvents into separate streams * Implemented & tested first parts of method channel implementation * Remove unused EventChannelMock class * Add missing unit tests * Added placeholders in default method channel implementation * Updated platform interface * Update packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart Co-authored-by: Maurits van Beusekom * Add unit test for availableCameras * Expand availableCameras unit test. Added unit test for takePicture. * Add unit test for startVideoRecording * Add unit test for prepareForVideoRecording * Add unit test for stopVideoRecording * Add unit test for pauseVideoRecording * Add unit test for buildView * WIP: Dart and Android implementation * Fix formatting * Have resolution stream replay last value on subscription. Replace stream_transform with rxdart. * Added reverse method channel to replace event channel. Updated initialise and takePicture implementations for android. WIP implementation for startVideoRecording * Fixed example app for Android. Removed isRecordingVideo and isStreamingImages from buildView method. * Added some first tests for camera/camera * More tests and some feedback * iOS implementation: Removed standard event channel. Added reverse method channel. Updated initialize method. Added resolution changed event. Updated error reporting to use new method channel. * Started splitting initialize method * Finish splitting up initialize for iOS * Update unit tests * Fix takePicture method on iOS * Split initialize method on Android * Fix video recording on iOS. Updated platform interface. * Update unit tests * Update error handling of video methods in iOS code. Make iOS code more consistent. * Updated startVideoRecording documentation * Make sure file is returned by stopVideoRecording * Use correct event-type after initializing * Fix DartMessenger unit-tests * Change cast * Fix formatting * Fixed tests, formatting and analysis warnings * Added missing license to Dart files * Updated CHANGELOG and version * Added additional unit-tests to platform_interface * Added more tests * Formatted code * Re-added the CameraPreview widget * Use import/export instead of part implementation * fixed formatting * Resolved additional feedback * Update dependency to git repo * Depend on pub.dev for camera_platform_interface * Fix JAVA formatting * Fix changelog * Make sure camera package can be published * Assert when stream methods are called from wrong platform * Add dev_dependency on plugin_platform_interface package, required by tests. * Remove pedantic requirement from initialize() method. Remove unnecessary completers. * Remove dependency on dart:io * Restrict exposed types from platform interface * Moved test for image stream in separate file * Fixed formatting issue * Fix deprecation warning * Apply feedback from bparrishMines * Fix formatting issues * Removed redundant podspec files * Removed redundant ios files * Handle SecurityException Co-authored-by: Maurits van Beusekom Co-authored-by: Maurits van Beusekom Co-authored-by: daniel Co-authored-by: David Iglesias Teixeira --- packages/camera/camera/CHANGELOG.md | 10 + .../io/flutter/plugins/camera/Camera.java | 59 +- .../flutter/plugins/camera/DartMessenger.java | 61 +- .../plugins/camera/MethodCallHandlerImpl.java | 31 +- .../plugins/camera/DartMessengerTest.java | 63 +- .../example/integration_test/camera_test.dart | 25 +- .../ios/Runner.xcodeproj/project.pbxproj | 22 +- packages/camera/camera/example/lib/main.dart | 75 +- .../camera/camera/ios/Classes/CameraPlugin.m | 212 +++--- packages/camera/camera/lib/camera.dart | 651 +----------------- .../camera/lib/src/camera_controller.dart | 484 +++++++++++++ .../camera/lib/{ => src}/camera_image.dart | 8 +- .../camera/camera/lib/src/camera_preview.dart | 23 + packages/camera/camera/pubspec.yaml | 5 +- .../camera/test/camera_image_stream_test.dart | 187 +++++ .../camera/camera/test/camera_image_test.dart | 113 +++ packages/camera/camera/test/camera_test.dart | 317 +++++++++ .../camera/camera/test/camera_value_test.dart | 102 +++ .../test/utils/method_channel_mock.dart | 38 + .../ios/Runner.xcodeproj/project.pbxproj | 22 +- 20 files changed, 1580 insertions(+), 928 deletions(-) create mode 100644 packages/camera/camera/lib/src/camera_controller.dart rename packages/camera/camera/lib/{ => src}/camera_image.dart (96%) create mode 100644 packages/camera/camera/lib/src/camera_preview.dart create mode 100644 packages/camera/camera/test/camera_image_stream_test.dart create mode 100644 packages/camera/camera/test/camera_image_test.dart create mode 100644 packages/camera/camera/test/camera_value_test.dart create mode 100644 packages/camera/camera/test/utils/method_channel_mock.dart diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index d1d11c4d8877..cb8dfedd1d9a 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.6.0 + +As part of implementing federated architecture and making the interface compatible with the web this version contains the following **breaking changes**: + +Method changes in `CameraController`: +- The `takePicture` method no longer accepts the `path` parameter, but instead returns the captured image as an instance of the `XFile` class; +- The `startVideoRecording` method no longer accepts the `filePath`. Instead the recorded video is now returned as a `XFile` instance when the `stopVideoRecording` method completes; +- The `stopVideoRecording` method now returns the captured video when it completes; +- Added the `buildPreview` method which is now used to implement the CameraPreview widget. + ## 0.5.8+19 * Update Flutter SDK constraint. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 9cf111b9ee69..306dd447cfb9 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -65,8 +65,10 @@ public class Camera { private CaptureRequest.Builder captureRequestBuilder; private MediaRecorder mediaRecorder; private boolean recordingVideo; + private File videoRecordingFile; private CamcorderProfile recordingProfile; private int currentOrientation = ORIENTATION_UNKNOWN; + private Context applicationContext; // Mirrors camera.dart public enum ResolutionPreset { @@ -94,6 +96,7 @@ public Camera( this.flutterTexture = flutterTexture; this.dartMessenger = dartMessenger; this.cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); + this.applicationContext = activity.getApplicationContext(); orientationEventListener = new OrientationEventListener(activity.getApplicationContext()) { @Override @@ -135,7 +138,7 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException { } @SuppressLint("MissingPermission") - public void open(@NonNull final Result result) throws CameraAccessException { + public void open() throws CameraAccessException { pictureImageReader = ImageReader.newInstance( captureSize.getWidth(), captureSize.getHeight(), ImageFormat.JPEG, 2); @@ -154,15 +157,13 @@ public void onOpened(@NonNull CameraDevice device) { try { startPreview(); } catch (CameraAccessException e) { - result.error("CameraAccess", e.getMessage(), null); + dartMessenger.sendCameraErrorEvent(e.getMessage()); close(); return; } - Map reply = new HashMap<>(); - reply.put("textureId", flutterTexture.id()); - reply.put("previewWidth", previewSize.getWidth()); - reply.put("previewHeight", previewSize.getHeight()); - result.success(reply); + + dartMessenger.sendCameraInitializedEvent( + previewSize.getWidth(), previewSize.getHeight()); } @Override @@ -174,7 +175,7 @@ public void onClosed(@NonNull CameraDevice camera) { @Override public void onDisconnected(@NonNull CameraDevice cameraDevice) { close(); - dartMessenger.send(DartMessenger.EventType.ERROR, "The camera was disconnected."); + dartMessenger.sendCameraErrorEvent("The camera was disconnected."); } @Override @@ -200,7 +201,7 @@ public void onError(@NonNull CameraDevice cameraDevice, int errorCode) { default: errorDescription = "Unknown camera error"; } - dartMessenger.send(DartMessenger.EventType.ERROR, errorDescription); + dartMessenger.sendCameraErrorEvent(errorDescription); } }, null); @@ -218,12 +219,13 @@ SurfaceTextureEntry getFlutterTexture() { return flutterTexture; } - public void takePicture(String filePath, @NonNull final Result result) { - final File file = new File(filePath); - - if (file.exists()) { - result.error( - "fileExists", "File at path '" + filePath + "' already exists. Cannot overwrite.", null); + public void takePicture(@NonNull final Result result) { + final File outputDir = applicationContext.getCacheDir(); + final File file; + try { + file = File.createTempFile("CAP", ".jpg", outputDir); + } catch (IOException | SecurityException e) { + result.error("cannotCreateFile", e.getMessage(), null); return; } @@ -232,7 +234,7 @@ public void takePicture(String filePath, @NonNull final Result result) { try (Image image = reader.acquireLatestImage()) { ByteBuffer buffer = image.getPlanes()[0].getBuffer(); writeToFile(buffer, file); - result.success(null); + result.success(file.getAbsolutePath()); } catch (IOException e) { result.error("IOError", "Failed saving image", null); } @@ -308,8 +310,7 @@ private void createCaptureSession( public void onConfigured(@NonNull CameraCaptureSession session) { try { if (cameraDevice == null) { - dartMessenger.send( - DartMessenger.EventType.ERROR, "The camera was closed during configuration."); + dartMessenger.sendCameraErrorEvent("The camera was closed during configuration."); return; } cameraCaptureSession = session; @@ -320,14 +321,13 @@ public void onConfigured(@NonNull CameraCaptureSession session) { onSuccessCallback.run(); } } catch (CameraAccessException | IllegalStateException | IllegalArgumentException e) { - dartMessenger.send(DartMessenger.EventType.ERROR, e.getMessage()); + dartMessenger.sendCameraErrorEvent(e.getMessage()); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { - dartMessenger.send( - DartMessenger.EventType.ERROR, "Failed to configure camera session."); + dartMessenger.sendCameraErrorEvent("Failed to configure camera session."); } }; @@ -369,18 +369,24 @@ private void createCaptureSession( cameraDevice.createCaptureSession(surfaces, callback, null); } - public void startVideoRecording(String filePath, Result result) { - if (new File(filePath).exists()) { - result.error("fileExists", "File at path '" + filePath + "' already exists.", null); + public void startVideoRecording(Result result) { + final File outputDir = applicationContext.getCacheDir(); + try { + videoRecordingFile = File.createTempFile("REC", ".mp4", outputDir); + } catch (IOException | SecurityException e) { + result.error("cannotCreateFile", e.getMessage(), null); return; } + try { - prepareMediaRecorder(filePath); + prepareMediaRecorder(videoRecordingFile.getAbsolutePath()); recordingVideo = true; createCaptureSession( CameraDevice.TEMPLATE_RECORD, () -> mediaRecorder.start(), mediaRecorder.getSurface()); result.success(null); } catch (CameraAccessException | IOException e) { + recordingVideo = false; + videoRecordingFile = null; result.error("videoRecordingFailed", e.getMessage(), null); } } @@ -396,7 +402,8 @@ public void stopVideoRecording(@NonNull final Result result) { mediaRecorder.stop(); mediaRecorder.reset(); startPreview(); - result.success(null); + result.success(videoRecordingFile.getAbsolutePath()); + videoRecordingFile = null; } catch (CameraAccessException | IllegalStateException e) { result.error("videoRecordingFailed", e.getMessage(), null); } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java index fe385bef7818..49f9d9a76de0 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java @@ -3,49 +3,56 @@ import android.text.TextUtils; import androidx.annotation.Nullable; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.EventChannel; +import io.flutter.plugin.common.MethodChannel; import java.util.HashMap; import java.util.Map; class DartMessenger { - @Nullable private EventChannel.EventSink eventSink; + @Nullable private MethodChannel channel; enum EventType { ERROR, CAMERA_CLOSING, + INITIALIZED, } - DartMessenger(BinaryMessenger messenger, long eventChannelId) { - new EventChannel(messenger, "flutter.io/cameraPlugin/cameraEvents" + eventChannelId) - .setStreamHandler( - new EventChannel.StreamHandler() { - @Override - public void onListen(Object arguments, EventChannel.EventSink sink) { - eventSink = sink; - } - - @Override - public void onCancel(Object arguments) { - eventSink = null; - } - }); + DartMessenger(BinaryMessenger messenger, long cameraId) { + channel = new MethodChannel(messenger, "flutter.io/cameraPlugin/camera" + cameraId); + } + + void sendCameraInitializedEvent(Integer previewWidth, Integer previewHeight) { + this.send( + EventType.INITIALIZED, + new HashMap() { + { + if (previewWidth != null) put("previewWidth", previewWidth.doubleValue()); + if (previewHeight != null) put("previewHeight", previewHeight.doubleValue()); + } + }); } void sendCameraClosingEvent() { - send(EventType.CAMERA_CLOSING, null); + send(EventType.CAMERA_CLOSING); } - void send(EventType eventType, @Nullable String description) { - if (eventSink == null) { - return; - } + void sendCameraErrorEvent(@Nullable String description) { + this.send( + EventType.ERROR, + new HashMap() { + { + if (!TextUtils.isEmpty(description)) put("description", description); + } + }); + } + + void send(EventType eventType) { + send(eventType, new HashMap<>()); + } - Map event = new HashMap<>(); - event.put("eventType", eventType.toString().toLowerCase()); - // Only errors have a description. - if (eventType == EventType.ERROR && !TextUtils.isEmpty(description)) { - event.put("errorDescription", description); + void send(EventType eventType, Map args) { + if (channel == null) { + return; } - eventSink.success(event); + channel.invokeMethod(eventType.toString().toLowerCase(), args); } } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 132075555f26..6c2e65e76f9e 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -11,6 +11,8 @@ import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.camera.CameraPermissions.PermissionsRegistry; import io.flutter.view.TextureRegistry; +import java.util.HashMap; +import java.util.Map; final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { private final Activity activity; @@ -49,11 +51,12 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) handleException(e, result); } break; - case "initialize": + case "create": { if (camera != null) { camera.close(); } + cameraPermissions.requestPermissions( activity, permissionsRegistry, @@ -69,12 +72,28 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) result.error(errCode, errDesc, null); } }); - + break; + } + case "initialize": + { + if (camera != null) { + try { + camera.open(); + result.success(null); + } catch (Exception e) { + handleException(e, result); + } + } else { + result.error( + "cameraNotFound", + "Camera not found. Please call the 'create' method before calling 'initialize'.", + null); + } break; } case "takePicture": { - camera.takePicture(call.argument("path"), result); + camera.takePicture(result); break; } case "prepareForVideoRecording": @@ -85,7 +104,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) } case "startVideoRecording": { - camera.startVideoRecording(call.argument("filePath"), result); + camera.startVideoRecording(result); break; } case "stopVideoRecording": @@ -157,7 +176,9 @@ private void instantiateCamera(MethodCall call, Result result) throws CameraAcce resolutionPreset, enableAudio); - camera.open(result); + Map reply = new HashMap<>(); + reply.put("cameraId", flutterSurfaceTexture.id()); + result.success(reply); } // We move catching CameraAccessException out of onMethodCall because it causes a crash diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java index 5a5358229c15..a689f2b6128f 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java @@ -2,42 +2,34 @@ import static junit.framework.TestCase.assertNull; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import androidx.annotation.NonNull; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.StandardMethodCodec; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import java.util.Map; import org.junit.Before; import org.junit.Test; public class DartMessengerTest { /** A {@link BinaryMessenger} implementation that does nothing but save its messages. */ private static class FakeBinaryMessenger implements BinaryMessenger { - private BinaryMessageHandler handler; private final List sentMessages = new ArrayList<>(); @Override - public void send(String channel, ByteBuffer message) { + public void send(@NonNull String channel, ByteBuffer message) { sentMessages.add(message); } @Override - public void send(String channel, ByteBuffer message, BinaryReply callback) { + public void send(@NonNull String channel, ByteBuffer message, BinaryReply callback) { send(channel, message); } @Override - public void setMessageHandler(String channel, BinaryMessageHandler handler) { - this.handler = handler; - } - - BinaryMessageHandler getMessageHandler() { - return handler; - } + public void setMessageHandler(@NonNull String channel, BinaryMessageHandler handler) {} List getMessages() { return new ArrayList<>(sentMessages); @@ -54,55 +46,42 @@ public void setUp() { } @Test - public void setsStreamHandler() { - assertNotNull(fakeBinaryMessenger.getMessageHandler()); - } - - @Test - public void send_handlesNullEventSinks() { - dartMessenger.send(DartMessenger.EventType.ERROR, "error description"); + public void sendCameraErrorEvent_includesErrorDescriptions() { + dartMessenger.sendCameraErrorEvent("error description"); List sentMessages = fakeBinaryMessenger.getMessages(); - assertEquals(0, sentMessages.size()); + assertEquals(1, sentMessages.size()); + MethodCall call = decodeSentMessage(sentMessages.get(0)); + assertEquals("error", call.method); + assertEquals("error description", call.argument("description")); } @Test - public void send_includesErrorDescriptions() { - initializeEventSink(); - - dartMessenger.send(DartMessenger.EventType.ERROR, "error description"); + public void sendCameraInitializedEvent_includesPreviewSize() { + dartMessenger.sendCameraInitializedEvent(0, 0); List sentMessages = fakeBinaryMessenger.getMessages(); assertEquals(1, sentMessages.size()); - Map event = decodeSentMessage(sentMessages.get(0)); - assertEquals(DartMessenger.EventType.ERROR.toString().toLowerCase(), event.get("eventType")); - assertEquals("error description", event.get("errorDescription")); + MethodCall call = decodeSentMessage(sentMessages.get(0)); + assertEquals("initialized", call.method); + assertEquals(0, (double) call.argument("previewWidth"), 0); + assertEquals(0, (double) call.argument("previewHeight"), 0); } @Test public void sendCameraClosingEvent() { - initializeEventSink(); - dartMessenger.sendCameraClosingEvent(); List sentMessages = fakeBinaryMessenger.getMessages(); assertEquals(1, sentMessages.size()); - Map event = decodeSentMessage(sentMessages.get(0)); - assertEquals( - DartMessenger.EventType.CAMERA_CLOSING.toString().toLowerCase(), event.get("eventType")); - assertNull(event.get("errorDescription")); + MethodCall call = decodeSentMessage(sentMessages.get(0)); + assertEquals("camera_closing", call.method); + assertNull(call.argument("description")); } - @SuppressWarnings("unchecked") - private Map decodeSentMessage(ByteBuffer sentMessage) { + private MethodCall decodeSentMessage(ByteBuffer sentMessage) { sentMessage.position(0); - return (Map) StandardMethodCodec.INSTANCE.decodeEnvelope(sentMessage); - } - private void initializeEventSink() { - MethodCall call = new MethodCall("listen", null); - ByteBuffer encodedCall = StandardMethodCodec.INSTANCE.encodeMethodCall(call); - encodedCall.position(0); - fakeBinaryMessenger.getMessageHandler().onMessage(encodedCall, reply -> {}); + return StandardMethodCodec.INSTANCE.decodeMethodCall(sentMessage); } } diff --git a/packages/camera/camera/example/integration_test/camera_test.dart b/packages/camera/camera/example/integration_test/camera_test.dart index ef4646f5ced9..c2e73e0f1563 100644 --- a/packages/camera/camera/example/integration_test/camera_test.dart +++ b/packages/camera/camera/example/integration_test/camera_test.dart @@ -2,9 +2,9 @@ import 'dart:async'; import 'dart:io'; import 'dart:ui'; +import 'package:camera/camera.dart'; import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:camera/camera.dart'; import 'package:path_provider/path_provider.dart'; import 'package:video_player/video_player.dart'; import 'package:integration_test/integration_test.dart'; @@ -55,12 +55,10 @@ void main() { 'Capturing photo at $preset (${expectedSize.width}x${expectedSize.height}) using camera ${controller.description.name}'); // Take Picture - final String filePath = - '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.jpg'; - await controller.takePicture(filePath); + final file = await controller.takePicture(); // Load picture - final File fileImage = File(filePath); + final File fileImage = File(file.path); final Image image = await decodeImageFromList(fileImage.readAsBytesSync()); // Verify image dimensions are as expected @@ -102,14 +100,12 @@ void main() { 'Capturing video at $preset (${expectedSize.width}x${expectedSize.height}) using camera ${controller.description.name}'); // Take Video - final String filePath = - '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.mp4'; - await controller.startVideoRecording(filePath); + await controller.startVideoRecording(); sleep(const Duration(milliseconds: 300)); - await controller.stopVideoRecording(); + final file = await controller.stopVideoRecording(); // Load video metadata - final File videoFile = File(filePath); + final File videoFile = File(file.path); final VideoPlayerController videoController = VideoPlayerController.file(videoFile); await videoController.initialize(); @@ -160,13 +156,10 @@ void main() { await controller.initialize(); await controller.prepareForVideoRecording(); - final String filePath = - '${testDir.path}/${DateTime.now().millisecondsSinceEpoch}.mp4'; - int startPause; int timePaused = 0; - await controller.startVideoRecording(filePath); + await controller.startVideoRecording(); final int recordingStart = DateTime.now().millisecondsSinceEpoch; sleep(const Duration(milliseconds: 500)); @@ -186,11 +179,11 @@ void main() { sleep(const Duration(milliseconds: 500)); - await controller.stopVideoRecording(); + final file = await controller.stopVideoRecording(); final int recordingTime = DateTime.now().millisecondsSinceEpoch - recordingStart; - final File videoFile = File(filePath); + final File videoFile = File(file.path); final VideoPlayerController videoController = VideoPlayerController.file( videoFile, ); diff --git a/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj index 862ee64fb666..d51240a02c14 100644 --- a/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj @@ -9,11 +9,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 75201D617916C49BDEDF852A /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 620DDA07C00B5FF2F937CB5B /* libPods-Runner.a */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -28,8 +24,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -40,7 +34,6 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 483D985F075B951ADBAD218E /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 620DDA07C00B5FF2F937CB5B /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -48,7 +41,6 @@ 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -63,8 +55,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 75201D617916C49BDEDF852A /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -83,9 +73,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -181,6 +169,7 @@ TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = 7624MWN53C; }; }; }; @@ -229,7 +218,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 3E30118C54AB12C3EB9EDF27 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; @@ -269,9 +258,12 @@ files = ( ); inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../Flutter/Flutter.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -315,7 +307,6 @@ /* Begin XCBuildConfiguration section */ 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -372,7 +363,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -426,6 +416,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 7624MWN53C; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -447,6 +438,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 7624MWN53C; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 3ec6604ad788..e1edc1b06386 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -9,7 +9,6 @@ import 'dart:io'; import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:video_player/video_player.dart'; class CameraExampleHome extends StatefulWidget { @@ -38,8 +37,8 @@ void logError(String code, String message) => class _CameraExampleHomeState extends State with WidgetsBindingObserver { CameraController controller; - String imagePath; - String videoPath; + XFile imageFile; + XFile videoFile; VideoPlayerController videoController; VoidCallback videoPlayerListener; bool enableAudio = true; @@ -166,11 +165,11 @@ class _CameraExampleHomeState extends State child: Row( mainAxisSize: MainAxisSize.min, children: [ - videoController == null && imagePath == null + videoController == null && imageFile == null ? Container() : SizedBox( child: (videoController == null) - ? Image.file(File(imagePath)) + ? Image.file(File(imageFile.path)) : Container( child: Center( child: AspectRatio( @@ -306,29 +305,32 @@ class _CameraExampleHomeState extends State } void onTakePictureButtonPressed() { - takePicture().then((String filePath) { + takePicture().then((XFile file) { if (mounted) { setState(() { - imagePath = filePath; + imageFile = file; videoController?.dispose(); videoController = null; }); - if (filePath != null) showInSnackBar('Picture saved to $filePath'); + if (file != null) showInSnackBar('Picture saved to ${file.path}'); } }); } void onVideoRecordButtonPressed() { - startVideoRecording().then((String filePath) { + startVideoRecording().then((_) { if (mounted) setState(() {}); - if (filePath != null) showInSnackBar('Saving video to $filePath'); }); } void onStopButtonPressed() { - stopVideoRecording().then((_) { + stopVideoRecording().then((file) { if (mounted) setState(() {}); - showInSnackBar('Video recorded to: $videoPath'); + if (file != null) { + showInSnackBar('Video recorded to ${file.path}'); + videoFile = file; + _startVideoPlayer(); + } }); } @@ -346,45 +348,36 @@ class _CameraExampleHomeState extends State }); } - Future startVideoRecording() async { + Future startVideoRecording() async { if (!controller.value.isInitialized) { showInSnackBar('Error: select a camera first.'); - return null; + return; } - final Directory extDir = await getApplicationDocumentsDirectory(); - final String dirPath = '${extDir.path}/Movies/flutter_test'; - await Directory(dirPath).create(recursive: true); - final String filePath = '$dirPath/${timestamp()}.mp4'; - if (controller.value.isRecordingVideo) { // A recording is already started, do nothing. - return null; + return; } try { - videoPath = filePath; - await controller.startVideoRecording(filePath); + await controller.startVideoRecording(); } on CameraException catch (e) { _showCameraException(e); - return null; + return; } - return filePath; } - Future stopVideoRecording() async { + Future stopVideoRecording() async { if (!controller.value.isRecordingVideo) { return null; } try { - await controller.stopVideoRecording(); + return controller.stopVideoRecording(); } on CameraException catch (e) { _showCameraException(e); return null; } - - await _startVideoPlayer(); } Future pauseVideoRecording() async { @@ -414,8 +407,8 @@ class _CameraExampleHomeState extends State } Future _startVideoPlayer() async { - final VideoPlayerController vcontroller = - VideoPlayerController.file(File(videoPath)); + final VideoPlayerController vController = + VideoPlayerController.file(File(videoFile.path)); videoPlayerListener = () { if (videoController != null && videoController.value.size != null) { // Refreshing the state to update video player with the correct ratio. @@ -423,28 +416,24 @@ class _CameraExampleHomeState extends State videoController.removeListener(videoPlayerListener); } }; - vcontroller.addListener(videoPlayerListener); - await vcontroller.setLooping(true); - await vcontroller.initialize(); + vController.addListener(videoPlayerListener); + await vController.setLooping(true); + await vController.initialize(); await videoController?.dispose(); if (mounted) { setState(() { - imagePath = null; - videoController = vcontroller; + imageFile = null; + videoController = vController; }); } - await vcontroller.play(); + await vController.play(); } - Future takePicture() async { + Future takePicture() async { if (!controller.value.isInitialized) { showInSnackBar('Error: select a camera first.'); return null; } - final Directory extDir = await getApplicationDocumentsDirectory(); - final String dirPath = '${extDir.path}/Pictures/flutter_test'; - await Directory(dirPath).create(recursive: true); - final String filePath = '$dirPath/${timestamp()}.jpg'; if (controller.value.isTakingPicture) { // A capture is already pending, do nothing. @@ -452,12 +441,12 @@ class _CameraExampleHomeState extends State } try { - await controller.takePicture(filePath); + XFile file = await controller.takePicture(); + return file; } on CameraException catch (e) { _showCameraException(e); return null; } - return filePath; } void _showCameraException(CameraException e) { diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index 525c1286717a..9455375b8524 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -7,6 +7,7 @@ #import #import #import +#import static FlutterError *getFlutterError(NSError *error) { return [FlutterError errorWithCode:[NSString stringWithFormat:@"Error %d", (int)error.code] @@ -51,10 +52,10 @@ @implementation FLTSavePhotoDelegate { self = [super init]; NSAssert(self, @"super init cannot be nil"); _path = path; - _result = result; _motionManager = motionManager; _cameraPosition = cameraPosition; selfReference = self; + _result = result; return self; } @@ -81,7 +82,7 @@ - (void)captureOutput:(AVCapturePhotoOutput *)output _result([FlutterError errorWithCode:@"IOError" message:@"Unable to write file" details:nil]); return; } - _result(nil); + _result(_path); } - (UIImageOrientation)getImageRotation { @@ -152,14 +153,12 @@ static ResolutionPreset getResolutionPresetForString(NSString *preset) { @interface FLTCam : NSObject + AVCaptureAudioDataOutputSampleBufferDelegate> @property(readonly, nonatomic) int64_t textureId; @property(nonatomic, copy) void (^onFrameAvailable)(void); @property BOOL enableAudio; -@property(nonatomic) FlutterEventChannel *eventChannel; @property(nonatomic) FLTImageStreamHandler *imageStreamHandler; -@property(nonatomic) FlutterEventSink eventSink; +@property(nonatomic) FlutterMethodChannel *methodChannel; @property(readonly, nonatomic) AVCaptureSession *captureSession; @property(readonly, nonatomic) AVCaptureDevice *captureDevice; @property(readonly, nonatomic) AVCapturePhotoOutput *capturePhotoOutput API_AVAILABLE(ios(10)); @@ -174,6 +173,7 @@ @interface FLTCam : NSObject _videoWriter.status == AVAssetWriterStatusCompleted) { - result(nil); + result(self->_videoRecordingPath); + self->_videoRecordingPath = nil; } else { - self->_eventSink(@{ - @"event" : @"error", - @"errorDescription" : @"AVAssetWriter could not finish writing!" - }); + result([FlutterError errorWithCode:@"IOError" + message:@"AVAssetWriter could not finish writing!" + details:nil]); } }]; } @@ -620,14 +640,16 @@ - (void)stopVideoRecordingWithResult:(FlutterResult)result { } } -- (void)pauseVideoRecording { +- (void)pauseVideoRecordingWithResult:(FlutterResult)result { _isRecordingPaused = YES; _videoIsDisconnected = YES; _audioIsDisconnected = YES; + result(nil); } -- (void)resumeVideoRecording { +- (void)resumeVideoRecordingWithResult:(FlutterResult)result { _isRecordingPaused = NO; + result(nil); } - (void)startImageStreamWithMessenger:(NSObject *)messenger { @@ -641,8 +663,8 @@ - (void)startImageStreamWithMessenger:(NSObject *)messen _isStreamingImages = YES; } else { - _eventSink( - @{@"event" : @"error", @"errorDescription" : @"Images from camera are already streaming!"}); + [_methodChannel invokeMethod:errorMethod + arguments:@"Images from camera are already streaming!"]; } } @@ -651,8 +673,7 @@ - (void)stopImageStream { _isStreamingImages = NO; _imageStreamHandler = nil; } else { - _eventSink( - @{@"event" : @"error", @"errorDescription" : @"Images from camera are not streaming!"}); + [_methodChannel invokeMethod:errorMethod arguments:@"Images from camera are not streaming!"]; } } @@ -672,7 +693,7 @@ - (BOOL)setupWriterForPath:(NSString *)path { error:&error]; NSParameterAssert(_videoWriter); if (error) { - _eventSink(@{@"event" : @"error", @"errorDescription" : error.description}); + [_methodChannel invokeMethod:errorMethod arguments:error.description]; return NO; } NSDictionary *videoSettings = [NSDictionary @@ -726,7 +747,7 @@ - (void)setUpCaptureSessionForAudio { AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error]; if (error) { - _eventSink(@{@"event" : @"error", @"errorDescription" : error.description}); + [_methodChannel invokeMethod:errorMethod arguments:error.description]; } // Setup the audio output. _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; @@ -738,10 +759,8 @@ - (void)setUpCaptureSessionForAudio { [_captureSession addOutput:_audioOutput]; _isAudioSetup = YES; } else { - _eventSink(@{ - @"event" : @"error", - @"errorDescription" : @"Unable to add Audio input/output to session capture" - }); + [_methodChannel invokeMethod:errorMethod + arguments:@"Unable to add Audio input/output to session capture"]; _isAudioSetup = NO; } } @@ -819,7 +838,7 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re } else { result(FlutterMethodNotImplemented); } - } else if ([@"initialize" isEqualToString:call.method]) { + } else if ([@"create" isEqualToString:call.method]) { NSString *cameraName = call.arguments[@"cameraName"]; NSString *resolutionPreset = call.arguments[@"resolutionPreset"]; NSNumber *enableAudio = call.arguments[@"enableAudio"]; @@ -829,6 +848,7 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re enableAudio:[enableAudio boolValue] dispatchQueue:_dispatchQueue error:&error]; + if (error) { result(getFlutterError(error)); } else { @@ -837,25 +857,10 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re } int64_t textureId = [_registry registerTexture:cam]; _camera = cam; - __weak CameraPlugin *weakSelf = self; - cam.onFrameAvailable = ^{ - [weakSelf.registry textureFrameAvailable:textureId]; - }; - FlutterEventChannel *eventChannel = [FlutterEventChannel - eventChannelWithName:[NSString - stringWithFormat:@"flutter.io/cameraPlugin/cameraEvents%lld", - textureId] - binaryMessenger:_messenger]; - [eventChannel setStreamHandler:cam]; - cam.eventChannel = eventChannel; + result(@{ - @"textureId" : @(textureId), - @"previewWidth" : @(cam.previewSize.width), - @"previewHeight" : @(cam.previewSize.height), - @"captureWidth" : @(cam.captureSize.width), - @"captureHeight" : @(cam.captureSize.height), + @"cameraId" : @(textureId), }); - [cam start]; } } else if ([@"startImageStream" isEqualToString:call.method]) { [_camera startImageStreamWithMessenger:_messenger]; @@ -863,23 +868,34 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re } else if ([@"stopImageStream" isEqualToString:call.method]) { [_camera stopImageStream]; result(nil); - } else if ([@"pauseVideoRecording" isEqualToString:call.method]) { - [_camera pauseVideoRecording]; - result(nil); - } else if ([@"resumeVideoRecording" isEqualToString:call.method]) { - [_camera resumeVideoRecording]; - result(nil); } else { NSDictionary *argsMap = call.arguments; - NSUInteger textureId = ((NSNumber *)argsMap[@"textureId"]).unsignedIntegerValue; - if ([@"takePicture" isEqualToString:call.method]) { + NSUInteger cameraId = ((NSNumber *)argsMap[@"cameraId"]).unsignedIntegerValue; + if ([@"initialize" isEqualToString:call.method]) { + __weak CameraPlugin *weakSelf = self; + _camera.onFrameAvailable = ^{ + [weakSelf.registry textureFrameAvailable:cameraId]; + }; + FlutterMethodChannel *methodChannel = [FlutterMethodChannel + methodChannelWithName:[NSString stringWithFormat:@"flutter.io/cameraPlugin/camera%lu", + (unsigned long)cameraId] + binaryMessenger:_messenger]; + _camera.methodChannel = methodChannel; + [methodChannel invokeMethod:@"initialized" + arguments:@{ + @"previewWidth" : @(_camera.previewSize.width), + @"previewHeight" : @(_camera.previewSize.height) + }]; + [_camera start]; + result(nil); + } else if ([@"takePicture" isEqualToString:call.method]) { if (@available(iOS 10.0, *)) { - [_camera captureToFile:call.arguments[@"path"] result:result]; + [_camera captureToFile:result]; } else { result(FlutterMethodNotImplemented); } } else if ([@"dispose" isEqualToString:call.method]) { - [_registry unregisterTexture:textureId]; + [_registry unregisterTexture:cameraId]; [_camera close]; _dispatchQueue = nil; result(nil); @@ -887,9 +903,13 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re [_camera setUpCaptureSessionForAudio]; result(nil); } else if ([@"startVideoRecording" isEqualToString:call.method]) { - [_camera startVideoRecordingAtPath:call.arguments[@"filePath"] result:result]; + [_camera startVideoRecordingWithResult:result]; } else if ([@"stopVideoRecording" isEqualToString:call.method]) { [_camera stopVideoRecordingWithResult:result]; + } else if ([@"pauseVideoRecording" isEqualToString:call.method]) { + [_camera pauseVideoRecordingWithResult:result]; + } else if ([@"resumeVideoRecording" isEqualToString:call.method]) { + [_camera resumeVideoRecordingWithResult:result]; } else { result(FlutterMethodNotImplemented); } diff --git a/packages/camera/camera/lib/camera.dart b/packages/camera/camera/lib/camera.dart index 3b2cd77c5757..6c6d90b9bcee 100644 --- a/packages/camera/camera/lib/camera.dart +++ b/packages/camera/camera/lib/camera.dart @@ -2,643 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; - -part 'camera_image.dart'; - -final MethodChannel _channel = const MethodChannel('plugins.flutter.io/camera'); - -/// The direction the camera is facing. -enum CameraLensDirection { - /// Front facing camera (a user looking at the screen is seen by the camera). - front, - - /// Back facing camera (a user looking at the screen is not seen by the camera). - back, - - /// External camera which may not be mounted to the device. - external, -} - -/// Affect the quality of video recording and image capture: -/// -/// If a preset is not available on the camera being used a preset of lower quality will be selected automatically. -enum ResolutionPreset { - /// 352x288 on iOS, 240p (320x240) on Android - low, - - /// 480p (640x480 on iOS, 720x480 on Android) - medium, - - /// 720p (1280x720) - high, - - /// 1080p (1920x1080) - veryHigh, - - /// 2160p (3840x2160) - ultraHigh, - - /// The highest resolution available. - max, -} - -/// Signature for a callback receiving the a camera image. -/// -/// This is used by [CameraController.startImageStream]. -// ignore: inference_failure_on_function_return_type -typedef onLatestImageAvailable = Function(CameraImage image); - -/// Returns the resolution preset as a String. -String serializeResolutionPreset(ResolutionPreset resolutionPreset) { - switch (resolutionPreset) { - case ResolutionPreset.max: - return 'max'; - case ResolutionPreset.ultraHigh: - return 'ultraHigh'; - case ResolutionPreset.veryHigh: - return 'veryHigh'; - case ResolutionPreset.high: - return 'high'; - case ResolutionPreset.medium: - return 'medium'; - case ResolutionPreset.low: - return 'low'; - } - throw ArgumentError('Unknown ResolutionPreset value'); -} - -CameraLensDirection _parseCameraLensDirection(String string) { - switch (string) { - case 'front': - return CameraLensDirection.front; - case 'back': - return CameraLensDirection.back; - case 'external': - return CameraLensDirection.external; - } - throw ArgumentError('Unknown CameraLensDirection value'); -} - -/// Completes with a list of available cameras. -/// -/// May throw a [CameraException]. -Future> availableCameras() async { - try { - final List> cameras = await _channel - .invokeListMethod>('availableCameras'); - return cameras.map((Map camera) { - return CameraDescription( - name: camera['name'], - lensDirection: _parseCameraLensDirection(camera['lensFacing']), - sensorOrientation: camera['sensorOrientation'], - ); - }).toList(); - } on PlatformException catch (e) { - throw CameraException(e.code, e.message); - } -} - -/// Properties of a camera device. -class CameraDescription { - /// Creates a new camera description with the given properties. - CameraDescription({this.name, this.lensDirection, this.sensorOrientation}); - - /// The name of the camera device. - final String name; - - /// The direction the camera is facing. - final CameraLensDirection lensDirection; - - /// Clockwise angle through which the output image needs to be rotated to be upright on the device screen in its native orientation. - /// - /// **Range of valid values:** - /// 0, 90, 180, 270 - /// - /// On Android, also defines the direction of rolling shutter readout, which - /// is from top to bottom in the sensor's coordinate system. - final int sensorOrientation; - - @override - bool operator ==(Object o) { - return o is CameraDescription && - o.name == name && - o.lensDirection == lensDirection; - } - - @override - int get hashCode { - return hashValues(name, lensDirection); - } - - @override - String toString() { - return '$runtimeType($name, $lensDirection, $sensorOrientation)'; - } -} - -/// This is thrown when the plugin reports an error. -class CameraException implements Exception { - /// Creates a new camera exception with the given error code and description. - CameraException(this.code, this.description); - - /// Error code. - // TODO(bparrishMines): Document possible error codes. - // https://github.com/flutter/flutter/issues/69298 - String code; - - /// Textual description of the error. - String description; - - @override - String toString() => '$runtimeType($code, $description)'; -} - -/// A widget showing a live camera preview. -class CameraPreview extends StatelessWidget { - /// Creates a preview widget for the given camera controller. - const CameraPreview(this.controller); - - /// The controller for the camera that the preview is shown for. - final CameraController controller; - - @override - Widget build(BuildContext context) { - return controller.value.isInitialized - ? Texture(textureId: controller._textureId) - : Container(); - } -} - -/// The state of a [CameraController]. -class CameraValue { - /// Creates a new camera controller state. - const CameraValue({ - this.isInitialized, - this.errorDescription, - this.previewSize, - this.isRecordingVideo, - this.isTakingPicture, - this.isStreamingImages, - bool isRecordingPaused, - }) : _isRecordingPaused = isRecordingPaused; - - /// Creates a new camera controller state for an uninitialzed controller. - const CameraValue.uninitialized() - : this( - isInitialized: false, - isRecordingVideo: false, - isTakingPicture: false, - isStreamingImages: false, - isRecordingPaused: false, - ); - - /// True after [CameraController.initialize] has completed successfully. - final bool isInitialized; - - /// True when a picture capture request has been sent but as not yet returned. - final bool isTakingPicture; - - /// True when the camera is recording (not the same as previewing). - final bool isRecordingVideo; - - /// True when images from the camera are being streamed. - final bool isStreamingImages; - - final bool _isRecordingPaused; - - /// True when camera [isRecordingVideo] and recording is paused. - bool get isRecordingPaused => isRecordingVideo && _isRecordingPaused; - - /// Description of an error state. - /// - /// This is null while the controller is not in an error state. - /// When [hasError] is true this contains the error description. - final String errorDescription; - - /// The size of the preview in pixels. - /// - /// Is `null` until [isInitialized] is `true`. - final Size previewSize; - - /// Convenience getter for `previewSize.height / previewSize.width`. - /// - /// Can only be called when [initialize] is done. - double get aspectRatio => previewSize.height / previewSize.width; - - /// Whether the controller is in an error state. - /// - /// When true [errorDescription] describes the error. - bool get hasError => errorDescription != null; - - /// Creates a modified copy of the object. - /// - /// Explicitly specified fields get the specified value, all other fields get - /// the same value of the current object. - CameraValue copyWith({ - bool isInitialized, - bool isRecordingVideo, - bool isTakingPicture, - bool isStreamingImages, - String errorDescription, - Size previewSize, - bool isRecordingPaused, - }) { - return CameraValue( - isInitialized: isInitialized ?? this.isInitialized, - errorDescription: errorDescription, - previewSize: previewSize ?? this.previewSize, - isRecordingVideo: isRecordingVideo ?? this.isRecordingVideo, - isTakingPicture: isTakingPicture ?? this.isTakingPicture, - isStreamingImages: isStreamingImages ?? this.isStreamingImages, - isRecordingPaused: isRecordingPaused ?? _isRecordingPaused, - ); - } - - @override - String toString() { - return '$runtimeType(' - 'isRecordingVideo: $isRecordingVideo, ' - 'isRecordingVideo: $isRecordingVideo, ' - 'isInitialized: $isInitialized, ' - 'errorDescription: $errorDescription, ' - 'previewSize: $previewSize, ' - 'isStreamingImages: $isStreamingImages)'; - } -} - -/// Controls a device camera. -/// -/// Use [availableCameras] to get a list of available cameras. -/// -/// Before using a [CameraController] a call to [initialize] must complete. -/// -/// To show the camera preview on the screen use a [CameraPreview] widget. -class CameraController extends ValueNotifier { - /// Creates a new camera controller in an uninitialized state. - CameraController( - this.description, - this.resolutionPreset, { - this.enableAudio = true, - }) : super(const CameraValue.uninitialized()); - - /// The properties of the camera device controlled by this controller. - final CameraDescription description; - - /// The resolution this controller is targeting. - /// - /// This resolution preset is not guaranteed to be available on the device, - /// if unavailable a lower resolution will be used. - /// - /// See also: [ResolutionPreset]. - final ResolutionPreset resolutionPreset; - - /// Whether to include audio when recording a video. - final bool enableAudio; - - int _textureId; - bool _isDisposed = false; - StreamSubscription _eventSubscription; - StreamSubscription _imageStreamSubscription; - Completer _creatingCompleter; - - /// Checks whether [CameraController.dispose] has completed successfully. - /// - /// This is a no-op when asserts are disabled. - void debugCheckIsDisposed() { - assert(_isDisposed); - } - - /// Initializes the camera on the device. - /// - /// Throws a [CameraException] if the initialization fails. - Future initialize() async { - if (_isDisposed) { - return Future.value(); - } - try { - _creatingCompleter = Completer(); - final Map reply = - await _channel.invokeMapMethod( - 'initialize', - { - 'cameraName': description.name, - 'resolutionPreset': serializeResolutionPreset(resolutionPreset), - 'enableAudio': enableAudio, - }, - ); - _textureId = reply['textureId']; - value = value.copyWith( - isInitialized: true, - previewSize: Size( - reply['previewWidth'].toDouble(), - reply['previewHeight'].toDouble(), - ), - ); - } on PlatformException catch (e) { - throw CameraException(e.code, e.message); - } - _eventSubscription = - EventChannel('flutter.io/cameraPlugin/cameraEvents$_textureId') - .receiveBroadcastStream() - .listen(_listener); - _creatingCompleter.complete(); - return _creatingCompleter.future; - } - - /// Prepare the capture session for video recording. - /// - /// Use of this method is optional, but it may be called for performance - /// reasons on iOS. - /// - /// Preparing audio can cause a minor delay in the CameraPreview view on iOS. - /// If video recording is intended, calling this early eliminates this delay - /// that would otherwise be experienced when video recording is started. - /// This operation is a no-op on Android. - /// - /// Throws a [CameraException] if the prepare fails. - Future prepareForVideoRecording() async { - await _channel.invokeMethod('prepareForVideoRecording'); - } - - /// Listen to events from the native plugins. - /// - /// A "cameraClosing" event is sent when the camera is closed automatically by the system (for example when the app go to background). The plugin will try to reopen the camera automatically but any ongoing recording will end. - void _listener(dynamic event) { - final Map map = event; - if (_isDisposed) { - return; - } - - switch (map['eventType']) { - case 'error': - value = value.copyWith(errorDescription: event['errorDescription']); - break; - case 'cameraClosing': - value = value.copyWith(isRecordingVideo: false); - break; - } - } - - /// Captures an image and saves it to [path]. - /// - /// A path can for example be obtained using - /// [path_provider](https://pub.dartlang.org/packages/path_provider). - /// - /// If a file already exists at the provided path an error will be thrown. - /// The file can be read as this function returns. - /// - /// Throws a [CameraException] if the capture fails. - Future takePicture(String path) async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController.', - 'takePicture was called on uninitialized CameraController', - ); - } - if (value.isTakingPicture) { - throw CameraException( - 'Previous capture has not returned yet.', - 'takePicture was called before the previous capture returned.', - ); - } - try { - value = value.copyWith(isTakingPicture: true); - await _channel.invokeMethod( - 'takePicture', - {'textureId': _textureId, 'path': path}, - ); - value = value.copyWith(isTakingPicture: false); - } on PlatformException catch (e) { - value = value.copyWith(isTakingPicture: false); - throw CameraException(e.code, e.message); - } - } - - /// Start streaming images from platform camera. - /// - /// Settings for capturing images on iOS and Android is set to always use the - /// latest image available from the camera and will drop all other images. - /// - /// When running continuously with [CameraPreview] widget, this function runs - /// best with [ResolutionPreset.low]. Running on [ResolutionPreset.high] can - /// have significant frame rate drops for [CameraPreview] on lower end - /// devices. - /// - /// Throws a [CameraException] if image streaming or video recording has - /// already started. - // TODO(bmparr): Add settings for resolution and fps. - Future startImageStream(onLatestImageAvailable onAvailable) async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'startImageStream was called on uninitialized CameraController.', - ); - } - if (value.isRecordingVideo) { - throw CameraException( - 'A video recording is already started.', - 'startImageStream was called while a video is being recorded.', - ); - } - if (value.isStreamingImages) { - throw CameraException( - 'A camera has started streaming images.', - 'startImageStream was called while a camera was streaming images.', - ); - } - - try { - await _channel.invokeMethod('startImageStream'); - value = value.copyWith(isStreamingImages: true); - } on PlatformException catch (e) { - throw CameraException(e.code, e.message); - } - const EventChannel cameraEventChannel = - EventChannel('plugins.flutter.io/camera/imageStream'); - _imageStreamSubscription = - cameraEventChannel.receiveBroadcastStream().listen( - (dynamic imageData) { - onAvailable(CameraImage._fromPlatformData(imageData)); - }, - ); - } - - /// Stop streaming images from platform camera. - /// - /// Throws a [CameraException] if image streaming was not started or video - /// recording was started. - Future stopImageStream() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'stopImageStream was called on uninitialized CameraController.', - ); - } - if (value.isRecordingVideo) { - throw CameraException( - 'A video recording is already started.', - 'stopImageStream was called while a video is being recorded.', - ); - } - if (!value.isStreamingImages) { - throw CameraException( - 'No camera is streaming images', - 'stopImageStream was called when no camera is streaming images.', - ); - } - - try { - value = value.copyWith(isStreamingImages: false); - await _channel.invokeMethod('stopImageStream'); - } on PlatformException catch (e) { - throw CameraException(e.code, e.message); - } - - await _imageStreamSubscription.cancel(); - _imageStreamSubscription = null; - } - - /// Start a video recording and save the file to [path]. - /// - /// A path can for example be obtained using - /// [path_provider](https://pub.dartlang.org/packages/path_provider). - /// - /// The file is written on the flight as the video is being recorded. - /// If a file already exists at the provided path an error will be thrown. - /// The file can be read as soon as [stopVideoRecording] returns. - /// - /// Throws a [CameraException] if the capture fails. - Future startVideoRecording(String filePath) async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'startVideoRecording was called on uninitialized CameraController', - ); - } - if (value.isRecordingVideo) { - throw CameraException( - 'A video recording is already started.', - 'startVideoRecording was called when a recording is already started.', - ); - } - if (value.isStreamingImages) { - throw CameraException( - 'A camera has started streaming images.', - 'startVideoRecording was called while a camera was streaming images.', - ); - } - - try { - await _channel.invokeMethod( - 'startVideoRecording', - {'textureId': _textureId, 'filePath': filePath}, - ); - value = value.copyWith(isRecordingVideo: true, isRecordingPaused: false); - } on PlatformException catch (e) { - throw CameraException(e.code, e.message); - } - } - - /// Stop recording. - Future stopVideoRecording() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'stopVideoRecording was called on uninitialized CameraController', - ); - } - if (!value.isRecordingVideo) { - throw CameraException( - 'No video is recording', - 'stopVideoRecording was called when no video is recording.', - ); - } - try { - value = value.copyWith(isRecordingVideo: false); - await _channel.invokeMethod( - 'stopVideoRecording', - {'textureId': _textureId}, - ); - } on PlatformException catch (e) { - throw CameraException(e.code, e.message); - } - } - - /// Pause video recording. - /// - /// This feature is only available on iOS and Android sdk 24+. - Future pauseVideoRecording() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'pauseVideoRecording was called on uninitialized CameraController', - ); - } - if (!value.isRecordingVideo) { - throw CameraException( - 'No video is recording', - 'pauseVideoRecording was called when no video is recording.', - ); - } - try { - value = value.copyWith(isRecordingPaused: true); - await _channel.invokeMethod( - 'pauseVideoRecording', - {'textureId': _textureId}, - ); - } on PlatformException catch (e) { - throw CameraException(e.code, e.message); - } - } - - /// Resume video recording after pausing. - /// - /// This feature is only available on iOS and Android sdk 24+. - Future resumeVideoRecording() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'resumeVideoRecording was called on uninitialized CameraController', - ); - } - if (!value.isRecordingVideo) { - throw CameraException( - 'No video is recording', - 'resumeVideoRecording was called when no video is recording.', - ); - } - try { - value = value.copyWith(isRecordingPaused: false); - await _channel.invokeMethod( - 'resumeVideoRecording', - {'textureId': _textureId}, - ); - } on PlatformException catch (e) { - throw CameraException(e.code, e.message); - } - } - - /// Releases the resources of this camera. - @override - Future dispose() async { - if (_isDisposed) { - return; - } - _isDisposed = true; - super.dispose(); - if (_creatingCompleter != null) { - await _creatingCompleter.future; - await _channel.invokeMethod( - 'dispose', - {'textureId': _textureId}, - ); - await _eventSubscription?.cancel(); - } - } -} +export 'src/camera_controller.dart'; +export 'src/camera_image.dart'; +export 'src/camera_preview.dart'; + +export 'package:camera_platform_interface/camera_platform_interface.dart' + show + CameraDescription, + CameraException, + CameraLensDirection, + ResolutionPreset, + XFile; diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart new file mode 100644 index 000000000000..fcf00245ce7f --- /dev/null +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -0,0 +1,484 @@ +// Copyright 2018 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:async'; + +import 'package:camera/camera.dart'; +import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +final MethodChannel _channel = const MethodChannel('plugins.flutter.io/camera'); + +/// Signature for a callback receiving the a camera image. +/// +/// This is used by [CameraController.startImageStream]. +// ignore: inference_failure_on_function_return_type +typedef onLatestImageAvailable = Function(CameraImage image); + +/// Completes with a list of available cameras. +/// +/// May throw a [CameraException]. +Future> availableCameras() async { + return CameraPlatform.instance.availableCameras(); +} + +/// The state of a [CameraController]. +class CameraValue { + /// Creates a new camera controller state. + const CameraValue({ + this.isInitialized, + this.errorDescription, + this.previewSize, + this.isRecordingVideo, + this.isTakingPicture, + this.isStreamingImages, + bool isRecordingPaused, + }) : _isRecordingPaused = isRecordingPaused; + + /// Creates a new camera controller state for an uninitialized controller. + const CameraValue.uninitialized() + : this( + isInitialized: false, + isRecordingVideo: false, + isTakingPicture: false, + isStreamingImages: false, + isRecordingPaused: false, + ); + + /// True after [CameraController.initialize] has completed successfully. + final bool isInitialized; + + /// True when a picture capture request has been sent but as not yet returned. + final bool isTakingPicture; + + /// True when the camera is recording (not the same as previewing). + final bool isRecordingVideo; + + /// True when images from the camera are being streamed. + final bool isStreamingImages; + + final bool _isRecordingPaused; + + /// True when camera [isRecordingVideo] and recording is paused. + bool get isRecordingPaused => isRecordingVideo && _isRecordingPaused; + + /// Description of an error state. + /// + /// This is null while the controller is not in an error state. + /// When [hasError] is true this contains the error description. + final String errorDescription; + + /// The size of the preview in pixels. + /// + /// Is `null` until [isInitialized] is `true`. + final Size previewSize; + + /// Convenience getter for `previewSize.height / previewSize.width`. + /// + /// Can only be called when [initialize] is done. + double get aspectRatio => previewSize.height / previewSize.width; + + /// Whether the controller is in an error state. + /// + /// When true [errorDescription] describes the error. + bool get hasError => errorDescription != null; + + /// Creates a modified copy of the object. + /// + /// Explicitly specified fields get the specified value, all other fields get + /// the same value of the current object. + CameraValue copyWith({ + bool isInitialized, + bool isRecordingVideo, + bool isTakingPicture, + bool isStreamingImages, + String errorDescription, + Size previewSize, + bool isRecordingPaused, + }) { + return CameraValue( + isInitialized: isInitialized ?? this.isInitialized, + errorDescription: errorDescription, + previewSize: previewSize ?? this.previewSize, + isRecordingVideo: isRecordingVideo ?? this.isRecordingVideo, + isTakingPicture: isTakingPicture ?? this.isTakingPicture, + isStreamingImages: isStreamingImages ?? this.isStreamingImages, + isRecordingPaused: isRecordingPaused ?? _isRecordingPaused, + ); + } + + @override + String toString() { + return '$runtimeType(' + 'isRecordingVideo: $isRecordingVideo, ' + 'isInitialized: $isInitialized, ' + 'errorDescription: $errorDescription, ' + 'previewSize: $previewSize, ' + 'isStreamingImages: $isStreamingImages)'; + } +} + +/// Controls a device camera. +/// +/// Use [availableCameras] to get a list of available cameras. +/// +/// Before using a [CameraController] a call to [initialize] must complete. +/// +/// To show the camera preview on the screen use a [CameraPreview] widget. +class CameraController extends ValueNotifier { + /// Creates a new camera controller in an uninitialized state. + CameraController( + this.description, + this.resolutionPreset, { + this.enableAudio = true, + }) : super(const CameraValue.uninitialized()); + + /// The properties of the camera device controlled by this controller. + final CameraDescription description; + + /// The resolution this controller is targeting. + /// + /// This resolution preset is not guaranteed to be available on the device, + /// if unavailable a lower resolution will be used. + /// + /// See also: [ResolutionPreset]. + final ResolutionPreset resolutionPreset; + + /// Whether to include audio when recording a video. + final bool enableAudio; + + int _cameraId; + bool _isDisposed = false; + StreamSubscription _imageStreamSubscription; + FutureOr _initCalled; + + /// Checks whether [CameraController.dispose] has completed successfully. + /// + /// This is a no-op when asserts are disabled. + void debugCheckIsDisposed() { + assert(_isDisposed); + } + + /// The camera identifier with which the controller is associated. + int get cameraId => _cameraId; + + /// Initializes the camera on the device. + /// + /// Throws a [CameraException] if the initialization fails. + Future initialize() async { + if (_isDisposed) { + throw CameraException( + 'Disposed CameraController', + 'initialize was called on a disposed CameraController', + ); + } + try { + _cameraId = await CameraPlatform.instance.createCamera( + description, + resolutionPreset, + enableAudio: enableAudio, + ); + + final previewSize = + CameraPlatform.instance.onCameraInitialized(_cameraId).map((event) { + return Size( + event.previewWidth, + event.previewHeight, + ); + }).first; + + await CameraPlatform.instance.initializeCamera(_cameraId); + + value = value.copyWith( + isInitialized: true, + previewSize: await previewSize, + ); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + + _initCalled = true; + } + + /// Prepare the capture session for video recording. + /// + /// Use of this method is optional, but it may be called for performance + /// reasons on iOS. + /// + /// Preparing audio can cause a minor delay in the CameraPreview view on iOS. + /// If video recording is intended, calling this early eliminates this delay + /// that would otherwise be experienced when video recording is started. + /// This operation is a no-op on Android. + /// + /// Throws a [CameraException] if the prepare fails. + Future prepareForVideoRecording() async { + await CameraPlatform.instance.prepareForVideoRecording(); + } + + /// Captures an image and saves it to [path]. + /// + /// A path can for example be obtained using + /// [path_provider](https://pub.dartlang.org/packages/path_provider). + /// + /// If a file already exists at the provided path an error will be thrown. + /// The file can be read as this function returns. + /// + /// Throws a [CameraException] if the capture fails. + Future takePicture() async { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController.', + 'takePicture was called on uninitialized CameraController', + ); + } + if (value.isTakingPicture) { + throw CameraException( + 'Previous capture has not returned yet.', + 'takePicture was called before the previous capture returned.', + ); + } + try { + value = value.copyWith(isTakingPicture: true); + XFile file = await CameraPlatform.instance.takePicture(_cameraId); + value = value.copyWith(isTakingPicture: false); + return file; + } on PlatformException catch (e) { + value = value.copyWith(isTakingPicture: false); + throw CameraException(e.code, e.message); + } + } + + /// Start streaming images from platform camera. + /// + /// Settings for capturing images on iOS and Android is set to always use the + /// latest image available from the camera and will drop all other images. + /// + /// When running continuously with [CameraPreview] widget, this function runs + /// best with [ResolutionPreset.low]. Running on [ResolutionPreset.high] can + /// have significant frame rate drops for [CameraPreview] on lower end + /// devices. + /// + /// Throws a [CameraException] if image streaming or video recording has + /// already started. + /// + /// The `startImageStream` method is only available on Android and iOS (other + /// platforms won't be supported in current setup). + /// + // TODO(bmparr): Add settings for resolution and fps. + Future startImageStream(onLatestImageAvailable onAvailable) async { + assert(defaultTargetPlatform == TargetPlatform.android || + defaultTargetPlatform == TargetPlatform.iOS); + + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'startImageStream was called on uninitialized CameraController.', + ); + } + if (value.isRecordingVideo) { + throw CameraException( + 'A video recording is already started.', + 'startImageStream was called while a video is being recorded.', + ); + } + if (value.isStreamingImages) { + throw CameraException( + 'A camera has started streaming images.', + 'startImageStream was called while a camera was streaming images.', + ); + } + + try { + await _channel.invokeMethod('startImageStream'); + value = value.copyWith(isStreamingImages: true); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + const EventChannel cameraEventChannel = + EventChannel('plugins.flutter.io/camera/imageStream'); + _imageStreamSubscription = + cameraEventChannel.receiveBroadcastStream().listen( + (dynamic imageData) { + onAvailable(CameraImage.fromPlatformData(imageData)); + }, + ); + } + + /// Stop streaming images from platform camera. + /// + /// Throws a [CameraException] if image streaming was not started or video + /// recording was started. + /// + /// The `stopImageStream` method is only available on Android and iOS (other + /// platforms won't be supported in current setup). + Future stopImageStream() async { + assert(defaultTargetPlatform == TargetPlatform.android || + defaultTargetPlatform == TargetPlatform.iOS); + + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'stopImageStream was called on uninitialized CameraController.', + ); + } + if (value.isRecordingVideo) { + throw CameraException( + 'A video recording is already started.', + 'stopImageStream was called while a video is being recorded.', + ); + } + if (!value.isStreamingImages) { + throw CameraException( + 'No camera is streaming images', + 'stopImageStream was called when no camera is streaming images.', + ); + } + + try { + value = value.copyWith(isStreamingImages: false); + await _channel.invokeMethod('stopImageStream'); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + + await _imageStreamSubscription.cancel(); + _imageStreamSubscription = null; + } + + /// Start a video recording. + /// + /// The video is returned as a [XFile] after calling [stopVideoRecording]. + /// Throws a [CameraException] if the capture fails. + Future startVideoRecording() async { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'startVideoRecording was called on uninitialized CameraController', + ); + } + if (value.isRecordingVideo) { + throw CameraException( + 'A video recording is already started.', + 'startVideoRecording was called when a recording is already started.', + ); + } + if (value.isStreamingImages) { + throw CameraException( + 'A camera has started streaming images.', + 'startVideoRecording was called while a camera was streaming images.', + ); + } + + try { + await CameraPlatform.instance.startVideoRecording(_cameraId); + value = value.copyWith(isRecordingVideo: true, isRecordingPaused: false); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Stops the video recording and returns the file where it was saved. + /// + /// Throws a [CameraException] if the capture failed. + Future stopVideoRecording() async { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'stopVideoRecording was called on uninitialized CameraController', + ); + } + if (!value.isRecordingVideo) { + throw CameraException( + 'No video is recording', + 'stopVideoRecording was called when no video is recording.', + ); + } + try { + XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); + value = value.copyWith(isRecordingVideo: false); + return file; + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Pause video recording. + /// + /// This feature is only available on iOS and Android sdk 24+. + Future pauseVideoRecording() async { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'pauseVideoRecording was called on uninitialized CameraController', + ); + } + if (!value.isRecordingVideo) { + throw CameraException( + 'No video is recording', + 'pauseVideoRecording was called when no video is recording.', + ); + } + try { + await CameraPlatform.instance.pauseVideoRecording(_cameraId); + value = value.copyWith(isRecordingPaused: true); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Resume video recording after pausing. + /// + /// This feature is only available on iOS and Android sdk 24+. + Future resumeVideoRecording() async { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'resumeVideoRecording was called on uninitialized CameraController', + ); + } + if (!value.isRecordingVideo) { + throw CameraException( + 'No video is recording', + 'resumeVideoRecording was called when no video is recording.', + ); + } + try { + await CameraPlatform.instance.resumeVideoRecording(_cameraId); + value = value.copyWith(isRecordingPaused: false); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Returns a widget showing a live camera preview. + Widget buildPreview() { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'buildView() was called on uninitialized CameraController.', + ); + } + try { + return CameraPlatform.instance.buildPreview(_cameraId); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Releases the resources of this camera. + @override + Future dispose() async { + if (_isDisposed) { + return; + } + _isDisposed = true; + super.dispose(); + if (_initCalled != null) { + await _initCalled; + await CameraPlatform.instance.dispose(_cameraId); + } + } +} diff --git a/packages/camera/camera/lib/camera_image.dart b/packages/camera/camera/lib/src/camera_image.dart similarity index 96% rename from packages/camera/camera/lib/camera_image.dart rename to packages/camera/camera/lib/src/camera_image.dart index cebc14873f52..ca8115eb758d 100644 --- a/packages/camera/camera/lib/camera_image.dart +++ b/packages/camera/camera/lib/src/camera_image.dart @@ -2,7 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -part of 'camera.dart'; +import 'dart:typed_data'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; /// A single color plane of image data. /// @@ -113,7 +116,8 @@ ImageFormatGroup _asImageFormatGroup(dynamic rawFormat) { /// Although not all image formats are planar on iOS, we treat 1-dimensional /// images as single planar images. class CameraImage { - CameraImage._fromPlatformData(Map data) + /// CameraImage Constructor + CameraImage.fromPlatformData(Map data) : format = ImageFormat._fromPlatformData(data['format']), height = data['height'], width = data['width'], diff --git a/packages/camera/camera/lib/src/camera_preview.dart b/packages/camera/camera/lib/src/camera_preview.dart new file mode 100644 index 000000000000..bf7862eb9151 --- /dev/null +++ b/packages/camera/camera/lib/src/camera_preview.dart @@ -0,0 +1,23 @@ +// Copyright 2018 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 'package:camera/camera.dart'; +import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter/material.dart'; + +/// A widget showing a live camera preview. +class CameraPreview extends StatelessWidget { + /// Creates a preview widget for the given camera controller. + const CameraPreview(this.controller); + + /// The controller for the camera that the preview is shown for. + final CameraController controller; + + @override + Widget build(BuildContext context) { + return controller.value.isInitialized + ? CameraPlatform.instance.buildPreview(controller.cameraId) + : Container(); + } +} diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 146219d8366f..64d5bba61159 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,12 +2,13 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.5.8+19 +version: 0.6.0 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: flutter: sdk: flutter + camera_platform_interface: ^1.0.0 dev_dependencies: path_provider: ^0.5.0 @@ -17,6 +18,8 @@ dev_dependencies: flutter_driver: sdk: flutter pedantic: ^1.8.0 + mockito: ^4.1.3 + plugin_platform_interface: ^1.0.3 flutter: plugin: diff --git a/packages/camera/camera/test/camera_image_stream_test.dart b/packages/camera/camera/test/camera_image_stream_test.dart new file mode 100644 index 000000000000..be7047f2220f --- /dev/null +++ b/packages/camera/camera/test/camera_image_stream_test.dart @@ -0,0 +1,187 @@ +import 'package:camera/camera.dart'; +import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'camera_test.dart'; +import 'utils/method_channel_mock.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + + setUp(() { + CameraPlatform.instance = MockCameraPlatform(); + }); + + test('startImageStream() throws $CameraException when uninitialized', () { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + expect( + () => cameraController.startImageStream((image) => null), + throwsA(isA().having( + (error) => error.description, + 'Uninitialized CameraController.', + 'startImageStream was called on uninitialized CameraController.', + ))); + }); + + test('startImageStream() throws $CameraException when recording videos', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + + cameraController.value = + cameraController.value.copyWith(isRecordingVideo: true); + + expect( + () => cameraController.startImageStream((image) => null), + throwsA(isA().having( + (error) => error.description, + 'A video recording is already started.', + 'startImageStream was called while a video is being recorded.', + ))); + }); + test( + 'startImageStream() throws $CameraException when already streaming images', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + cameraController.value = + cameraController.value.copyWith(isStreamingImages: true); + expect( + () => cameraController.startImageStream((image) => null), + throwsA(isA().having( + (error) => error.description, + 'A camera has started streaming images.', + 'startImageStream was called while a camera was streaming images.', + ))); + }); + + test('startImageStream() calls CameraPlatform', () async { + MethodChannelMock cameraChannelMock = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'startImageStream': {}}); + MethodChannelMock streamChannelMock = MethodChannelMock( + channelName: 'plugins.flutter.io/camera/imageStream', + methods: {'listen': {}}); + + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.startImageStream((image) => null); + + expect(cameraChannelMock.log, + [isMethodCall('startImageStream', arguments: null)]); + expect(streamChannelMock.log, + [isMethodCall('listen', arguments: null)]); + }); + + test('stopImageStream() throws $CameraException when uninitialized', () { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + expect( + cameraController.stopImageStream, + throwsA(isA().having( + (error) => error.description, + 'Uninitialized CameraController.', + 'stopImageStream was called on uninitialized CameraController.', + ))); + }); + + test('stopImageStream() throws $CameraException when recording videos', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.startImageStream((image) => null); + cameraController.value = + cameraController.value.copyWith(isRecordingVideo: true); + expect( + cameraController.stopImageStream, + throwsA(isA().having( + (error) => error.description, + 'A video recording is already started.', + 'stopImageStream was called while a video is being recorded.', + ))); + }); + + test('stopImageStream() throws $CameraException when not streaming images', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + expect( + cameraController.stopImageStream, + throwsA(isA().having( + (error) => error.description, + 'No camera is streaming images', + 'stopImageStream was called when no camera is streaming images.', + ))); + }); + + test('stopImageStream() intended behaviour', () async { + MethodChannelMock cameraChannelMock = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'startImageStream': {}, 'stopImageStream': {}}); + MethodChannelMock streamChannelMock = MethodChannelMock( + channelName: 'plugins.flutter.io/camera/imageStream', + methods: {'listen': {}, 'cancel': {}}); + + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + await cameraController.startImageStream((image) => null); + await cameraController.stopImageStream(); + + expect(cameraChannelMock.log, [ + isMethodCall('startImageStream', arguments: null), + isMethodCall('stopImageStream', arguments: null) + ]); + + expect(streamChannelMock.log, [ + isMethodCall('listen', arguments: null), + isMethodCall('cancel', arguments: null) + ]); + }); +} diff --git a/packages/camera/camera/test/camera_image_test.dart b/packages/camera/camera/test/camera_image_test.dart new file mode 100644 index 000000000000..c8f808f2c1a1 --- /dev/null +++ b/packages/camera/camera/test/camera_image_test.dart @@ -0,0 +1,113 @@ +// Copyright 2019 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:typed_data'; + +import 'package:camera/camera.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('$CameraImage tests', () { + test('$CameraImage can be created', () { + debugDefaultTargetPlatformOverride = TargetPlatform.android; + CameraImage cameraImage = CameraImage.fromPlatformData({ + 'format': 35, + 'height': 1, + 'width': 4, + 'planes': [ + { + 'bytes': Uint8List.fromList([1, 2, 3, 4]), + 'bytesPerPixel': 1, + 'bytesPerRow': 4, + 'height': 1, + 'width': 4 + } + ] + }); + expect(cameraImage.height, 1); + expect(cameraImage.width, 4); + expect(cameraImage.format.group, ImageFormatGroup.yuv420); + expect(cameraImage.planes.length, 1); + }); + + test('$CameraImage has ImageFormatGroup.yuv420 for iOS', () { + debugDefaultTargetPlatformOverride = TargetPlatform.iOS; + + CameraImage cameraImage = CameraImage.fromPlatformData({ + 'format': 875704438, + 'height': 1, + 'width': 4, + 'planes': [ + { + 'bytes': Uint8List.fromList([1, 2, 3, 4]), + 'bytesPerPixel': 1, + 'bytesPerRow': 4, + 'height': 1, + 'width': 4 + } + ] + }); + expect(cameraImage.format.group, ImageFormatGroup.yuv420); + }); + + test('$CameraImage has ImageFormatGroup.yuv420 for Android', () { + debugDefaultTargetPlatformOverride = TargetPlatform.android; + + CameraImage cameraImage = CameraImage.fromPlatformData({ + 'format': 35, + 'height': 1, + 'width': 4, + 'planes': [ + { + 'bytes': Uint8List.fromList([1, 2, 3, 4]), + 'bytesPerPixel': 1, + 'bytesPerRow': 4, + 'height': 1, + 'width': 4 + } + ] + }); + expect(cameraImage.format.group, ImageFormatGroup.yuv420); + }); + + test('$CameraImage has ImageFormatGroup.bgra8888 for iOS', () { + debugDefaultTargetPlatformOverride = TargetPlatform.iOS; + + CameraImage cameraImage = CameraImage.fromPlatformData({ + 'format': 1111970369, + 'height': 1, + 'width': 4, + 'planes': [ + { + 'bytes': Uint8List.fromList([1, 2, 3, 4]), + 'bytesPerPixel': 1, + 'bytesPerRow': 4, + 'height': 1, + 'width': 4 + } + ] + }); + expect(cameraImage.format.group, ImageFormatGroup.bgra8888); + }); + test('$CameraImage has ImageFormatGroup.unknown', () { + CameraImage cameraImage = CameraImage.fromPlatformData({ + 'format': null, + 'height': 1, + 'width': 4, + 'planes': [ + { + 'bytes': Uint8List.fromList([1, 2, 3, 4]), + 'bytesPerPixel': 1, + 'bytesPerRow': 4, + 'height': 1, + 'width': 4 + } + ] + }); + expect(cameraImage.format.group, ImageFormatGroup.unknown); + }); + }); +} diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index cc33b369f000..b129849cd141 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -1,10 +1,46 @@ // 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:async'; +import 'dart:ui'; + import 'package:camera/camera.dart'; +import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +get mockAvailableCameras => [ + CameraDescription( + name: 'camBack', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + CameraDescription( + name: 'camFront', + lensDirection: CameraLensDirection.front, + sensorOrientation: 180), + ]; + +get mockInitializeCamera => 13; + +get mockOnCameraInitializedEvent => CameraInitializedEvent(13, 75, 75); + +get mockOnCameraClosingEvent => null; + +get mockOnCameraErrorEvent => CameraErrorEvent(13, 'closing'); + +XFile mockTakePicture = XFile('foo/bar.png'); + +get mockVideoRecordingXFile => null; + +bool mockPlatformException = false; void main() { + WidgetsFlutterBinding.ensureInitialized(); + group('camera', () { test('debugCheckIsDisposed should not throw assertion error when disposed', () { @@ -32,9 +68,290 @@ void main() { throwsAssertionError, ); }); + + test('availableCameras() has camera', () async { + CameraPlatform.instance = MockCameraPlatform(); + + var camList = await availableCameras(); + + expect(camList, equals(mockAvailableCameras)); + }); + }); + + group('$CameraController', () { + setUpAll(() { + CameraPlatform.instance = MockCameraPlatform(); + }); + + test('Can be initialized', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + expect(cameraController.value.aspectRatio, 1); + expect(cameraController.value.previewSize, Size(75, 75)); + expect(cameraController.value.isInitialized, isTrue); + }); + + test('can be disposed', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + expect(cameraController.value.aspectRatio, 1); + expect(cameraController.value.previewSize, Size(75, 75)); + expect(cameraController.value.isInitialized, isTrue); + + await cameraController.dispose(); + + verify(CameraPlatform.instance.dispose(13)).called(1); + }); + + test('initialize() throws CameraException when disposed', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + expect(cameraController.value.aspectRatio, 1); + expect(cameraController.value.previewSize, Size(75, 75)); + expect(cameraController.value.isInitialized, isTrue); + + await cameraController.dispose(); + + verify(CameraPlatform.instance.dispose(13)).called(1); + + expect( + cameraController.initialize, + throwsA(isA().having( + (error) => error.description, + 'Error description', + 'initialize was called on a disposed CameraController', + ))); + }); + + test('initialize() throws $CameraException on $PlatformException ', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + mockPlatformException = true; + + expect( + cameraController.initialize, + throwsA(isA().having( + (error) => error.description, + 'foo', + 'bar', + ))); + mockPlatformException = false; + }); + + test('prepareForVideoRecording() calls $CameraPlatform ', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.prepareForVideoRecording(); + + verify(CameraPlatform.instance.prepareForVideoRecording()).called(1); + }); + + test('takePicture() throws $CameraException when uninitialized ', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + expect( + cameraController.takePicture(), + throwsA(isA().having( + (error) => error.description, + 'Uninitialized CameraController.', + 'takePicture was called on uninitialized CameraController', + ))); + }); + + test('takePicture() throws $CameraException when takePicture is true', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + cameraController.value = + cameraController.value.copyWith(isTakingPicture: true); + expect( + cameraController.takePicture(), + throwsA(isA().having( + (error) => error.description, + 'Previous capture has not returned yet.', + 'takePicture was called before the previous capture returned.', + ))); + }); + + test('takePicture() returns $XFile', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + XFile xFile = await cameraController.takePicture(); + + expect(xFile.path, mockTakePicture.path); + }); + + test('takePicture() throws $CameraException on $PlatformException', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + mockPlatformException = true; + expect( + cameraController.takePicture(), + throwsA(isA().having( + (error) => error.description, + 'foo', + 'bar', + ))); + mockPlatformException = false; + }); + + test('startVideoRecording() throws $CameraException when uninitialized', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + expect( + cameraController.startVideoRecording(), + throwsA(isA().having( + (error) => error.description, + 'Uninitialized CameraController', + 'startVideoRecording was called on uninitialized CameraController', + ))); + }); + test('startVideoRecording() throws $CameraException when recording videos', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + + cameraController.value = + cameraController.value.copyWith(isRecordingVideo: true); + + expect( + cameraController.startVideoRecording(), + throwsA(isA().having( + (error) => error.description, + 'A video recording is already started.', + 'startVideoRecording was called when a recording is already started.', + ))); + }); + + test( + 'startVideoRecording() throws $CameraException when already streaming images', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + + cameraController.value = + cameraController.value.copyWith(isStreamingImages: true); + + expect( + cameraController.startVideoRecording(), + throwsA(isA().having( + (error) => error.description, + 'A camera has started streaming images.', + 'startVideoRecording was called while a camera was streaming images.', + ))); + }); }); } +class MockCameraPlatform extends Mock + with MockPlatformInterfaceMixin + implements CameraPlatform { + @override + Future> availableCameras() => + Future.value(mockAvailableCameras); + + @override + Future createCamera( + CameraDescription description, + ResolutionPreset resolutionPreset, { + bool enableAudio, + }) => + mockPlatformException + ? throw PlatformException(code: 'foo', message: 'bar') + : Future.value(mockInitializeCamera); + + @override + Stream onCameraInitialized(int cameraId) => + Stream.value(mockOnCameraInitializedEvent); + + @override + Stream onCameraClosing(int cameraId) => + Stream.value(mockOnCameraClosingEvent); + + @override + Stream onCameraError(int cameraId) => + Stream.value(mockOnCameraErrorEvent); + + @override + Future takePicture(int cameraId) => mockPlatformException + ? throw PlatformException(code: 'foo', message: 'bar') + : Future.value(mockTakePicture); + + @override + Future startVideoRecording(int cameraId) => + Future.value(mockVideoRecordingXFile); +} + class MockCameraDescription extends CameraDescription { @override CameraLensDirection get lensDirection => CameraLensDirection.back; diff --git a/packages/camera/camera/test/camera_value_test.dart b/packages/camera/camera/test/camera_value_test.dart new file mode 100644 index 000000000000..28255eb0a568 --- /dev/null +++ b/packages/camera/camera/test/camera_value_test.dart @@ -0,0 +1,102 @@ +// Copyright 2019 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:ui'; + +import 'package:camera/camera.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('camera_value', () { + test('Can be created', () { + var cameraValue = const CameraValue( + isInitialized: false, + errorDescription: null, + previewSize: Size(10, 10), + isRecordingPaused: false, + isRecordingVideo: false, + isTakingPicture: false, + isStreamingImages: false, + ); + + expect(cameraValue, isA()); + expect(cameraValue.isInitialized, isFalse); + expect(cameraValue.errorDescription, null); + expect(cameraValue.previewSize, Size(10, 10)); + expect(cameraValue.isRecordingPaused, isFalse); + expect(cameraValue.isRecordingVideo, isFalse); + expect(cameraValue.isTakingPicture, isFalse); + expect(cameraValue.isStreamingImages, isFalse); + }); + + test('Can be created as uninitialized', () { + var cameraValue = const CameraValue.uninitialized(); + + expect(cameraValue, isA()); + expect(cameraValue.isInitialized, isFalse); + expect(cameraValue.errorDescription, null); + expect(cameraValue.previewSize, null); + expect(cameraValue.isRecordingPaused, isFalse); + expect(cameraValue.isRecordingVideo, isFalse); + expect(cameraValue.isTakingPicture, isFalse); + expect(cameraValue.isStreamingImages, isFalse); + }); + + test('Can be copied with isInitialized', () { + var cv = const CameraValue.uninitialized(); + var cameraValue = cv.copyWith(isInitialized: true); + + expect(cameraValue, isA()); + expect(cameraValue.isInitialized, isTrue); + expect(cameraValue.errorDescription, null); + expect(cameraValue.previewSize, null); + expect(cameraValue.isRecordingPaused, isFalse); + expect(cameraValue.isRecordingVideo, isFalse); + expect(cameraValue.isTakingPicture, isFalse); + expect(cameraValue.isStreamingImages, isFalse); + }); + + test('Has aspectRatio after setting size', () { + var cv = const CameraValue.uninitialized(); + var cameraValue = + cv.copyWith(isInitialized: true, previewSize: Size(20, 10)); + + expect(cameraValue.aspectRatio, 0.5); + }); + + test('hasError is true after setting errorDescription', () { + var cv = const CameraValue.uninitialized(); + var cameraValue = cv.copyWith(errorDescription: 'error'); + + expect(cameraValue.hasError, isTrue); + expect(cameraValue.errorDescription, 'error'); + }); + + test('Recording paused is false when not recording', () { + var cv = const CameraValue.uninitialized(); + var cameraValue = cv.copyWith( + isInitialized: true, + isRecordingVideo: false, + isRecordingPaused: true); + + expect(cameraValue.isRecordingPaused, isFalse); + }); + + test('toString() works as expected', () { + var cameraValue = const CameraValue( + isInitialized: false, + errorDescription: null, + previewSize: Size(10, 10), + isRecordingPaused: false, + isRecordingVideo: false, + isTakingPicture: false, + isStreamingImages: false, + ); + + expect(cameraValue.toString(), + 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false)'); + }); + }); +} diff --git a/packages/camera/camera/test/utils/method_channel_mock.dart b/packages/camera/camera/test/utils/method_channel_mock.dart new file mode 100644 index 000000000000..cdf393f82b5f --- /dev/null +++ b/packages/camera/camera/test/utils/method_channel_mock.dart @@ -0,0 +1,38 @@ +// Copyright 2019 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 'package:flutter/services.dart'; + +class MethodChannelMock { + final Duration delay; + final MethodChannel methodChannel; + final Map methods; + final log = []; + + MethodChannelMock({ + String channelName, + this.delay, + this.methods, + }) : methodChannel = MethodChannel(channelName) { + methodChannel.setMockMethodCallHandler(_handler); + } + + Future _handler(MethodCall methodCall) async { + log.add(methodCall); + + if (!methods.containsKey(methodCall.method)) { + throw MissingPluginException('No implementation found for method ' + '${methodCall.method} on channel ${methodChannel.name}'); + } + + return Future.delayed(delay ?? Duration.zero, () { + final result = methods[methodCall.method]; + if (result is Exception) { + throw result; + } + + return Future.value(result); + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj index f6a2d6ec291a..75392aeb82e5 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -9,11 +9,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4510D964F3B1259FEDD3ABA6 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7755F8F4BABC3D6A0BD4048B /* libPods-Runner.a */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -28,8 +24,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -40,14 +34,12 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 7755F8F4BABC3D6A0BD4048B /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -63,8 +55,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 4510D964F3B1259FEDD3ABA6 /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -83,9 +73,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -230,7 +218,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 74BF216DF17B0C7F983459BD /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; @@ -270,9 +258,12 @@ files = ( ); inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", + "${PODS_ROOT}/GoogleMaps/Maps/Frameworks/GoogleMaps.framework/Resources/GoogleMaps.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMaps.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -285,9 +276,12 @@ files = ( ); inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../Flutter/Flutter.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -331,7 +325,6 @@ /* Begin XCBuildConfiguration section */ 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -388,7 +381,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; From ad6d03c13ba58375e093fae2d4d76f8a31ea9542 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Mon, 14 Dec 2020 13:33:59 -0800 Subject: [PATCH 043/924] Merge null-safety plugins (#3324) --- .../connectivity/connectivity/CHANGELOG.md | 8 + .../connectivity/analysis_options.yaml | 4 + .../connectivity/example/lib/main.dart | 6 +- .../connectivity/example/pubspec.yaml | 3 +- .../integration_test/connectivity_test.dart | 3 + .../integration_test/connectivity_test.dart | 3 + .../connectivity/lib/connectivity.dart | 4 +- .../connectivity/connectivity/pubspec.yaml | 17 +- .../connectivity/test/connectivity_test.dart | 4 +- .../connectivity_macos/CHANGELOG.md | 4 + .../connectivity_macos/pubspec.yaml | 4 +- .../CHANGELOG.md | 8 + .../analysis_options.yaml | 4 + .../lib/connectivity_platform_interface.dart | 6 +- .../lib/src/method_channel_connectivity.dart | 48 +-- .../pubspec.yaml | 10 +- .../method_channel_connectivity_test.dart | 10 +- packages/device_info/device_info/CHANGELOG.md | 8 + .../device_info/analysis_options.yaml | 4 + .../integration_test/device_info_test.dart | 3 + .../device_info/example/lib/main.dart | 2 +- .../device_info/example/pubspec.yaml | 4 +- .../example/test_driver/integration_test.dart | 3 + .../device_info/lib/device_info.dart | 4 +- packages/device_info/device_info/pubspec.yaml | 14 +- .../CHANGELOG.md | 13 + .../analysis_options.yaml | 4 + .../lib/model/android_device_info.dart | 121 ++++---- .../lib/model/ios_device_info.dart | 51 ++-- .../pubspec.yaml | 12 +- .../test/method_channel_device_info_test.dart | 124 +++++++- .../CHANGELOG.md | 8 + .../example/pubspec.yaml | 2 +- .../pubspec.yaml | 4 +- .../test/google_sign_in_test.dart | 2 +- packages/local_auth/CHANGELOG.md | 4 + packages/local_auth/lib/auth_strings.dart | 24 +- packages/local_auth/lib/local_auth.dart | 23 +- packages/local_auth/pubspec.yaml | 14 +- packages/local_auth/test/local_auth_test.dart | 2 +- .../CHANGELOG.md | 4 + .../lib/path_provider_platform_interface.dart | 18 +- .../lib/src/method_channel_path_provider.dart | 18 +- .../pubspec.yaml | 12 +- .../method_channel_path_provider_test.dart | 28 +- .../plugin_platform_interface/CHANGELOG.md | 8 + .../analysis_options.yaml | 4 + .../lib/plugin_platform_interface.dart | 2 +- .../plugin_platform_interface/pubspec.yaml | 10 +- .../test/plugin_platform_interface_test.dart | 2 + .../test/shared_preferences_test.dart | 2 +- .../url_launcher/url_launcher/CHANGELOG.md | 8 + .../url_launcher/analysis_options.yaml | 4 + .../integration_test/url_launcher_test.dart | 3 + .../url_launcher/example/lib/main.dart | 4 +- .../url_launcher/example/pubspec.yaml | 4 +- .../test/url_launcher_example_test.dart | 7 + .../example/test_driver/integration_test.dart | 3 + .../url_launcher/lib/src/link.dart | 21 +- .../url_launcher/lib/url_launcher.dart | 47 ++- .../url_launcher/url_launcher/pubspec.yaml | 26 +- .../url_launcher/test/link_test.dart | 3 +- .../url_launcher/test/url_launcher_test.dart | 8 +- .../url_launcher_linux/CHANGELOG.md | 4 + .../url_launcher_linux/pubspec.yaml | 4 +- .../url_launcher_macos/CHANGELOG.md | 8 + .../url_launcher_macos/pubspec.yaml | 4 +- .../CHANGELOG.md | 8 + .../analysis_options.yaml | 4 + .../lib/link.dart | 14 +- .../lib/method_channel_url_launcher.dart | 21 +- .../lib/url_launcher_platform_interface.dart | 17 +- .../pubspec.yaml | 9 +- .../test/link_test.dart | 3 + .../method_channel_url_launcher_test.dart | 26 ++ .../url_launcher_web/CHANGELOG.md | 2 +- .../url_launcher_web/pubspec.yaml | 9 + .../url_launcher_web/test/pubspec.yaml | 2 +- .../url_launcher_windows/CHANGELOG.md | 8 + .../url_launcher_windows/pubspec.yaml | 4 +- .../video_player/video_player/CHANGELOG.md | 16 + .../video_player/analysis_options.yaml | 4 + .../flutter/plugins/videoplayer/Messages.java | 4 +- .../integration_test/video_player_test.dart | 4 +- .../video_player/example/lib/main.dart | 11 +- .../video_player/example/pubspec.yaml | 3 +- .../example/test_driver/integration_test.dart | 3 + .../example/test_driver/video_player.dart | 14 + .../test_driver/video_player_test.dart | 30 ++ .../video_player/ios/Classes/messages.h | 2 +- .../video_player/ios/Classes/messages.m | 36 ++- .../lib/src/closed_caption_file.dart | 11 +- .../video_player/lib/src/sub_rip.dart | 7 +- .../video_player/lib/video_player.dart | 167 ++++++----- .../video_player/pigeons/messages.dart | 2 + .../video_player/video_player/pubspec.yaml | 15 +- .../video_player/test/sub_rip_file_test.dart | 2 +- .../video_player_initialization_test.dart | 2 - .../video_player/test/video_player_test.dart | 90 +++--- .../CHANGELOG.md | 16 + .../analysis_options.yaml | 4 + .../lib/messages.dart | 273 ++++++++++-------- .../lib/method_channel_video_player.dart | 4 +- .../lib/video_player_platform_interface.dart | 22 +- .../pubspec.yaml | 8 +- .../method_channel_video_player_test.dart | 3 + .../video_player_web/CHANGELOG.md | 8 + .../video_player_web/analysis_options.yaml | 12 + .../lib/video_player_web.dart | 40 +-- .../video_player_web/pubspec.yaml | 10 +- .../test/video_player_web_test.dart | 10 +- script/incremental_build.sh | 13 +- script/nnbd_plugins.sh | 9 + 113 files changed, 1174 insertions(+), 670 deletions(-) create mode 100644 packages/connectivity/connectivity/analysis_options.yaml create mode 100644 packages/connectivity/connectivity_platform_interface/analysis_options.yaml create mode 100644 packages/device_info/device_info/analysis_options.yaml create mode 100644 packages/device_info/device_info_platform_interface/analysis_options.yaml create mode 100644 packages/plugin_platform_interface/analysis_options.yaml create mode 100644 packages/url_launcher/url_launcher/analysis_options.yaml create mode 100644 packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml create mode 100644 packages/video_player/video_player/analysis_options.yaml create mode 100644 packages/video_player/video_player/example/test_driver/video_player.dart create mode 100644 packages/video_player/video_player/example/test_driver/video_player_test.dart create mode 100644 packages/video_player/video_player_platform_interface/analysis_options.yaml create mode 100644 packages/video_player/video_player_web/analysis_options.yaml diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index b993bf15dc8b..60765d14c080 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,3 +1,11 @@ +## 3.0.0-nullsafety.1 + +* Bump Dart SDK to support null safety. + +## 3.0.0-nullsafety + +* Migrate to null safety. + ## 2.0.3 * Update Flutter SDK constraint. diff --git a/packages/connectivity/connectivity/analysis_options.yaml b/packages/connectivity/connectivity/analysis_options.yaml new file mode 100644 index 000000000000..3d64bb57fe49 --- /dev/null +++ b/packages/connectivity/connectivity/analysis_options.yaml @@ -0,0 +1,4 @@ +include: ../../../analysis_options.yaml +analyzer: + enable-experiment: + - non-nullable diff --git a/packages/connectivity/connectivity/example/lib/main.dart b/packages/connectivity/connectivity/example/lib/main.dart index e05497136b86..19285ce889fd 100644 --- a/packages/connectivity/connectivity/example/lib/main.dart +++ b/packages/connectivity/connectivity/example/lib/main.dart @@ -40,7 +40,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @@ -51,7 +51,7 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { String _connectionStatus = 'Unknown'; final Connectivity _connectivity = Connectivity(); - StreamSubscription _connectivitySubscription; + late StreamSubscription _connectivitySubscription; @override void initState() { @@ -69,7 +69,7 @@ class _MyHomePageState extends State { // Platform messages are asynchronous, so we initialize in an async method. Future initConnectivity() async { - ConnectivityResult result; + ConnectivityResult result = ConnectivityResult.none; // Platform messages may fail, so we use a try/catch PlatformException. try { result = await _connectivity.checkConnectivity(); diff --git a/packages/connectivity/connectivity/example/pubspec.yaml b/packages/connectivity/connectivity/example/pubspec.yaml index bff35483d763..94c8505c8096 100644 --- a/packages/connectivity/connectivity/example/pubspec.yaml +++ b/packages/connectivity/connectivity/example/pubspec.yaml @@ -10,9 +10,10 @@ dependencies: dev_dependencies: flutter_driver: sdk: flutter + test: ^1.10.0-nullsafety.1 integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 flutter: uses-material-design: true diff --git a/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart b/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart index d48deae3403d..3177b66ea48a 100644 --- a/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart +++ b/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(cyanglaz): Remove once https://github.com/flutter/plugins/pull/3158 is landed. +// @dart = 2.9 + import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:connectivity/connectivity.dart'; diff --git a/packages/connectivity/connectivity/integration_test/connectivity_test.dart b/packages/connectivity/connectivity/integration_test/connectivity_test.dart index d48deae3403d..3177b66ea48a 100644 --- a/packages/connectivity/connectivity/integration_test/connectivity_test.dart +++ b/packages/connectivity/connectivity/integration_test/connectivity_test.dart @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(cyanglaz): Remove once https://github.com/flutter/plugins/pull/3158 is landed. +// @dart = 2.9 + import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:connectivity/connectivity.dart'; diff --git a/packages/connectivity/connectivity/lib/connectivity.dart b/packages/connectivity/connectivity/lib/connectivity.dart index c9655365f772..0f30a9347b74 100644 --- a/packages/connectivity/connectivity/lib/connectivity.dart +++ b/packages/connectivity/connectivity/lib/connectivity.dart @@ -22,12 +22,12 @@ class Connectivity { if (_singleton == null) { _singleton = Connectivity._(); } - return _singleton; + return _singleton!; } Connectivity._(); - static Connectivity _singleton; + static Connectivity? _singleton; static ConnectivityPlatform get _platform => ConnectivityPlatform.instance; diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index 1a53f42fa3cb..2f6d78134796 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -2,7 +2,7 @@ name: connectivity description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity -version: 2.0.3 +version: 3.0.0-nullsafety.1 flutter: plugin: @@ -21,21 +21,24 @@ dependencies: flutter: sdk: flutter meta: ^1.0.5 - connectivity_platform_interface: ^1.0.2 - connectivity_macos: ^0.1.0 - connectivity_for_web: ^0.3.0 + connectivity_platform_interface: ^2.0.0-nullsafety.1 + #TODO(cyanglaz): re-endorse the below plugins when they have migrated to nnbd. + # https://github.com/flutter/flutter/issues/68669 + connectivity_macos: ^0.2.0-nullsafety + # connectivity_for_web: ^0.3.0 dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter + test: ^1.10.0-nullsafety.1 integration_test: path: ../../integration_test mockito: ^4.1.1 - plugin_platform_interface: ^1.0.0 - pedantic: ^1.8.0 + plugin_platform_interface: ^1.1.0-nullsafety.1 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/connectivity/connectivity/test/connectivity_test.dart b/packages/connectivity/connectivity/test/connectivity_test.dart index b7749ca7a6be..e83196546cd2 100644 --- a/packages/connectivity/connectivity/test/connectivity_test.dart +++ b/packages/connectivity/connectivity/test/connectivity_test.dart @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - +// TODO(cyanglaz): Remove once Mockito is migrated to null safety. +// @dart = 2.9 import 'package:connectivity/connectivity.dart'; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/connectivity/connectivity_macos/CHANGELOG.md b/packages/connectivity/connectivity_macos/CHANGELOG.md index f7c893e6fdb4..9261b0e789fe 100644 --- a/packages/connectivity/connectivity_macos/CHANGELOG.md +++ b/packages/connectivity/connectivity_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.0-nullsafety + +* Update Dart SDK constraint. + ## 0.1.0+8 * Update Flutter SDK constraint. diff --git a/packages/connectivity/connectivity_macos/pubspec.yaml b/packages/connectivity/connectivity_macos/pubspec.yaml index acd608fa2505..dd193f715c2a 100644 --- a/packages/connectivity/connectivity_macos/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the connectivity plugin. # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.0+8 +version: 0.2.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_macos flutter: @@ -13,7 +13,7 @@ flutter: pluginClass: ConnectivityPlugin environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.10.0" dependencies: diff --git a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md index 2a16860c3cc4..8e38341be42f 100644 --- a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md +++ b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.0.0-nullsafety.1 + +* Bump Dart SDK to support null safety. + +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.0.7 * Update Flutter SDK constraint. diff --git a/packages/connectivity/connectivity_platform_interface/analysis_options.yaml b/packages/connectivity/connectivity_platform_interface/analysis_options.yaml new file mode 100644 index 000000000000..3d64bb57fe49 --- /dev/null +++ b/packages/connectivity/connectivity_platform_interface/analysis_options.yaml @@ -0,0 +1,4 @@ +include: ../../../analysis_options.yaml +analyzer: + enable-experiment: + - non-nullable diff --git a/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart b/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart index cfd9cf648a9c..8e9f0fd6af06 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart @@ -50,17 +50,17 @@ abstract class ConnectivityPlatform extends PlatformInterface { } /// Obtains the wifi name (SSID) of the connected network - Future getWifiName() { + Future getWifiName() { throw UnimplementedError('getWifiName() has not been implemented.'); } /// Obtains the wifi BSSID of the connected network. - Future getWifiBSSID() { + Future getWifiBSSID() { throw UnimplementedError('getWifiBSSID() has not been implemented.'); } /// Obtains the IP address of the connected wifi network - Future getWifiIP() { + Future getWifiIP() { throw UnimplementedError('getWifiIP() has not been implemented.'); } diff --git a/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart b/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart index 87deaa21ea3b..b411b5bc069b 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart @@ -22,29 +22,29 @@ class MethodChannelConnectivity extends ConnectivityPlatform { EventChannel eventChannel = EventChannel('plugins.flutter.io/connectivity_status'); - Stream _onConnectivityChanged; + Stream? _onConnectivityChanged; /// Fires whenever the connectivity state changes. Stream get onConnectivityChanged { if (_onConnectivityChanged == null) { - _onConnectivityChanged = eventChannel - .receiveBroadcastStream() - .map((dynamic result) => result.toString()) - .map(parseConnectivityResult); + _onConnectivityChanged = + eventChannel.receiveBroadcastStream().map((dynamic result) { + return result != null ? result.toString() : ''; + }).map(parseConnectivityResult); } - return _onConnectivityChanged; + return _onConnectivityChanged!; } @override - Future checkConnectivity() { - return methodChannel - .invokeMethod('check') - .then(parseConnectivityResult); + Future checkConnectivity() async { + final String checkResult = + await methodChannel.invokeMethod('check') ?? ''; + return parseConnectivityResult(checkResult); } @override - Future getWifiName() async { - String wifiName = await methodChannel.invokeMethod('wifiName'); + Future getWifiName() async { + String? wifiName = await methodChannel.invokeMethod('wifiName'); // as Android might return , uniforming result // our iOS implementation will return null if (wifiName == '') { @@ -54,29 +54,31 @@ class MethodChannelConnectivity extends ConnectivityPlatform { } @override - Future getWifiBSSID() { + Future getWifiBSSID() { return methodChannel.invokeMethod('wifiBSSID'); } @override - Future getWifiIP() { + Future getWifiIP() { return methodChannel.invokeMethod('wifiIPAddress'); } @override Future requestLocationServiceAuthorization({ bool requestAlwaysLocationUsage = false, - }) { - return methodChannel.invokeMethod( - 'requestLocationServiceAuthorization', [ - requestAlwaysLocationUsage - ]).then(parseLocationAuthorizationStatus); + }) async { + final String requestLocationServiceResult = await methodChannel + .invokeMethod('requestLocationServiceAuthorization', + [requestAlwaysLocationUsage]) ?? + ''; + return parseLocationAuthorizationStatus(requestLocationServiceResult); } @override - Future getLocationServiceAuthorization() { - return methodChannel - .invokeMethod('getLocationServiceAuthorization') - .then(parseLocationAuthorizationStatus); + Future getLocationServiceAuthorization() async { + final String getLocationServiceResult = await methodChannel + .invokeMethod('getLocationServiceAuthorization') ?? + ''; + return parseLocationAuthorizationStatus(getLocationServiceResult); } } diff --git a/packages/connectivity/connectivity_platform_interface/pubspec.yaml b/packages/connectivity/connectivity_platform_interface/pubspec.yaml index 7aa415c9d36f..114915a10b60 100644 --- a/packages/connectivity/connectivity_platform_interface/pubspec.yaml +++ b/packages/connectivity/connectivity_platform_interface/pubspec.yaml @@ -3,19 +3,19 @@ description: A common platform interface for the connectivity plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_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.0.7 +version: 2.0.0-nullsafety.1 dependencies: flutter: sdk: flutter - meta: ^1.0.5 - plugin_platform_interface: ^1.0.1 + meta: ^1.3.0-nullsafety.3 + plugin_platform_interface: ^1.1.0-nullsafety.1 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart b/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart index 3d9c405c30ab..0c30530fc9ab 100644 --- a/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart +++ b/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart @@ -12,7 +12,7 @@ void main() { group('$MethodChannelConnectivity', () { final List log = []; - MethodChannelConnectivity methodChannelConnectivity; + late MethodChannelConnectivity methodChannelConnectivity; setUp(() async { methodChannelConnectivity = MethodChannelConnectivity(); @@ -42,7 +42,7 @@ void main() { .setMockMethodCallHandler((MethodCall methodCall) async { switch (methodCall.method) { case 'listen': - await ServicesBinding.instance.defaultBinaryMessenger + await ServicesBinding.instance!.defaultBinaryMessenger .handlePlatformMessage( methodChannelConnectivity.eventChannel.name, methodChannelConnectivity.eventChannel.codec @@ -64,7 +64,7 @@ void main() { }); test('getWifiName', () async { - final String result = await methodChannelConnectivity.getWifiName(); + final String? result = await methodChannelConnectivity.getWifiName(); expect(result, '1337wifi'); expect( log, @@ -78,7 +78,7 @@ void main() { }); test('getWifiBSSID', () async { - final String result = await methodChannelConnectivity.getWifiBSSID(); + final String? result = await methodChannelConnectivity.getWifiBSSID(); expect(result, 'c0:ff:33:c0:d3:55'); expect( log, @@ -92,7 +92,7 @@ void main() { }); test('getWifiIP', () async { - final String result = await methodChannelConnectivity.getWifiIP(); + final String? result = await methodChannelConnectivity.getWifiIP(); expect(result, '127.0.0.1'); expect( log, diff --git a/packages/device_info/device_info/CHANGELOG.md b/packages/device_info/device_info/CHANGELOG.md index 29382c1ccb61..cee321742843 100644 --- a/packages/device_info/device_info/CHANGELOG.md +++ b/packages/device_info/device_info/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.0.0-nullsafety.1 + +* Bump Dart SDK to support null safety. + +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.0.1 * Update Flutter SDK constraint. diff --git a/packages/device_info/device_info/analysis_options.yaml b/packages/device_info/device_info/analysis_options.yaml new file mode 100644 index 000000000000..3d64bb57fe49 --- /dev/null +++ b/packages/device_info/device_info/analysis_options.yaml @@ -0,0 +1,4 @@ +include: ../../../analysis_options.yaml +analyzer: + enable-experiment: + - non-nullable diff --git a/packages/device_info/device_info/example/integration_test/device_info_test.dart b/packages/device_info/device_info/example/integration_test/device_info_test.dart index 2fd1d9a9a491..61c4396b0d8e 100644 --- a/packages/device_info/device_info/example/integration_test/device_info_test.dart +++ b/packages/device_info/device_info/example/integration_test/device_info_test.dart @@ -2,6 +2,9 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// TODO(cyanglaz): Remove once https://github.com/flutter/plugins/pull/3158 is landed. +// @dart = 2.9 + import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:device_info/device_info.dart'; diff --git a/packages/device_info/device_info/example/lib/main.dart b/packages/device_info/device_info/example/lib/main.dart index 63912b37c3ce..805de1417f15 100644 --- a/packages/device_info/device_info/example/lib/main.dart +++ b/packages/device_info/device_info/example/lib/main.dart @@ -36,7 +36,7 @@ class _MyAppState extends State { } Future initPlatformState() async { - Map deviceData; + Map deviceData = {}; try { if (Platform.isAndroid) { diff --git a/packages/device_info/device_info/example/pubspec.yaml b/packages/device_info/device_info/example/pubspec.yaml index 58d54cba6d70..09567fd967b2 100644 --- a/packages/device_info/device_info/example/pubspec.yaml +++ b/packages/device_info/device_info/example/pubspec.yaml @@ -12,11 +12,11 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 flutter: uses-material-design: true environment: - sdk: ">=2.1.0<3.0.0" + sdk: ">=2.10.0-56.0.dev <3.0.0" flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/device_info/device_info/example/test_driver/integration_test.dart b/packages/device_info/device_info/example/test_driver/integration_test.dart index 7a2c21338786..13327bb884c9 100644 --- a/packages/device_info/device_info/example/test_driver/integration_test.dart +++ b/packages/device_info/device_info/example/test_driver/integration_test.dart @@ -2,6 +2,9 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// TODO(cyanglaz): Remove once https://github.com/flutter/flutter/issues/59879 is fixed. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/device_info/device_info/lib/device_info.dart b/packages/device_info/device_info/lib/device_info.dart index f63730c4323f..bccc3d2fbfa6 100644 --- a/packages/device_info/device_info/lib/device_info.dart +++ b/packages/device_info/device_info/lib/device_info.dart @@ -15,7 +15,7 @@ class DeviceInfoPlugin { DeviceInfoPlugin(); /// This information does not change from call to call. Cache it. - AndroidDeviceInfo _cachedAndroidDeviceInfo; + AndroidDeviceInfo? _cachedAndroidDeviceInfo; /// Information derived from `android.os.Build`. /// @@ -25,7 +25,7 @@ class DeviceInfoPlugin { await DeviceInfoPlatform.instance.androidInfo(); /// This information does not change from call to call. Cache it. - IosDeviceInfo _cachedIosDeviceInfo; + IosDeviceInfo? _cachedIosDeviceInfo; /// Information derived from `UIDevice`. /// diff --git a/packages/device_info/device_info/pubspec.yaml b/packages/device_info/device_info/pubspec.yaml index 0f31234414f5..57c1741270c2 100644 --- a/packages/device_info/device_info/pubspec.yaml +++ b/packages/device_info/device_info/pubspec.yaml @@ -2,7 +2,10 @@ name: device_info description: Flutter plugin providing detailed information about the device (make, model, etc.), and Android or iOS version the app is running on. homepage: https://github.com/flutter/plugins/tree/master/packages/device_info -version: 1.0.1 +# 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump +# the version to 2.0.0. +# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 +version: 2.0.0-nullsafety.1 flutter: plugin: @@ -16,14 +19,13 @@ flutter: dependencies: flutter: sdk: flutter - device_info_platform_interface: ^1.0.0 - + device_info_platform_interface: ^2.0.0-nullsafety.1 dev_dependencies: - test: ^1.3.0 + test: ^1.10.0-nullsafety.1 flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.1.0<3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/device_info/device_info_platform_interface/CHANGELOG.md b/packages/device_info/device_info_platform_interface/CHANGELOG.md index e513c662bef7..d4bc81e0f0aa 100644 --- a/packages/device_info/device_info_platform_interface/CHANGELOG.md +++ b/packages/device_info/device_info_platform_interface/CHANGELOG.md @@ -1,3 +1,16 @@ +## 2.0.0-nullsafety.2 + +* Make `baseOS`, `previewSdkInt`, and `securityPatch` nullable types. +* Remove default values for non-nullable types. + +## 2.0.0-nullsafety.1 + +* Bump Dart SDK to support null safety. + +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.0.2 - Update Flutter SDK constraint. diff --git a/packages/device_info/device_info_platform_interface/analysis_options.yaml b/packages/device_info/device_info_platform_interface/analysis_options.yaml new file mode 100644 index 000000000000..3d64bb57fe49 --- /dev/null +++ b/packages/device_info/device_info_platform_interface/analysis_options.yaml @@ -0,0 +1,4 @@ +include: ../../../analysis_options.yaml +analyzer: + enable-experiment: + - non-nullable diff --git a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart index 5b326cc5350a..4fb940c3effa 100644 --- a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart @@ -8,28 +8,28 @@ class AndroidDeviceInfo { /// Android device Info class. AndroidDeviceInfo({ - this.version, - this.board, - this.bootloader, - this.brand, - this.device, - this.display, - this.fingerprint, - this.hardware, - this.host, - this.id, - this.manufacturer, - this.model, - this.product, - List supported32BitAbis, - List supported64BitAbis, - List supportedAbis, - this.tags, - this.type, - this.isPhysicalDevice, - this.androidId, - List systemFeatures, - }) : supported32BitAbis = List.unmodifiable(supported32BitAbis), + required this.version, + required this.board, + required this.bootloader, + required this.brand, + required this.device, + required this.display, + required this.fingerprint, + required this.hardware, + required this.host, + required this.id, + required this.manufacturer, + required this.model, + required this.product, + required List supported32BitAbis, + required List supported64BitAbis, + required List supportedAbis, + required this.tags, + required this.type, + required this.isPhysicalDevice, + required this.androidId, + required List systemFeatures, + }) : supported32BitAbis = List.unmodifiable(supported32BitAbis), supported64BitAbis = List.unmodifiable(supported64BitAbis), supportedAbis = List.unmodifiable(supportedAbis), systemFeatures = List.unmodifiable(systemFeatures); @@ -113,28 +113,28 @@ class AndroidDeviceInfo { /// Deserializes from the message received from [_kChannel]. static AndroidDeviceInfo fromMap(Map map) { return AndroidDeviceInfo( - version: AndroidBuildVersion._fromMap( - map['version']?.cast() ?? {}), - board: map['board'], - bootloader: map['bootloader'], - brand: map['brand'], - device: map['device'], - display: map['display'], - fingerprint: map['fingerprint'], - hardware: map['hardware'], - host: map['host'], - id: map['id'], - manufacturer: map['manufacturer'], - model: map['model'], - product: map['product'], - supported32BitAbis: _fromList(map['supported32BitAbis'] ?? []), - supported64BitAbis: _fromList(map['supported64BitAbis'] ?? []), - supportedAbis: _fromList(map['supportedAbis'] ?? []), - tags: map['tags'], - type: map['type'], - isPhysicalDevice: map['isPhysicalDevice'], - androidId: map['androidId'], - systemFeatures: _fromList(map['systemFeatures'] ?? []), + version: + AndroidBuildVersion._fromMap(map['version']!.cast()), + board: map['board']!, + bootloader: map['bootloader']!, + brand: map['brand']!, + device: map['device']!, + display: map['display']!, + fingerprint: map['fingerprint']!, + hardware: map['hardware']!, + host: map['host']!, + id: map['id']!, + manufacturer: map['manufacturer']!, + model: map['model']!, + product: map['product']!, + supported32BitAbis: _fromList(map['supported32BitAbis']!), + supported64BitAbis: _fromList(map['supported64BitAbis']!), + supportedAbis: _fromList(map['supportedAbis']!), + tags: map['tags']!, + type: map['type']!, + isPhysicalDevice: map['isPhysicalDevice']!, + androidId: map['androidId']!, + systemFeatures: _fromList(map['systemFeatures']!), ); } @@ -152,16 +152,25 @@ class AndroidDeviceInfo { class AndroidBuildVersion { AndroidBuildVersion._({ this.baseOS, - this.codename, - this.incremental, this.previewSdkInt, - this.release, - this.sdkInt, this.securityPatch, + required this.codename, + required this.incremental, + required this.release, + required this.sdkInt, }); /// The base OS build the product is based on. - final String baseOS; + /// This is only available on Android 6.0 or above. + String? baseOS; + + /// The developer preview revision of a prerelease SDK. + /// This is only available on Android 6.0 or above. + int? previewSdkInt; + + /// The user-visible security patch level. + /// This is only available on Android 6.0 or above. + final String? securityPatch; /// The current development codename, or the string "REL" if this is a release build. final String codename; @@ -169,9 +178,6 @@ class AndroidBuildVersion { /// The internal value used by the underlying source control to represent this build. final String incremental; - /// The developer preview revision of a prerelease SDK. - final int previewSdkInt; - /// The user-visible version string. final String release; @@ -180,19 +186,16 @@ class AndroidBuildVersion { /// Possible values are defined in: https://developer.android.com/reference/android/os/Build.VERSION_CODES.html final int sdkInt; - /// The user-visible security patch level. - final String securityPatch; - /// Deserializes from the map message received from [_kChannel]. static AndroidBuildVersion _fromMap(Map map) { return AndroidBuildVersion._( baseOS: map['baseOS'], - codename: map['codename'], - incremental: map['incremental'], previewSdkInt: map['previewSdkInt'], - release: map['release'], - sdkInt: map['sdkInt'], securityPatch: map['securityPatch'], + codename: map['codename']!, + incremental: map['incremental']!, + release: map['release']!, + sdkInt: map['sdkInt']!, ); } } diff --git a/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart index d41202492101..eb6e5874073b 100644 --- a/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart @@ -8,14 +8,14 @@ class IosDeviceInfo { /// IOS device info class. IosDeviceInfo({ - this.name, - this.systemName, - this.systemVersion, - this.model, - this.localizedModel, - this.identifierForVendor, - this.isPhysicalDevice, - this.utsname, + required this.name, + required this.systemName, + required this.systemVersion, + required this.model, + required this.localizedModel, + required this.identifierForVendor, + required this.isPhysicalDevice, + required this.utsname, }); /// Device name. @@ -45,15 +45,14 @@ class IosDeviceInfo { /// Deserializes from the map message received from [_kChannel]. static IosDeviceInfo fromMap(Map map) { return IosDeviceInfo( - name: map['name'], - systemName: map['systemName'], - systemVersion: map['systemVersion'], - model: map['model'], - localizedModel: map['localizedModel'], - identifierForVendor: map['identifierForVendor'], + name: map['name']!, + systemName: map['systemName']!, + systemVersion: map['systemVersion']!, + model: map['model']!, + localizedModel: map['localizedModel']!, + identifierForVendor: map['identifierForVendor']!, isPhysicalDevice: map['isPhysicalDevice'] == 'true', - utsname: - IosUtsname._fromMap(map['utsname']?.cast() ?? {}), + utsname: IosUtsname._fromMap(map['utsname']!.cast()), ); } } @@ -62,11 +61,11 @@ class IosDeviceInfo { /// See http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysutsname.h.html for details. class IosUtsname { IosUtsname._({ - this.sysname, - this.nodename, - this.release, - this.version, - this.machine, + required this.sysname, + required this.nodename, + required this.release, + required this.version, + required this.machine, }); /// Operating system name. @@ -87,11 +86,11 @@ class IosUtsname { /// Deserializes from the map message received from [_kChannel]. static IosUtsname _fromMap(Map map) { return IosUtsname._( - sysname: map['sysname'], - nodename: map['nodename'], - release: map['release'], - version: map['version'], - machine: map['machine'], + sysname: map['sysname']!, + nodename: map['nodename']!, + release: map['release']!, + version: map['version']!, + machine: map['machine']!, ); } } diff --git a/packages/device_info/device_info_platform_interface/pubspec.yaml b/packages/device_info/device_info_platform_interface/pubspec.yaml index fedaba6c6522..ca72cc753b63 100644 --- a/packages/device_info/device_info_platform_interface/pubspec.yaml +++ b/packages/device_info/device_info_platform_interface/pubspec.yaml @@ -3,20 +3,20 @@ description: A common platform interface for the device_info plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/device_info # 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.0.2 +version: 2.0.0-nullsafety.2 dependencies: flutter: sdk: flutter - meta: ^1.1.8 - plugin_platform_interface: ^1.0.2 + meta: ^1.3.0-nullsafety.3 + plugin_platform_interface: ^1.1.0-nullsafety.1 dev_dependencies: flutter_test: sdk: flutter - mockito: ^4.1.1 - pedantic: ^1.8.0 + test: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.9.1+hotfix.4" diff --git a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart index 1da52e2cf39f..15963854ab12 100644 --- a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart +++ b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(cyanglaz): Remove once https://github.com/flutter/flutter/issues/59879 is fixed. +// @dart = 2.9 + import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - import 'package:device_info_platform_interface/device_info_platform_interface.dart'; - import 'package:device_info_platform_interface/method_channel/method_channel_device_info.dart'; void main() { @@ -23,11 +24,68 @@ void main() { switch (methodCall.method) { case 'getAndroidDeviceInfo': return ({ - "brand": "Google", + "version": { + "securityPatch": "2018-09-05", + "sdkInt": 28, + "release": "9", + "previewSdkInt": 0, + "incremental": "5124027", + "codename": "REL", + "baseOS": "", + }, + "board": "goldfish_x86_64", + "bootloader": "unknown", + "brand": "google", + "device": "generic_x86_64", + "display": "PSR1.180720.075", + "fingerprint": + "google/sdk_gphone_x86_64/generic_x86_64:9/PSR1.180720.075/5124027:user/release-keys", + "hardware": "ranchu", + "host": "abfarm730", + "id": "PSR1.180720.075", + "manufacturer": "Google", + "model": "Android SDK built for x86_64", + "product": "sdk_gphone_x86_64", + "supported32BitAbis": [ + "x86", + ], + "supported64BitAbis": [ + "x86_64", + ], + "supportedAbis": [ + "x86_64", + "x86", + ], + "tags": "release-keys", + "type": "user", + "isPhysicalDevice": false, + "androidId": "f47571f3b4648f45", + "systemFeatures": [ + "android.hardware.sensor.proximity", + "android.software.adoptable_storage", + "android.hardware.sensor.accelerometer", + "android.hardware.faketouch", + "android.software.backup", + "android.hardware.touchscreen", + ], }); case 'getIosDeviceInfo': return ({ - "name": "iPhone 10", + "name": "iPhone 13", + "systemName": "iOS", + "systemVersion": "13.0", + "model": "iPhone", + "localizedModel": "iPhone", + "identifierForVendor": "88F59280-55AD-402C-B922-3203B4794C06", + "isPhysicalDevice": false, + "utsname": { + "sysname": "Darwin", + "nodename": "host", + "release": "19.6.0", + "version": + "Darwin Kernel Version 19.6.0: Thu Jun 18 20:49:00 PDT 2020; root:xnu-6153.141.1~1/RELEASE_X86_64", + "machine": "x86_64", + } }); default: return null; @@ -38,12 +96,66 @@ void main() { test("androidInfo", () async { final AndroidDeviceInfo result = await methodChannelDeviceInfo.androidInfo(); - expect(result.brand, "Google"); + + expect(result.version.securityPatch, "2018-09-05"); + expect(result.version.sdkInt, 28); + expect(result.version.release, "9"); + expect(result.version.previewSdkInt, 0); + expect(result.version.incremental, "5124027"); + expect(result.version.codename, "REL"); + expect(result.board, "goldfish_x86_64"); + expect(result.bootloader, "unknown"); + expect(result.brand, "google"); + expect(result.device, "generic_x86_64"); + expect(result.display, "PSR1.180720.075"); + expect(result.fingerprint, + "google/sdk_gphone_x86_64/generic_x86_64:9/PSR1.180720.075/5124027:user/release-keys"); + expect(result.hardware, "ranchu"); + expect(result.host, "abfarm730"); + expect(result.id, "PSR1.180720.075"); + expect(result.manufacturer, "Google"); + expect(result.model, "Android SDK built for x86_64"); + expect(result.product, "sdk_gphone_x86_64"); + expect(result.supported32BitAbis, [ + "x86", + ]); + expect(result.supported64BitAbis, [ + "x86_64", + ]); + expect(result.supportedAbis, [ + "x86_64", + "x86", + ]); + expect(result.tags, "release-keys"); + expect(result.type, "user"); + expect(result.isPhysicalDevice, false); + expect(result.androidId, "f47571f3b4648f45"); + expect(result.systemFeatures, [ + "android.hardware.sensor.proximity", + "android.software.adoptable_storage", + "android.hardware.sensor.accelerometer", + "android.hardware.faketouch", + "android.software.backup", + "android.hardware.touchscreen", + ]); }); test("iosInfo", () async { final IosDeviceInfo result = await methodChannelDeviceInfo.iosInfo(); - expect(result.name, "iPhone 10"); + expect(result.name, "iPhone 13"); + expect(result.systemName, "iOS"); + expect(result.systemVersion, "13.0"); + expect(result.model, "iPhone"); + expect(result.localizedModel, "iPhone"); + expect( + result.identifierForVendor, "88F59280-55AD-402C-B922-3203B4794C06"); + expect(result.isPhysicalDevice, false); + expect(result.utsname.sysname, "Darwin"); + expect(result.utsname.nodename, "host"); + expect(result.utsname.release, "19.6.0"); + expect(result.utsname.version, + "Darwin Kernel Version 19.6.0: Thu Jun 18 20:49:00 PDT 2020; root:xnu-6153.141.1~1/RELEASE_X86_64"); + expect(result.utsname.machine, "x86_64"); }); }); } diff --git a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md index 43797321f614..6403638b02d4 100644 --- a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md +++ b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.0.0-nullsafety.1 + +* Fix example app SDK. + +## 2.0.0-nullsafety + +* Bump Dart SDK. + ## 1.0.12 * Update Flutter SDK constraint. diff --git a/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml index a040dbe95d92..2532ab047dcc 100644 --- a/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml @@ -3,7 +3,7 @@ description: Demonstrates how to use the flutter_plugin_android_lifecycle plugin publish_to: 'none' environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" dependencies: flutter: diff --git a/packages/flutter_plugin_android_lifecycle/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/pubspec.yaml index 57441d08de7a..66b3eba5cb94 100644 --- a/packages/flutter_plugin_android_lifecycle/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/pubspec.yaml @@ -1,10 +1,10 @@ name: flutter_plugin_android_lifecycle description: Flutter plugin for accessing an Android Lifecycle within other plugins. -version: 1.0.12 +version: 2.0.0-nullsafety.1 homepage: https://github.com/flutter/plugins/tree/master/packages/flutter_plugin_android_lifecycle environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13" dependencies: diff --git a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart index bc709197d77d..7305800296f9 100755 --- a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 +// @dart = 2.9 import 'dart:async'; diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index 0ea59f37bf45..d83798ad4889 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0-nullsafety + +* Migrate to null safety. + ## 0.6.3+5 * Update Flutter SDK constraint. diff --git a/packages/local_auth/lib/auth_strings.dart b/packages/local_auth/lib/auth_strings.dart index a8f34f88723c..3afc23827d98 100644 --- a/packages/local_auth/lib/auth_strings.dart +++ b/packages/local_auth/lib/auth_strings.dart @@ -25,14 +25,14 @@ class AndroidAuthMessages { this.goToSettingsDescription, }); - final String fingerprintHint; - final String fingerprintNotRecognized; - final String fingerprintSuccess; - final String cancelButton; - final String signInTitle; - final String fingerprintRequiredTitle; - final String goToSettingsButton; - final String goToSettingsDescription; + final String? fingerprintHint; + final String? fingerprintNotRecognized; + final String? fingerprintSuccess; + final String? cancelButton; + final String? signInTitle; + final String? fingerprintRequiredTitle; + final String? goToSettingsButton; + final String? goToSettingsDescription; Map get args { return { @@ -62,10 +62,10 @@ class IOSAuthMessages { this.cancelButton, }); - final String lockOut; - final String goToSettingsButton; - final String goToSettingsDescription; - final String cancelButton; + final String? lockOut; + final String? goToSettingsButton; + final String? goToSettingsDescription; + final String? cancelButton; Map get args { return { diff --git a/packages/local_auth/lib/local_auth.dart b/packages/local_auth/lib/local_auth.dart index b2b03b920d64..f1dbdd4840a8 100644 --- a/packages/local_auth/lib/local_auth.dart +++ b/packages/local_auth/lib/local_auth.dart @@ -67,7 +67,7 @@ class LocalAuthentication { /// [PlatformException] with error code [otherOperatingSystem] on the iOS /// simulator. Future authenticateWithBiometrics({ - @required String localizedReason, + required String localizedReason, bool useErrorDialogs = true, bool stickyAuth = false, AndroidAuthMessages androidAuthStrings = const AndroidAuthMessages(), @@ -92,8 +92,9 @@ class LocalAuthentication { 'operating systems.', details: 'Your operating system is ${_platform.operatingSystem}'); } - return await _channel.invokeMethod( - 'authenticateWithBiometrics', args); + final bool? result = + await _channel.invokeMethod('authenticateWithBiometrics', args); + return result!; } /// Returns true if auth was cancelled successfully. @@ -101,18 +102,20 @@ class LocalAuthentication { /// Returns false if there was some error or no auth in progress. /// /// Returns [Future] bool true or false: - Future stopAuthentication() { + Future stopAuthentication() async { if (_platform.isAndroid) { - return _channel.invokeMethod('stopAuthentication'); + final bool? result = + await _channel.invokeMethod('stopAuthentication'); + return result!; } - return Future.sync(() => true); + return true; } /// Returns true if device is capable of checking biometrics /// /// Returns a [Future] bool true or false: Future get canCheckBiometrics async => - (await _channel.invokeListMethod('getAvailableBiometrics')) + (await _channel.invokeListMethod('getAvailableBiometrics'))! .isNotEmpty; /// Returns a list of enrolled biometrics @@ -122,10 +125,10 @@ class LocalAuthentication { /// - BiometricType.fingerprint /// - BiometricType.iris (not yet implemented) Future> getAvailableBiometrics() async { - final List result = - (await _channel.invokeListMethod('getAvailableBiometrics')); + final List? result = + await _channel.invokeListMethod('getAvailableBiometrics'); final List biometrics = []; - result.forEach((String value) { + result!.forEach((String value) { switch (value) { case 'face': biometrics.add(BiometricType.face); diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 834980b7131d..f61f8b3ca4a7 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth description: Flutter plugin for Android and iOS device authentication sensors such as Fingerprint Reader and Touch ID. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 0.6.3+5 +version: 1.0.0-nullsafety flutter: plugin: @@ -16,10 +16,10 @@ flutter: dependencies: flutter: sdk: flutter - meta: ^1.0.5 - intl: ">=0.15.1 <0.17.0" - platform: ">=2.0.0 <4.0.0" - flutter_plugin_android_lifecycle: ^1.0.2 + meta: ^1.3.0-nullsafety.3 + intl: ^0.17.0-nullsafety.2 + platform: ^3.0.0-nullsafety.4 + flutter_plugin_android_lifecycle: ^2.0.0-nullsafety dev_dependencies: integration_test: @@ -28,8 +28,8 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/local_auth/test/local_auth_test.dart b/packages/local_auth/test/local_auth_test.dart index 205c5f785708..52b8dbf21f72 100644 --- a/packages/local_auth/test/local_auth_test.dart +++ b/packages/local_auth/test/local_auth_test.dart @@ -19,7 +19,7 @@ void main() { ); final List log = []; - LocalAuthentication localAuthentication; + late LocalAuthentication localAuthentication; setUp(() { channel.setMockMethodCallHandler((MethodCall methodCall) { diff --git a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md index 47e4fee3f13b..97121268c790 100644 --- a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md +++ b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.0.5 * Update Flutter SDK constraint. diff --git a/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart b/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart index 4f796aaeec33..1ff2a978c5a4 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart @@ -40,26 +40,26 @@ abstract class PathProviderPlatform extends PlatformInterface { /// Path to the temporary directory on the device that is not backed up and is /// suitable for storing caches of downloaded files. - Future getTemporaryPath() { + Future getTemporaryPath() { throw UnimplementedError('getTemporaryPath() has not been implemented.'); } /// Path to a directory where the application may place application support /// files. - Future getApplicationSupportPath() { + Future getApplicationSupportPath() { throw UnimplementedError( 'getApplicationSupportPath() has not been implemented.'); } /// Path to the directory where application can store files that are persistent, /// backed up, and not visible to the user, such as sqlite.db. - Future getLibraryPath() { + Future getLibraryPath() { throw UnimplementedError('getLibraryPath() has not been implemented.'); } /// Path to a directory where the application may place data that is /// user-generated, or that cannot otherwise be recreated by your application. - Future getApplicationDocumentsPath() { + Future getApplicationDocumentsPath() { throw UnimplementedError( 'getApplicationDocumentsPath() has not been implemented.'); } @@ -67,7 +67,7 @@ abstract class PathProviderPlatform extends PlatformInterface { /// Path to a directory where the application may access top level storage. /// The current operating system should be determined before issuing this /// function call, as this functionality is only available on Android. - Future getExternalStoragePath() { + Future getExternalStoragePath() { throw UnimplementedError( 'getExternalStoragePath() has not been implemented.'); } @@ -76,7 +76,7 @@ abstract class PathProviderPlatform extends PlatformInterface { /// stored. These paths typically reside on external storage like separate /// partitions or SD cards. Phones may have multiple storage directories /// available. - Future> getExternalCachePaths() { + Future?> getExternalCachePaths() { throw UnimplementedError( 'getExternalCachePaths() has not been implemented.'); } @@ -84,10 +84,10 @@ abstract class PathProviderPlatform extends PlatformInterface { /// Paths to directories where application specific data can be stored. /// These paths typically reside on external storage like separate partitions /// or SD cards. Phones may have multiple storage directories available. - Future> getExternalStoragePaths({ + Future?> getExternalStoragePaths({ /// Optional parameter. See [StorageDirectory] for more informations on /// how this type translates to Android storage directories. - StorageDirectory type, + StorageDirectory? type, }) { throw UnimplementedError( 'getExternalStoragePaths() has not been implemented.'); @@ -95,7 +95,7 @@ abstract class PathProviderPlatform extends PlatformInterface { /// Path to the directory where downloaded files can be stored. /// This is typically only relevant on desktop operating systems. - Future getDownloadsPath() { + Future getDownloadsPath() { throw UnimplementedError('getDownloadsPath() has not been implemented.'); } } diff --git a/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart b/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart index 7826fa4365be..728c1068f876 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart @@ -30,34 +30,34 @@ class MethodChannelPathProvider extends PathProviderPlatform { _platform = platform; } - Future getTemporaryPath() { + Future getTemporaryPath() { return methodChannel.invokeMethod('getTemporaryDirectory'); } - Future getApplicationSupportPath() { + Future getApplicationSupportPath() { return methodChannel.invokeMethod('getApplicationSupportDirectory'); } - Future getLibraryPath() { + Future getLibraryPath() { if (!_platform.isIOS && !_platform.isMacOS) { throw UnsupportedError('Functionality only available on iOS/macOS'); } return methodChannel.invokeMethod('getLibraryDirectory'); } - Future getApplicationDocumentsPath() { + Future getApplicationDocumentsPath() { return methodChannel .invokeMethod('getApplicationDocumentsDirectory'); } - Future getExternalStoragePath() { + Future getExternalStoragePath() { if (!_platform.isAndroid) { throw UnsupportedError('Functionality only available on Android'); } return methodChannel.invokeMethod('getStorageDirectory'); } - Future> getExternalCachePaths() { + Future?> getExternalCachePaths() { if (!_platform.isAndroid) { throw UnsupportedError('Functionality only available on Android'); } @@ -65,8 +65,8 @@ class MethodChannelPathProvider extends PathProviderPlatform { .invokeListMethod('getExternalCacheDirectories'); } - Future> getExternalStoragePaths({ - StorageDirectory type, + Future?> getExternalStoragePaths({ + StorageDirectory? type, }) async { if (!_platform.isAndroid) { throw UnsupportedError('Functionality only available on Android'); @@ -77,7 +77,7 @@ class MethodChannelPathProvider extends PathProviderPlatform { ); } - Future getDownloadsPath() { + Future getDownloadsPath() { if (!_platform.isMacOS) { throw UnsupportedError('Functionality only available on macOS'); } diff --git a/packages/path_provider/path_provider_platform_interface/pubspec.yaml b/packages/path_provider/path_provider_platform_interface/pubspec.yaml index fc3d4696b51c..946d2ed4b4fd 100644 --- a/packages/path_provider/path_provider_platform_interface/pubspec.yaml +++ b/packages/path_provider/path_provider_platform_interface/pubspec.yaml @@ -3,20 +3,20 @@ description: A common platform interface for the path_provider plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_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.0.5 +version: 2.0.0-nullsafety dependencies: flutter: sdk: flutter - meta: ^1.0.5 - platform: ">=2.0.0 <4.0.0" - plugin_platform_interface: ^1.0.1 + meta: ^1.3.0-nullsafety.3 + platform: ^3.0.0-nullsafety.4 + plugin_platform_interface: ^1.1.0-nullsafety dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.10.0" diff --git a/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart b/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart index 99c9349f9ae5..7130d7743e69 100644 --- a/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart +++ b/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart @@ -19,7 +19,7 @@ void main() { const String kDownloadsPath = 'downloadsPath'; group('$MethodChannelPathProvider', () { - MethodChannelPathProvider methodChannelPathProvider; + late MethodChannelPathProvider methodChannelPathProvider; final List log = []; setUp(() async { @@ -59,7 +59,7 @@ void main() { }); test('getTemporaryPath', () async { - final String path = await methodChannelPathProvider.getTemporaryPath(); + final String? path = await methodChannelPathProvider.getTemporaryPath(); expect( log, [isMethodCall('getTemporaryDirectory', arguments: null)], @@ -68,7 +68,7 @@ void main() { }); test('getApplicationSupportPath', () async { - final String path = + final String? path = await methodChannelPathProvider.getApplicationSupportPath(); expect( log, @@ -92,7 +92,7 @@ void main() { methodChannelPathProvider .setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); - final String path = await methodChannelPathProvider.getLibraryPath(); + final String? path = await methodChannelPathProvider.getLibraryPath(); expect( log, [isMethodCall('getLibraryDirectory', arguments: null)], @@ -104,7 +104,7 @@ void main() { methodChannelPathProvider .setMockPathProviderPlatform(FakePlatform(operatingSystem: 'macos')); - final String path = await methodChannelPathProvider.getLibraryPath(); + final String? path = await methodChannelPathProvider.getLibraryPath(); expect( log, [isMethodCall('getLibraryDirectory', arguments: null)], @@ -113,7 +113,7 @@ void main() { }); test('getApplicationDocumentsPath', () async { - final String path = + final String? path = await methodChannelPathProvider.getApplicationDocumentsPath(); expect( log, @@ -125,13 +125,13 @@ void main() { }); test('getExternalCachePaths android succeeds', () async { - final List result = + final List? result = await methodChannelPathProvider.getExternalCachePaths(); expect( log, [isMethodCall('getExternalCacheDirectories', arguments: null)], ); - expect(result.length, 1); + expect(result!.length, 1); expect(result.first, kExternalCachePaths); }); @@ -147,10 +147,12 @@ void main() { } }); - for (StorageDirectory type - in StorageDirectory.values + [null]) { + for (StorageDirectory? type in [ + null, + ...StorageDirectory.values + ]) { test('getExternalStoragePaths (type: $type) android succeeds', () async { - final List result = + final List? result = await methodChannelPathProvider.getExternalStoragePaths(type: type); expect( log, @@ -162,7 +164,7 @@ void main() { ], ); - expect(result.length, 1); + expect(result!.length, 1); expect(result.first, kExternalStoragePaths); }); @@ -182,7 +184,7 @@ void main() { test('getDownloadsPath macos succeeds', () async { methodChannelPathProvider .setMockPathProviderPlatform(FakePlatform(operatingSystem: 'macos')); - final String result = await methodChannelPathProvider.getDownloadsPath(); + final String? result = await methodChannelPathProvider.getDownloadsPath(); expect( log, [isMethodCall('getDownloadsDirectory', arguments: null)], diff --git a/packages/plugin_platform_interface/CHANGELOG.md b/packages/plugin_platform_interface/CHANGELOG.md index 01b5ff7d1252..7df1834966dd 100644 --- a/packages/plugin_platform_interface/CHANGELOG.md +++ b/packages/plugin_platform_interface/CHANGELOG.md @@ -1,3 +1,11 @@ +## 1.1.0-nullsafety.1 + +* Bump Dart SDK to support null safety. + +## 1.1.0-nullsafety + +* Migrate to null safety. + ## 1.0.3 * Fix homepage in `pubspec.yaml`. diff --git a/packages/plugin_platform_interface/analysis_options.yaml b/packages/plugin_platform_interface/analysis_options.yaml new file mode 100644 index 000000000000..f4819cd5c313 --- /dev/null +++ b/packages/plugin_platform_interface/analysis_options.yaml @@ -0,0 +1,4 @@ +include: ../../analysis_options.yaml +analyzer: + enable-experiment: + - non-nullable diff --git a/packages/plugin_platform_interface/lib/plugin_platform_interface.dart b/packages/plugin_platform_interface/lib/plugin_platform_interface.dart index be4871928686..cd87b04dc739 100644 --- a/packages/plugin_platform_interface/lib/plugin_platform_interface.dart +++ b/packages/plugin_platform_interface/lib/plugin_platform_interface.dart @@ -41,7 +41,7 @@ import 'package:meta/meta.dart'; /// [MockPlatformInterfaceMixin] for a sample of using Mockito to mock a platform interface. abstract class PlatformInterface { /// Pass a private, class-specific `const Object()` as the `token`. - PlatformInterface({@required Object token}) : _instanceToken = token; + PlatformInterface({required Object token}) : _instanceToken = token; final Object _instanceToken; diff --git a/packages/plugin_platform_interface/pubspec.yaml b/packages/plugin_platform_interface/pubspec.yaml index ae11b144ca8c..05fc918bf9b5 100644 --- a/packages/plugin_platform_interface/pubspec.yaml +++ b/packages/plugin_platform_interface/pubspec.yaml @@ -12,17 +12,17 @@ description: Reusable base class for Flutter plugin platform interfaces. # be done when absolutely necessary and after the ecosystem has already migrated to 1.X.Y version # that is forward compatible with 2.0.0 (ideally the ecosystem have migrated to depend on: # `plugin_platform_interface: >=1.X.Y <3.0.0`). -version: 1.0.3 +version: 1.1.0-nullsafety.1 repository: https://github.com/flutter/plugins/tree/master/packages/plugin_platform_interface environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" dependencies: - meta: ^1.0.0 + meta: ^1.3.0-nullsafety.3 dev_dependencies: mockito: ^4.1.1 - test: ^1.9.4 - pedantic: ^1.8.0 + test: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0-nullsafety.1 diff --git a/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart b/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart index 0488c20f3efb..b07dd4dcede1 100644 --- a/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart +++ b/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(egarciad): Remove once Mockito is migrated to null safety. +// @dart = 2.9 import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; diff --git a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart index 763d32642cfa..80faba404154 100755 --- a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 +// @dart = 2.9 import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 9c2d8ce19672..aaf958a52624 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,11 @@ +## 6.0.0-nullsafety.1 + +* Bump Dart SDK to support null safety. + +## 6.0.0-nullsafety + +* Migrate to null safety. + ## 5.7.13 * Update Flutter SDK constraint. diff --git a/packages/url_launcher/url_launcher/analysis_options.yaml b/packages/url_launcher/url_launcher/analysis_options.yaml new file mode 100644 index 000000000000..3d64bb57fe49 --- /dev/null +++ b/packages/url_launcher/url_launcher/analysis_options.yaml @@ -0,0 +1,4 @@ +include: ../../../analysis_options.yaml +analyzer: + enable-experiment: + - non-nullable diff --git a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart index 4c0f5031ee6b..80d21b740c1e 100644 --- a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart @@ -2,6 +2,9 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// TODO(egarciad): Remove once integration_test is migrated to null safety. +// @dart = 2.9 + import 'dart:io' show Platform; import 'package:flutter/foundation.dart' show kIsWeb; diff --git a/packages/url_launcher/url_launcher/example/lib/main.dart b/packages/url_launcher/url_launcher/example/lib/main.dart index f7d90c4bef65..b3e65f38a794 100644 --- a/packages/url_launcher/url_launcher/example/lib/main.dart +++ b/packages/url_launcher/url_launcher/example/lib/main.dart @@ -27,7 +27,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override @@ -35,7 +35,7 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - Future _launched; + Future? _launched; String _phone = ''; Future _launchInBrowser(String url) async { diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml index 94df1a4b4959..1fdb73cef666 100644 --- a/packages/url_launcher/url_launcher/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher/example/pubspec.yaml @@ -12,9 +12,9 @@ dev_dependencies: path: ../../../integration_test flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 mockito: ^4.1.1 - plugin_platform_interface: ^1.0.0 + plugin_platform_interface: ^1.1.0-nullsafety.1 flutter: uses-material-design: true diff --git a/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart b/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart index 41b9f6f5ec6c..eddc126a8e66 100644 --- a/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart +++ b/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart @@ -1,3 +1,10 @@ +// 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. + +// TODO(egarciad): Remove once mockito is migrated to null safety. +// @dart = 2.9 + import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/material.dart'; import 'package:mockito/mockito.dart'; diff --git a/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart index 7a2c21338786..e56756f38cbd 100644 --- a/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart @@ -2,6 +2,9 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// TODO(egarciad): Remove once flutter_driver is migrated to null safety. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/url_launcher/url_launcher/lib/src/link.dart b/packages/url_launcher/url_launcher/lib/src/link.dart index bd54789accfb..f859bc4ad2cf 100644 --- a/packages/url_launcher/url_launcher/lib/src/link.dart +++ b/packages/url_launcher/url_launcher/lib/src/link.dart @@ -40,7 +40,7 @@ class Link extends StatelessWidget implements LinkInfo { final LinkWidgetBuilder builder; /// The destination that this link leads to. - final Uri uri; + final Uri? uri; /// The target indicating where to open the link. final LinkTarget target; @@ -51,12 +51,11 @@ class Link extends StatelessWidget implements LinkInfo { /// Creates a widget that renders a real link on the web, and uses WebViews in /// native platforms to open links. Link({ - Key key, - @required this.uri, - LinkTarget target, - @required this.builder, - }) : target = target ?? LinkTarget.defaultTarget, - super(key: key); + Key? key, + required this.uri, + this.target = LinkTarget.defaultTarget, + required this.builder, + }) : super(key: key); LinkDelegate get _effectiveDelegate { return UrlLauncherPlatform.instance.linkDelegate ?? @@ -90,16 +89,17 @@ class DefaultLinkDelegate extends StatelessWidget { bool get _useWebView { if (link.target == LinkTarget.self) return true; if (link.target == LinkTarget.blank) return false; - return null; + return false; } Future _followLink(BuildContext context) async { - if (!link.uri.hasScheme) { + if (!link.uri!.hasScheme) { // A uri that doesn't have a scheme is an internal route name. In this // case, we push it via Flutter's navigation system instead of letting the // browser handle it. final String routeName = link.uri.toString(); - return pushRouteNameToFramework(context, routeName); + await pushRouteNameToFramework(context, routeName); + return; } // At this point, we know that the link is external. So we use the `launch` @@ -119,7 +119,6 @@ class DefaultLinkDelegate extends StatelessWidget { context: ErrorDescription('during launching a link'), )); } - return Future.value(null); } @override diff --git a/packages/url_launcher/url_launcher/lib/url_launcher.dart b/packages/url_launcher/url_launcher/lib/url_launcher.dart index 25aa623a590f..6138fff2e3d9 100644 --- a/packages/url_launcher/url_launcher/lib/url_launcher.dart +++ b/packages/url_launcher/url_launcher/lib/url_launcher.dart @@ -62,16 +62,15 @@ import 'package:url_launcher_platform_interface/url_launcher_platform_interface. /// is set to true and the universal link failed to launch. Future launch( String urlString, { - bool forceSafariVC, - bool forceWebView, - bool enableJavaScript, - bool enableDomStorage, - bool universalLinksOnly, - Map headers, - Brightness statusBarBrightness, - String webOnlyWindowName, + bool forceSafariVC = true, + bool forceWebView = false, + bool enableJavaScript = false, + bool enableDomStorage = false, + bool universalLinksOnly = false, + Map headers = const {}, + Brightness? statusBarBrightness, + String? webOnlyWindowName, }) async { - assert(urlString != null); final Uri url = Uri.parse(urlString.trimLeft()); final bool isWebURL = url.scheme == 'http' || url.scheme == 'https'; if ((forceSafariVC == true || forceWebView == true) && !isWebURL) { @@ -84,29 +83,32 @@ Future launch( /// [true] so that ui is automatically computed if [statusBarBrightness] is set. bool previousAutomaticSystemUiAdjustment = true; if (statusBarBrightness != null && - defaultTargetPlatform == TargetPlatform.iOS) { + defaultTargetPlatform == TargetPlatform.iOS && + WidgetsBinding.instance != null) { previousAutomaticSystemUiAdjustment = - WidgetsBinding.instance.renderView.automaticSystemUiAdjustment; - WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = false; + WidgetsBinding.instance!.renderView.automaticSystemUiAdjustment; + WidgetsBinding.instance!.renderView.automaticSystemUiAdjustment = false; SystemChrome.setSystemUIOverlayStyle(statusBarBrightness == Brightness.light ? SystemUiOverlayStyle.dark : SystemUiOverlayStyle.light); } + final bool result = await UrlLauncherPlatform.instance.launch( urlString, - useSafariVC: forceSafariVC ?? isWebURL, - useWebView: forceWebView ?? false, - enableJavaScript: enableJavaScript ?? false, - enableDomStorage: enableDomStorage ?? false, - universalLinksOnly: universalLinksOnly ?? false, - headers: headers ?? {}, + useSafariVC: forceSafariVC, + useWebView: forceWebView, + enableJavaScript: enableJavaScript, + enableDomStorage: enableDomStorage, + universalLinksOnly: universalLinksOnly, + headers: headers, webOnlyWindowName: webOnlyWindowName, ); - assert(previousAutomaticSystemUiAdjustment != null); - if (statusBarBrightness != null) { - WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = + + if (statusBarBrightness != null && WidgetsBinding.instance != null) { + WidgetsBinding.instance!.renderView.automaticSystemUiAdjustment = previousAutomaticSystemUiAdjustment; } + return result; } @@ -118,9 +120,6 @@ Future launch( /// For more information see the [Managing package visibility](https://developer.android.com/training/basics/intents/package-visibility) /// article in the Android docs. Future canLaunch(String urlString) async { - if (urlString == null) { - return false; - } return await UrlLauncherPlatform.instance.canLaunch(urlString); } diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 8b731faa1a96..d0abd941a9c2 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 5.7.13 +version: 6.0.0-nullsafety.1 flutter: plugin: @@ -12,8 +12,9 @@ flutter: pluginClass: UrlLauncherPlugin ios: pluginClass: FLTURLLauncherPlugin - web: - default_package: url_launcher_web + # TODO(mvanbeusekom): Temporary disabled until web is migrated to nnbd (advised by @blasten). + #web: + # default_package: url_launcher_web linux: default_package: url_laucher_linux macos: @@ -24,25 +25,26 @@ flutter: dependencies: flutter: sdk: flutter - url_launcher_platform_interface: ^1.0.9 + url_launcher_platform_interface: ^2.0.0-nullsafety # The design on https://flutter.dev/go/federated-plugins was to leave # this constraint as "any". We cannot do it right now as it fails pub publish # validation, so we set a ^ constraint. # TODO(amirh): Revisit this (either update this part in the design or the pub tool). # https://github.com/flutter/flutter/issues/46264 - url_launcher_web: ^0.1.5 - url_launcher_linux: ^0.0.1 - url_launcher_macos: ^0.0.1 - url_launcher_windows: ^0.0.1 + url_launcher_linux: ^0.1.0-nullsafety + url_launcher_macos: ^0.1.0-nullsafety + url_launcher_windows: ^0.1.0-nullsafety + # TODO(mvanbeusekom): Temporary disabled until web is migrated to nnbd (advised by @blasten). + #url_launcher_web: ^0.1.3 dev_dependencies: flutter_test: sdk: flutter - test: ^1.3.0 + test: ^1.10.0-nullsafety.1 mockito: ^4.1.1 - plugin_platform_interface: ^1.0.0 - pedantic: ^1.8.0 + plugin_platform_interface: ^1.1.0-nullsafety.1 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/url_launcher/url_launcher/test/link_test.dart b/packages/url_launcher/url_launcher/test/link_test.dart index d525153dc0a0..46903aadaede 100644 --- a/packages/url_launcher/url_launcher/test/link_test.dart +++ b/packages/url_launcher/url_launcher/test/link_test.dart @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 +// TODO(egarciad): Remove once Mockito has been migrated to null safety. +// @dart = 2.9 import 'dart:ui'; import 'package:flutter/material.dart'; diff --git a/packages/url_launcher/url_launcher/test/url_launcher_test.dart b/packages/url_launcher/url_launcher/test/url_launcher_test.dart index f18e16c7e318..89a7801e1ca8 100644 --- a/packages/url_launcher/url_launcher/test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/test/url_launcher_test.dart @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 +// TODO(mvanbeusekom): Remove once Mockito is migrated to null safety. +// @dart = 2.9 import 'dart:async'; import 'dart:ui'; + import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:flutter/foundation.dart'; @@ -41,10 +43,6 @@ void main() { }); }); group('launch', () { - test('requires a non-null urlString', () { - expect(() => launch(null), throwsAssertionError); - }); - test('default behavior', () async { await launch('http://flutter.dev/'); expect( diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md index 57da89f50785..bad287a7a744 100644 --- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0-nullsafety.1 + +* Migrate to null safety. + ## 0.0.2+1 * Update Flutter SDK constraint. diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml index 65e10e05e166..e2fb5fc52e69 100644 --- a/packages/url_launcher/url_launcher_linux/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: url_launcher_linux description: Linux implementation of the url_launcher plugin. -version: 0.0.2+1 +version: 0.1.0-nullsafety.1 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux flutter: @@ -10,7 +10,7 @@ flutter: pluginClass: UrlLauncherPlugin environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.8" dependencies: diff --git a/packages/url_launcher/url_launcher_macos/CHANGELOG.md b/packages/url_launcher/url_launcher_macos/CHANGELOG.md index ab132757bbf2..8a0e6575b5f2 100644 --- a/packages/url_launcher/url_launcher_macos/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_macos/CHANGELOG.md @@ -1,3 +1,11 @@ +# 0.1.0-nullsafety.1 + +* Bump SDK to support null safety. + +# 0.1.0-nullsafety + +* Migrate to null safety. + ## 0.0.2+1 * Update Flutter SDK constraint. diff --git a/packages/url_launcher/url_launcher_macos/pubspec.yaml b/packages/url_launcher/url_launcher_macos/pubspec.yaml index 12ce6a0b0907..9ce9c9c47ea9 100644 --- a/packages/url_launcher/url_launcher_macos/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the url_launcher plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.2+1 +version: 0.1.0-nullsafety.1 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos flutter: @@ -14,7 +14,7 @@ flutter: fileName: url_launcher_macos.dart environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.8" dependencies: diff --git a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md index 26047c748ae6..5bbbe9d28cd1 100644 --- a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.0.0-nullsafety.1 + +* Bump Dart SDK to support null safety. + +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.0.10 * Update Flutter SDK constraint. diff --git a/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml b/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml new file mode 100644 index 000000000000..3d64bb57fe49 --- /dev/null +++ b/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml @@ -0,0 +1,4 @@ +include: ../../../analysis_options.yaml +analyzer: + enable-experiment: + - non-nullable diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/link.dart b/packages/url_launcher/url_launcher_platform_interface/lib/link.dart index 425dc886d29f..a176972e06bd 100644 --- a/packages/url_launcher/url_launcher_platform_interface/lib/link.dart +++ b/packages/url_launcher/url_launcher_platform_interface/lib/link.dart @@ -16,7 +16,7 @@ typedef FollowLink = Future Function(); /// the widget tree under it. typedef LinkWidgetBuilder = Widget Function( BuildContext context, - FollowLink followLink, + FollowLink? followLink, ); /// Signature for a delegate function to build the [Link] widget. @@ -31,7 +31,7 @@ final MethodCodec _codec = const JSONMethodCodec(); class LinkTarget { /// Const private constructor with a [debugLabel] to allow the creation of /// multiple distinct const instances. - const LinkTarget._({this.debugLabel}); + const LinkTarget._({required this.debugLabel}); /// Used to distinguish multiple const instances of [LinkTarget]. final String debugLabel; @@ -64,7 +64,7 @@ abstract class LinkInfo { LinkWidgetBuilder get builder; /// The destination that this link leads to. - Uri get uri; + Uri? get uri; /// The target indicating where to open the link. LinkTarget get target; @@ -80,10 +80,14 @@ Future pushRouteNameToFramework( String routeName, { @visibleForTesting bool debugForceRouter = false, }) { + final PlatformMessageCallback? onPlatformMessage = window.onPlatformMessage; + if (onPlatformMessage == null) { + return Future.value(null); + } final Completer completer = Completer(); if (debugForceRouter || _hasRouter(context)) { SystemNavigator.routeInformationUpdated(location: routeName); - window.onPlatformMessage( + onPlatformMessage( 'flutter/navigation', _codec.encodeMethodCall( MethodCall('pushRouteInformation', { @@ -94,7 +98,7 @@ Future pushRouteNameToFramework( completer.complete, ); } else { - window.onPlatformMessage( + onPlatformMessage( 'flutter/navigation', _codec.encodeMethodCall(MethodCall('pushRoute', routeName)), completer.complete, diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart b/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart index ac5bfa230289..7b9dfc9cc5cf 100644 --- a/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart +++ b/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart @@ -5,7 +5,6 @@ import 'dart:async'; import 'package:flutter/services.dart'; -import 'package:meta/meta.dart' show required; import 'link.dart'; import 'url_launcher_platform_interface.dart'; @@ -15,14 +14,14 @@ const MethodChannel _channel = MethodChannel('plugins.flutter.io/url_launcher'); /// An implementation of [UrlLauncherPlatform] that uses method channels. class MethodChannelUrlLauncher extends UrlLauncherPlatform { @override - final LinkDelegate linkDelegate = null; + final LinkDelegate? linkDelegate = null; @override Future canLaunch(String url) { return _channel.invokeMethod( 'canLaunch', {'url': url}, - ); + ).then((value) => value ?? false); } @override @@ -33,13 +32,13 @@ class MethodChannelUrlLauncher extends UrlLauncherPlatform { @override Future launch( String url, { - @required bool useSafariVC, - @required bool useWebView, - @required bool enableJavaScript, - @required bool enableDomStorage, - @required bool universalLinksOnly, - @required Map headers, - String webOnlyWindowName, + required bool useSafariVC, + required bool useWebView, + required bool enableJavaScript, + required bool enableDomStorage, + required bool universalLinksOnly, + required Map headers, + String? webOnlyWindowName, }) { return _channel.invokeMethod( 'launch', @@ -52,6 +51,6 @@ class MethodChannelUrlLauncher extends UrlLauncherPlatform { 'universalLinksOnly': universalLinksOnly, 'headers': headers, }, - ); + ).then((value) => value ?? false); } } diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart b/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart index 75002ff9eb4d..2a4edfa8d1af 100644 --- a/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart +++ b/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.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:url_launcher_platform_interface/link.dart'; @@ -40,7 +39,7 @@ abstract class UrlLauncherPlatform extends PlatformInterface { } /// The delegate used by the Link widget to build itself. - LinkDelegate get linkDelegate; + LinkDelegate? get linkDelegate; /// Returns `true` if this platform is able to launch [url]. Future canLaunch(String url) { @@ -53,13 +52,13 @@ abstract class UrlLauncherPlatform extends PlatformInterface { /// in `package:url_launcher/url_launcher.dart`. Future launch( String url, { - @required bool useSafariVC, - @required bool useWebView, - @required bool enableJavaScript, - @required bool enableDomStorage, - @required bool universalLinksOnly, - @required Map headers, - String webOnlyWindowName, + required bool useSafariVC, + required bool useWebView, + required bool enableJavaScript, + required bool enableDomStorage, + required bool universalLinksOnly, + required Map headers, + String? webOnlyWindowName, }) { throw UnimplementedError('launch() has not been implemented.'); } diff --git a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml index b8b05b8ec837..e576e967ec46 100644 --- a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml +++ b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml @@ -3,20 +3,19 @@ description: A common platform interface for the url_launcher plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_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.0.10 +version: 2.0.0-nullsafety.1 dependencies: flutter: sdk: flutter - meta: ^1.0.5 - plugin_platform_interface: ^1.0.1 + plugin_platform_interface: ^1.1.0-nullsafety.1 dev_dependencies: flutter_test: sdk: flutter mockito: ^4.1.1 - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.22.0" diff --git a/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart b/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart index 99a885ccc179..58cdd22dca02 100644 --- a/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart +++ b/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(egarciad): Remove once Mockito has been migrated to null safety. +// @dart = 2.9 + import 'dart:ui'; import 'package:mockito/mockito.dart'; diff --git a/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart b/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart index d88f53ad58d0..dfd4b7380c3e 100644 --- a/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(mvanbeusekom): Remove once Mockito is migrated to null safety. +// @dart = 2.9 import 'package:mockito/mockito.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -42,6 +44,10 @@ void main() { final List log = []; channel.setMockMethodCallHandler((MethodCall methodCall) async { log.add(methodCall); + + // Return null explicitly instead of relying on the implicit null + // returned by the method channel if no return statement is specified. + return null; }); final MethodChannelUrlLauncher launcher = MethodChannelUrlLauncher(); @@ -62,6 +68,12 @@ void main() { ); }); + test('canLaunch should return false if platform returns null', () async { + final canLaunch = await launcher.canLaunch('http://example.com/'); + + expect(canLaunch, false); + }); + test('launch', () async { await launcher.launch( 'http://example.com/', @@ -270,6 +282,20 @@ void main() { ); }); + test('launch should return false if platform returns null', () async { + final launched = await launcher.launch( + 'http://example.com/', + useSafariVC: true, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: const {}, + ); + + expect(launched, false); + }); + test('closeWebView default behavior', () async { await launcher.closeWebView(); expect( diff --git a/packages/url_launcher/url_launcher_web/CHANGELOG.md b/packages/url_launcher/url_launcher_web/CHANGELOG.md index e8db0e49aeb7..c8d52f5df13f 100644 --- a/packages/url_launcher/url_launcher_web/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_web/CHANGELOG.md @@ -41,7 +41,7 @@ # 0.1.2 -- Adds "tel" and "sms" support +- Adds "tel" and "sms" support # 0.1.1+6 diff --git a/packages/url_launcher/url_launcher_web/pubspec.yaml b/packages/url_launcher/url_launcher_web/pubspec.yaml index 049c4bb44544..2d1b8af8e49f 100644 --- a/packages/url_launcher/url_launcher_web/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/pubspec.yaml @@ -15,6 +15,12 @@ flutter: dependencies: url_launcher_platform_interface: ^1.0.9 + # TODO(mvanbeusekom): Update to use pub.dev once null safety version is published. + # url_launcher_platform_interface: + # git: + # url: https://github.com/flutter/plugins.git + # ref: nnbd + # path: packages/url_launcher/url_launcher_platform_interface flutter: sdk: flutter flutter_web_plugins: @@ -25,6 +31,9 @@ dev_dependencies: flutter_test: sdk: flutter url_launcher: ^5.2.5 + # TODO(mvanbeusekom): Update to use pub.dev once null safety version is published. + # url_launcher: + # path: ../url_launcher pedantic: ^1.8.0 mockito: ^4.1.1 integration_test: diff --git a/packages/url_launcher/url_launcher_web/test/pubspec.yaml b/packages/url_launcher/url_launcher_web/test/pubspec.yaml index e755dff85004..b8c541f72986 100644 --- a/packages/url_launcher/url_launcher_web/test/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/test/pubspec.yaml @@ -2,7 +2,7 @@ name: regular_integration_tests publish_to: none environment: - sdk: ">=2.2.2 <3.0.0" + sdk: ">=2.10.0-56.0.dev <3.0.0" dependencies: flutter: diff --git a/packages/url_launcher/url_launcher_windows/CHANGELOG.md b/packages/url_launcher/url_launcher_windows/CHANGELOG.md index fb1a83f0190d..e9649ff6fd1e 100644 --- a/packages/url_launcher/url_launcher_windows/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_windows/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.1.0-nullsafety.1 + +* Bump Dart SDK to support null safety. + +## 0.1.0-nullsafety + +* Migrate to null-safety. + ## 0.0.2+1 * Update Flutter SDK constraint. diff --git a/packages/url_launcher/url_launcher_windows/pubspec.yaml b/packages/url_launcher/url_launcher_windows/pubspec.yaml index 8db8d94fc411..d2da4c534322 100644 --- a/packages/url_launcher/url_launcher_windows/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/pubspec.yaml @@ -3,7 +3,7 @@ description: Windows implementation of the url_launcher plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.2+1 +version: 0.1.0-nullsafety.1 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows flutter: @@ -13,7 +13,7 @@ flutter: pluginClass: UrlLauncherPlugin environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.8" dependencies: diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 32614b43d261..14eaae381756 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,19 @@ +## 2.0.0-nullsafety.3 + +* Dart null safety requires `2.12`. + +## 2.0.0-nullsafety.2 + +* Bump SDK version. + +## 2.0.0-nullsafety.1 + +* Merge master. + +## 2.0.0-nullsafety + +* Migration to null safety. + ## 1.0.2 * Update Flutter SDK constraint. diff --git a/packages/video_player/video_player/analysis_options.yaml b/packages/video_player/video_player/analysis_options.yaml new file mode 100644 index 000000000000..3d64bb57fe49 --- /dev/null +++ b/packages/video_player/video_player/analysis_options.yaml @@ -0,0 +1,4 @@ +include: ../../../analysis_options.yaml +analyzer: + enable-experiment: + - non-nullable diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java index 78da7150edf0..98cf6dbaacea 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v0.1.7), do not edit directly. +// Autogenerated from Pigeon (v0.1.12), do not edit directly. // See also: https://pub.dev/packages/pigeon package io.flutter.plugins.videoplayer; @@ -597,7 +597,7 @@ static void setup(BinaryMessenger binaryMessenger, VideoPlayerApi api) { private static HashMap wrapError(Exception exception) { HashMap errorMap = new HashMap<>(); errorMap.put("message", exception.toString()); - errorMap.put("code", null); + errorMap.put("code", exception.getClass().getSimpleName()); errorMap.put("details", null); return errorMap; } diff --git a/packages/video_player/video_player/example/integration_test/video_player_test.dart b/packages/video_player/video_player/example/integration_test/video_player_test.dart index 639cca9b8631..d2f38367ce9a 100644 --- a/packages/video_player/video_player/example/integration_test/video_player_test.dart +++ b/packages/video_player/video_player/example/integration_test/video_player_test.dart @@ -11,7 +11,7 @@ const Duration _playDuration = Duration(seconds: 1); void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - VideoPlayerController _controller; + late VideoPlayerController _controller; tearDown(() async => _controller.dispose()); group('asset videos', () { @@ -22,7 +22,7 @@ void main() { testWidgets('can be initialized', (WidgetTester tester) async { await _controller.initialize(); - expect(_controller.value.initialized, true); + expect(_controller.value.isInitialized, true); expect(_controller.value.position, const Duration(seconds: 0)); expect(_controller.value.isPlaying, false); expect(_controller.value.duration, diff --git a/packages/video_player/video_player/example/lib/main.dart b/packages/video_player/video_player/example/lib/main.dart index a99b9da6bd0c..42eaaa578fcf 100644 --- a/packages/video_player/video_player/example/lib/main.dart +++ b/packages/video_player/video_player/example/lib/main.dart @@ -108,7 +108,7 @@ class _ButterFlyAssetVideoInList extends StatelessWidget { /// A filler card to show the video in a list of scrolling contents. class _ExampleCard extends StatelessWidget { - const _ExampleCard({Key key, this.title}) : super(key: key); + const _ExampleCard({Key? key, required this.title}) : super(key: key); final String title; @@ -150,7 +150,7 @@ class _ButterFlyAssetVideo extends StatefulWidget { } class _ButterFlyAssetVideoState extends State<_ButterFlyAssetVideo> { - VideoPlayerController _controller; + late VideoPlayerController _controller; @override void initState() { @@ -206,7 +206,7 @@ class _BumbleBeeRemoteVideo extends StatefulWidget { } class _BumbleBeeRemoteVideoState extends State<_BumbleBeeRemoteVideo> { - VideoPlayerController _controller; + late VideoPlayerController _controller; Future _loadCaptions() async { final String fileContents = await DefaultAssetBundle.of(context) @@ -265,7 +265,8 @@ class _BumbleBeeRemoteVideoState extends State<_BumbleBeeRemoteVideo> { } class _ControlsOverlay extends StatelessWidget { - const _ControlsOverlay({Key key, this.controller}) : super(key: key); + const _ControlsOverlay({Key? key, required this.controller}) + : super(key: key); static const _examplePlaybackRates = [ 0.25, @@ -345,7 +346,7 @@ class _PlayerVideoAndPopPage extends StatefulWidget { } class _PlayerVideoAndPopPageState extends State<_PlayerVideoAndPopPage> { - VideoPlayerController _videoPlayerController; + late VideoPlayerController _videoPlayerController; bool startedPlaying = false; @override diff --git a/packages/video_player/video_player/example/pubspec.yaml b/packages/video_player/video_player/example/pubspec.yaml index dd8fd8d06bd8..6cfa93213afb 100644 --- a/packages/video_player/video_player/example/pubspec.yaml +++ b/packages/video_player/video_player/example/pubspec.yaml @@ -16,7 +16,8 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + test: any + pedantic: ^1.10.0-nullsafety.1 flutter: uses-material-design: true diff --git a/packages/video_player/video_player/example/test_driver/integration_test.dart b/packages/video_player/video_player/example/test_driver/integration_test.dart index 7a2c21338786..7873abae2996 100644 --- a/packages/video_player/video_player/example/test_driver/integration_test.dart +++ b/packages/video_player/video_player/example/test_driver/integration_test.dart @@ -2,6 +2,9 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// TODO(egarciad): Remove once Flutter driver is migrated to null safety. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/video_player/video_player/example/test_driver/video_player.dart b/packages/video_player/video_player/example/test_driver/video_player.dart new file mode 100644 index 000000000000..c1ced19e9b7e --- /dev/null +++ b/packages/video_player/video_player/example/test_driver/video_player.dart @@ -0,0 +1,14 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// TODO(egarciad): Remove once Flutter driver is migrated to null safety. +// @dart = 2.9 + +import 'package:flutter_driver/driver_extension.dart'; +import 'package:video_player_example/main.dart' as app; + +void main() { + enableFlutterDriverExtension(); + app.main(); +} diff --git a/packages/video_player/video_player/example/test_driver/video_player_test.dart b/packages/video_player/video_player/example/test_driver/video_player_test.dart new file mode 100644 index 000000000000..fcbdbb274f7a --- /dev/null +++ b/packages/video_player/video_player/example/test_driver/video_player_test.dart @@ -0,0 +1,30 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// TODO(egarciad): Remove once Flutter driver is migrated to null safety. +// @dart = 2.9 + +import 'dart:async'; +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:test/test.dart'; + +Future main() async { + final FlutterDriver driver = await FlutterDriver.connect(); + tearDownAll(() async { + await driver.close(); + }); + + //TODO(cyanglaz): Use TabBar tabs to navigate between pages after https://github.com/flutter/flutter/issues/16991 is fixed. + //TODO(cyanglaz): Un-skip the test after https://github.com/flutter/flutter/issues/43012 is fixed + test('Push a page contains video and pop back, do not crash.', () async { + final SerializableFinder pushTab = find.byValueKey('push_tab'); + await driver.waitFor(pushTab); + await driver.tap(pushTab); + await driver.waitForAbsent(pushTab); + await driver.waitFor(find.byValueKey('home_page')); + await driver.waitUntilNoTransientCallbacks(); + final Health health = await driver.checkHealth(); + expect(health.status, HealthStatus.ok); + }, skip: 'Cirrus CI currently hangs while playing videos'); +} diff --git a/packages/video_player/video_player/ios/Classes/messages.h b/packages/video_player/video_player/ios/Classes/messages.h index 3c68b3dd24d4..84e8fc5e5cff 100644 --- a/packages/video_player/video_player/ios/Classes/messages.h +++ b/packages/video_player/video_player/ios/Classes/messages.h @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v0.1.7), do not edit directly. +// Autogenerated from Pigeon (v0.1.12), do not edit directly. // See also: https://pub.dev/packages/pigeon #import @protocol FlutterBinaryMessenger; diff --git a/packages/video_player/video_player/ios/Classes/messages.m b/packages/video_player/video_player/ios/Classes/messages.m index e71f8b89254d..58ff7292d2b2 100644 --- a/packages/video_player/video_player/ios/Classes/messages.m +++ b/packages/video_player/video_player/ios/Classes/messages.m @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v0.1.7), do not edit directly. +// Autogenerated from Pigeon (v0.1.12), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "messages.h" #import @@ -7,6 +7,7 @@ #error File requires ARC to be enabled. #endif +#ifndef __clang_analyzer__ static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) { NSDictionary *errorDict = (NSDictionary *)[NSNull null]; if (error) { @@ -59,9 +60,9 @@ + (FLTTextureMessage *)fromMap:(NSDictionary *)dict { return result; } - (NSDictionary *)toMap { - return [NSDictionary - dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]), - @"textureId", nil]; + return + [NSDictionary dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), + @"textureId", nil]; } @end @@ -112,10 +113,9 @@ + (FLTLoopingMessage *)fromMap:(NSDictionary *)dict { } - (NSDictionary *)toMap { return [NSDictionary - dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]), - @"textureId", - (self.isLooping != nil ? self.isLooping : [NSNull null]), - @"isLooping", nil]; + dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId", + (self.isLooping ? self.isLooping : [NSNull null]), @"isLooping", + nil]; } @end @@ -134,9 +134,8 @@ + (FLTVolumeMessage *)fromMap:(NSDictionary *)dict { } - (NSDictionary *)toMap { return [NSDictionary - dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]), - @"textureId", (self.volume != nil ? self.volume : [NSNull null]), - @"volume", nil]; + dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId", + (self.volume ? self.volume : [NSNull null]), @"volume", nil]; } @end @@ -155,9 +154,8 @@ + (FLTPlaybackSpeedMessage *)fromMap:(NSDictionary *)dict { } - (NSDictionary *)toMap { return [NSDictionary - dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]), - @"textureId", (self.speed != nil ? self.speed : [NSNull null]), - @"speed", nil]; + dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId", + (self.speed ? self.speed : [NSNull null]), @"speed", nil]; } @end @@ -176,10 +174,9 @@ + (FLTPositionMessage *)fromMap:(NSDictionary *)dict { } - (NSDictionary *)toMap { return [NSDictionary - dictionaryWithObjectsAndKeys:(self.textureId != nil ? self.textureId : [NSNull null]), - @"textureId", - (self.position != nil ? self.position : [NSNull null]), - @"position", nil]; + dictionaryWithObjectsAndKeys:(self.textureId ? self.textureId : [NSNull null]), @"textureId", + (self.position ? self.position : [NSNull null]), @"position", + nil]; } @end @@ -194,7 +191,7 @@ + (FLTMixWithOthersMessage *)fromMap:(NSDictionary *)dict { } - (NSDictionary *)toMap { return [NSDictionary - dictionaryWithObjectsAndKeys:(self.mixWithOthers != nil ? self.mixWithOthers : [NSNull null]), + dictionaryWithObjectsAndKeys:(self.mixWithOthers ? self.mixWithOthers : [NSNull null]), @"mixWithOthers", nil]; } @end @@ -365,3 +362,4 @@ void FLTVideoPlayerApiSetup(id binaryMessenger, id _parseCaptionsFromSubRipString(String file) { end: startAndEnd.end, text: text, ); - - if (newCaption.start != null && newCaption.end != null) { + if (newCaption.start != newCaption.end) { captions.add(newCaption); } } @@ -64,7 +63,7 @@ class _StartAndEnd { RegExp(_subRipTimeStamp + _subRipArrow + _subRipTimeStamp); if (!format.hasMatch(line)) { - return _StartAndEnd(null, null); + return _StartAndEnd(Duration.zero, Duration.zero); } final List times = line.split(_subRipArrow); @@ -84,7 +83,7 @@ class _StartAndEnd { // Duration(hours: 0, minutes: 1, seconds: 59, milliseconds: 084) Duration _parseSubRipTimestamp(String timestampString) { if (!RegExp(_subRipTimeStamp).hasMatch(timestampString)) { - return null; + return Duration.zero; } final List commaSections = timestampString.split(','); diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index ac1645085e36..6a2af76fa547 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -28,11 +28,12 @@ class VideoPlayerValue { /// Constructs a video with the given values. Only [duration] is required. The /// rest will initialize with default values when unset. VideoPlayerValue({ - @required this.duration, - this.size, - this.position = const Duration(), - this.caption = const Caption(), + required this.duration, + this.size = Size.zero, + this.position = Duration.zero, + this.caption = Caption.none, this.buffered = const [], + this.isInitialized = false, this.isPlaying = false, this.isLooping = false, this.isBuffering = false, @@ -41,17 +42,20 @@ class VideoPlayerValue { this.errorDescription, }); - /// Returns an instance with a `null` [Duration]. - VideoPlayerValue.uninitialized() : this(duration: null); + /// Returns an instance for a video that hasn't been loaded. + VideoPlayerValue.uninitialized() + : this(duration: Duration.zero, isInitialized: false); - /// Returns an instance with a `null` [Duration] and the given - /// [errorDescription]. + /// Returns an instance with the given [errorDescription]. VideoPlayerValue.erroneous(String errorDescription) - : this(duration: null, errorDescription: errorDescription); + : this( + duration: Duration.zero, + isInitialized: false, + errorDescription: errorDescription); /// The total duration of the video. /// - /// Is null when [initialized] is false. + /// The duration is [Duration.zero] if the video hasn't been initialized. final Duration duration; /// The current playback position. @@ -60,7 +64,7 @@ class VideoPlayerValue { /// The [Caption] that should be displayed based on the current [position]. /// /// This field will never be null. If there is no caption for the current - /// [position], this will be an empty [Caption] object. + /// [position], this will be a [Caption.none] object. final Caption caption; /// The currently buffered ranges. @@ -84,7 +88,7 @@ class VideoPlayerValue { /// A description of the error if present. /// /// If [hasError] is false this is [null]. - final String errorDescription; + final String? errorDescription; /// The [size] of the currently loaded video. /// @@ -92,7 +96,7 @@ class VideoPlayerValue { final Size size; /// Indicates whether or not the video has been loaded and is ready to play. - bool get initialized => duration != null; + final bool isInitialized; /// Indicates whether or not the video is in an error state. If this is true /// [errorDescription] should have information about the problem. @@ -101,7 +105,7 @@ class VideoPlayerValue { /// Returns [size.width] / [size.height] when size is non-null, or `1.0.` when /// size is null or the aspect ratio would be less than or equal to 0.0. double get aspectRatio { - if (size == null || size.width == 0 || size.height == 0) { + if (!isInitialized || size.width == 0 || size.height == 0) { return 1.0; } final double aspectRatio = size.width / size.height; @@ -114,17 +118,18 @@ class VideoPlayerValue { /// Returns a new instance that has the same values as this current instance, /// except for any overrides passed in as arguments to [copyWidth]. VideoPlayerValue copyWith({ - Duration duration, - Size size, - Duration position, - Caption caption, - List buffered, - bool isPlaying, - bool isLooping, - bool isBuffering, - double volume, - double playbackSpeed, - String errorDescription, + Duration? duration, + Size? size, + Duration? position, + Caption? caption, + List? buffered, + bool? isInitialized, + bool? isPlaying, + bool? isLooping, + bool? isBuffering, + double? volume, + double? playbackSpeed, + String? errorDescription, }) { return VideoPlayerValue( duration: duration ?? this.duration, @@ -132,6 +137,7 @@ class VideoPlayerValue { position: position ?? this.position, caption: caption ?? this.caption, buffered: buffered ?? this.buffered, + isInitialized: isInitialized ?? this.isInitialized, isPlaying: isPlaying ?? this.isPlaying, isLooping: isLooping ?? this.isLooping, isBuffering: isBuffering ?? this.isBuffering, @@ -149,6 +155,7 @@ class VideoPlayerValue { 'position: $position, ' 'caption: $caption, ' 'buffered: [${buffered.join(', ')}], ' + 'isInitialized: $isInitialized, ' 'isPlaying: $isPlaying, ' 'isLooping: $isLooping, ' 'isBuffering: $isBuffering, ' @@ -178,7 +185,7 @@ class VideoPlayerController extends ValueNotifier { {this.package, this.closedCaptionFile, this.videoPlayerOptions}) : dataSourceType = DataSourceType.asset, formatHint = null, - super(VideoPlayerValue(duration: null)); + super(VideoPlayerValue(duration: Duration.zero)); /// Constructs a [VideoPlayerController] playing a video from obtained from /// the network. @@ -191,7 +198,7 @@ class VideoPlayerController extends ValueNotifier { {this.formatHint, this.closedCaptionFile, this.videoPlayerOptions}) : dataSourceType = DataSourceType.network, package = null, - super(VideoPlayerValue(duration: null)); + super(VideoPlayerValue(duration: Duration.zero)); /// Constructs a [VideoPlayerController] playing a video from a file. /// @@ -203,9 +210,7 @@ class VideoPlayerController extends ValueNotifier { dataSourceType = DataSourceType.file, package = null, formatHint = null, - super(VideoPlayerValue(duration: null)); - - int _textureId; + super(VideoPlayerValue(duration: Duration.zero)); /// The URI to the video file. This will be in different formats depending on /// the [DataSourceType] of the original video. @@ -213,31 +218,36 @@ class VideoPlayerController extends ValueNotifier { /// **Android only**. Will override the platform's generic file format /// detection with whatever is set here. - final VideoFormat formatHint; + final VideoFormat? formatHint; /// Describes the type of data source this [VideoPlayerController] /// is constructed with. final DataSourceType dataSourceType; /// Provide additional configuration options (optional). Like setting the audio mode to mix - final VideoPlayerOptions videoPlayerOptions; + final VideoPlayerOptions? videoPlayerOptions; /// Only set for [asset] videos. The package that the asset was loaded from. - final String package; + final String? package; /// Optional field to specify a file containing the closed /// captioning. /// /// This future will be awaited and the file will be loaded when /// [initialize()] is called. - final Future closedCaptionFile; + final Future? closedCaptionFile; - ClosedCaptionFile _closedCaptionFile; - Timer _timer; + ClosedCaptionFile? _closedCaptionFile; + Timer? _timer; bool _isDisposed = false; - Completer _creatingCompleter; - StreamSubscription _eventSubscription; - _VideoAppLifeCycleObserver _lifeCycleObserver; + Completer? _creatingCompleter; + StreamSubscription? _eventSubscription; + late _VideoAppLifeCycleObserver _lifeCycleObserver; + + /// The id of a texture that hasn't been initialized. + @visibleForTesting + static const int kUninitializedTextureId = -1; + int _textureId = kUninitializedTextureId; /// This is just exposed for testing. It shouldn't be used by anyone depending /// on the plugin. @@ -250,7 +260,7 @@ class VideoPlayerController extends ValueNotifier { _lifeCycleObserver.initialize(); _creatingCompleter = Completer(); - DataSource dataSourceDescription; + late DataSource dataSourceDescription; switch (dataSourceType) { case DataSourceType.asset: dataSourceDescription = DataSource( @@ -276,11 +286,12 @@ class VideoPlayerController extends ValueNotifier { if (videoPlayerOptions?.mixWithOthers != null) { await _videoPlayerPlatform - .setMixWithOthers(videoPlayerOptions.mixWithOthers); + .setMixWithOthers(videoPlayerOptions!.mixWithOthers); } - _textureId = await _videoPlayerPlatform.create(dataSourceDescription); - _creatingCompleter.complete(null); + _textureId = (await _videoPlayerPlatform.create(dataSourceDescription)) ?? + kUninitializedTextureId; + _creatingCompleter!.complete(null); final Completer initializingCompleter = Completer(); void eventListener(VideoEvent event) { @@ -293,6 +304,7 @@ class VideoPlayerController extends ValueNotifier { value = value.copyWith( duration: event.duration, size: event.size, + isInitialized: event.duration != null, ); initializingCompleter.complete(null); _applyLooping(); @@ -325,8 +337,8 @@ class VideoPlayerController extends ValueNotifier { } void errorListener(Object obj) { - final PlatformException e = obj; - value = VideoPlayerValue.erroneous(e.message); + final PlatformException e = obj as PlatformException; + value = VideoPlayerValue.erroneous(e.message!); _timer?.cancel(); if (!initializingCompleter.isCompleted) { initializingCompleter.completeError(obj); @@ -342,7 +354,7 @@ class VideoPlayerController extends ValueNotifier { @override Future dispose() async { if (_creatingCompleter != null) { - await _creatingCompleter.future; + await _creatingCompleter!.future; if (!_isDisposed) { _isDisposed = true; _timer?.cancel(); @@ -379,14 +391,14 @@ class VideoPlayerController extends ValueNotifier { } Future _applyLooping() async { - if (!value.initialized || _isDisposed) { + if (!value.isInitialized || _isDisposed) { return; } await _videoPlayerPlatform.setLooping(_textureId, value.isLooping); } Future _applyPlayPause() async { - if (!value.initialized || _isDisposed) { + if (!value.isInitialized || _isDisposed) { return; } if (value.isPlaying) { @@ -400,8 +412,8 @@ class VideoPlayerController extends ValueNotifier { if (_isDisposed) { return; } - final Duration newPosition = await position; - if (_isDisposed) { + final Duration? newPosition = await position; + if (newPosition == null) { return; } _updatePosition(newPosition); @@ -419,14 +431,14 @@ class VideoPlayerController extends ValueNotifier { } Future _applyVolume() async { - if (!value.initialized || _isDisposed) { + if (!value.isInitialized || _isDisposed) { return; } await _videoPlayerPlatform.setVolume(_textureId, value.volume); } Future _applyPlaybackSpeed() async { - if (!value.initialized || _isDisposed) { + if (!value.isInitialized || _isDisposed) { return; } @@ -442,7 +454,7 @@ class VideoPlayerController extends ValueNotifier { } /// The position in the current video. - Future get position async { + Future get position async { if (_isDisposed) { return null; } @@ -519,17 +531,17 @@ class VideoPlayerController extends ValueNotifier { /// [Caption]. Caption _getCaptionAt(Duration position) { if (_closedCaptionFile == null) { - return Caption(); + return Caption.none; } // TODO: This would be more efficient as a binary search. - for (final caption in _closedCaptionFile.captions) { + for (final caption in _closedCaptionFile!.captions) { if (caption.start <= position && caption.end >= position) { return caption; } } - return Caption(); + return Caption.none; } void _updatePosition(Duration position) { @@ -545,7 +557,7 @@ class _VideoAppLifeCycleObserver extends Object with WidgetsBindingObserver { final VideoPlayerController _controller; void initialize() { - WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance!.addObserver(this); } @override @@ -565,7 +577,7 @@ class _VideoAppLifeCycleObserver extends Object with WidgetsBindingObserver { } void dispose() { - WidgetsBinding.instance.removeObserver(this); + WidgetsBinding.instance!.removeObserver(this); } } @@ -594,8 +606,9 @@ class _VideoPlayerState extends State { }; } - VoidCallback _listener; - int _textureId; + late VoidCallback _listener; + + late int _textureId; @override void initState() { @@ -622,7 +635,7 @@ class _VideoPlayerState extends State { @override Widget build(BuildContext context) { - return _textureId == null + return _textureId == VideoPlayerController.kUninitializedTextureId ? Container() : _videoPlayerPlatform.buildView(_textureId); } @@ -646,7 +659,7 @@ class VideoProgressColors { /// [backgroundColor] defaults to gray at 50% opacity. This is the background /// color behind both [playedColor] and [bufferedColor] to denote the total /// size of the video compared to either of those values. - VideoProgressColors({ + const VideoProgressColors({ this.playedColor = const Color.fromRGBO(255, 0, 0, 0.7), this.bufferedColor = const Color.fromRGBO(50, 50, 200, 0.2), this.backgroundColor = const Color.fromRGBO(200, 200, 200, 0.5), @@ -670,8 +683,8 @@ class VideoProgressColors { class _VideoScrubber extends StatefulWidget { _VideoScrubber({ - @required this.child, - @required this.controller, + required this.child, + required this.controller, }); final Widget child; @@ -689,7 +702,7 @@ class _VideoScrubberState extends State<_VideoScrubber> { @override Widget build(BuildContext context) { void seekToRelativePosition(Offset globalPosition) { - final RenderBox box = context.findRenderObject(); + final RenderBox box = context.findRenderObject() as RenderBox; final Offset tapPos = box.globalToLocal(globalPosition); final double relative = tapPos.dx / box.size.width; final Duration position = controller.value.duration * relative; @@ -700,7 +713,7 @@ class _VideoScrubberState extends State<_VideoScrubber> { behavior: HitTestBehavior.opaque, child: widget.child, onHorizontalDragStart: (DragStartDetails details) { - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { return; } _controllerWasPlaying = controller.value.isPlaying; @@ -709,7 +722,7 @@ class _VideoScrubberState extends State<_VideoScrubber> { } }, onHorizontalDragUpdate: (DragUpdateDetails details) { - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { return; } seekToRelativePosition(details.globalPosition); @@ -720,7 +733,7 @@ class _VideoScrubberState extends State<_VideoScrubber> { } }, onTapDown: (TapDownDetails details) { - if (!controller.value.initialized) { + if (!controller.value.isInitialized) { return; } seekToRelativePosition(details.globalPosition); @@ -745,10 +758,10 @@ class VideoProgressIndicator extends StatefulWidget { /// to `top: 5.0`. VideoProgressIndicator( this.controller, { - VideoProgressColors colors, - this.allowScrubbing, + this.colors = const VideoProgressColors(), + required this.allowScrubbing, this.padding = const EdgeInsets.only(top: 5.0), - }) : colors = colors ?? VideoProgressColors(); + }); /// The [VideoPlayerController] that actually associates a video with this /// widget. @@ -785,7 +798,7 @@ class _VideoProgressIndicatorState extends State { }; } - VoidCallback listener; + late VoidCallback listener; VideoPlayerController get controller => widget.controller; @@ -806,7 +819,7 @@ class _VideoProgressIndicatorState extends State { @override Widget build(BuildContext context) { Widget progressIndicator; - if (controller.value.initialized) { + if (controller.value.isInitialized) { final int duration = controller.value.duration.inMilliseconds; final int position = controller.value.position.inMilliseconds; @@ -878,17 +891,17 @@ class ClosedCaption extends StatelessWidget { /// [VideoPlayerValue.caption]. /// /// If [text] is null, nothing will be displayed. - const ClosedCaption({Key key, this.text, this.textStyle}) : super(key: key); + const ClosedCaption({Key? key, this.text, this.textStyle}) : super(key: key); /// The text that will be shown in the closed caption, or null if no caption /// should be shown. - final String text; + final String? text; /// Specifies how the text in the closed caption should look. /// /// If null, defaults to [DefaultTextStyle.of(context).style] with size 36 /// font colored white. - final TextStyle textStyle; + final TextStyle? textStyle; @override Widget build(BuildContext context) { @@ -913,7 +926,7 @@ class ClosedCaption extends StatelessWidget { ), child: Padding( padding: EdgeInsets.symmetric(horizontal: 2.0), - child: Text(text, style: effectiveTextStyle), + child: Text(text!, style: effectiveTextStyle), ), ), ), diff --git a/packages/video_player/video_player/pigeons/messages.dart b/packages/video_player/video_player/pigeons/messages.dart index 427aea279071..f1771afecb45 100644 --- a/packages/video_player/video_player/pigeons/messages.dart +++ b/packages/video_player/video_player/pigeons/messages.dart @@ -1,3 +1,5 @@ +// @dart = 2.9 + import 'package:pigeon/pigeon_lib.dart'; class TextureMessage { diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index fa55ba43b945..cfbc4c65c1de 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,7 +1,10 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -version: 1.0.2 +# 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump +# the version to 2.0.0. +# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 +version: 2.0.0-nullsafety.3 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: @@ -16,15 +19,15 @@ flutter: default_package: video_player_web dependencies: - meta: ^1.0.5 - video_player_platform_interface: ^2.2.0 + meta: ^1.3.0-nullsafety.3 + video_player_platform_interface: ^3.0.0-nullsafety.3 # The design on https://flutter.dev/go/federated-plugins was to leave # this constraint as "any". We cannot do it right now as it fails pub publish # validation, so we set a ^ constraint. # TODO(amirh): Revisit this (either update this part in the design or the pub tool). # https://github.com/flutter/flutter/issues/46264 - video_player_web: ">=0.1.4 <2.0.0" + video_player_web: ^2.0.0-nullsafety.1 flutter: sdk: flutter @@ -32,9 +35,9 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 pigeon: 0.1.7 environment: - sdk: ">=2.8.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/video_player/video_player/test/sub_rip_file_test.dart b/packages/video_player/video_player/test/sub_rip_file_test.dart index cf25ff73e438..2b9803d8275e 100644 --- a/packages/video_player/video_player/test/sub_rip_file_test.dart +++ b/packages/video_player/video_player/test/sub_rip_file_test.dart @@ -108,6 +108,6 @@ This one is valid 3 00:01:54,724 --> 00:01:6,760 -This one should be ignored because the +This one should be ignored because the ned time is missing a digit. '''; diff --git a/packages/video_player/video_player/test/video_player_initialization_test.dart b/packages/video_player/video_player/test/video_player_initialization_test.dart index 231c399bb8fe..1a09ed9f718c 100644 --- a/packages/video_player/video_player/test/video_player_initialization_test.dart +++ b/packages/video_player/video_player/test/video_player_initialization_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:video_player/video_player.dart'; diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart index a7b23c3b1f27..3e9800f2b68e 100644 --- a/packages/video_player/video_player/test/video_player_test.dart +++ b/packages/video_player/video_player/test/video_player_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:io'; @@ -18,7 +16,7 @@ import 'package:video_player_platform_interface/video_player_platform_interface. class FakeController extends ValueNotifier implements VideoPlayerController { - FakeController() : super(VideoPlayerValue(duration: null)); + FakeController() : super(VideoPlayerValue(duration: Duration.zero)); @override Future dispose() async { @@ -26,7 +24,7 @@ class FakeController extends ValueNotifier } @override - int textureId; + int textureId = VideoPlayerController.kUninitializedTextureId; @override String get dataSource => ''; @@ -35,7 +33,7 @@ class FakeController extends ValueNotifier DataSourceType get dataSourceType => DataSourceType.file; @override - String get package => null; + String get package => ''; @override Future get position async => value.position; @@ -62,13 +60,13 @@ class FakeController extends ValueNotifier Future setLooping(bool looping) async {} @override - VideoFormat get formatHint => null; + VideoFormat? get formatHint => null; @override Future get closedCaptionFile => _loadClosedCaption(); @override - VideoPlayerOptions get videoPlayerOptions => null; + VideoPlayerOptions? get videoPlayerOptions => null; } Future _loadClosedCaption() async => @@ -80,11 +78,13 @@ class _FakeClosedCaptionFile extends ClosedCaptionFile { return [ Caption( text: 'one', + number: 0, start: Duration(milliseconds: 100), end: Duration(milliseconds: 200), ), Caption( text: 'two', + number: 1, start: Duration(milliseconds: 300), end: Duration(milliseconds: 400), ), @@ -101,6 +101,7 @@ void main() { controller.textureId = 123; controller.value = controller.value.copyWith( duration: const Duration(milliseconds: 100), + isInitialized: true, ); await tester.pump(); @@ -133,8 +134,8 @@ void main() { await tester.pumpWidget(MaterialApp(home: ClosedCaption(text: text))); final Text textWidget = tester.widget(find.text(text)); - expect(textWidget.style.fontSize, 36.0); - expect(textWidget.style.color, Colors.white); + expect(textWidget.style!.fontSize, 36.0); + expect(textWidget.style!.color, Colors.white); }); testWidgets('uses given text and style', (WidgetTester tester) async { @@ -149,7 +150,7 @@ void main() { expect(find.text(text), findsOneWidget); final Text textWidget = tester.widget(find.text(text)); - expect(textWidget.style.fontSize, textStyle.fontSize); + expect(textWidget.style!.fontSize, textStyle.fontSize); }); testWidgets('handles null text', (WidgetTester tester) async { @@ -173,7 +174,7 @@ void main() { }); group('VideoPlayerController', () { - FakeVideoPlayerPlatform fakeVideoPlayerPlatform; + late FakeVideoPlayerPlatform fakeVideoPlayerPlatform; setUp(() { fakeVideoPlayerPlatform = FakeVideoPlayerPlatform(); @@ -221,7 +222,7 @@ void main() { 'http://testing.com/invalid_url', ); try { - dynamic error; + late dynamic error; fakeVideoPlayerPlatform.forceInitError = true; await controller.initialize().catchError((dynamic e) => error = e); final PlatformException platformEx = error; @@ -245,13 +246,14 @@ void main() { final VideoPlayerController controller = VideoPlayerController.network( 'https://127.0.0.1', ); - expect(controller.textureId, isNull); + expect( + controller.textureId, VideoPlayerController.kUninitializedTextureId); expect(await controller.position, const Duration(seconds: 0)); await controller.initialize(); await controller.dispose(); - expect(controller.textureId, isNotNull); + expect(controller.textureId, 0); expect(await controller.position, isNull); }); @@ -390,19 +392,19 @@ void main() { await controller.initialize(); expect(controller.value.position, const Duration()); - expect(controller.value.caption.text, isNull); + expect(controller.value.caption.text, ''); await controller.seekTo(const Duration(milliseconds: 100)); expect(controller.value.caption.text, 'one'); await controller.seekTo(const Duration(milliseconds: 250)); - expect(controller.value.caption.text, isNull); + expect(controller.value.caption.text, ''); await controller.seekTo(const Duration(milliseconds: 300)); expect(controller.value.caption.text, 'two'); await controller.seekTo(const Duration(milliseconds: 500)); - expect(controller.value.caption.text, isNull); + expect(controller.value.caption.text, ''); await controller.seekTo(const Duration(milliseconds: 300)); expect(controller.value.caption.text, 'two'); @@ -419,8 +421,7 @@ void main() { await controller.play(); expect(controller.value.isPlaying, isTrue); final FakeVideoEventStream fakeVideoEventStream = - fakeVideoPlayerPlatform.streams[controller.textureId]; - assert(fakeVideoEventStream != null); + fakeVideoPlayerPlatform.streams[controller.textureId]!; fakeVideoEventStream.eventsChannel .sendEvent({'event': 'completed'}); @@ -438,8 +439,7 @@ void main() { expect(controller.value.isBuffering, false); expect(controller.value.buffered, isEmpty); final FakeVideoEventStream fakeVideoEventStream = - fakeVideoPlayerPlatform.streams[controller.textureId]; - assert(fakeVideoEventStream != null); + fakeVideoPlayerPlatform.streams[controller.textureId]!; fakeVideoEventStream.eventsChannel .sendEvent({'event': 'bufferingStart'}); @@ -496,9 +496,9 @@ void main() { test('uninitialized()', () { final VideoPlayerValue uninitialized = VideoPlayerValue.uninitialized(); - expect(uninitialized.duration, isNull); - expect(uninitialized.position, equals(const Duration(seconds: 0))); - expect(uninitialized.caption, equals(const Caption())); + expect(uninitialized.duration, equals(Duration.zero)); + expect(uninitialized.position, equals(Duration.zero)); + expect(uninitialized.caption, equals(Caption.none)); expect(uninitialized.buffered, isEmpty); expect(uninitialized.isPlaying, isFalse); expect(uninitialized.isLooping, isFalse); @@ -506,9 +506,8 @@ void main() { expect(uninitialized.volume, 1.0); expect(uninitialized.playbackSpeed, 1.0); expect(uninitialized.errorDescription, isNull); - expect(uninitialized.size, isNull); - expect(uninitialized.size, isNull); - expect(uninitialized.initialized, isFalse); + expect(uninitialized.size, equals(Size.zero)); + expect(uninitialized.isInitialized, isFalse); expect(uninitialized.hasError, isFalse); expect(uninitialized.aspectRatio, 1.0); }); @@ -517,9 +516,9 @@ void main() { const String errorMessage = 'foo'; final VideoPlayerValue error = VideoPlayerValue.erroneous(errorMessage); - expect(error.duration, isNull); - expect(error.position, equals(const Duration(seconds: 0))); - expect(error.caption, equals(const Caption())); + expect(error.duration, equals(Duration.zero)); + expect(error.position, equals(Duration.zero)); + expect(error.caption, equals(Caption.none)); expect(error.buffered, isEmpty); expect(error.isPlaying, isFalse); expect(error.isLooping, isFalse); @@ -527,9 +526,8 @@ void main() { expect(error.volume, 1.0); expect(error.playbackSpeed, 1.0); expect(error.errorDescription, errorMessage); - expect(error.size, isNull); - expect(error.size, isNull); - expect(error.initialized, isFalse); + expect(error.size, equals(Size.zero)); + expect(error.isInitialized, isFalse); expect(error.hasError, isTrue); expect(error.aspectRatio, 1.0); }); @@ -538,10 +536,12 @@ void main() { const Duration duration = Duration(seconds: 5); const Size size = Size(400, 300); const Duration position = Duration(seconds: 1); - const Caption caption = Caption(text: 'foo'); + const Caption caption = Caption( + text: 'foo', number: 0, start: Duration.zero, end: Duration.zero); final List buffered = [ DurationRange(const Duration(seconds: 0), const Duration(seconds: 4)) ]; + const bool isInitialized = true; const bool isPlaying = true; const bool isLooping = true; const bool isBuffering = true; @@ -554,6 +554,7 @@ void main() { position: position, caption: caption, buffered: buffered, + isInitialized: isInitialized, isPlaying: isPlaying, isLooping: isLooping, isBuffering: isBuffering, @@ -568,6 +569,7 @@ void main() { 'position: 0:00:01.000000, ' 'caption: Caption(number: null, start: null, end: null, text: foo), ' 'buffered: [DurationRange(start: 0:00:00.000000, end: 0:00:04.000000)], ' + 'isInitialized: true, ' 'isPlaying: true, ' 'isLooping: true, ' 'isBuffering: true, ' @@ -586,15 +588,16 @@ void main() { group('aspectRatio', () { test('640x480 -> 4:3', () { final value = VideoPlayerValue( + isInitialized: true, size: Size(640, 480), duration: Duration(seconds: 1), ); expect(value.aspectRatio, 4 / 3); }); - test('null size -> 1.0', () { + test('no size -> 1.0', () { final value = VideoPlayerValue( - size: null, + isInitialized: true, duration: Duration(seconds: 1), ); expect(value.aspectRatio, 1.0); @@ -602,6 +605,7 @@ void main() { test('height = 0 -> 1.0', () { final value = VideoPlayerValue( + isInitialized: true, size: Size(640, 0), duration: Duration(seconds: 1), ); @@ -610,6 +614,7 @@ void main() { test('width = 0 -> 1.0', () { final value = VideoPlayerValue( + isInitialized: true, size: Size(0, 480), duration: Duration(seconds: 1), ); @@ -618,6 +623,7 @@ void main() { test('negative aspect ratio -> 1.0', () { final value = VideoPlayerValue( + isInitialized: true, size: Size(640, -480), duration: Duration(seconds: 1), ); @@ -646,7 +652,7 @@ void main() { File(''), videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true)); await controller.initialize(); - expect(controller.videoPlayerOptions.mixWithOthers, true); + expect(controller.videoPlayerOptions!.mixWithOthers, true); }); } @@ -706,7 +712,7 @@ class FakeVideoPlayerPlatform extends TestHostVideoPlayerApi { @override void seekTo(PositionMessage arg) { calls.add('seekTo'); - _positions[arg.textureId] = Duration(milliseconds: arg.position); + _positions[arg.textureId!] = Duration(milliseconds: arg.position!); } @override @@ -742,7 +748,7 @@ class FakeVideoEventStream { int height; Duration duration; bool initWithError; - FakeEventsChannel eventsChannel; + late FakeEventsChannel eventsChannel; void onListen() { if (!initWithError) { @@ -764,7 +770,7 @@ class FakeEventsChannel { eventsMethodChannel.setMockMethodCallHandler(onMethodCall); } - MethodChannel eventsMethodChannel; + late MethodChannel eventsMethodChannel; VoidCallback onListen; Future onMethodCall(MethodCall call) { @@ -780,7 +786,7 @@ class FakeEventsChannel { _sendMessage(const StandardMethodCodec().encodeSuccessEnvelope(event)); } - void sendError(String code, [String message, dynamic details]) { + void sendError(String code, [String? message, dynamic details]) { _sendMessage(const StandardMethodCodec().encodeErrorEnvelope( code: code, message: message, @@ -794,6 +800,6 @@ class FakeEventsChannel { // available on all the versions of Flutter that we test. // ignore: deprecated_member_use defaultBinaryMessenger.handlePlatformMessage( - eventsMethodChannel.name, data, (ByteData data) {}); + eventsMethodChannel.name, data, (ByteData? data) {}); } } diff --git a/packages/video_player/video_player_platform_interface/CHANGELOG.md b/packages/video_player/video_player_platform_interface/CHANGELOG.md index fea2357a7ea2..446fffd9a60e 100644 --- a/packages/video_player/video_player_platform_interface/CHANGELOG.md +++ b/packages/video_player/video_player_platform_interface/CHANGELOG.md @@ -1,3 +1,19 @@ +## 3.0.0-nullsafety.3 + +* `messages.dart` sets Dart `2.12`. + +## 3.0.0-nullsafety.2 + +* Bump Dart SDK to support null safety. + +## 3.0.0-nullsafety.1 + +* Make DataSource's `uri` parameter nullable. + +## 3.0.0-nullsafety + +* Migrate to null safety. + ## 2.2.1 * Update Flutter SDK constraint. diff --git a/packages/video_player/video_player_platform_interface/analysis_options.yaml b/packages/video_player/video_player_platform_interface/analysis_options.yaml new file mode 100644 index 000000000000..3d64bb57fe49 --- /dev/null +++ b/packages/video_player/video_player_platform_interface/analysis_options.yaml @@ -0,0 +1,4 @@ +include: ../../../analysis_options.yaml +analyzer: + enable-experiment: + - non-nullable diff --git a/packages/video_player/video_player_platform_interface/lib/messages.dart b/packages/video_player/video_player_platform_interface/lib/messages.dart index bfe65f1fd2ea..252cad6993ca 100644 --- a/packages/video_player/video_player_platform_interface/lib/messages.dart +++ b/packages/video_player/video_player_platform_interface/lib/messages.dart @@ -1,13 +1,13 @@ -// Autogenerated from Pigeon (v0.1.7), do not edit directly. +// Autogenerated from Pigeon (v0.1.12), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import -// @dart = 2.8 +// @dart = 2.12 import 'dart:async'; import 'package:flutter/services.dart'; import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; class TextureMessage { - int textureId; + int? textureId; // ignore: unused_element Map _toMap() { final Map pigeonMap = {}; @@ -17,9 +17,6 @@ class TextureMessage { // ignore: unused_element static TextureMessage _fromMap(Map pigeonMap) { - if (pigeonMap == null) { - return null; - } final TextureMessage result = TextureMessage(); result.textureId = pigeonMap['textureId']; return result; @@ -27,10 +24,10 @@ class TextureMessage { } class CreateMessage { - String asset; - String uri; - String packageName; - String formatHint; + String? asset; + String? uri; + String? packageName; + String? formatHint; // ignore: unused_element Map _toMap() { final Map pigeonMap = {}; @@ -43,9 +40,6 @@ class CreateMessage { // ignore: unused_element static CreateMessage _fromMap(Map pigeonMap) { - if (pigeonMap == null) { - return null; - } final CreateMessage result = CreateMessage(); result.asset = pigeonMap['asset']; result.uri = pigeonMap['uri']; @@ -56,8 +50,8 @@ class CreateMessage { } class LoopingMessage { - int textureId; - bool isLooping; + int? textureId; + bool? isLooping; // ignore: unused_element Map _toMap() { final Map pigeonMap = {}; @@ -68,9 +62,6 @@ class LoopingMessage { // ignore: unused_element static LoopingMessage _fromMap(Map pigeonMap) { - if (pigeonMap == null) { - return null; - } final LoopingMessage result = LoopingMessage(); result.textureId = pigeonMap['textureId']; result.isLooping = pigeonMap['isLooping']; @@ -79,8 +70,8 @@ class LoopingMessage { } class VolumeMessage { - int textureId; - double volume; + int? textureId; + double? volume; // ignore: unused_element Map _toMap() { final Map pigeonMap = {}; @@ -91,9 +82,6 @@ class VolumeMessage { // ignore: unused_element static VolumeMessage _fromMap(Map pigeonMap) { - if (pigeonMap == null) { - return null; - } final VolumeMessage result = VolumeMessage(); result.textureId = pigeonMap['textureId']; result.volume = pigeonMap['volume']; @@ -102,8 +90,8 @@ class VolumeMessage { } class PlaybackSpeedMessage { - int textureId; - double speed; + int? textureId; + double? speed; // ignore: unused_element Map _toMap() { final Map pigeonMap = {}; @@ -114,9 +102,6 @@ class PlaybackSpeedMessage { // ignore: unused_element static PlaybackSpeedMessage _fromMap(Map pigeonMap) { - if (pigeonMap == null) { - return null; - } final PlaybackSpeedMessage result = PlaybackSpeedMessage(); result.textureId = pigeonMap['textureId']; result.speed = pigeonMap['speed']; @@ -125,8 +110,8 @@ class PlaybackSpeedMessage { } class PositionMessage { - int textureId; - int position; + int? textureId; + int? position; // ignore: unused_element Map _toMap() { final Map pigeonMap = {}; @@ -137,9 +122,6 @@ class PositionMessage { // ignore: unused_element static PositionMessage _fromMap(Map pigeonMap) { - if (pigeonMap == null) { - return null; - } final PositionMessage result = PositionMessage(); result.textureId = pigeonMap['textureId']; result.position = pigeonMap['position']; @@ -148,7 +130,7 @@ class PositionMessage { } class MixWithOthersMessage { - bool mixWithOthers; + bool? mixWithOthers; // ignore: unused_element Map _toMap() { final Map pigeonMap = {}; @@ -158,9 +140,6 @@ class MixWithOthersMessage { // ignore: unused_element static MixWithOthersMessage _fromMap(Map pigeonMap) { - if (pigeonMap == null) { - return null; - } final MixWithOthersMessage result = MixWithOthersMessage(); result.mixWithOthers = pigeonMap['mixWithOthers']; return result; @@ -172,7 +151,7 @@ class VideoPlayerApi { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.initialize', StandardMessageCodec()); - final Map replyMap = await channel.send(null); + final Map? replyMap = await channel.send(null); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -194,7 +173,7 @@ class VideoPlayerApi { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec()); - final Map replyMap = await channel.send(requestMap); + final Map? replyMap = await channel.send(requestMap); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -216,7 +195,7 @@ class VideoPlayerApi { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec()); - final Map replyMap = await channel.send(requestMap); + final Map? replyMap = await channel.send(requestMap); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -238,7 +217,7 @@ class VideoPlayerApi { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.setLooping', StandardMessageCodec()); - final Map replyMap = await channel.send(requestMap); + final Map? replyMap = await channel.send(requestMap); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -260,7 +239,7 @@ class VideoPlayerApi { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.setVolume', StandardMessageCodec()); - final Map replyMap = await channel.send(requestMap); + final Map? replyMap = await channel.send(requestMap); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -283,7 +262,7 @@ class VideoPlayerApi { 'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed', StandardMessageCodec()); - final Map replyMap = await channel.send(requestMap); + final Map? replyMap = await channel.send(requestMap); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -305,7 +284,7 @@ class VideoPlayerApi { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec()); - final Map replyMap = await channel.send(requestMap); + final Map? replyMap = await channel.send(requestMap); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -327,7 +306,7 @@ class VideoPlayerApi { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()); - final Map replyMap = await channel.send(requestMap); + final Map? replyMap = await channel.send(requestMap); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -349,7 +328,7 @@ class VideoPlayerApi { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec()); - final Map replyMap = await channel.send(requestMap); + final Map? replyMap = await channel.send(requestMap); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -371,7 +350,7 @@ class VideoPlayerApi { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec()); - final Map replyMap = await channel.send(requestMap); + final Map? replyMap = await channel.send(requestMap); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -394,7 +373,7 @@ class VideoPlayerApi { 'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers', StandardMessageCodec()); - final Map replyMap = await channel.send(requestMap); + final Map? replyMap = await channel.send(requestMap); if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -424,131 +403,175 @@ abstract class TestHostVideoPlayerApi { void seekTo(PositionMessage arg); void pause(TextureMessage arg); void setMixWithOthers(MixWithOthersMessage arg); - static void setup(TestHostVideoPlayerApi api) { + static void setup(TestHostVideoPlayerApi? api) { { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.initialize', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - api.initialize(); - return {}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + api.initialize(); + return {}; + }); + } } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final CreateMessage input = CreateMessage._fromMap(mapMessage); - final TextureMessage output = api.create(input); - return {'result': output._toMap()}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + final Map mapMessage = + message as Map; + final CreateMessage input = CreateMessage._fromMap(mapMessage); + final TextureMessage output = api.create(input); + return {'result': output._toMap()}; + }); + } } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final TextureMessage input = TextureMessage._fromMap(mapMessage); - api.dispose(input); - return {}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + final Map mapMessage = + message as Map; + final TextureMessage input = TextureMessage._fromMap(mapMessage); + api.dispose(input); + return {}; + }); + } } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.setLooping', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final LoopingMessage input = LoopingMessage._fromMap(mapMessage); - api.setLooping(input); - return {}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + final Map mapMessage = + message as Map; + final LoopingMessage input = LoopingMessage._fromMap(mapMessage); + api.setLooping(input); + return {}; + }); + } } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.setVolume', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final VolumeMessage input = VolumeMessage._fromMap(mapMessage); - api.setVolume(input); - return {}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + final Map mapMessage = + message as Map; + final VolumeMessage input = VolumeMessage._fromMap(mapMessage); + api.setVolume(input); + return {}; + }); + } } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final PlaybackSpeedMessage input = - PlaybackSpeedMessage._fromMap(mapMessage); - api.setPlaybackSpeed(input); - return {}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + final Map mapMessage = + message as Map; + final PlaybackSpeedMessage input = + PlaybackSpeedMessage._fromMap(mapMessage); + api.setPlaybackSpeed(input); + return {}; + }); + } } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final TextureMessage input = TextureMessage._fromMap(mapMessage); - api.play(input); - return {}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + final Map mapMessage = + message as Map; + final TextureMessage input = TextureMessage._fromMap(mapMessage); + api.play(input); + return {}; + }); + } } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final TextureMessage input = TextureMessage._fromMap(mapMessage); - final PositionMessage output = api.position(input); - return {'result': output._toMap()}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + final Map mapMessage = + message as Map; + final TextureMessage input = TextureMessage._fromMap(mapMessage); + final PositionMessage output = api.position(input); + return {'result': output._toMap()}; + }); + } } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final PositionMessage input = PositionMessage._fromMap(mapMessage); - api.seekTo(input); - return {}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + final Map mapMessage = + message as Map; + final PositionMessage input = PositionMessage._fromMap(mapMessage); + api.seekTo(input); + return {}; + }); + } } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final TextureMessage input = TextureMessage._fromMap(mapMessage); - api.pause(input); - return {}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + final Map mapMessage = + message as Map; + final TextureMessage input = TextureMessage._fromMap(mapMessage); + api.pause(input); + return {}; + }); + } } { const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers', StandardMessageCodec()); - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final MixWithOthersMessage input = - MixWithOthersMessage._fromMap(mapMessage); - api.setMixWithOthers(input); - return {}; - }); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((dynamic message) async { + final Map mapMessage = + message as Map; + final MixWithOthersMessage input = + MixWithOthersMessage._fromMap(mapMessage); + api.setMixWithOthers(input); + return {}; + }); + } } } } diff --git a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart index 0ea443fb6e12..9b007d00d6a9 100644 --- a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart +++ b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart @@ -26,7 +26,7 @@ class MethodChannelVideoPlayer extends VideoPlayerPlatform { } @override - Future create(DataSource dataSource) async { + Future create(DataSource dataSource) async { CreateMessage message = CreateMessage(); switch (dataSource.sourceType) { @@ -91,7 +91,7 @@ class MethodChannelVideoPlayer extends VideoPlayerPlatform { Future getPosition(int textureId) async { PositionMessage response = await _api.position(TextureMessage()..textureId = textureId); - return Duration(milliseconds: response.position); + return Duration(milliseconds: response.position!); } @override diff --git a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart index 2757fb135af6..f2bc00205acc 100644 --- a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart +++ b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart @@ -7,7 +7,7 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:meta/meta.dart' show required, visibleForTesting; +import 'package:meta/meta.dart' show visibleForTesting; import 'method_channel_video_player.dart'; @@ -66,7 +66,7 @@ abstract class VideoPlayerPlatform { } /// Creates an instance of a video player and returns its textureId. - Future create(DataSource dataSource) { + Future create(DataSource dataSource) { throw UnimplementedError('create() has not been implemented.'); } @@ -146,7 +146,7 @@ class DataSource { /// The [package] argument must be non-null when the asset comes from a /// package and null otherwise. DataSource({ - @required this.sourceType, + required this.sourceType, this.uri, this.formatHint, this.asset, @@ -163,18 +163,18 @@ class DataSource { /// /// This will be in different formats depending on the [DataSourceType] of /// the original video. - final String uri; + final String? uri; /// **Android only**. Will override the platform's generic file format /// detection with whatever is set here. - final VideoFormat formatHint; + final VideoFormat? formatHint; /// The name of the asset. Only set for [DataSourceType.asset] videos. - final String asset; + final String? asset; /// The package that the asset was loaded from. Only set for /// [DataSourceType.asset] videos. - final String package; + final String? package; } /// The way in which the video was originally loaded. @@ -216,7 +216,7 @@ class VideoEvent { /// Depending on the [eventType], the [duration], [size] and [buffered] /// arguments can be null. VideoEvent({ - @required this.eventType, + required this.eventType, this.duration, this.size, this.buffered, @@ -228,17 +228,17 @@ class VideoEvent { /// Duration of the video. /// /// Only used if [eventType] is [VideoEventType.initialized]. - final Duration duration; + final Duration? duration; /// Size of the video. /// /// Only used if [eventType] is [VideoEventType.initialized]. - final Size size; + final Size? size; /// Buffered parts of the video. /// /// Only used if [eventType] is [VideoEventType.bufferingUpdate]. - final List buffered; + final List? buffered; @override bool operator ==(Object other) { diff --git a/packages/video_player/video_player_platform_interface/pubspec.yaml b/packages/video_player/video_player_platform_interface/pubspec.yaml index 0c1dcad32648..ea8d3179cf1d 100644 --- a/packages/video_player/video_player_platform_interface/pubspec.yaml +++ b/packages/video_player/video_player_platform_interface/pubspec.yaml @@ -3,19 +3,19 @@ description: A common platform interface for the video_player plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_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: 2.2.1 +version: 3.0.0-nullsafety.3 dependencies: flutter: sdk: flutter - meta: ^1.0.5 + meta: ^1.3.0-nullsafety.3 dev_dependencies: flutter_test: sdk: flutter mockito: ^4.1.1 - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.8.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.10.0" diff --git a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart index c4791001ad92..5c19ebca0d12 100644 --- a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart +++ b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(egarciad): Remove once Mockito is migrated to null safety. +// @dart = 2.9 + import 'dart:ui'; import 'package:flutter/services.dart'; diff --git a/packages/video_player/video_player_web/CHANGELOG.md b/packages/video_player/video_player_web/CHANGELOG.md index cbb07e8b9295..52c2042d1e95 100644 --- a/packages/video_player/video_player_web/CHANGELOG.md +++ b/packages/video_player/video_player_web/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.0.0-nullsafety.1 + +* Bump Dart SDK to support null safety. + +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 0.1.4+2 * Update Flutter SDK constraint. diff --git a/packages/video_player/video_player_web/analysis_options.yaml b/packages/video_player/video_player_web/analysis_options.yaml new file mode 100644 index 000000000000..7e5b7b306a83 --- /dev/null +++ b/packages/video_player/video_player_web/analysis_options.yaml @@ -0,0 +1,12 @@ +# This is a temporary file to allow us to unblock the flutter/plugins repo CI. +# It disables some of lints that were disabled inline. Disabling lints inline +# is no longer possible, so this file is required. +# TODO(ditman) https://github.com/flutter/flutter/issues/55000 (clean this up) + +include: ../../../analysis_options.yaml + +analyzer: + enable-experiment: + - non-nullable + errors: + undefined_prefixed_name: ignore diff --git a/packages/video_player/video_player_web/lib/video_player_web.dart b/packages/video_player/video_player_web/lib/video_player_web.dart index 6715d5aca53b..de8f6a7e4cf7 100644 --- a/packages/video_player/video_player_web/lib/video_player_web.dart +++ b/packages/video_player/video_player_web/lib/video_player_web.dart @@ -50,7 +50,7 @@ class VideoPlayerPlugin extends VideoPlayerPlatform { @override Future dispose(int textureId) async { - _videoPlayers[textureId].dispose(); + _videoPlayers[textureId]!.dispose(); _videoPlayers.remove(textureId); return null; } @@ -66,16 +66,16 @@ class VideoPlayerPlugin extends VideoPlayerPlatform { final int textureId = _textureCounter; _textureCounter++; - String uri; + late String uri; switch (dataSource.sourceType) { case DataSourceType.network: // Do NOT modify the incoming uri, it can be a Blob, and Safari doesn't // like blobs that have changed. - uri = dataSource.uri; + uri = dataSource.uri ?? ''; break; case DataSourceType.asset: - String assetUrl = dataSource.asset; - if (dataSource.package != null && dataSource.package.isNotEmpty) { + String assetUrl = dataSource.asset!; + if (dataSource.package != null && dataSource.package!.isNotEmpty) { assetUrl = 'packages/${dataSource.package}/$assetUrl'; } assetUrl = ui.webOnlyAssetManager.getAssetUrl(assetUrl); @@ -99,45 +99,45 @@ class VideoPlayerPlugin extends VideoPlayerPlatform { @override Future setLooping(int textureId, bool looping) async { - return _videoPlayers[textureId].setLooping(looping); + return _videoPlayers[textureId]!.setLooping(looping); } @override Future play(int textureId) async { - return _videoPlayers[textureId].play(); + return _videoPlayers[textureId]!.play(); } @override Future pause(int textureId) async { - return _videoPlayers[textureId].pause(); + return _videoPlayers[textureId]!.pause(); } @override Future setVolume(int textureId, double volume) async { - return _videoPlayers[textureId].setVolume(volume); + return _videoPlayers[textureId]!.setVolume(volume); } @override Future setPlaybackSpeed(int textureId, double speed) async { assert(speed > 0); - return _videoPlayers[textureId].setPlaybackSpeed(speed); + return _videoPlayers[textureId]!.setPlaybackSpeed(speed); } @override Future seekTo(int textureId, Duration position) async { - return _videoPlayers[textureId].seekTo(position); + return _videoPlayers[textureId]!.seekTo(position); } @override Future getPosition(int textureId) async { - _videoPlayers[textureId].sendBufferingUpdate(); - return _videoPlayers[textureId].getPosition(); + _videoPlayers[textureId]!.sendBufferingUpdate(); + return _videoPlayers[textureId]!.getPosition(); } @override Stream videoEventsFor(int textureId) { - return _videoPlayers[textureId].eventController.stream; + return _videoPlayers[textureId]!.eventController.stream; } @override @@ -147,14 +147,14 @@ class VideoPlayerPlugin extends VideoPlayerPlatform { } class _VideoPlayer { - _VideoPlayer({this.uri, this.textureId}); + _VideoPlayer({required this.uri, required this.textureId}); final StreamController eventController = StreamController(); final String uri; final int textureId; - VideoElement videoElement; + late VideoElement videoElement; bool isInitialized = false; void initialize() { @@ -183,9 +183,9 @@ class _VideoPlayer { // The Event itself (_) doesn't contain info about the actual error. // We need to look at the HTMLMediaElement.error. // See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/error - MediaError error = videoElement.error; + MediaError error = videoElement.error!; eventController.addError(PlatformException( - code: _kErrorValueToErrorName[error.code], + code: _kErrorValueToErrorName[error.code]!, message: error.message != '' ? error.message : _kDefaultErrorMessage, details: _kErrorValueToErrorDescription[error.code], )); @@ -258,8 +258,8 @@ class _VideoPlayer { milliseconds: (videoElement.duration * 1000).round(), ), size: Size( - videoElement.videoWidth.toDouble() ?? 0.0, - videoElement.videoHeight.toDouble() ?? 0.0, + videoElement.videoWidth.toDouble(), + videoElement.videoHeight.toDouble(), ), ), ); diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml index 37cadbd3a1b3..dc1af16c5d94 100644 --- a/packages/video_player/video_player_web/pubspec.yaml +++ b/packages/video_player/video_player_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/v # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.4+2 +version: 2.0.0-nullsafety.1 flutter: plugin: @@ -18,16 +18,16 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - meta: ^1.1.7 - video_player_platform_interface: ^2.2.0 + meta: ^1.3.0-nullsafety.3 + video_player_platform_interface: ^3.0.0-nullsafety.3 dev_dependencies: flutter_test: sdk: flutter video_player: path: ../video_player - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.8.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.8" diff --git a/packages/video_player/video_player_web/test/video_player_web_test.dart b/packages/video_player/video_player_web/test/video_player_web_test.dart index 453079bfcd40..c433d82027f0 100644 --- a/packages/video_player/video_player_web/test/video_player_web_test.dart +++ b/packages/video_player/video_player_web/test/video_player_web_test.dart @@ -14,16 +14,16 @@ import 'package:video_player_web/video_player_web.dart'; void main() { group('VideoPlayer for Web', () { - int textureId; + late int textureId; setUp(() async { VideoPlayerPlatform.instance = VideoPlayerPlugin(); - textureId = await VideoPlayerPlatform.instance.create( + textureId = (await VideoPlayerPlatform.instance.create( DataSource( sourceType: DataSourceType.network, uri: 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4'), - ); + ))!; }); test('$VideoPlayerPlugin is the live instance', () { @@ -84,12 +84,12 @@ void main() { }); test('throws PlatformException when playing bad media', () async { - int videoPlayerId = await VideoPlayerPlatform.instance.create( + int videoPlayerId = (await VideoPlayerPlatform.instance.create( DataSource( sourceType: DataSourceType.network, uri: 'https://flutter.github.io/assets-for-api-docs/assets/videos/_non_existent_video.mp4'), - ); + ))!; Stream eventStream = VideoPlayerPlatform.instance.videoEventsFor(videoPlayerId); diff --git a/script/incremental_build.sh b/script/incremental_build.sh index 671ce66a086f..95e42c4cfcee 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -29,6 +29,16 @@ fi # # TODO(mklim): Remove everything from this list. https://github.com/flutter/flutter/issues/45440 CUSTOM_ANALYSIS_PLUGINS=( + "plugin_platform_interface" + "video_player/video_player" + "video_player/video_player_platform_interface" + "video_player/video_player_web" + "url_launcher/url_launcher_platform_interface" + "url_launcher/url_launcher" + "device_info/device_info_platform_interface" + "device_info/device_info" + "connectivity/connectivity_platform_interface" + "connectivity/connectivity" ) # Comma-separated string of the list above readonly CUSTOM_FLAG=$(IFS=, ; echo "${CUSTOM_ANALYSIS_PLUGINS[*]}") @@ -61,6 +71,7 @@ else echo running "${ACTIONS[@]}" (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" --plugins="$CHANGED_PACKAGES" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) echo "Running version check for changed packages" - (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools version-check --base_sha="$(get_branch_base_sha)") + # TODO(egarciad): Enable this check once in master. + # (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools version-check --base_sha="$(get_branch_base_sha)") fi fi diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 5d167d7b5da6..8b73ecc24e99 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -5,7 +5,16 @@ # null-safe is available on stable. readonly NNBD_PLUGINS_LIST=( + "connectivity" + "device_info" + "flutter_plugin_android_lifecycle" "flutter_webview" + "google_sign_in" + "local_auth" + "path_provider" + "plugin_platform_interface" + "url_launcher" + "video_player" ) export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}") From 78eff18ff7f847bb99f414da6454a7ac987355a2 Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Tue, 15 Dec 2020 08:25:20 -0800 Subject: [PATCH 044/924] [webview_flutter] Migrate to nnbd (#3327) --- packages/webview_flutter/CHANGELOG.md | 4 + .../lib/platform_interface.dart | 64 ++-- .../lib/src/webview_android.dart | 10 +- .../lib/src/webview_cupertino.dart | 10 +- .../lib/src/webview_method_channel.dart | 56 ++-- .../webview_flutter/lib/webview_flutter.dart | 109 ++++--- packages/webview_flutter/pubspec.yaml | 6 +- .../test/webview_flutter_test.dart | 289 ++++++++---------- script/nnbd_plugins.sh | 1 + 9 files changed, 273 insertions(+), 276 deletions(-) diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 447e263e54ff..352613997aa0 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migration to null-safety. + ## 1.0.8 * Update Flutter SDK constraint. diff --git a/packages/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/lib/platform_interface.dart index 6c991b14a76e..f162e58cf0f9 100644 --- a/packages/webview_flutter/lib/platform_interface.dart +++ b/packages/webview_flutter/lib/platform_interface.dart @@ -21,7 +21,8 @@ abstract class WebViewPlatformCallbacksHandler { /// Invoked by [WebViewPlatformController] when a navigation request is pending. /// /// If true is returned the navigation is allowed, otherwise it is blocked. - FutureOr onNavigationRequest({String url, bool isForMainFrame}); + FutureOr onNavigationRequest( + {required String url, required bool isForMainFrame}); /// Invoked by [WebViewPlatformController] when a page has started loading. void onPageStarted(String url); @@ -103,8 +104,8 @@ class WebResourceError { /// A user should not need to instantiate this class, but will receive one in /// [WebResourceErrorCallback]. WebResourceError({ - @required this.errorCode, - @required this.description, + required this.errorCode, + required this.description, this.domain, this.errorType, this.failingUrl, @@ -131,7 +132,7 @@ class WebResourceError { /// in Objective-C. See /// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/ErrorObjectsDomains/ErrorObjectsDomains.html /// for more information on error handling on iOS. - final String domain; + final String? domain; /// Description of the error that can be used to communicate the problem to the user. final String description; @@ -139,13 +140,13 @@ class WebResourceError { /// The type this error can be categorized as. /// /// This will never be `null` on Android, but can be `null` on iOS. - final WebResourceErrorType errorType; + final WebResourceErrorType? errorType; /// Gets the URL for which the resource request was made. /// /// This value is not provided on iOS. Alternatively, you can keep track of /// the last values provided to [WebViewPlatformController.loadUrl]. - final String failingUrl; + final String? failingUrl; } /// Interface for talking to the webview's platform implementation. @@ -176,7 +177,7 @@ abstract class WebViewPlatformController { /// Throws an ArgumentError if `url` is not a valid URL string. Future loadUrl( String url, - Map headers, + Map? headers, ) { throw UnimplementedError( "WebView loadUrl is not implemented on the current platform"); @@ -194,7 +195,7 @@ abstract class WebViewPlatformController { /// Accessor to the current URL that the WebView is displaying. /// /// If no URL was ever loaded, returns `null`. - Future currentUrl() { + Future currentUrl() { throw UnimplementedError( "WebView currentUrl is not implemented on the current platform"); } @@ -281,7 +282,7 @@ abstract class WebViewPlatformController { } /// Returns the title of the currently loaded page. - Future getTitle() { + Future getTitle() { throw UnimplementedError( "WebView getTitle is not implemented on the current platform"); } @@ -337,7 +338,7 @@ class WebSetting { : _value = value, isPresent = true; - final T _value; + final T? _value; /// The setting's value. /// @@ -347,7 +348,14 @@ class WebSetting { throw StateError('Cannot access a value of an absent WebSetting'); } assert(isPresent); - return _value; + // The intention of this getter is to return T whether it is nullable or + // not whereas _value is of type T? since _value can be null even when + // T is not nullable (when isPresent == false). + // + // We promote _value to T using `as T` instead of `!` operator to handle + // the case when _value is legitimately null (and T is a nullable type). + // `!` operator would always throw if _value is null. + return _value as T; } /// True when this web setting instance contains a value. @@ -358,7 +366,7 @@ class WebSetting { @override bool operator ==(Object other) { if (other.runtimeType != runtimeType) return false; - final WebSetting typedOther = other; + final WebSetting typedOther = other as WebSetting; return typedOther.isPresent == isPresent && typedOther._value == _value; } @@ -382,19 +390,19 @@ class WebSettings { this.hasNavigationDelegate, this.debuggingEnabled, this.gestureNavigationEnabled, - @required this.userAgent, + required this.userAgent, }) : assert(userAgent != null); /// The JavaScript execution mode to be used by the webview. - final JavascriptMode javascriptMode; + final JavascriptMode? javascriptMode; /// Whether the [WebView] has a [NavigationDelegate] set. - final bool hasNavigationDelegate; + final bool? hasNavigationDelegate; /// Whether to enable the platform's webview content debugging tools. /// /// See also: [WebView.debuggingEnabled]. - final bool debuggingEnabled; + final bool? debuggingEnabled; /// The value used for the HTTP `User-Agent:` request header. /// @@ -404,12 +412,12 @@ class WebSettings { /// last time it was set. /// /// See also [WebView.userAgent]. - final WebSetting userAgent; + final WebSetting userAgent; /// Whether to allow swipe based navigation in iOS. /// /// See also: [WebView.gestureNavigationEnabled] - final bool gestureNavigationEnabled; + final bool? gestureNavigationEnabled; @override String toString() { @@ -428,7 +436,7 @@ class CreationParams { CreationParams({ this.initialUrl, this.webSettings, - this.javascriptChannelNames, + this.javascriptChannelNames = const {}, this.userAgent, this.autoMediaPlaybackPolicy = AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, @@ -437,12 +445,12 @@ class CreationParams { /// The initialUrl to load in the webview. /// /// When null the webview will be created without loading any page. - final String initialUrl; + final String? initialUrl; /// The initial [WebSettings] for the new webview. /// /// This can later be updated with [WebViewPlatformController.updateSettings]. - final WebSettings webSettings; + final WebSettings? webSettings; /// The initial set of JavaScript channels that are configured for this webview. /// @@ -460,7 +468,7 @@ class CreationParams { /// The value used for the HTTP User-Agent: request header. /// /// When null the platform's webview default is used for the User-Agent header. - final String userAgent; + final String? userAgent; /// Which restrictions apply on automatic media playback. final AutoMediaPlaybackPolicy autoMediaPlaybackPolicy; @@ -475,7 +483,7 @@ class CreationParams { /// /// See also the `onWebViewPlatformCreated` argument for [WebViewPlatform.build]. typedef WebViewPlatformCreatedCallback = void Function( - WebViewPlatformController webViewPlatformController); + WebViewPlatformController? webViewPlatformController); /// Interface for a platform implementation of a WebView. /// @@ -505,14 +513,14 @@ abstract class WebViewPlatform { /// /// `webViewPlatformHandler` must not be null. Widget build({ - BuildContext context, + required BuildContext context, // TODO(amirh): convert this to be the actual parameters. // I'm starting without it as the PR is starting to become pretty big. // I'll followup with the conversion PR. - CreationParams creationParams, - @required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, - WebViewPlatformCreatedCallback onWebViewPlatformCreated, - Set> gestureRecognizers, + required CreationParams creationParams, + required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, + WebViewPlatformCreatedCallback? onWebViewPlatformCreated, + Set>? gestureRecognizers, }); /// Clears all cookies for all [WebView] instances. diff --git a/packages/webview_flutter/lib/src/webview_android.dart b/packages/webview_flutter/lib/src/webview_android.dart index f7afcc0637a3..cba9e1b698b8 100644 --- a/packages/webview_flutter/lib/src/webview_android.dart +++ b/packages/webview_flutter/lib/src/webview_android.dart @@ -20,11 +20,11 @@ import 'webview_method_channel.dart'; class AndroidWebView implements WebViewPlatform { @override Widget build({ - BuildContext context, - CreationParams creationParams, - @required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, - WebViewPlatformCreatedCallback onWebViewPlatformCreated, - Set> gestureRecognizers, + required BuildContext context, + required CreationParams creationParams, + required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, + WebViewPlatformCreatedCallback? onWebViewPlatformCreated, + Set>? gestureRecognizers, }) { assert(webViewPlatformCallbacksHandler != null); return GestureDetector( diff --git a/packages/webview_flutter/lib/src/webview_cupertino.dart b/packages/webview_flutter/lib/src/webview_cupertino.dart index 0e84908261e4..e6816555f73b 100644 --- a/packages/webview_flutter/lib/src/webview_cupertino.dart +++ b/packages/webview_flutter/lib/src/webview_cupertino.dart @@ -20,11 +20,11 @@ import 'webview_method_channel.dart'; class CupertinoWebView implements WebViewPlatform { @override Widget build({ - BuildContext context, - CreationParams creationParams, - @required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, - WebViewPlatformCreatedCallback onWebViewPlatformCreated, - Set> gestureRecognizers, + required BuildContext context, + required CreationParams creationParams, + required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, + WebViewPlatformCreatedCallback? onWebViewPlatformCreated, + Set>? gestureRecognizers, }) { return UiKitView( viewType: 'plugins.flutter.io/webview', diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart index 348b225bb257..1c666d7686ef 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -25,31 +25,31 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { static const MethodChannel _cookieManagerChannel = MethodChannel('plugins.flutter.io/cookie_manager'); - Future _onMethodCall(MethodCall call) async { + Future _onMethodCall(MethodCall call) async { switch (call.method) { case 'javascriptChannelMessage': - final String channel = call.arguments['channel']; - final String message = call.arguments['message']; + final String channel = call.arguments['channel']!; + final String message = call.arguments['message']!; _platformCallbacksHandler.onJavaScriptChannelMessage(channel, message); return true; case 'navigationRequest': return await _platformCallbacksHandler.onNavigationRequest( - url: call.arguments['url'], - isForMainFrame: call.arguments['isForMainFrame'], + url: call.arguments['url']!, + isForMainFrame: call.arguments['isForMainFrame']!, ); case 'onPageFinished': - _platformCallbacksHandler.onPageFinished(call.arguments['url']); + _platformCallbacksHandler.onPageFinished(call.arguments['url']!); return null; case 'onPageStarted': - _platformCallbacksHandler.onPageStarted(call.arguments['url']); + _platformCallbacksHandler.onPageStarted(call.arguments['url']!); return null; case 'onWebResourceError': _platformCallbacksHandler.onWebResourceError( WebResourceError( - errorCode: call.arguments['errorCode'], - description: call.arguments['description'], + errorCode: call.arguments['errorCode']!, + description: call.arguments['description']!, + failingUrl: call.arguments['failingUrl']!, domain: call.arguments['domain'], - failingUrl: call.arguments['failingUrl'], errorType: call.arguments['errorType'] == null ? null : WebResourceErrorType.values.firstWhere( @@ -71,7 +71,7 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { @override Future loadUrl( String url, - Map headers, + Map? headers, ) async { assert(url != null); return _channel.invokeMethod('loadUrl', { @@ -81,13 +81,15 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { } @override - Future currentUrl() => _channel.invokeMethod('currentUrl'); + Future currentUrl() => _channel.invokeMethod('currentUrl'); @override - Future canGoBack() => _channel.invokeMethod("canGoBack"); + Future canGoBack() => + _channel.invokeMethod("canGoBack").then((result) => result!); @override - Future canGoForward() => _channel.invokeMethod("canGoForward"); + Future canGoForward() => + _channel.invokeMethod("canGoForward").then((result) => result!); @override Future goBack() => _channel.invokeMethod("goBack"); @@ -102,18 +104,18 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { Future clearCache() => _channel.invokeMethod("clearCache"); @override - Future updateSettings(WebSettings settings) { + Future updateSettings(WebSettings settings) async { final Map updatesMap = _webSettingsToMap(settings); - if (updatesMap.isEmpty) { - return null; + if (updatesMap.isNotEmpty) { + await _channel.invokeMethod('updateSettings', updatesMap); } - return _channel.invokeMethod('updateSettings', updatesMap); } @override Future evaluateJavascript(String javascriptString) { - return _channel.invokeMethod( - 'evaluateJavascript', javascriptString); + return _channel + .invokeMethod('evaluateJavascript', javascriptString) + .then((result) => result!); } @override @@ -129,7 +131,7 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { } @override - Future getTitle() => _channel.invokeMethod("getTitle"); + Future getTitle() => _channel.invokeMethod("getTitle"); @override Future scrollTo(int x, int y) { @@ -148,19 +150,21 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { } @override - Future getScrollX() => _channel.invokeMethod("getScrollX"); + Future getScrollX() => + _channel.invokeMethod("getScrollX").then((result) => result!); @override - Future getScrollY() => _channel.invokeMethod("getScrollY"); + Future getScrollY() => + _channel.invokeMethod("getScrollY").then((result) => result!); /// Method channel implementation for [WebViewPlatform.clearCookies]. static Future clearCookies() { return _cookieManagerChannel .invokeMethod('clearCookies') - .then((dynamic result) => result); + .then((dynamic result) => result!); } - static Map _webSettingsToMap(WebSettings settings) { + static Map _webSettingsToMap(WebSettings? settings) { final Map map = {}; void _addIfNonNull(String key, dynamic value) { if (value == null) { @@ -176,7 +180,7 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { map[key] = setting.value; } - _addIfNonNull('jsMode', settings.javascriptMode?.index); + _addIfNonNull('jsMode', settings!.javascriptMode?.index); _addIfNonNull('hasNavigationDelegate', settings.hasNavigationDelegate); _addIfNonNull('debuggingEnabled', settings.debuggingEnabled); _addIfNonNull( diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 2fdf639180a7..4327c789afbe 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -44,7 +44,7 @@ typedef void JavascriptMessageHandler(JavascriptMessage message); /// Information about a navigation action that is about to be executed. class NavigationRequest { - NavigationRequest._({this.url, this.isForMainFrame}); + NavigationRequest._({required this.url, required this.isForMainFrame}); /// The URL that will be loaded if the navigation is executed. final String url; @@ -79,11 +79,11 @@ enum NavigationDecision { class SurfaceAndroidWebView extends AndroidWebView { @override Widget build({ - BuildContext context, - CreationParams creationParams, - WebViewPlatformCreatedCallback onWebViewPlatformCreated, - Set> gestureRecognizers, - @required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, + required BuildContext context, + required CreationParams creationParams, + WebViewPlatformCreatedCallback? onWebViewPlatformCreated, + Set>? gestureRecognizers, + required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, }) { assert(webViewPlatformCallbacksHandler != null); return PlatformViewLink( @@ -93,7 +93,7 @@ class SurfaceAndroidWebView extends AndroidWebView { PlatformViewController controller, ) { return AndroidViewSurface( - controller: controller, + controller: controller as AndroidViewController, gestureRecognizers: gestureRecognizers ?? const >{}, hitTestBehavior: PlatformViewHitTestBehavior.opaque, @@ -172,9 +172,9 @@ class JavascriptChannel { /// /// The parameters `name` and `onMessageReceived` must not be null. JavascriptChannel({ - @required this.name, - @required this.onMessageReceived, - }) : assert(name != null), + required this.name, + required this.onMessageReceived, + }) : assert(name != null), assert(onMessageReceived != null), assert(_validChannelNames.hasMatch(name)); @@ -208,7 +208,7 @@ class WebView extends StatefulWidget { /// /// The `javascriptMode` and `autoMediaPlaybackPolicy` parameters must not be null. const WebView({ - Key key, + Key? key, this.onWebViewCreated, this.initialUrl, this.javascriptMode = JavascriptMode.disabled, @@ -227,7 +227,7 @@ class WebView extends StatefulWidget { assert(initialMediaPlaybackPolicy != null), super(key: key); - static WebViewPlatform _platform; + static WebViewPlatform? _platform; /// Sets a custom [WebViewPlatform]. /// @@ -236,7 +236,7 @@ class WebView extends StatefulWidget { /// Setting `platform` doesn't affect [WebView]s that were already created. /// /// The default value is [AndroidWebView] on Android and [CupertinoWebView] on iOS. - static set platform(WebViewPlatform platform) { + static set platform(WebViewPlatform? platform) { _platform = platform; } @@ -257,11 +257,11 @@ class WebView extends StatefulWidget { "Trying to use the default webview implementation for $defaultTargetPlatform but there isn't a default one"); } } - return _platform; + return _platform!; } /// If not null invoked once the web view is created. - final WebViewCreatedCallback onWebViewCreated; + final WebViewCreatedCallback? onWebViewCreated; /// Which gestures should be consumed by the web view. /// @@ -272,10 +272,10 @@ class WebView extends StatefulWidget { /// /// When this set is empty or null, the web view will only handle pointer events for gestures that /// were not claimed by any other gesture recognizer. - final Set> gestureRecognizers; + final Set>? gestureRecognizers; /// The initial URL to load. - final String initialUrl; + final String? initialUrl; /// Whether Javascript execution is enabled. final JavascriptMode javascriptMode; @@ -307,7 +307,7 @@ class WebView extends StatefulWidget { /// channels in the list. /// /// A null value is equivalent to an empty set. - final Set javascriptChannels; + final Set? javascriptChannels; /// A delegate function that decides how to handle navigation actions. /// @@ -331,10 +331,10 @@ class WebView extends StatefulWidget { /// * When a navigationDelegate is set pages with frames are not properly handled by the /// webview, and frames will be opened in the main frame. /// * When a navigationDelegate is set HTTP requests do not include the HTTP referer header. - final NavigationDelegate navigationDelegate; + final NavigationDelegate? navigationDelegate; /// Invoked when a page starts loading. - final PageStartedCallback onPageStarted; + final PageStartedCallback? onPageStarted; /// Invoked when a page has finished loading. /// @@ -346,13 +346,13 @@ class WebView extends StatefulWidget { /// When invoked on iOS or Android, any Javascript code that is embedded /// directly in the HTML has been loaded and code injected with /// [WebViewController.evaluateJavascript] can assume this. - final PageFinishedCallback onPageFinished; + final PageFinishedCallback? onPageFinished; /// Invoked when a web resource has failed to load. /// /// This can be called for any resource (iframe, image, etc.), not just for /// the main page. - final WebResourceErrorCallback onWebResourceError; + final WebResourceErrorCallback? onWebResourceError; /// Controls whether WebView debugging is enabled. /// @@ -386,7 +386,7 @@ class WebView extends StatefulWidget { /// user agent. /// /// By default `userAgent` is null. - final String userAgent; + final String? userAgent; /// Which restrictions apply on automatic media playback. /// @@ -404,7 +404,7 @@ class _WebViewState extends State { final Completer _controller = Completer(); - _PlatformCallbacksHandler _platformCallbacksHandler; + late _PlatformCallbacksHandler _platformCallbacksHandler; @override Widget build(BuildContext context) { @@ -434,22 +434,22 @@ class _WebViewState extends State { }); } - void _onWebViewPlatformCreated(WebViewPlatformController webViewPlatform) { - final WebViewController controller = - WebViewController._(widget, webViewPlatform, _platformCallbacksHandler); + void _onWebViewPlatformCreated(WebViewPlatformController? webViewPlatform) { + final WebViewController controller = WebViewController._( + widget, webViewPlatform!, _platformCallbacksHandler); _controller.complete(controller); if (widget.onWebViewCreated != null) { - widget.onWebViewCreated(controller); + widget.onWebViewCreated!(controller); } } void _assertJavascriptChannelNamesAreUnique() { if (widget.javascriptChannels == null || - widget.javascriptChannels.isEmpty) { + widget.javascriptChannels!.isEmpty) { return; } assert(_extractChannelNames(widget.javascriptChannels).length == - widget.javascriptChannels.length); + widget.javascriptChannels!.length); } } @@ -469,7 +469,7 @@ WebSettings _webSettingsFromWidget(WebView widget) { hasNavigationDelegate: widget.navigationDelegate != null, debuggingEnabled: widget.debuggingEnabled, gestureNavigationEnabled: widget.gestureNavigationEnabled, - userAgent: WebSetting.of(widget.userAgent), + userAgent: WebSetting.of(widget.userAgent), ); } @@ -479,16 +479,16 @@ WebSettings _clearUnchangedWebSettings( assert(currentValue.javascriptMode != null); assert(currentValue.hasNavigationDelegate != null); assert(currentValue.debuggingEnabled != null); - assert(currentValue.userAgent.isPresent); + assert(currentValue.userAgent != null); assert(newValue.javascriptMode != null); assert(newValue.hasNavigationDelegate != null); assert(newValue.debuggingEnabled != null); - assert(newValue.userAgent.isPresent); + assert(newValue.userAgent != null); - JavascriptMode javascriptMode; - bool hasNavigationDelegate; - bool debuggingEnabled; - WebSetting userAgent = WebSetting.absent(); + JavascriptMode? javascriptMode; + bool? hasNavigationDelegate; + bool? debuggingEnabled; + WebSetting userAgent = WebSetting.absent(); if (currentValue.javascriptMode != newValue.javascriptMode) { javascriptMode = newValue.javascriptMode; } @@ -510,7 +510,7 @@ WebSettings _clearUnchangedWebSettings( ); } -Set _extractChannelNames(Set channels) { +Set _extractChannelNames(Set? channels) { final Set channelNames = channels == null ? {} : channels.map((JavascriptChannel channel) => channel.name).toSet(); @@ -530,15 +530,18 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler { @override void onJavaScriptChannelMessage(String channel, String message) { - _javascriptChannels[channel].onMessageReceived(JavascriptMessage(message)); + _javascriptChannels[channel]!.onMessageReceived(JavascriptMessage(message)); } @override - FutureOr onNavigationRequest({String url, bool isForMainFrame}) async { + FutureOr onNavigationRequest({ + required String url, + required bool isForMainFrame, + }) async { final NavigationRequest request = NavigationRequest._(url: url, isForMainFrame: isForMainFrame); final bool allowNavigation = _widget.navigationDelegate == null || - await _widget.navigationDelegate(request) == + await _widget.navigationDelegate!(request) == NavigationDecision.navigate; return allowNavigation; } @@ -546,25 +549,25 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler { @override void onPageStarted(String url) { if (_widget.onPageStarted != null) { - _widget.onPageStarted(url); + _widget.onPageStarted!(url); } } @override void onPageFinished(String url) { if (_widget.onPageFinished != null) { - _widget.onPageFinished(url); + _widget.onPageFinished!(url); } } @override void onWebResourceError(WebResourceError error) { if (_widget.onWebResourceError != null) { - _widget.onWebResourceError(error); + _widget.onWebResourceError!(error); } } - void _updateJavascriptChannelsFromSet(Set channels) { + void _updateJavascriptChannelsFromSet(Set? channels) { _javascriptChannels.clear(); if (channels == null) { return; @@ -592,7 +595,7 @@ class WebViewController { final _PlatformCallbacksHandler _platformCallbacksHandler; - WebSettings _settings; + late WebSettings _settings; WebView _widget; @@ -606,7 +609,7 @@ class WebViewController { /// Throws an ArgumentError if `url` is not a valid URL string. Future loadUrl( String url, { - Map headers, + Map? headers, }) async { assert(url != null); _validateUrlString(url); @@ -620,7 +623,7 @@ class WebViewController { /// current URL changes again by the time this function returns (in other /// words, by the time this future completes, the WebView may be displaying a /// different URL). - Future currentUrl() { + Future currentUrl() { return _webViewPlatformController.currentUrl(); } @@ -688,7 +691,7 @@ class WebViewController { } Future _updateJavascriptChannels( - Set newChannels) async { + Set? newChannels) async { final Set currentChannels = _platformCallbacksHandler._javascriptChannels.keys.toSet(); final Set newChannelNames = _extractChannelNames(newChannels); @@ -727,10 +730,6 @@ class WebViewController { return Future.error(FlutterError( 'JavaScript mode must be enabled/unrestricted when calling evaluateJavascript.')); } - if (javascriptString == null) { - return Future.error( - ArgumentError('The argument javascriptString must not be null.')); - } // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter. // https://github.com/flutter/flutter/issues/26431 // ignore: strong_mode_implicit_dynamic_method @@ -738,7 +737,7 @@ class WebViewController { } /// Returns the title of the currently loaded page. - Future getTitle() { + Future getTitle() { return _webViewPlatformController.getTitle(); } @@ -780,7 +779,7 @@ class CookieManager { CookieManager._(); - static CookieManager _instance; + static CookieManager? _instance; /// Clears all cookies for all [WebView] instances. /// diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index de99c4b7cdb8..de62a50ada17 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,10 +1,10 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 1.0.8 +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.22.0" dependencies: @@ -16,7 +16,7 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 flutter: plugin: diff --git a/packages/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/test/webview_flutter_test.dart index c7cf46a080d7..662a2f7f976a 100644 --- a/packages/webview_flutter/test/webview_flutter_test.dart +++ b/packages/webview_flutter/test/webview_flutter_test.dart @@ -40,7 +40,7 @@ void main() { }); testWidgets('Initial url', (WidgetTester tester) async { - WebViewController controller; + late WebViewController controller; await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', @@ -60,7 +60,7 @@ void main() { )); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformWebView.javascriptMode, JavascriptMode.unrestricted); @@ -72,7 +72,7 @@ void main() { }); testWidgets('Load url', (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( onWebViewCreated: (WebViewController webViewController) { @@ -83,13 +83,13 @@ void main() { expect(controller, isNotNull); - await controller.loadUrl('https://flutter.io'); + await controller!.loadUrl('https://flutter.io'); - expect(await controller.currentUrl(), 'https://flutter.io'); + expect(await controller!.currentUrl(), 'https://flutter.io'); }); testWidgets('Invalid urls', (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( onWebViewCreated: (WebViewController webViewController) { @@ -100,19 +100,18 @@ void main() { expect(controller, isNotNull); - expect(() => controller.loadUrl(null), throwsA(anything)); - expect(await controller.currentUrl(), isNull); + expect(await controller!.currentUrl(), isNull); - expect(() => controller.loadUrl(''), throwsA(anything)); - expect(await controller.currentUrl(), isNull); + expect(() => controller!.loadUrl(''), throwsA(anything)); + expect(await controller!.currentUrl(), isNull); // Missing schema. - expect(() => controller.loadUrl('flutter.io'), throwsA(anything)); - expect(await controller.currentUrl(), isNull); + expect(() => controller!.loadUrl('flutter.io'), throwsA(anything)); + expect(await controller!.currentUrl(), isNull); }); testWidgets('Headers in loadUrl', (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( onWebViewCreated: (WebViewController webViewController) { @@ -126,13 +125,13 @@ void main() { final Map headers = { 'CACHE-CONTROL': 'ABC' }; - await controller.loadUrl('https://flutter.io', headers: headers); - expect(await controller.currentUrl(), equals('https://flutter.io')); + await controller!.loadUrl('https://flutter.io', headers: headers); + expect(await controller!.currentUrl(), equals('https://flutter.io')); }); testWidgets("Can't go back before loading a page", (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( onWebViewCreated: (WebViewController webViewController) { @@ -143,13 +142,13 @@ void main() { expect(controller, isNotNull); - final bool canGoBackNoPageLoaded = await controller.canGoBack(); + final bool canGoBackNoPageLoaded = await controller!.canGoBack(); expect(canGoBackNoPageLoaded, false); }); testWidgets("Clear Cache", (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( onWebViewCreated: (WebViewController webViewController) { @@ -159,15 +158,15 @@ void main() { ); expect(controller, isNotNull); - expect(fakePlatformViewsController.lastCreatedView.hasCache, true); + expect(fakePlatformViewsController.lastCreatedView!.hasCache, true); - await controller.clearCache(); + await controller!.clearCache(); - expect(fakePlatformViewsController.lastCreatedView.hasCache, false); + expect(fakePlatformViewsController.lastCreatedView!.hasCache, false); }); testWidgets("Can't go back with no history", (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( initialUrl: 'https://flutter.io', @@ -178,13 +177,13 @@ void main() { ); expect(controller, isNotNull); - final bool canGoBackFirstPageLoaded = await controller.canGoBack(); + final bool canGoBackFirstPageLoaded = await controller!.canGoBack(); expect(canGoBackFirstPageLoaded, false); }); testWidgets('Can go back', (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( initialUrl: 'https://flutter.io', @@ -196,15 +195,15 @@ void main() { expect(controller, isNotNull); - await controller.loadUrl('https://www.google.com'); - final bool canGoBackSecondPageLoaded = await controller.canGoBack(); + await controller!.loadUrl('https://www.google.com'); + final bool canGoBackSecondPageLoaded = await controller!.canGoBack(); expect(canGoBackSecondPageLoaded, true); }); testWidgets("Can't go forward before loading a page", (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( onWebViewCreated: (WebViewController webViewController) { @@ -215,13 +214,13 @@ void main() { expect(controller, isNotNull); - final bool canGoForwardNoPageLoaded = await controller.canGoForward(); + final bool canGoForwardNoPageLoaded = await controller!.canGoForward(); expect(canGoForwardNoPageLoaded, false); }); testWidgets("Can't go forward with no history", (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( initialUrl: 'https://flutter.io', @@ -232,13 +231,13 @@ void main() { ); expect(controller, isNotNull); - final bool canGoForwardFirstPageLoaded = await controller.canGoForward(); + final bool canGoForwardFirstPageLoaded = await controller!.canGoForward(); expect(canGoForwardFirstPageLoaded, false); }); testWidgets('Can go forward', (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( initialUrl: 'https://flutter.io', @@ -250,15 +249,15 @@ void main() { expect(controller, isNotNull); - await controller.loadUrl('https://youtube.com'); - await controller.goBack(); - final bool canGoForwardFirstPageBacked = await controller.canGoForward(); + await controller!.loadUrl('https://youtube.com'); + await controller!.goBack(); + final bool canGoForwardFirstPageBacked = await controller!.canGoForward(); expect(canGoForwardFirstPageBacked, true); }); testWidgets('Go back', (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', @@ -270,19 +269,19 @@ void main() { expect(controller, isNotNull); - expect(await controller.currentUrl(), 'https://youtube.com'); + expect(await controller!.currentUrl(), 'https://youtube.com'); - await controller.loadUrl('https://flutter.io'); + await controller!.loadUrl('https://flutter.io'); - expect(await controller.currentUrl(), 'https://flutter.io'); + expect(await controller!.currentUrl(), 'https://flutter.io'); - await controller.goBack(); + await controller!.goBack(); - expect(await controller.currentUrl(), 'https://youtube.com'); + expect(await controller!.currentUrl(), 'https://youtube.com'); }); testWidgets('Go forward', (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', @@ -294,23 +293,23 @@ void main() { expect(controller, isNotNull); - expect(await controller.currentUrl(), 'https://youtube.com'); + expect(await controller!.currentUrl(), 'https://youtube.com'); - await controller.loadUrl('https://flutter.io'); + await controller!.loadUrl('https://flutter.io'); - expect(await controller.currentUrl(), 'https://flutter.io'); + expect(await controller!.currentUrl(), 'https://flutter.io'); - await controller.goBack(); + await controller!.goBack(); - expect(await controller.currentUrl(), 'https://youtube.com'); + expect(await controller!.currentUrl(), 'https://youtube.com'); - await controller.goForward(); + await controller!.goForward(); - expect(await controller.currentUrl(), 'https://flutter.io'); + expect(await controller!.currentUrl(), 'https://flutter.io'); }); testWidgets('Current URL', (WidgetTester tester) async { - WebViewController controller; + WebViewController? controller; await tester.pumpWidget( WebView( onWebViewCreated: (WebViewController webViewController) { @@ -322,20 +321,20 @@ void main() { expect(controller, isNotNull); // Test a WebView without an explicitly set first URL. - expect(await controller.currentUrl(), isNull); + expect(await controller!.currentUrl(), isNull); - await controller.loadUrl('https://youtube.com'); - expect(await controller.currentUrl(), 'https://youtube.com'); + await controller!.loadUrl('https://youtube.com'); + expect(await controller!.currentUrl(), 'https://youtube.com'); - await controller.loadUrl('https://flutter.io'); - expect(await controller.currentUrl(), 'https://flutter.io'); + await controller!.loadUrl('https://flutter.io'); + expect(await controller!.currentUrl(), 'https://flutter.io'); - await controller.goBack(); - expect(await controller.currentUrl(), 'https://youtube.com'); + await controller!.goBack(); + expect(await controller!.currentUrl(), 'https://youtube.com'); }); testWidgets('Reload url', (WidgetTester tester) async { - WebViewController controller; + late WebViewController controller; await tester.pumpWidget( WebView( initialUrl: 'https://flutter.io', @@ -346,7 +345,7 @@ void main() { ); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformWebView.currentUrl, 'https://flutter.io'); expect(platformWebView.amountOfReloadsOnCurrentUrl, 0); @@ -362,7 +361,7 @@ void main() { }); testWidgets('evaluate Javascript', (WidgetTester tester) async { - WebViewController controller; + late WebViewController controller; await tester.pumpWidget( WebView( initialUrl: 'https://flutter.io', @@ -375,15 +374,11 @@ void main() { expect( await controller.evaluateJavascript("fake js string"), "fake js string", reason: 'should get the argument'); - expect( - () => controller.evaluateJavascript(null), - throwsA(anything), - ); }); testWidgets('evaluate Javascript with JavascriptMode disabled', (WidgetTester tester) async { - WebViewController controller; + late WebViewController controller; await tester.pumpWidget( WebView( initialUrl: 'https://flutter.io', @@ -397,10 +392,6 @@ void main() { () => controller.evaluateJavascript('fake js string'), throwsA(anything), ); - expect( - () => controller.evaluateJavascript(null), - throwsA(anything), - ); }); testWidgets('Cookies can be cleared once', (WidgetTester tester) async { @@ -444,7 +435,7 @@ void main() { ); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformWebView.javascriptChannelNames, unorderedEquals(['Tts', 'Alarm'])); @@ -517,7 +508,7 @@ void main() { ); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformWebView.javascriptChannelNames, unorderedEquals(['Tts', 'Alarm2', 'Alarm3'])); @@ -560,7 +551,7 @@ void main() { ); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformWebView.javascriptChannelNames, unorderedEquals(['Tts'])); @@ -590,7 +581,7 @@ void main() { ); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(ttsMessagesReceived, isEmpty); expect(alarmMessagesReceived, isEmpty); @@ -603,7 +594,7 @@ void main() { group('$PageStartedCallback', () { testWidgets('onPageStarted is not null', (WidgetTester tester) async { - String returnedUrl; + String? returnedUrl; await tester.pumpWidget(WebView( initialUrl: 'https://youtube.com', @@ -613,7 +604,7 @@ void main() { )); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; platformWebView.fakeOnPageStartedCallback(); @@ -627,7 +618,7 @@ void main() { )); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; // The platform side will always invoke a call for onPageStarted. This is // to test that it does not crash on a null callback. @@ -635,7 +626,7 @@ void main() { }); testWidgets('onPageStarted changed', (WidgetTester tester) async { - String returnedUrl; + String? returnedUrl; await tester.pumpWidget(WebView( initialUrl: 'https://youtube.com', @@ -650,7 +641,7 @@ void main() { )); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; platformWebView.fakeOnPageStartedCallback(); @@ -660,7 +651,7 @@ void main() { group('$PageFinishedCallback', () { testWidgets('onPageFinished is not null', (WidgetTester tester) async { - String returnedUrl; + String? returnedUrl; await tester.pumpWidget(WebView( initialUrl: 'https://youtube.com', @@ -670,7 +661,7 @@ void main() { )); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; platformWebView.fakeOnPageFinishedCallback(); @@ -684,7 +675,7 @@ void main() { )); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; // The platform side will always invoke a call for onPageFinished. This is // to test that it does not crash on a null callback. @@ -692,7 +683,7 @@ void main() { }); testWidgets('onPageFinished changed', (WidgetTester tester) async { - String returnedUrl; + String? returnedUrl; await tester.pumpWidget(WebView( initialUrl: 'https://youtube.com', @@ -707,7 +698,7 @@ void main() { )); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; platformWebView.fakeOnPageFinishedCallback(); @@ -722,13 +713,14 @@ void main() { )); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformWebView.hasNavigationDelegate, false); await tester.pumpWidget(WebView( initialUrl: 'https://youtube.com', - navigationDelegate: (NavigationRequest r) => null, + navigationDelegate: (NavigationRequest r) => + NavigationDecision.navigate, )); expect(platformWebView.hasNavigationDelegate, true); @@ -748,7 +740,7 @@ void main() { })); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformWebView.hasNavigationDelegate, true); @@ -773,7 +765,7 @@ void main() { )); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformWebView.debuggingEnabled, true); }); @@ -782,7 +774,7 @@ void main() { await tester.pumpWidget(const WebView()); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformWebView.debuggingEnabled, false); }); @@ -792,7 +784,7 @@ void main() { await tester.pumpWidget(WebView(key: key)); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; await tester.pumpWidget(WebView( key: key, @@ -826,8 +818,8 @@ void main() { ), ); - final MyWebViewPlatform builder = WebView.platform; - final MyWebViewPlatformController platform = builder.lastPlatformBuilt; + final MyWebViewPlatform builder = WebView.platform as MyWebViewPlatform; + final MyWebViewPlatformController platform = builder.lastPlatformBuilt!; expect( platform.creationParams, @@ -837,17 +829,14 @@ void main() { javascriptMode: JavascriptMode.disabled, hasNavigationDelegate: false, debuggingEnabled: false, - userAgent: WebSetting.of(null), + userAgent: WebSetting.of(null), gestureNavigationEnabled: true, ), - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannelNames: Set(), ))); }); testWidgets('loadUrl', (WidgetTester tester) async { - WebViewController controller; + late WebViewController controller; await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', @@ -857,8 +846,8 @@ void main() { ), ); - final MyWebViewPlatform builder = WebView.platform; - final MyWebViewPlatformController platform = builder.lastPlatformBuilt; + final MyWebViewPlatform builder = WebView.platform as MyWebViewPlatform; + final MyWebViewPlatformController platform = builder.lastPlatformBuilt!; final Map headers = { 'header': 'value', @@ -877,7 +866,7 @@ void main() { )); final FakePlatformWebView platformWebView = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformWebView.userAgent, isNull); @@ -892,9 +881,9 @@ void main() { } class FakePlatformWebView { - FakePlatformWebView(int id, Map params) { + FakePlatformWebView(int? id, Map params) { if (params.containsKey('initialUrl')) { - final String initialUrl = params['initialUrl']; + final String? initialUrl = params['initialUrl']; if (initialUrl != null) { history.add(initialUrl); currentPosition++; @@ -914,20 +903,20 @@ class FakePlatformWebView { channel.setMockMethodCallHandler(onMethodCall); } - MethodChannel channel; + late MethodChannel channel; - List history = []; + List history = []; int currentPosition = -1; int amountOfReloadsOnCurrentUrl = 0; bool hasCache = true; - String get currentUrl => history.isEmpty ? null : history[currentPosition]; - JavascriptMode javascriptMode; - List javascriptChannelNames; + String? get currentUrl => history.isEmpty ? null : history[currentPosition]; + JavascriptMode? javascriptMode; + List? javascriptChannelNames; - bool hasNavigationDelegate; - bool debuggingEnabled; - String userAgent; + bool? hasNavigationDelegate; + bool? debuggingEnabled; + String? userAgent; Future onMethodCall(MethodCall call) { switch (call.method) { @@ -949,34 +938,28 @@ class FakePlatformWebView { break; case 'canGoBack': return Future.sync(() => currentPosition > 0); - break; case 'canGoForward': return Future.sync(() => currentPosition < history.length - 1); - break; case 'goBack': currentPosition = max(-1, currentPosition - 1); return Future.sync(() {}); - break; case 'goForward': currentPosition = min(history.length - 1, currentPosition + 1); return Future.sync(() {}); case 'reload': amountOfReloadsOnCurrentUrl++; return Future.sync(() {}); - break; case 'currentUrl': - return Future.value(currentUrl); - break; + return Future.value(currentUrl); case 'evaluateJavascript': return Future.value(call.arguments); - break; case 'addJavascriptChannels': final List channelNames = List.from(call.arguments); - javascriptChannelNames.addAll(channelNames); + javascriptChannelNames!.addAll(channelNames); break; case 'removeJavascriptChannels': final List channelNames = List.from(call.arguments); - javascriptChannelNames + javascriptChannelNames! .removeWhere((String channel) => channelNames.contains(channel)); break; case 'clearCache': @@ -994,14 +977,14 @@ class FakePlatformWebView { }; final ByteData data = codec .encodeMethodCall(MethodCall('javascriptChannelMessage', arguments)); - ServicesBinding.instance.defaultBinaryMessenger - .handlePlatformMessage(channel.name, data, (ByteData data) {}); + ServicesBinding.instance!.defaultBinaryMessenger + .handlePlatformMessage(channel.name, data, (ByteData? data) {}); } // Fakes a main frame navigation that was initiated by the webview, e.g when // the user clicks a link in the currently loaded page. void fakeNavigate(String url) { - if (!hasNavigationDelegate) { + if (!hasNavigationDelegate!) { print('no navigation delegate'); _loadUrl(url); return; @@ -1013,9 +996,9 @@ class FakePlatformWebView { }; final ByteData data = codec.encodeMethodCall(MethodCall('navigationRequest', arguments)); - ServicesBinding.instance.defaultBinaryMessenger - .handlePlatformMessage(channel.name, data, (ByteData data) { - final bool allow = codec.decodeEnvelope(data); + ServicesBinding.instance!.defaultBinaryMessenger + .handlePlatformMessage(channel.name, data, (ByteData? data) { + final bool allow = codec.decodeEnvelope(data!); if (allow) { _loadUrl(url); } @@ -1030,10 +1013,10 @@ class FakePlatformWebView { {'url': currentUrl}, )); - ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage( + ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage( channel.name, data, - (ByteData data) {}, + (ByteData? data) {}, ); } @@ -1045,14 +1028,14 @@ class FakePlatformWebView { {'url': currentUrl}, )); - ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage( + ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage( channel.name, data, - (ByteData data) {}, + (ByteData? data) {}, ); } - void _loadUrl(String url) { + void _loadUrl(String? url) { history = history.sublist(0, currentPosition + 1); history.add(url); currentPosition++; @@ -1061,13 +1044,13 @@ class FakePlatformWebView { } class _FakePlatformViewsController { - FakePlatformWebView lastCreatedView; + FakePlatformWebView? lastCreatedView; Future fakePlatformViewsMethodHandler(MethodCall call) { switch (call.method) { case 'create': final Map args = call.arguments; - final Map params = _decodeParams(args['params']); + final Map params = _decodeParams(args['params'])!; lastCreatedView = FakePlatformWebView( args['id'], params, @@ -1083,7 +1066,7 @@ class _FakePlatformViewsController { } } -Map _decodeParams(Uint8List paramsMessage) { +Map? _decodeParams(Uint8List paramsMessage) { final ByteBuffer buffer = paramsMessage.buffer; final ByteData messageBytes = buffer.asByteData( paramsMessage.offsetInBytes, @@ -1114,9 +1097,8 @@ class _FakeCookieManager { return Future.sync(() { return hadCookies; }); - break; } - return Future.sync(() => null); + return Future.sync(() => true); } void reset() { @@ -1125,26 +1107,26 @@ class _FakeCookieManager { } class MyWebViewPlatform implements WebViewPlatform { - MyWebViewPlatformController lastPlatformBuilt; + MyWebViewPlatformController? lastPlatformBuilt; @override Widget build({ - BuildContext context, - CreationParams creationParams, - @required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, - @required WebViewPlatformCreatedCallback onWebViewPlatformCreated, - Set> gestureRecognizers, + BuildContext? context, + CreationParams? creationParams, + required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, + WebViewPlatformCreatedCallback? onWebViewPlatformCreated, + Set>? gestureRecognizers, }) { assert(onWebViewPlatformCreated != null); lastPlatformBuilt = MyWebViewPlatformController( creationParams, gestureRecognizers, webViewPlatformCallbacksHandler); - onWebViewPlatformCreated(lastPlatformBuilt); + onWebViewPlatformCreated!(lastPlatformBuilt); return Container(); } @override Future clearCookies() { - return Future.sync(() => null); + return Future.sync(() => true); } } @@ -1153,25 +1135,24 @@ class MyWebViewPlatformController extends WebViewPlatformController { WebViewPlatformCallbacksHandler platformHandler) : super(platformHandler); - CreationParams creationParams; - Set> gestureRecognizers; + CreationParams? creationParams; + Set>? gestureRecognizers; - String lastUrlLoaded; - Map lastRequestHeaders; + String? lastUrlLoaded; + Map? lastRequestHeaders; @override - Future loadUrl(String url, Map headers) { + Future loadUrl(String url, Map? headers) async { equals(1, 1); lastUrlLoaded = url; lastRequestHeaders = headers; - return null; } } class MatchesWebSettings extends Matcher { MatchesWebSettings(this._webSettings); - final WebSettings _webSettings; + final WebSettings? _webSettings; @override Description describe(Description description) => @@ -1180,13 +1161,13 @@ class MatchesWebSettings extends Matcher { @override bool matches( covariant WebSettings webSettings, Map matchState) { - return _webSettings.javascriptMode == webSettings.javascriptMode && - _webSettings.hasNavigationDelegate == + return _webSettings!.javascriptMode == webSettings.javascriptMode && + _webSettings!.hasNavigationDelegate == webSettings.hasNavigationDelegate && - _webSettings.debuggingEnabled == webSettings.debuggingEnabled && - _webSettings.gestureNavigationEnabled == + _webSettings!.debuggingEnabled == webSettings.debuggingEnabled && + _webSettings!.gestureNavigationEnabled == webSettings.gestureNavigationEnabled && - _webSettings.userAgent == webSettings.userAgent; + _webSettings!.userAgent == webSettings.userAgent; } } @@ -1204,7 +1185,7 @@ class MatchesCreationParams extends Matcher { Map matchState) { return _creationParams.initialUrl == creationParams.initialUrl && MatchesWebSettings(_creationParams.webSettings) - .matches(creationParams.webSettings, matchState) && + .matches(creationParams.webSettings!, matchState) && orderedEquals(_creationParams.javascriptChannelNames) .matches(creationParams.javascriptChannelNames, matchState); } diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 8b73ecc24e99..6e08c72df4bf 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -15,6 +15,7 @@ readonly NNBD_PLUGINS_LIST=( "plugin_platform_interface" "url_launcher" "video_player" + "webview_flutter" ) export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}") From 88466ff7325a112dd6158ab3a3f8f21a9ff66b80 Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Tue, 15 Dec 2020 08:29:06 -0800 Subject: [PATCH 045/924] [share] Migrate to null-safety (#3311) --- packages/share/CHANGELOG.md | 4 ++++ packages/share/lib/share.dart | 12 ++++++------ packages/share/pubspec.yaml | 17 +++++++---------- packages/share/test/share_test.dart | 18 +----------------- script/nnbd_plugins.sh | 1 + 5 files changed, 19 insertions(+), 33 deletions(-) diff --git a/packages/share/CHANGELOG.md b/packages/share/CHANGELOG.md index 8a3806209c1c..86906bbd56be 100644 --- a/packages/share/CHANGELOG.md +++ b/packages/share/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 0.6.5+5 * Update Flutter SDK constraint. diff --git a/packages/share/lib/share.dart b/packages/share/lib/share.dart index 4a3ff6f1de09..f15566714857 100644 --- a/packages/share/lib/share.dart +++ b/packages/share/lib/share.dart @@ -33,8 +33,8 @@ class Share { /// from [MethodChannel]. static Future share( String text, { - String subject, - Rect sharePositionOrigin, + String? subject, + Rect? sharePositionOrigin, }) { assert(text != null); assert(text.isNotEmpty); @@ -67,10 +67,10 @@ class Share { /// from [MethodChannel]. static Future shareFiles( List paths, { - List mimeTypes, - String subject, - String text, - Rect sharePositionOrigin, + List? mimeTypes, + String? subject, + String? text, + Rect? sharePositionOrigin, }) { assert(paths != null); assert(paths.isNotEmpty); diff --git a/packages/share/pubspec.yaml b/packages/share/pubspec.yaml index 23644d290473..69d0fdbd5eb8 100644 --- a/packages/share/pubspec.yaml +++ b/packages/share/pubspec.yaml @@ -2,10 +2,7 @@ name: share description: Flutter plugin for sharing content via the platform share UI, using the ACTION_SEND intent on Android and UIActivityViewController on iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/share -# 0.6.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.6.5+5 +version: 2.0.0-nullsafety flutter: plugin: @@ -17,20 +14,20 @@ flutter: pluginClass: FLTSharePlugin dependencies: - meta: ^1.0.5 - mime: ^0.9.7 + meta: ^1.3.0-nullsafety.6 + mime: ^1.0.0-nullsafety.0 flutter: sdk: flutter dev_dependencies: - test: ^1.3.0 - mockito: ^3.0.0 + test: ^1.16.0-nullsafety.13 + mockito: ^4.1.3 flutter_test: sdk: flutter integration_test: path: ../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.3 environment: - sdk: ">=2.1.0 <3.0.0" flutter: ">=1.12.13+hotfix.5" + sdk: ">=2.12.0-0 <3.0.0" diff --git a/packages/share/test/share_test.dart b/packages/share/test/share_test.dart index e862d1baf579..fa9f980beae3 100644 --- a/packages/share/test/share_test.dart +++ b/packages/share/test/share_test.dart @@ -15,7 +15,7 @@ import 'package:flutter/services.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - MockMethodChannel mockChannel; + late MockMethodChannel mockChannel; setUp(() { mockChannel = MockMethodChannel(); @@ -26,14 +26,6 @@ void main() { }); }); - test('sharing null fails', () { - expect( - () => Share.share(null), - throwsA(const TypeMatcher()), - ); - verifyZeroInteractions(mockChannel); - }); - test('sharing empty fails', () { expect( () => Share.share(''), @@ -58,14 +50,6 @@ void main() { })); }); - test('sharing null file fails', () { - expect( - () => Share.shareFiles([null]), - throwsA(const TypeMatcher()), - ); - verifyZeroInteractions(mockChannel); - }); - test('sharing empty file fails', () { expect( () => Share.shareFiles(['']), diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 6e08c72df4bf..5e671c23d5fd 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -13,6 +13,7 @@ readonly NNBD_PLUGINS_LIST=( "local_auth" "path_provider" "plugin_platform_interface" + "share" "url_launcher" "video_player" "webview_flutter" From f8a53a5f27f3f6eeb58e4ae0cfedcc362e8950b9 Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Tue, 15 Dec 2020 09:54:42 -0800 Subject: [PATCH 046/924] [android_intent] Migrate to nnbd (#3328) --- packages/android_intent/CHANGELOG.md | 4 +++ .../android_intent/lib/android_intent.dart | 27 ++++++++++--------- packages/android_intent/pubspec.yaml | 17 +++++------- .../test/android_intent_test.dart | 4 ++- script/nnbd_plugins.sh | 1 + 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/packages/android_intent/CHANGELOG.md b/packages/android_intent/CHANGELOG.md index f3534982a971..65c991c6f7b2 100644 --- a/packages/android_intent/CHANGELOG.md +++ b/packages/android_intent/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 0.3.7+8 * Update Flutter SDK constraint. diff --git a/packages/android_intent/lib/android_intent.dart b/packages/android_intent/lib/android_intent.dart index 9d701979b392..0ab2d7bee420 100644 --- a/packages/android_intent/lib/android_intent.dart +++ b/packages/android_intent/lib/android_intent.dart @@ -36,7 +36,7 @@ class AndroidIntent { this.arguments, this.package, this.componentName, - Platform platform, + Platform? platform, this.type, }) : assert(action != null || componentName != null, 'action or component (or both) must be specified'), @@ -47,8 +47,8 @@ class AndroidIntent { /// app code, it may break without warning. @visibleForTesting AndroidIntent.private({ - @required Platform platform, - @required MethodChannel channel, + required Platform platform, + required MethodChannel channel, this.action, this.flags, this.category, @@ -66,47 +66,47 @@ class AndroidIntent { /// includes constants like `ACTION_VIEW`. /// /// See https://developer.android.com/reference/android/content/Intent.html#intent-structure. - final String action; + final String? action; /// Constants that can be set on an intent to tweak how it is finally handled. /// Some of the constants are mirrored to Dart via [Flag]. /// /// See https://developer.android.com/reference/android/content/Intent.html#setFlags(int). - final List flags; + final List? flags; /// An optional additional constant qualifying the given [action]. /// /// See https://developer.android.com/reference/android/content/Intent.html#intent-structure. - final String category; + final String? category; /// The Uri that the [action] is pointed towards. /// /// See https://developer.android.com/reference/android/content/Intent.html#intent-structure. - final String data; + final String? data; /// The equivalent of `extras`, a generic `Bundle` of data that the Intent can /// carry. This is a slot for extraneous data that the listener may use. /// /// See https://developer.android.com/reference/android/content/Intent.html#intent-structure. - final Map arguments; + final Map? arguments; /// Sets the [data] to only resolve within this given package. /// /// See https://developer.android.com/reference/android/content/Intent.html#setPackage(java.lang.String). - final String package; + final String? package; /// Set the exact `ComponentName` that should handle the intent. If this is /// set [package] should also be non-null. /// /// See https://developer.android.com/reference/android/content/Intent.html#setComponent(android.content.ComponentName). - final String componentName; + final String? componentName; final MethodChannel _channel; final Platform _platform; /// Set an explicit MIME data type. /// /// See https://developer.android.com/reference/android/content/Intent.html#intent-structure. - final String type; + final String? type; bool _isPowerOfTwo(int x) { /* First x in the below expression is for the case when x is 0 */ @@ -146,17 +146,18 @@ class AndroidIntent { return false; } - return await _channel.invokeMethod( + final result = await _channel.invokeMethod( 'canResolveActivity', _buildArguments(), ); + return result!; } /// Constructs the map of arguments which is passed to the plugin. Map _buildArguments() { return { if (action != null) 'action': action, - if (flags != null) 'flags': convertFlags(flags), + if (flags != null) 'flags': convertFlags(flags!), if (category != null) 'category': category, if (data != null) 'data': data, if (arguments != null) 'arguments': arguments, diff --git a/packages/android_intent/pubspec.yaml b/packages/android_intent/pubspec.yaml index 1b63371e488c..aec7ad0d5a18 100644 --- a/packages/android_intent/pubspec.yaml +++ b/packages/android_intent/pubspec.yaml @@ -1,10 +1,7 @@ name: android_intent description: Flutter plugin for launching Android Intents. Not supported on iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/android_intent -# 0.3.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.3.7+8 +version: 2.0.0-nullsafety flutter: plugin: @@ -16,15 +13,15 @@ flutter: dependencies: flutter: sdk: flutter - platform: ">=2.0.0 <4.0.0" - meta: ^1.0.5 + platform: ^3.0.0-nullsafety.4 + meta: ^1.3.0-nullsafety.6 dev_dependencies: - test: ^1.3.0 - mockito: ^3.0.0 + test: ^1.16.0-nullsafety.13 + mockito: ^4.1.3 flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.3.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/android_intent/test/android_intent_test.dart b/packages/android_intent/test/android_intent_test.dart index 311628853159..b0fa48e22fee 100644 --- a/packages/android_intent/test/android_intent_test.dart +++ b/packages/android_intent/test/android_intent_test.dart @@ -11,9 +11,11 @@ import 'package:platform/platform.dart'; void main() { AndroidIntent androidIntent; - MockMethodChannel mockChannel; + late MockMethodChannel mockChannel; setUp(() { mockChannel = MockMethodChannel(); + when(mockChannel.invokeMethod('canResolveActivity', any)) + .thenAnswer((realInvocation) async => true); }); group('AndroidIntent', () { diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 5e671c23d5fd..0cab28abe2ab 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -5,6 +5,7 @@ # null-safe is available on stable. readonly NNBD_PLUGINS_LIST=( + "android_intent" "connectivity" "device_info" "flutter_plugin_android_lifecycle" From bad9fd1578ad66db6a5559baef2ad21a6286992a Mon Sep 17 00:00:00 2001 From: Febry Ardiansyah Date: Wed, 16 Dec 2020 02:07:13 +0700 Subject: [PATCH 047/924] [wifi_info_flutter] Edit sample wifi_info_flutter plugin (#3271) --- packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md | 4 ++++ packages/wifi_info_flutter/wifi_info_flutter/README.md | 6 +++--- packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md b/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md index 9073486aa601..5c3ea32e8ef9 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md +++ b/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.3 + +* Fix README example. + ## 1.0.2 * Update Flutter SDK constraint. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/README.md b/packages/wifi_info_flutter/wifi_info_flutter/README.md index 0c2eff383c16..e1c0c84dc04b 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/README.md +++ b/packages/wifi_info_flutter/wifi_info_flutter/README.md @@ -24,9 +24,9 @@ You can get wi-fi related information using: ```dart import 'package:wifi_info_flutter/wifi_info_flutter.dart'; -var wifiBSSID = await WifiFlutter().getWifiBSSID(); -var wifiIP = await WifiFlutter().getWifiIP(); -var wifiName = await WifiFlutter().getWifiName(); +var wifiBSSID = await WifiInfo().getWifiBSSID(); +var wifiIP = await WifiInfo().getWifiIP(); +var wifiName = await WifiInfo().getWifiName(); ``` ### iOS 12 diff --git a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml index 09dff3a48104..4f5ecafb50b4 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: wifi_info_flutter description: A new flutter plugin project. -version: 1.0.2 +version: 1.0.3 homepage: https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter/wifi_info_flutter environment: From b85d8eb326a6f197fd613966c94ae69f8278c552 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Wed, 16 Dec 2020 08:45:03 +0100 Subject: [PATCH 048/924] [camera_platform_interface] Add torch definition to the FlashModes enum (#3326) * Fix formatting issues * Make sure torch value is serialized correctly --- packages/camera/camera_platform_interface/CHANGELOG.md | 4 ++++ .../lib/src/method_channel/method_channel_camera.dart | 2 ++ .../lib/src/platform_interface/camera_platform.dart | 2 +- .../camera_platform_interface/lib/src/types/flash_mode.dart | 3 +++ packages/camera/camera_platform_interface/pubspec.yaml | 2 +- .../test/types/flash_mode_test.dart | 5 +++-- 6 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index 500e8d67a6e4..ea9821e841f9 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.4 + +- Added the torch option to the FlashMode enum, which when implemented indicates the flash light should be turned on continuously. + ## 1.0.3 - Update Flutter SDK constraint. diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index bc836b0ac98e..3bf996fedb19 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -226,6 +226,8 @@ class MethodChannelCamera extends CameraPlatform { return 'auto'; case FlashMode.always: return 'always'; + case FlashMode.torch: + return 'torch'; default: throw ArgumentError('Unknown FlashMode value'); } diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index c398e9e9ef17..6f96079dc55c 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -108,7 +108,7 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('resumeVideoRecording() is not implemented.'); } - /// Sets the flash mode for taking pictures. + /// Sets the flash mode for the selected camera. Future setFlashMode(int cameraId, FlashMode mode) { throw UnimplementedError('setFlashMode() is not implemented.'); } diff --git a/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart index 6ed92e4801eb..7feb59caeab8 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart @@ -12,4 +12,7 @@ enum FlashMode { /// Always use the flash when taking a picture. always, + + /// Turns on the flash light and keeps it on until switched off. + torch, } diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index 9349c5536ff2..8cb643e84ca6 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.0.3 +version: 1.0.4 dependencies: flutter: diff --git a/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart b/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart index 59726acf7873..c9df64152cef 100644 --- a/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart +++ b/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart @@ -6,10 +6,10 @@ import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - test('FlashMode should contain 3 options', () { + test('FlashMode should contain 4 options', () { final values = FlashMode.values; - expect(values.length, 3); + expect(values.length, 4); }); test("FlashMode enum should have items in correct index", () { @@ -18,5 +18,6 @@ void main() { expect(values[0], FlashMode.off); expect(values[1], FlashMode.auto); expect(values[2], FlashMode.always); + expect(values[3], FlashMode.torch); }); } From aa8fcb4b758f65b8968c427b4e18694ffd9d530d Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Wed, 16 Dec 2020 09:51:19 -0800 Subject: [PATCH 049/924] [webview_flutter] Added 'allowsInlineMediaPlayback' property (#3334) --- packages/webview_flutter/CHANGELOG.md | 4 + .../webviewflutter/FlutterWebView.java | 3 + .../example/assets/sample_video.mp4 | Bin 0 -> 1053651 bytes .../webview_flutter_test.dart | 225 +++++++++++++++++- .../webview_flutter/example/lib/main.dart | 6 +- packages/webview_flutter/example/pubspec.yaml | 1 + .../ios/Classes/FlutterWebView.m | 3 + .../lib/platform_interface.dart | 8 +- .../lib/src/webview_method_channel.dart | 2 + .../webview_flutter/lib/webview_flutter.dart | 10 + packages/webview_flutter/pubspec.yaml | 2 +- .../test/webview_flutter_test.dart | 42 ++-- 12 files changed, 263 insertions(+), 43 deletions(-) create mode 100644 packages/webview_flutter/example/assets/sample_video.mp4 diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 352613997aa0..a10c28dc20b7 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.1 + +* Added `allowsInlineMediaPlayback` property. + ## 2.0.0-nullsafety * Migration to null-safety. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java index bfb79a39e8ba..ef9f006f6e5b 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java @@ -372,6 +372,9 @@ private void applySettings(Map settings) { case "userAgent": updateUserAgent((String) settings.get(key)); break; + case "allowsInlineMediaPlayback": + // no-op inline media playback is always allowed on Android. + break; default: throw new IllegalArgumentException("Unknown WebView setting: " + key); } diff --git a/packages/webview_flutter/example/assets/sample_video.mp4 b/packages/webview_flutter/example/assets/sample_video.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..a203d0cdf13ea5106cdb8c98b52301f0e3719bac GIT binary patch literal 1053651 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%0A0_A2BB?T)i~ z4N2W5nUMXhn#m5ZjZ%8r@Zo^*hAJ$sW*4*wd7e z-^TSy`GRU+6j(e{#3C)$=TSoCvXhQ~i^5G`ofJ5H1Z3HM)UsT1Coa+z;Y7uEc0L$+P?b`&$h#6;Yn%gIcBF+k7a&xe@o$Bh~szTL@SG zT)$gE=cK;ka@n3^lyUynKCW8B-PT8qelkZD(p2E)OHfV`|IC)anf? zXHgh~dn(MW&9GyMCugeU#Cy||Bqd}VgD9hSYV51>!eh1?d3T5-#)3}6ZJUinQXnP^ z;*${1{1F^$7KNfuI$E)L=5yDpAh4BNO+c5$1xW7x#OG3owTv)i_)h!cjohtgw6V

Jbq-814NPd$TYkZAM*DuEbPgkd!5Mv&pQs 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%0A$ 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

F^h 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�L$2-vNN2qd&Na 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%0D@5 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%0Ar{$@$bdoE3f zl+)Mctbu8+cf2|ZjG4pJdASDk3rIyAtP$Vil5r_2J=$ajGZKuZ(6c+qweFga?LnP& z$B9ce!%KXsjXq5SRfiPXswS-iY((b=Cco(GpJg%HS)DkqdeAqujLe#wR1zIZXdXP{ z{tH_2aQ2**7FUgJ)s3-;>kvl}STp0|mAA_vm-_%l7@!GoQnEZj3wN(80xE$qG2{SZ zIMDDIsc1tgV(E1RH4YJVhAu$OSF2jgifS7B-^nsAh0uNyKAFA00E3gW={GK;j+f~h zohq|x14})MW>4@JUmZX(s#ELWl|&eClZa?zxfeI^w{P$BU}>beL!G4Rep3Q0XhY|# zxX-5XZ-SNl@9g(p$H;TR8^d%KYV;`5n>Y_aoKvj|F~_3CwYLL;Zix|MBKN2Gc{jQ^juMuW*km>*!flJ3%IgUW|mpYG8n(BlD(= zYaIL2*Z$588bvRM9b$(#z4=TEXV9>co`${%P2`k7B7-~6>N(aHVi(&XpuZ-pXx}8J%at2o*u<+f=PXCZey2HqS=mzo{*yq2fLiL}*XZ zFZeeaaI|A3?OjRz)Z6fr<&iM{;EgKuw)kJtQnzdIf=Lz8g5bD!>Ia zdi`-EPy%YiqM4s6@-AJS@SL0+)PksAdKJAS&*Ey};Xakz&^z;~{8{gTcy=q3YYClv zekUcJ%~sr=N{K9hX!$%3c3!|GFk!pb^G}j!x71<{nI&QBJUn2ymOZw%1&_z{D#Qo< z2$?==`s+b@XX*7fe2!fCvwA{W`$X9{i$w*gsz#xQ>Y{}mFMjgCOEcAfXwK!9Sp-=Z z9Usy4Z)(`b$B#j76y_&2ic<4cA7>hWa6R18Pl|eS%{#6@R=(Vqn!n)X_uW$mKnCW> z-*d;?76M%O1oGjbbt%9pej*EB^N1_ObjuI1Zh4YOKs@ncY-7 z2q=(=jyXe)u=tLTJ3$7Qzr*VJkHf9v#IOz>-5mCkOJz9fJ6>I0PLu7>h~29nGp1bc z8WiO5fOo6hUK4?w{!!hGwh^=aI}NAkma6QANzyC+1_`9i7#!|pW&6^cChdHbS5!S- zH!Ul?HZGc4CHp;M^{4EU@Olj=Bd$d*Z}RFF+fef(Zm?`MYCk7|d`lPn!FWqnQ`AA@ z4IU0gubhAd5BZBo`LAS86*b{r+#st5zw7dilQAoUbQ}twfKkI+qFZQi#`)^;o%Ru2 z^`^CM5Ohh6b9B)zbsa008rLxbYPmm=%ERRw~S9bM$Y0wsrahI#{GgU}6$>h<`*GDSby=9`8*n?2Yz8fw^8tTIp z^;e{gUf#2x;_5Dd#V9R@4JRhisFtJp!mXO!JUJxBWdF~6fNCq36aD{VKFHf$goW8; zT%)x&-uAMS6^e8$<9x{7((ihXPIjHt$77YB`Rek-MQUO+U^;GZ_nlOJ@z7=OISFHx z#^;?KyE;~DK58rpLf2Vm6az0E_wR4dR9h@t$)d*z2RLDaG_rYAX1k%auZNovLX;45 zJi)jrGgyF$L<3rvz=5k~dK zvFg1cs&u-v(42YX^B;@Ie*C`pjq+UIHhg;~EMiC1aF)SLYc}a-XDSlqQ7+o;qZhq8YUzO!c{RRD4xm>%0;ACrnaQ=0 zK)ht{r19Q3{cHDA6-qWhSpg�IeT~@r?-xXXpbi!xq0(h5wcR4zyG}?;yV7-{-lT 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�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 z z2`2-U4}a3zr7CFf7)QPnGWnb#-0*kGEia}BkwAOm((v#z%(WetckB00gJs?bD`y{l z9F|rUOPAq0>E<(0=f<8&r5uu>7ERQtxNH|^8i*Bl@t>3CmBq9l^rOG@9CS}!75JGk z3Sh|cBd1=af@Np0pTxjjzD)Q?;Onz!6FL(%16Z^unixyr`Rgp_&nYW^-n7OFk5-#T z2Bz@tdq#hX`i&j+`M&i^e#Z;xu~sMH2S5bb;@bJN0g%VCd>wGcQcW*#|2;OiI~sDd z4dkoL|60DI=mkd-Iyq0=u+Iccx85}ldDA$NwKcAC3%cRGK?Egy)tdEtd;Kz)dk%E{ z_G!t-ZT2B#pqlxIo->h^{)c->Xpr&%Z8NKg$RA;XA!Tz;`6D|%EVW^J;)nONL@Pwcz3UQS z{+z~ckGHnBZXeKT%i!0MXf`PgyMT7Pf>k6r#FrC?4&MYCh86Y-LGDjet!oU(a?74U`ELrRax$Za=z1%lFKZAcIVZ5i$H=%s`vGJXF za9>ETo4DrDlRIlmK)1{m<9U+Tl=rj=%a9AD7#aTk?NQMX(g_Hv&!lXchwJF~k5FKI zzYE%BQoIl*`4OFdo%!}GrKs_ErazY>OL=;3R;>=7SAXF~Vwjd%zjf7_;^9&7kd9qW zUEZ4Y%s347I;J!ntPAVUR!Q+Uk^5hw5STTU!KHv6-X$xHWx#^Zdx^9D3@8X}z--_> zI+e_-+)Ou|3$mVi&xU=Xosn3$qQ19h2{2Bw4J-=Eu0Q5R#gu(htp9ZQ*#7la|2SQ_ zB%mBM7BaPQ8v9W2&U;-nHt5;WD_5CgRT*q$7c zK;57D32NfGb1n?^inwSrQ4Rc+ZNzN+-hbZu?ZeW+YF)$4R>^5oQ_qk0s-D>Z2|zKQ zZrE6;Mz2@?mLkXZK!FzoZ7R0y2j2Q)i$uXZydVtJ*gxc(imr0DW4!10c6E8z5{tU{ zq8@`)=)jyGLBj~}?3*Y3+l%taO;c}w>(fSy_rrpz%)tDI@0nfChYz6u?^lC!x{|i5 zmf9+G2&Bp-P)QFb>$o4?TEElFriVU1rA}``L}mS$ckpM9Kv<_>=YA`f7%$4RzY&BE z;f1`XMLGnLM>c!kAp%29!Q-<^nDE}In23o9B5`l_@SUq z69p<{u*wR2TG5%|mp$(LSrg3-^iB35KOa$OHQSbHq(eLoMAF4C^;K=9`t#gT3hBRY zO`gNU7Ath_4>@eS28Pl!-StexvHE)WQ5v4!&N^?S)wUws--%Y|U0;`qVH_X7@m{+D zTOF?M$362%vSOctrm*FeKF~?V9@;#S@#E}$GE-P{7Jiw+k4E7yHE=Soi{I^F=s`6y zB^R0B(lMmbz>Bs?tf~B8a&<;5C*psD1%$aajljMz4F?=T!YGWRCralf!c4&%rv}=y z;piek+!)|aI9^D7Pbk1}3iBU#&;|ZguxkCF6N4^@v=j5MhlJ9R82JiY^fwuI)tc2- z8QZa74E-?S%cc-cYpU(Ag!3l56v+bR?D$ql`0etYZyzNThbi{g=BC@@#?ib3svE+< z!-OmdX<-HyN#>vO0cDtn44W8cm!#|pzm#ySRq9!*&B|Pv8dV!RSO;^y4r(UqZ!GTe z{l+QUR>JCuz)kfpTTS8deR538P-`Kob5)u8AQCOOrKmbq|_B=LE%G`ZPRY1vm+D% z^c&|ehGLK2WFp1Y@dp>}_7t=Fo#)53L*sURz-V%l<=I+w4xGL-_in*?g{(B{HR6!a zE=*?7vNO&3T!Q#E;B6ew3_U^uJWj)+#s z`a^v1E`9j2l1HF>F^I&!@27g%t0Thb zNXY!&j8)t`9P!UPyz3oxw@=PNaRb$Ak4by%c`vVSw0L(yFSe&gg11nN9NU0{YUsqP9&MsP@KN;>SWkF(ti5`0JaSv7akLbaHg&KBl0y8EU z(4#Z~)*=aBbB;b+I2S*oWZAjY4*nXwf>yJhvu`hB(m&p^!_Vi1wb?mu2#!gq-F3o* z-PRgE7(PytfdcrHqjP?+r%8KqKU_M#h zFdmLf$}jdr#&X03kQ3eV=K~wW?v8|48Wy!q;elD-XZt9bB@TSF2sje=BPVH z&{k8m>ux^kjd_o6y#&p8NrS%M#yRPKA{`Cb-lFj7u`Eh*-QTilDl(@2osZ7olwXK6 z^jZnOWiW4&2{fT4>LG*={DCmVo6n&AVqG-|(?GYv0MB&A|A&nw7RMKKMgX~R{qml$ z)Q6{Cjk*~1V9h~^I7jsjM{_oeq!ZxD*!Q%h`LrBJ-7y-_yVLh=7c;e%EGQ3UG<>&> z4%!3~U&XHg^dz$Lmm60-JSNz=aFqd@0AAb_Tf|9Ve`3V-v~byTwB6oE>TgUZOMgRO z#v9-<4(sIJ&jnyjVywAIZ2r7UVXSi3^I#4)UG|Y+Ri-yfy8=0S|MZ$dunR(aHf|Z2 zg06bx%>0;hh{4}Q?e6mXxLCm%q-+T}yxvLd?Fv6gr>U_e$!8xn9#cb-TNWZ8PWOm^ zZ~F5*X!IbHbVtVUr80JiGYTifHK>X%F42JEfRh*ertF%E>O|2{fV*1AV=^Ca#;=5W z7UgITIyS^Hj8Di1 zo{ao{sChvBzAO7HEd16kDdc8<#dj>Ai*FAd>+K_tONFTad zkVaO+xYOCZu+PovTjzh6WtVd<(W{F|r=o&eqlOzDA;huq{CkZ1Uwn|kH|ip`9R)%} zux#Q#WEVKJHJGhX11x0@7bje zbsu|vI{NJ+V4v*80fK2QdVf8T!qqFd5q5+1jtIWwdWBB^vnGMJWjqW!a33vG^ViIo z&~qD2*Urb+Ar;p?a!#kxWLmhbp-iitcA3=U-YLCn>p3;!eIiYt+0qmHu1?DLWi(>v zq$-F(U*nMZTl8heUVqMIc+e_(zL&yBTSVX{BV_!JB%7N7hC9taQq)XEg^3ms_TPe# z$Uub{7DfSXuq?Yg+i*)DR-6^Ik3Hnu{dUpKI)7!t&lg{1ozv@pe(#~6V05Kj3GMvhtl~-P8q+HqbRg%>l=o(`yHr=v=4%c3dIa9UQ z#e+%fH(ddxuw(j`MM%SgLQA7)I5zMN(+zY10>wAZgUjEr5QZnjL~ZC?(X0MA-RzZJ z8d6nF3}j1HceXA6PKEEXew01yB4n1ndQ#?*rWfh&5kky8dc5SGGU%`^vc9i1d|&4F z_5a2fxG)d&ylId)pDb^40RnB{k$=F+x^V|^LuLRxB(=G^SR?n9m)HCYR^vD!1e$i; z+ypSBgt2@6imu-a2umKG&=iq*#l0P;`Tf+zDN&Lj-oeAjlf$Ru{E4-hQ>_*pmiAb~ z7FM_l=JJrjLxRl;Gr^L0aJng3OhI{ljS{uRj8+u@vy>{?MLVV+60pC65ICdk+Er;U zR>61~zyN1z zky%SVxE}^~tKEOUHg~FdZ~~0Y$cDE3Oo_4&)wWfv>FTlwCCxsS5l#KcPwiP%)-hD1 z3tNQ$GZln4Mv)s7gU$UDnE(PE+8Gk_pCBF!Hk90SaFY%nd=3pe7wXt?B1C~5h$7$S z__F&vk5g+Ox2`m)ZE+Ybwbe$63eE-Ae!uX&8C(wtB;?Tg<)qsgW@JATqNZ>DIql1M zh}VbpPRn)xtwW>9Ga?0VISq?O1T3Ci@$>sLPxdSc&xwnYNNy)3 zA@$g-Q@FbquS*F;EeLAEvGhW(u>>kCozp*0pW>XF<-W=xc@_XO?*ii4sL+SQWj&hk z1P}*Ba>b)kv`o;$p-CR!K7iceP$oZZnDD@m3fK^8!io2vmVi!;2zIc-oH}5oz*vY@ zKWoD0=IMdhqT5B2ytI4XZAHNLPXWqYTYUG2e8s2Z{+_Gwrhx+!fZF0!DiHzkxZV**64GJvy*kNjAk&e5&i;ai(H>aF4KvZ+RhCNGp^ZhHN zqX@KLL`&7>){J9;h~KBDk`ebHde%>~E@C3?EhVG}%Q4?hxhwUZu5JC-zCr$?@_n`0 zyp|DP>*0IiGnb~=Dk6jr3uam=%#F@~eYXg)@_3NNk(?7*3!j|<2#k4ah~4fYP;Bh& zc(i>+c>S%1E!#ld%UH%}>@dk9v`#610B2U3mjOjBE(^{VSLOj-fxy!j9}^}q7)%N) zP>~}*iD73-vYu7n4rq@VUh?o>O?52Gs;hss=Q6vx=5PCshV|ZXh}N*q6R73+rUXL1 z1W^5;DKzE)YUK%DjLY9E@ec>weFPp8vEqNFJbd@WNwY=UxXc?(0w!2L28OC&Qg}A3x5rM=+{LtIZ%MX^Jg)zu#4@SYD&;X>h0zPu9#U1RS9pu5 zN3mP9xhP3#qoVa0COz1+@TYhXl72zL;#DjF@hscOBl^oEiy^fR(cM69)tM^~?<>C$ z5~?qEASr6U{?+f2iU9z1WIMN^V!z42diShv={!M;HegQOMUHujNzYfrP{$lY)7s0U zT8?qg7_g^ zlGkd_pl*e3$d)UvD*+>!u^m3GEuDW1j|VS0%2bLSnuLc>h3u#HDoKT95QTkNd@y$@U-4cx_a(pLb3C2MAj^)F zRxh6;FD9EWkWUxEz&+k3cf|4TFw(qX;`Bl3#3ZdgX;{hJm0Elh3-pCOsK{1Bg#Bmi?(ASTJ(&CxGn0x!QCrd%+O>?|Dqx_FvU!8SH9hT)R?3xo{ z?ID|}ciKti(dzkXG7{)%?u~KJGe73+P%0Zu&-?xecPGLUX|GPRb@aQd@0m%K)x4z} z{m%5)bvHItPT03fNAsB<(>2ik*D)jPa8zGd8wKiEk1?hNTx&$4>>~Z&MlaVDpx-T| z1|=9&;e=q25>nKN1teeScg_yab{~_t9!M-_C@ed;1TLEck*IRM%pU=I7tD;jdo@@6 zv|#dT1Dww|W5l6eSF~m{`i9Ct1jh9J@E!{q&swUpfNJ=>)%oViD}|3Mv=5At&)yh) z7Tf&&cN6h&;AV?0^O$KUSBD*@&$Z1as4wcWo$X~~+2`1OR*40|?2ETvhrrxmd zIPT}~7);9b)P02G{&pm^0x{q>abhI}Op~2u$pNM%7}YvV1o&Etsah-G&ik04;JrXP z(!nU`a+#w+*0K{!A+LqYn*OzVcVy6Dqyz>Bucp*E(6=>w5S>$-xofiQ;IxZAw#1}b zZxk%bX~pGXWepVCJKQPUWQ9{XCw!V=LexG(&aaS+$+1jPqy!0! zS~sa-v3Z9{r*Cf&&B};Pa{1yyUD*rK*wh*!U29+qz3=c7SAvcaNB-;PFSp257ILcH ziB8z-j2Lo8S-$&`Y*XnmC)pu%0?7EBK9m3>!%z)%XsD&X9JJyde+>TUTkpo{CCp!?pszAEcsG98$O*} z4pT~r+Nnw1W7uhkY?$wYyiMA|C_+co{&d@FzT0C_Y4-BIeaD|BHFm;ZRVZ2bsjGWx zFN1a_TyC!gfI>LEa%bh!YY!%+&E<6smJ8q7n0*8|hmB@nmO?wBCzFvQ!h`fdPVaTF zh{HjRHVSx%Frng!;C~4R5$0>KDj7J0>j*^hT45y2)Aj@u;Xgi0TkyGAHmp&D^obm4 zzXY5Bw~1YP8&L8=#V?$;@Oy6nYYf}sC*u$gk%TAXoBA{PS$=D$ZN>0Gb{Z$6J^{zD zaKLpv_0%%faF>lwu~i>PNsI6IUnkJ-;xEJI=Ud|IcECWb9z-_4G$1VVsq<_$$t?QC zKM^WdAOnUy$ziA3>pDD9evVfqbgq-m##U0ev~s1l@1XGj*=#6@%&RP(>_;)1i2@}u zxY1sv30#r_j+rn8yYImGbk-}^&Er`h&i?FW8-Pd&J&o08hNb=^2nhF+#Q3<|p@h^u zz*s2!?z{0TTa?i|s9L2e5WS>8x%BMqb@kHja<53;%Vfm*bQC5YBy92N9E0}0(c15$ z)ac_;^Je3Lp-&`cmO2>k{`;mKKXK*OVMSnZz>7kHr>+FD|2RHZRrw6h#j-;aGo}*^YKXIj#0%jTEqvM-1}icKtzd0kgn?X#4sM5bR0YYK`mE6GVg98`}YLXQUTSAsGz- z*lgqBrQKZ#pKf!1OB;UTGQe4uD0rUU5%Ib2ZD4h=KG)CL+1z$kUH-#ZJuK%>sqN14 zxDm{PY4Ki12-c@G zp28Dh9FDEI^I&K!2?@V08jPNn*UJL~qyB;#1#v4>`Q@l~*Su|d&o7>`r*E7x5)oE= zgod&tkkVVfUz?mxwE|}fnfB2JY6Y}TSQigei5(5>g03oY;|9gCiGjy~fiHYuyTMrE zstyZ2B5Vj)2xvlw12%U4^K&v_B7}*XV&F@%^lEEz<@%g98w+op`9t@1cV`>w7$0z< zD*u^!TQk1s1|8+&c%MFjnVMZ8J(qcGpjco` zgH!6}ND}9B%8KXDN30Npe)v&KPnML)b~9k3Ud4$tl3bZS z`KjyBcg`%XL60v4J`H&gq&^>AvUQcctb4R~6Ja$VUhJ6oKUF(cC@_rYlOVvw9TLuP2$-Xh14~PX z>AkP-ww7cy3}zlYGBCLGD!ZrgUOO7I+d<`>%F0YaOBJ;(FL3$>>32{5ZnNREhc&+z z7eGnj0kI#=*XaSA05@&V>>N&)>uHAogRYzR4#X?ZzX8Sgd3}ukM+GAN_noP{Sd?8xfN`GT00Uw#Cz_fh*wO4E;eOMBbO?>UpmH z&8J9;qK%O#3z2P010VgzVQ_tG8(V+hl$-0{>$jQ%W;FNujZclMMDg8qU%?Ky;GMn? zSwB4DrQNl#V)*VQRVkeg6uhJZx5K;3NMpk~y)-(0`2L*8*kI=Cmee=$nw>fuqNqnR zhxw3OK@!nr?JL6uG;svSMU%Ah%+8|*`do~^T44?bAqU!(wDN16afQY9<0teC5&yND zYmjMhGlN~*qF|;UJOD$Az;)d;;IG;o|FFLm8N?#Zk;?o4xuuiGAZAq z9&SK`zh2oE*+YgX{HF!}S4~Sii&TC@5@q3YDxmi1e7koU68&#+w$Qz0pNxENrgESY zt;@0uLb!CfOA$c^s)%ECkdAD!kXB;IXUNanvIQ92&LUSeOM5#dU*t>)U+t#k*8@mq zY`xTXDyBXq@(TKMy)nk>^~EI+MM-y`-c#VFb#Rr48vQ}l0QaH@x`F0Ex2-bZWqQcD z5{$_p!9atNB^B@>haab9i_+G;*>n*Em-ReU_bTxvOLlAH@*aG3%o8jViQc%qYKvoSTudRP**;P+n!kgwDgGUyA16k+m-5>umN zS1Nwxqv(KX67&#yLWxYJ(TmSv&Nq8SV`*POfq)c(Vg0!*c>e{1OID@y!MSg4Qbc&M zOr;&r4hf>8#EvY;DW6~-{KnzxLAd^bKggyZrv()2)|__vZI^PWd}3$0TE)f#Lf6huLQTc8T`` zHrW{n6>PX?liLnhH?FV1b8@Kt)LDtc!fhAh+<^Ss%znTd=$rno{p6!4p!%G8IAhMA zyUe|M(Xsczf#6pmW!CZ8qo1n0oo>n=CyOtnnO!UwhDEVUawH1cQta&R>Ix8BESmYR zr3(z^fr(>oMD#Fv?T)#LFWUJJZND=5^a|6Lmvx%>_JkY^OH{Tm4BLD4k>75BQ%i46 zJ$j%mchBv(o;TdEeyxp!^sn2y(0mPlSh_B9@}VhS9uNw(yNAU zx=Gyt!(1B3s`O3Vt;p14_h_`8pSZTvC)>-FG5n%EfH}%4QfSGn@KjCkgh#o~Gnz&G zH1ce*V5h50jwzcBH5Uc7hvJyiSCa@+(ZB!m;O3&4;D#UQFnX;`pM70#hCN1qLk&!Q zO|6t5ut&=ih%cPXgCxQ@ec^M@cC)a4a^jQC@1VLX@3!KUgjG=z0idWrI&;2A;xF~w zJsUDUuS+1|iCDMhi?>(1J(kKXu=;@KvBT8g8weS%_{-^<;CTb2V!7D+Ww(TjQj9wv z@*edg%nO)prgK%vHvPPrqplDs$GRhnbng3D9dbu*(Y5W-8;cNUF;DFAqg?hZihc9{ zYOnFca>oBRyEUz^(yoJL*kAy2F+Gz7_VEPI-CY_*iOL#F?I%)@3&UodpU()^dTXuz zX2q%g-6LNLy*$0n=ElK$`y^Sg*8Crhc(U8_x9iVFd%_Dr(1fcTotM17rla;7oDu0p3W?a&xON~#=ctw2E|763o zYxnYz=dpL>>nZa?&kvqv{Yf^o;Srl!t1k@8`x}cRFAmU2h-KhAK4MJSbwe3tt_!q6 z5Nplw>^t%Ch##syfa@sO!cG=Yy8p*@8&;GO8;Djd_uW+B~yl zug&MD2ydY$oZ(2oCp&ox2%N5hH8fC8`|RJ@CoSRWtXC2UY8)v+3yi&CdvH_}0wbh`G)Q^4CqDPY>?3Tx zM-IPdgj$%^Fpwjck+9^=_-gPnl|BH` z-`pFqif-h=NeV@H%anW`Y9K&q9;eIJ~ND~MzTt>Q++`$d!(uc zt*+V-V#4D?Afd)N#%)uCZmbb26lDicIBTBS0B1jg&mbFY&w*EmCQRkl5ecqy$?uai zYxVOThdKN6y$GwXO(A^OuDlE4w?Ai*Gz4CESc5!!Yv@w7zKav>oCKs&_3WBpN-B*w z8@5@8O%qwo=lQVplZeb2=5QO|Mslsx$aP$@$b!@uBq*-fpVSM!C&U42ftrH&zxYKE8#;CB0tY^nyv@cg<&ZJ`7DNz8SFT|9z{aV&nKtl^+j1RYVo|oL&r;NyJ5L?? z&}aP)HV!vDd|>5wW8p7vqQPy{SFy!!RA*=_GjRhH3O54mI89$FIFe!Lf>*?EFI1RS znu9m=5$5H-eaMLRu;=rnIRsy{t@-OIWyJeleZNTzH2pOs>yDWl{5TZz;|4%V}&R;=$kA9mxN~*gtk>)^=^QXl%P;+jhma zZKq;86+5Zewr!_k+pgGlu6^ClyW0M`)=!vi&Us>tWAu&&#Hvy%Y16VEmDZjgv=cA@ zeZbz;BPG!a{gERWCmy5xHFnM%7Rd8SUQSKvQ|(t_U--?xzp8EW2-KRU)M_B04Ff0*2oND4V#X}sDqF9?%H!Mv za}y2HEdwsisb zOlZ=1d7iw#mAUG{nv0asR7EhVpQa7`4SMrIGM3ERPM)}S{R5tVp7nzO0lrYg9R2>D zU_kH4%ZPTw2s{R5a%U|Ex=Qm;c}!!xZY}Hb&BZ#s!ltWg0(CrbTUJd|dxQ9i!?C;< z+9|=XEPZIJ)5k0Fvu9@GrR1(pRR{Is2A2B)yJ0;8r*Kr;#61MddANN~;n5)^0daKS zt~0C=*b@9;LdTcDrIv_I?jOYB71GqU+Hog;oO1b~;1r?0A~0C8VDZTCmFR3h_b4&d zQPNOYZ3JZ44O31)TB$f z#zY-ZQ%w(^-(QiOk;RR+NpL5PYJY3ixjC>4Q4j4n)tV=khMTD|L*D_T-WL^pU3BN6 zeu2={7zBqVtk}_Q4F{%J>)2-R{x0#5KPi0HMp-8R?>fa|W;z|AwQ@ z_=?PkrawvR+;<+QpKbLw>&L8T8PB%W-!K|sgz8??772xVw{+{UoUT z)@Ie~=k^?8$?6Ta9wsHSRyMVdwEyby+Fohe)^d-GEqH*%Ufb+gdCo>Gn)_FWYUd7@ z+58m>d-zSJqwxhOgx+!e~K!Il8>78aR zu_@rGn7p_}pmEB7*7HR9!@lvzd*B*&xg-Q)nH%gBYC_0eCBs3Ns*i)W6d~ege;g<&P$|S&xvTC%sr=7a;+rS7xhGw(+)X>V)N;PgeLfFV zsdZamE}f1w=NG}hA`%^|v*X%y;0SuneFXVz0@9siWnK1M5?ill>h3JpMCch*7&b9j zt=V(-*UoHSXE)6#B9powc{K{^I!MCbQ(T6mspn% zMm`Q2C1)hUq%2^f6uOD@u$h-}?>EF|sJSi;i(2!1OvzLgknr0V>H==-tK4^Gx_l#U z>&}l3dF~H_%I#G_&IE2M*0rjH*EH=J3m%L2)pz^bv#Kc|3BZX2&?)E$IMC-nAetRG z-Ip$(T%dA(l%n>GrL63RqqFPEmIkMe=7L|-D`T!6Q2q_vcV zDhUAsp1&U>OLcJnYdNNw!DTW|7r!3}hzFx$1Sr(?;hsi*|U-a0N)pqfo;5WWrbauGgHZI@0Or7{EE8NiaX)8a> zCjzSS-R@0-3m)R@A5?QV{_ly6_=SE!Z-7xwNib`Zf*s&?6Q4@rtERXhtg1-HrDaYr zMrGUkSZiWAIOsl1k7psaG1kWUmW@FFayXhQb1>FD2sf7<#(FnXXDRAzN>TS(Y^?lCz*V0jrjG9a->>#b6yskLt zU&jcKQaz6qNTmr{q({Z^*Rz*HDy2ThZ!p|+5K`C-S~;)kKk5>t(DZ0hs#?dLFz)MU z23j-gJC50>2KCzkd!}c8`4H4+mF(@;;d_R=x(WR6f?P( zNd#fAB~kGI+n5I}QG*p`!pCcxr!#ic74TwC3>s6n!DvJi8Li_Imn_fo@Z;&)#?E;1 zokx;c-hws^MA;REjgzBZ-=cg3$8WV~+&|i8vaOos)@WQElyCC>##~o|1vTOgG=e4u zAxuEQvKFxj!IL^D4Ob8WRu>!AEChmwVV`pTyzp7#4;!fYaS9Te;vRhscHv|Ap;mF` zqJ^v4I-->k>tm>rH#z7d(m+bjB7VpUxZs4CMy%hT$DfkrJHyYDybgEO+LW#@>2>p2 zrk{??-Hsn+RoQ=@8L0jf+{WCgWs{fHuhX)oJD-`an`l-cxflh7r${&*5R&-=(>599Pz?#4ZZHDcM%l(xKMf#6F<=)DwI=5K))@*;MXh8InuIZFh zeR(tE?ZqoF(xG?WOp-crk>B7FF7RneO1fVzRaVAoVXz&UK5Ux+9=6*X_C58SDV2QV zy=ByPkwYzNHo$Sx0;m`hN9{fpgx+P}QLnenfk`d25$5-<8%)fi=5r=sRh`cCF{!|f zv*AR|;TN9SV&JjO_Q&+*-CYvmL{Zfr4~*0{k80vm81T1|Q7wrWY{GbUH(zD^{+l6Z zQ7V%TI(!440{z=T;QKSSFfdEkFoLKVB$EwhM?r!Nd(hM1Y3l7%ViM)Rjyv8Tqw| zM7^A0&an9KIFfa!PO%{ow+f|s%|Ms#+k^-jA(+5>R}Y%ARCh&s$O227^~iCcvxYfFDL18~Aw$%}??wr%|G4_Ial-BOt# z6lc&h-x>tIrF(z79=G`?`cUFS`M(~4ZA%EwY&{#+s`f5DZqS6SK) z1`3-L<;4r|z5~>%xbW>*I?~e(NSk~l4cLO-kfJiY9BQw-+(Emc5|EVOK#lmA@q~b< zoParZW0s(4+0b!!0;971a-L0^yJX{DyPPUTw`55f@e1@CDOu?DbefZ8Q=c6ygBMfH z;)#hC+7#MBbJGW^?@d9$^`5u7&GAKAKsRtE(H#v-T8)%g0G3zNb>7V5L3TG#`Q~v# zwz@!$zLzjK`LVu4NrVv+ZOno9L{fGXaV5_P zsdlEKg(dW8E~B^qP0R?}#HglM%Jd({EiuUd6i|BlBVpSK-#aaube`twpxxc^2^Nrj z$x?;EvgY#<)5%hLI1(lm&KEOs*OGqp{@-O&Et`8KbXkfnKew_XHs=fHSJEPxleH~d z4kNaLouIBj`h=Y+$f5A09A0+gs=1Lx3Me$wZxKBbD~uy1G~du;k9EhfvaZb;mL?03 z-I4j8k@a{mLZEE%Omxu6{F_MYNLdp@G@q8;pxKV{%BFIDyuM<2GyZzt(;5tF`hUj7 zP=J>loErT03fWTckL#r0YrjisktT+Mwx7 zP2OOWPxls|rKzKZ`=wyn&FkyQELRt08%@D#j(E)Z`BFdMx1}I2H4QmaYAZZsBR?8G^EbOsMp)>4AK68IjRnFYnGqAmE ziiEKGlr5IfVoE5q^AryXIL61P(5hK6>^q*kECggcd!zhbYps<=4ZfR7ZuyFC8);NjF{ zr$yveqVNckse)QXhYxlB?HlY^IwY7{6emVV-vrJ@UjxM5(=^B05t1)ijx?3MMHkb? znavmGkkz+fU8gArTQ8$m`DI>+4tDDJ3}xBL#rC4#^JMt`1m(@@;hG-^ABYl?5IwXb z(i}lP%tBw^Cjs@ZxeV71O<%{K`?n2#crVLw^?+TsslF8e$LP-_O?Nwulp)Cdo|W`Q zvF3)6_Gc%0*CUnba6ZB7&ZJZA-O`~qxAT7b+lPGn(vPFddny6nLDc87InhkyXf7VVS`nkb>SWcTW)Go~CG}KM&zE74uPMu$b)|SNop4Hpk zT}ihp8sb8$=v}pKa^D~}S1OMVBDBkM@B&bs&95%MGYWW~mD)f^8fR3(0*BXRD3&O* zlNp$%mOP5Y22Np?cBr0{LgVT@wJjN|1`sp9SVgv`FSzwAx;f>Q$bURC7b4M=M7WC6 zxBYwdO`%Z4H^8i;r}DGxljt$oZ|LOTZm$dS&U3Oc+{35+#K8HV5eJAU%oNT#{{K?d z&Dm%q235Xid0+8dfYulKBRm<`ma*Wrr6&>DEZQkvbflK;KSFL5;kd|!(i7hE4{vZb zqgS%e(U4Qc2);#N_H*wP$ltO_GN5 zhZy|eT@^*ekH;L6V z*xV0;CJYoER<3Z7NZ$z_J#lS;RCi2TUvzMd_g}9?NM{QbZzs;dozFQcZ>6(;7qDz) zN?EErZrsf+gJsK($X~tL^LCb5_DooLQ{AIaoD#PAN}XzB|3u4r`nh*1c=@yBg7hx; zsTR80wSPwJNfUmlVCdg-L;SV5)3_1)-=PIuPF{?UAV(52&tTPz@KXVmZ>$qEw|5UO{U%ZOzX9|dHXZhWr(!+8TPDNUzYB4y#~#U?2+LMPg*+Tn|1${88uqrNd09>0k?%MX-KtaP7R-6 zZET3cx`)jcb7oRwEsT5V2gWPhKhga3!usW61^QG3Z=)H6txU8F|ibpnkC1q)Ob98;9 zr;#QX9nf}vi;alaNM)B>m6ZBjq`z4ir^c~RyptX@@V8g--}v3?z@fO*a52Ln8LRZF zLsIq4$fko@`rnw2+eUJrL9#h0LRwFy_;5eOUw0lm3R`)A+FcGJpH^FjI|R00`26cw zkfES->r9S43J*gi)L3a!2%2^t21oa-|2ATUHCOP1qRd(vmGds7pIBG110}TBq!Rm- z!dy(OHU>mf%2;pnS7cU=V>4t@JAb!0?fHJ-KFFhyKsvG*xDs?FXg4UFhb z?68DYL%jBPG3yP^y#P(x!YuD*j?q)hP)c=dQ!`C2VSI(KS0{a!@`v>Wo8A83t|sg# z_N+#;WvS?Q9f(aIS^Wx%lDIy`pgm7?sQe3?lH!GM-y+S>$gu?zIjd3(lrn4~WyRD5 z1o74qwX{*Ux}(abD~d5^Pp(*{Io~!^jytEJIMe&;F`Rw$ zQ~dyGt69I#wt%g=YSL@UAT#wS^sjIyFUzT-)mKuN@n}_ZO!RA8b@NJje5d|csp*r| z3_>8*IAR3}aerNkv`E4^n?*00caBSOA*C3IhtXrfGX0^#XQn0-iiFSL!bgX2qVmw~ za@ou_Z*`=@fnDd^{p91FHEFq>F+%+^NOCj=i`==_#@r2KD?er2%*28hwBpoFFB2mw z#0vgD{VHPM9#}tWX@KlETrwrQHVH%t>zI!FTUK^ z%Qm$8{xEhyMWU+N4}tySWkJ=9z|!`NfX&Me*+n9L7QEzFT@nvTx}|ZL$IV}NppoZX z@>EG!;s1A~Msfa-XmI1WRo4O5P&6VQr=)DywIRKfhkXCy$-bPAQSvDZALpA70kQ|a z2A&Trd(FYHWGpi?54tc{U3CmQ+bNf@Y_#uSA>74Ai_3 zhL)wSHUpa23Q~xYcz?5Z`maCi)AZp9pm+tNm(B9fGY>?uA)9yf8%f2UiV$Ud*|o{xZJ3&icbz9Yi9puZ*%*Gyqc`BiZ+{0On0sF=?`-rjT{f`DP==iC4u0prX@?9~59U)}l-QXUkdlnZ(7*s&EZl9_Ewj%+bY$!=_|9p20P z%$wZ3e^jEWI$CY#t2x_6QzBp+3||Jx<2*H-^7SzePDfbnC1Bs>e-LHSO%t^G7!-b8 zlVT|*xUc^K#`yI~DGG})Q5+=@u)bDqlBIA;k}QG`fy-DZN{)&$+3OQBk+#Q%dQDN_ z@|R)M6Vg2O-+PE1I=2%ECYsP8m!f~B2J={2!Y=#g*HGHryo+leA(S<*HP#PJJd!zp z1JcLz9w>=%et$YM77#c4_csgi|LiCGLgh-ofM9z)Ynk!nly*<^ zGeUm;l>&VMkK!%hmi@8uh)fm&#+jdSH4Oj^2wTbFU_!=&8s%#-Qvk<%X#G;?qKC8% zT(Z)1R|WK{W^j|mF!}0wXHKFe8{=y|UUOym+?(BTq2vv@*A0p2Qi<$0?+@RS0-f_X z7U{nDUS4rrudF8+kiObE^q_tI?N(Gftu78VtFqDIXXd39uEPJ|=vUIut1DaM?aGo= zb(6cU(v{1oc~AIDBnm83k@LT7teDNOMWMgEhjMwLVs(QZZFTQ>R@ zLMVR5v{+gNapzA>E%-w6@tF#p)l0EuXHUQRiu=2g?|{0C&3H2a20tAxj;G%EUu}du z+^RfZOT+Iv8W5Be=$GBEzHdQrQRDt}D_}k}>bFt;5+ycJ2opp?96^a)H5>PoGIH%8 zm&qZw$b{~!J{9co?U#Pi7xR&!;W~R`IfEq8Q#%8=Shf^Od)xg0oN_$<4F69mCX7H*(<-Z2Rc`vBM%%u7HdBM@d142;8Sk5R(G1_c>& zOOaxtM!t0)dR29+Et@YjT9mOC?-XiO+xq8bBJ4Ij99@4*Ki}+LJACC~OKi~s*q)B+ z6sA7}Qx((donJ3r+}robdk<2Es@`W-$_#G;W`860tIXG^NWX0-RK-Ei1-O4>mInI) zD#PEa?#0S1%ph2VexkfkqoP>=e(tJX_A%j{$tys_nC~5b?q*@Hh+ezXg&PFm-A=EK z^^A}!ih$N5hhZWbmZn3*$b2h5TEdO6mK^0Qw3l$$5qJ0zC;eO~(P~4|AW^2i7Aiam zQ2&QnT~l*O491%Oy$f7EhLnD>OW#;UDFevzxSxaWpm6~#w zry+?CJ4?vk!#;98zK#za8Ge(2*~K2atATWImp2WZk2Q8DTOV1Op5XPj|S+GKr&oj+T!Zz zeeIQj2l8eo0i!7aAMg3BTqOgcg4<@%(LM6nk3%j>h?R4$ch6SvzSGof(63|R6ZzGZ zGyE)Jz|}nvg}n@Ns7a8LAGuCsdHFhTLZSf~7YrN5~B!w>xaCTkEo zt_dKmvO7>f^7nfzg+DIHeBoCp3GztnXrnNmd%bCZQIK@?D`wG-IYdd?~>#!~)ww;)|Cbq7jt#C_>$oJ!(%#Zsigt^2+-hV$5nbErqQrt&mdcFBi*2IJ4zuPb9d zvjPcHVd-50aA>|v>%L=-DTra3Q$$n6niOiu~h`fFv9IxYH(_p4N_Q&>wKF|H>9!?2kY{?pcmYdswZ&0)`~(s z6fQQcRzNY7tp>z{aot)LXXMlUuly%915a#q zGuUOBAs!LQ9v@4*P)b;%=)GhHSO&*5k2}q?wcCbg4qH%G;kCuV*xf%uqJIK=lErPS z+=Vy$5$?ON>|9O5JI(51@(8Z3ui)BDAv?pRKsTKHwIa@ZvLOHXW-u!tPjx|1(8=A%_$gM7es!VFu z>C`?7B15AwqA!U_%FGagEXA&QTl1Jvfn06}8D3@lEY!Aur42FdnGfk-gP{etVny|+ z{Q2_@qz>CFjIEst+`3lKzWEt4&tKdhUVjj>?Z6YB^BIZ z|MqA{41QxgotwsPb00e$G2;F#`e;9PO4C2!l&zePxt~i^ZBJr|EH$Zm)hym#fk;>f zNB>QQ6D=b?yJWYL{I(MMN76ORQ6sX5|8Z$uw>>bygxsX*2ue)4TGkPta-19;glb8S zIoK{X(NH!!S!eBKD0e@7xVm#)U)#Elr=>A8--1H58kwu7GF*p}{5M#WZ4*yZAT*kXeEQLWv+5@v=|upFA!`AAq_$h$34d92!}HycO#C- zkb2sPI(;1mXkCL|k%E9?5a@bnA*2KXVqOr}z_2C-bS_%C+6PTK_E$73PMzKvm)mWY zxkXoOuj+a})|sq>tnc5UTxG`S*6AM}?IBnBd>CCa_bmc)ZqQXbR5ZUdLwyi+NUwAf; zm*sifL9qIZPe*U`mrhC84t3yNcpNdm@MnXNMA8>vV7&-65gV;tZ>|K*cgnW?thUnq z?HjEUJI^tyPKq^X|6iIc0@6Hte-6M&gy0MMcstbOG zkqM^f%uk$iEtC3hCX#Mhf@e`Vbsb2C7A^QRoSNs-nPx+6AE|C|j7v+rZ%gW|PG5a% z+j+t|qxy!GXWrz^W$`=F+^4&<;Pz^xH*)3H%X!yQt~JtUY+{#iY~?8{E<{BYBHeF$ z3ogX)X|jTl-P1q$F_(;-b1YG-v5Bgobl|5Nrb`@Dx=glMu2*6m(`u9}IegEl$xul2 zHUvEEdO;=SKcU9+S`UUTtlG5gw`rD z*=RW??MF>?DE>T70`53uK0UJ#JgkOkg3=nZ3wB(@0r~$^X#u8Cr*Ij7v8?5-#-ue{ zTw9oIeUV&&uMeqVKE|(`7msW@PyF*6)B5Jy^kcckmc$Q9T?!J!ZqZ6EF6Nlp5%9t05J&U^A;#QD6mdYt{I4F4=GAUbU1Q?l3m zvrBmMA@A5RWu=uTy_h+E+k~Oa1ACCMFN2z$&rR?1`ht-X?a`6D1uIl-WGZt@Ai^E( zU<}?WRIOMtXhoFQIU+$Y_|S*Y`Jys*d-%&2EZ;PXNUXpQ*N}GhsXC49xx|Wn-6h8% zxyqikgT7_^+TPy|Fz3H}>AeIfW?MM6=*xSbsD}=_gPSEIMa?@7F_w3i`W;O}MvPGE zvPc{|gHPv8U9E!nL!1N(B?Tp2e|0egn{n!Lffz(EWJa4lN%SGV!yk36A`^>ockY}EHGVa zxwOc9QyV`BK4ou|iDhXUw>42r0^`Ir5@!4gW(_y+ad-rj5 zewyW9NiR6;&t<%7^x+gnbbPk_&gWePpm3koqWF}Nw_E|T#q+yT%exK|34}-Nzus%o zF%YrZn}NK9xRV0VwoMTC4IrN2Z=~-^LXe`f4CJ0fzM2jaq_ATa*^m!G)-q=~Nv~k{C8#1c__JMk)<$ZEDm)nD90#A$LE&vGNv#_0OG8%yf3+MwPt|m*1s^dRWQ# zj4vHD@(k|e zwrA&S^viH`{g;g!E8tr0*(SFxn+)0N*y00%|4;mL({q1kR|o7VD|JuZxcJsKG1*Mh zAGAV63~duIFyS|++n(Yb1%KLc=hXBJ$~>N~@_GHX9-BNkhO!&^MOpeR_5tMpUp35B zEPUB!P+~d6@ENB-c+?4h-c8<=Z0i2GnNvOpy}`5~QWqhSL@N-QeJR|%D1`s(j{etw zn#Pe==CL^%EP3Q$?o~ARDbsh90zL0quH3v}TA=eyfQNQx0-H^w0NGwHWOgUZ5 z8mZnIru7}6JF=2#H&xh@PE~Wgtq(?V9|do;{UqDK_4(Z39N(5uo9VJi_qo?BJ8RVE z_mYpt<3zK-)^nAGL+5j;6a08_Jkg#uj~7b|rb{XK754`DY;Vv_oxo%X<=i4<7A*Wj z(m>Q$HWk#S2a-dxC-(^jM+^#z8b!j{ihf4b;=+6{X@+t3Gl1HkY-R`|%YdORb|qnF zI>z#X?lj^ciK~h=RM5|zZVlWDNeCYF1Qdk$|6*plF-?etK*}JWGvr|zx;6mv$3B`QlY~mF?fT~)72}o z%S^tV5?6^EE!!8F4w2XnzN>Y99gzTds>HwFlf?YRPPU%uW&c`(HXCIzT2DH3lg zB|EwT`7E_(870f|%qgUIS>}IR^rjc0!&ED$r)*$PIenNR&YPT`V*QhjeI&wn!Omnhc{gNyG9ix;R zH_3?v?UyA<*=iagW=;H7u89GL=+kxL?BuCj*!p~ZwjEb1zq_{m4H__tB3J-X0qQ}Y z<7?|%vX_$=35A0wp}%UmI?Xe?8j7wfeMkDIbFOIuJ{pS*-tH+jHC++WuM$d0UhSzp zeKV0K)YSkEF4nJ7KqDQ)iW#IfLQFGVsK0@E!tIDQx@2bi_jxem7K`#FZ$(0{1JD|F#L#5JnV4F1h}CkMa-0^4pIeC3<(L1&3*!t7^7fk5&s)bX;kx;ouFFkX zb+leuo))M3W;ZaOX1Nf5-Ygz^@GJqXZ#5cxe@rFQZncTd7Z*4J*u1zgARda$X`v|3K~>Z36ohIl6~$> z-UteLR20mVGBLFuG(UbGCUKZ?s&n}RCEz#y|16Q2l>hG$j2c5ElMSW(IP=CF7EDO2 z&IMa?YTNoms~>-ZShW+!mHi{=Zc3$p@Jr_J&%-}`%Kdz|z#Irk?V1uM=~}|n`Uf&# zKdu;^ZvAnX@V;ekF-JwfwOfKX==B0OrmMUDiAQC$hwXtk&$~=QM3VnQ=uA--O87C`mw$)y*Fcdfrwvq{k|Ru+T8;_5tZCP6Nm3V&cQwq`6?qd; zK`AQnY_~myj?w}Sbwl#sYf<*@o;R6~M97`|7flZ7M7N@5qew?|;H)?Wd6)YhLh&2x$@Sa04eP-j!U%Fr0af?+D z;mf_nCUj7hRW9acFrc>e1YLK5f1PxZn%}Oe!`#mbgO=sB!l83{gK+4TmJ^vMZk*|E zFfcx|B0E7ZxGO+|=sQe>{>VOUoduG>9lfvpP%bFeb+Nby#aSX&qxlcDXGW}Lg@ua{ z^cxLDEDROC=VaL>ug=Y9<*8;Rxr0`tGS|I=8gu0&Ja4uub?70`Ri`_NlgOd*16jfQ zXkBmM%e~I+@gaBp%Mw^YKl)ZlTswR9dD|D?UgenCm0vKw*q5uZ9vPpAAgRk$g_O88 zHUH=vn|xVJ8Q)0Y5;9lfoyigG_ovGmg3;AvF6|4mH#_ScGfCXInrhWg8Bnzspp-?k z=&$QNCh@=|k@JA8ks5JG7Gf890Jbb|wgKOOaiLQM9CQw#oD4-t1Op~wkb*gDwlDf5 z(j~Ve#HlN>R;A8Ynzf#2<#qi_uyVELb3EhypKVnqj@RkM33*lzKa1>_!Om=>K9%59 zV(6%N%i>1>UtyM6P1MQ9F@>1Tl`YC8LFrG?G5?mT;19`jQat&XeX3Qry*=Bvz2B{L z(nsslIn5bY2|48fGj8TO-nUQYnt1NRkCMe@W;7mqZ`U&FhqpY+>B#Ic^5*H0?*C}7 zUEqh!DW3dtXd%SlLPi4Xv*|H_3dRDX0vt*-AhJ=IITC>s`>d~ermb@KaHl2Xgrf^6 zhEwM`RGU1dOUse{{e&D_;pgG;tiBnp8Ora-ZO1_v_suq%8jIWfsj<$mJLS(sWf;u6 z+xiv)&bX=yYyivIO7dmbexrLjG(hb27M(89iorYOrG7>mi|X&LN?e(wB88%;vAB}r zDgdN&=v6yK=89TAh%}N-geb2JLhtiYngTAaaDQXQq$EhR(mGSrF|iqU|Fa4il*beh-U7D>@$YhU6iTae{kp@|EcFS*FS58b8<&Fulf^kHCw z3HAAM$?&i+)F3?UzTfy z0D}$QF7HpF)PWz#pe&<*oL|0t-vw5W0%9(5dREj(s;b}A>yG1P?*>10dt-!4lk3I^ zUmwPm<6(~p3@4xhTkNxmj?f{(RPTe(ah*|z-@=;8X1sop{j|OR;H~jbM*Pm!O_SM>b_4#ROZ z&sQd4zpRMhKV3`{ax#|BnV>htMdY*q99udPUkvI8B)L}%juL5alEP2^T#1gqA8na~ z0r~%y1A1ccU$Td@9Q8i%^JDs|=p|H#S{vQEagv?~a6z8cJy7dM5}`)P!g6Rx@a6qH8!%ei zwIZ#j)*?ce<0uJ6z~z~glSNeU9nO^I?soclb9Qn5_55&DSpPYj9^1(?OZJP1_fK%s zv1?yRL%PS=D`Pk29^~mrB<|-(-!9|O@gr$r;cZiR()O&@6Qk4LwWah9(x!}>`%Oq87QDJ`)iTIqxmKO^UIAdMy9;|l=r%U?5+ z!-b~>`wy7`gb^dCe0SFJJK5+z(6-pxk?3TKO)R1IrS#6uKMJJ0I7648K6|^gjZQ1t z%zp>C95G(3*eTwv({}=R?dGeUWLITBdo&IkWO|Uedo3@Y5+qG;_5m#`3~MWpXxL%^ zjmakn@3+G3`G;R=pT7l>^CteRQ*kh%P$$3<3OIe9?kj9KJX?(0%Tbxk*=VwE;hr@V zm?yW#`v>MJrf0-yhx8Q>m)MA-`=FH3Yd{Dffdj1`|1*OIg96*p%viXP|M`%|L>yt0 zbeCm-`*(vTTFE%A8n{4JAw``V!_Ssn=4C+Pv0sl0zfSLosOH-{V8^X#Ri3bp3THcf z(tKy!Gc8E5X1ZC9t?aD|&f~e`4)JSwigmgVH!OByTY}9t7BfWSqF&Ic3D3HXY_8%r!orpIOFhI_JtiDKC)t&b)R#ISY}0ou=Y(KmB^;p@HbVd~8y3|_BDw+e6d z{7y8#4*=ilOJeEwc!CG_wOdh=z~uA2J9&PfWAR5x+3R_ zhi`tLC`~GzT6K4#o>>XivGeHgS=q7dP&L<;{b0`b9l>u%XNo)?oig~ z@AB0^WZ1N3_vdgeRDm|0J9IRU=C4d!E1uGcP9dOBw+e+JGQy(S-ol zIMVRgqc*Z2;Hp@C$a=orRQOiZJ|(Mp2j{Hw?PHqG7Blawu%ig>hi5>Kc_8$e>9!;6 z3(Nl?J1Wvy-RN##Rp`tUOIg5^j_?QOLlQ^V z00jp>PqfDx%WLIslkhpSH*(fDb83Lyhdv&Y^S@{L9e1Bnl!)|Rf*5pzrfOt`Wo|uE zH6JcJJOA1aSwuHaj?HXxUI@5?*b3J_$hcFRqLC z>T^3=Y(2wP$@3`SyiD(@X%3iLmH5~Qk{DgoG|chvYyJ43;U2=JOlb9gxeg#HH$&hL zU`re7L@(>MX{>D5N3DpmW14aAK*;=En0Ba}MrIimfUUYIXK*4RPVrBYvFUtjYM{5? zZzPTcheJx#R)DeHpebaLD=S);6peacr9Mt71S1Tbq~O2T z!44Vo`#2r)Ymr{-9P|Hj{p!)1Ibb%$|9_0VV|!$6)U6#m9ox2@bZk2n zJL#Zf+Z}Yr?AW$#+eyc^?Rx8ep1qIb{kZ=^t+nd9#+YM{6YBqVr9vf%rc3=l$j)EK zd;0R;!`RlOLZ;u?`nGl)m^NCwFe-nEhSyhN(4*8TZ2F>ysk2*eXZO)j_M6^g@h?_n zUc9i@;#G(xoYQ=^VhTDgXsfSQsEoiGgXydN>iI%K`VmpVHx^AMf&%Vl9Vw&ki&LbN zg{V`4xrZr&76>C3&k=bcarYcq6MXJGYrvI8<;zYiGVE8LXqxEcI+%}*{QHln5i7=I z-qYQ89AX#G=t`TETF2YJ`JT~ReCvwV4QOS*ELekVht`TNqkQR>)VUI#J7*XQw8c;8 z5G&_?;Nh}0m6EIa`Qh9{ZE|P*So@?1_*HRE3$e>Jf%&E60KU0?vH$0qqn=<_M(5#( zAO+tQZi48tVsxo&k)khCjTy}gHOB_u1@mb5pE;lr884vd_cviHJ6Yn=>nRWGm84j_ zk@st2f&>q)yNpLpysOE(M`5_R$%qL5XP?Lg$|V(qGI{`>sjy6SzRHuTyY_EyOP;gr z?~jvgNs;9|h*iyiotPsb;x-xOb6qFzogcj4RtG5{!)eWbv5K{E20N|$8&OIpeY4cfB*-5EpuxBlGX3|@VX_oNl!k=d~%g82yaf- z60Zhk|9($g)_URBf6!Ke>=S#Gs4f%qM&kaHin5Z}%6H!+e9I-y$a0hRa+|}!-QH9= zkTF{dZUG*{_?IqQsr4We71+ux*7W2ai^ZX5#EM;PCSx!>Qg84;if;c@M*0d>BW5iG zk^Ts36D?Io;9eGo%3;ffy0R){a8e$MfHe^cf=h+cq`Xcqcu$Jg7bkd(w)nhfKp*3> zR850$g3IhiP3-DT8fVuNWJxr|FDd1EB|ePs|sHhRTZqmRdZMtbu>fj1Ruk_oMfyPx+b zSEvOzbt!}Z(@@+<>;yftA8(fJo8+!#`j5yJQkn;G^OsFii;2#SzmN#c2xtrPDXJaD zO+T*kF2QOOo6_Df7A2NO6cD6L@M*{>-}T8%5!-|XGlv~FK9pbYbJ?<67mH@|MYYdY zBLr1QMHBy5!LFL zHT#m34k?p+rBYL9!9r;TJAlCBJ4bo~7>FTJHdF;lJa{ot)HDeY)hceVs+;K1$0_}4 z#b!yjI#qo{U-7IBy+awMb*2va!q9)aS;@=&#kJ&29ai`;F=qQEC+EJWa3s$C6T93e zzGw$g&*@bd_NB`W#Cy3=DI>Hy8ti*>kfH}JV2Rt76Ysp*=X96bN#D`n7%W}SgvJqw zvnae&VKf7^$3*w$R?iWYhnzYW)dsSS9(A9<)M}#&@_Zd3hgHB?EGkw!zzHC7d$mCs zy#KvySV^Kmg9==8HOSTBCszc2VD;GVJ(ugp>kgOA;A>>U`S`D+@0NPk2_IE`DGI`# zvUIVuH%0N=sjrs78we)f=uy91r5lO8=)FvYe|z)s$ubv@yh+@DH>xOqJ0rcDTcM( zSd0`8H_K-c>^$EcYy}BIY>lNy7#GFHTk(D`7a14pqMi{$a5!uJ#YCgKmMK+I39U-2SRh_2D8}_I#TfdZ)=q8U$=euNrf*w!}Urw`WUoMl~yG09Ff7znVaESi#1>$8{U_Rm(in*bgLKK#kzPpp3 z*Kjx0dlCgOag{ncF;E0#s(M_N^xpoMKuNYY*{T#5S1T#v4j|erR0gE*)WlbRCZe4l z*LBkE#+H0<$o)4~i9Kd*B!T0Yf4Hf}AnzH{xW`LbxY&8P7mPOmdOD!eJ0$2Z2(#QY z88Oh6BWs0VUenh_)621QNuj-siT-TpQ^_AG_P+aK@9I{FQ8(bLA z=SKj7(uqeP9|@i3WlOV8fN4%UPlxmp!M5r;m7jVurV~#ak0M{rdw^d_+YCo@_#lwQ zq4f`CS;86r#>SZ&lu~n^LC(Y0qef8x?9TXy%jIBALN#1GPmJ?qS&H2kf;l;2%Y@#7 z!*n9RJ4`iXfy!etvVZE+w8oS!HH-s6nQ8z=1PYuGq%mlj@d-h#l^_rVNUuWmhma#= zY(8!`i*ZetFOVA;uxQTwl@}2L0{I(0Fo@3Mf0vB_H+*02S58~SXE_e_gSV>&d*qlq zfFY_zkY5#Z!ewOdzoUPY1^|7I+s$(o=e-CQO1?IMOg}{4RiOEUU!?}xcZt#+aJK4O z%mNNzhrh5r7lMv;47Z);YZHftU8hdv1G+l+Np^W?dI#Tzf`uW3k)f`cG@ zUoAl3LFpe{MEw8asd0mt@JJFSDrpkaj{x0_^Bj9K79FNxbOV-dPPsn6<+sg_n&QL4 zuQhI8gMe5Uop--htMQtPW+_&i-y+th>6`VFx72A*miLBbwSrSb?|MR;Z{eelEZrW` zuEY*{+LT+L;Jl9EhHvI0zpAZP1!+IgR9R+it92>4;D6A&Sv;O4dP2-zp%KyU}|ofTPPc^E697=!7Dc3 z?aT|9I@e`^txFyooPtC;b>J0gR#A1TyRFNekN@iPUsD==G4?%&1e!j2f+Zg8Dgn@s z=sU~fO3d*v#+kNjfS>J)HDA`#L%rLuyRsNWVu?ZCDXdY_ei9OG5=_Q${lTT(+h1SL z;Gl}uKez<=|Cs`DHlSu!wXeVaKSCbg4X%{DGui+EcKOa-x!Ss~9L=)sI>5lyQb7BC z^uMp3^9N36mmia<0SJ#?R{C@^&+G1+LNk70{=bELmhV!zZ%(?$w&#-HmZJ%VHP}M# ziN=`Qb^>N9>4X-_b_scOqWIz3Z%kd0w++7EouWibQd=ti-Hui4f;!jzcHx(GQ2q#}AIDPHtg?^Z=n)rceF6fFAju z(LKVoN8`&@HC;o~Q5{viKVMcF{

^$ywdz$5hK=ZG`Afn0K9XJjIQXceAoppq9T@ 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 OVI?aqAtfUr_5T3)u@DIW literal 0 HcmV?d00001 diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index 2a17c53a4c3f..86cf8ab73e05 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -120,16 +120,14 @@ void main() { controllerCompleter.complete(controller); }, javascriptMode: JavascriptMode.unrestricted, - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannels: [ + javascriptChannels: { JavascriptChannel( name: 'Echo', onMessageReceived: (JavascriptMessage message) { messagesReceived.add(message.message); }, ), - ].toSet(), + }, onPageStarted: (String url) { pageStarted.complete(null); }, @@ -180,16 +178,14 @@ void main() { onWebViewCreated: (WebViewController controller) { controllerCompleter.complete(controller); }, - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannels: [ + javascriptChannels: { JavascriptChannel( name: 'Resize', onMessageReceived: (JavascriptMessage message) { resizeCompleter.complete(true); }, ), - ].toSet(), + }, onPageStarted: (String url) { pageStarted.complete(null); }, @@ -327,7 +323,218 @@ void main() { expect(customUserAgent2, defaultPlatformUserAgent); }); - group('Media playback policy', () { + group('Video playback policy', () { + String videoTestBase64; + setUpAll(() async { + final ByteData videoData = + await rootBundle.load('assets/sample_video.mp4'); + final String base64VideoData = + base64Encode(Uint8List.view(videoData.buffer)); + final String videoTest = ''' + + Video auto play + + + + + + + '''; + videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest)); + }); + + test('Auto media playback', () async { + Completer controllerCompleter = + Completer(); + Completer pageLoaded = Completer(); + + await pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ), + ); + WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + String isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + + controllerCompleter = Completer(); + pageLoaded = Completer(); + + // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy + await pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ), + ); + + controller = await controllerCompleter.future; + await pageLoaded.future; + + isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(true)); + }); + + test('Changes to initialMediaPlaybackPolicy are ignored', () async { + final Completer controllerCompleter = + Completer(); + Completer pageLoaded = Completer(); + + final GlobalKey key = GlobalKey(); + await pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + String isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + + pageLoaded = Completer(); + + await pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ), + ); + + await controller.reload(); + + await pageLoaded.future; + + isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + }); + + test('Video plays inline when allowsInlineMediaPlayback is true', () async { + Completer controllerCompleter = + Completer(); + Completer pageLoaded = Completer(); + + await pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + allowsInlineMediaPlayback: true, + ), + ), + ); + WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + String isFullScreen = + await controller.evaluateJavascript('isFullScreen();'); + expect(isFullScreen, _webviewBool(false)); + + controllerCompleter = Completer(); + pageLoaded = Completer(); + + await pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + allowsInlineMediaPlayback: false, + ), + ), + ); + + controller = await controllerCompleter.future; + await pageLoaded.future; + + isFullScreen = await controller.evaluateJavascript('isFullScreen();'); + expect(isFullScreen, _webviewBool(true)); + }); + }); + + group('Audio playback policy', () { String audioTestBase64; setUpAll(() async { final ByteData audioData = diff --git a/packages/webview_flutter/example/lib/main.dart b/packages/webview_flutter/example/lib/main.dart index 7ec3008337d8..2a4b652d2658 100644 --- a/packages/webview_flutter/example/lib/main.dart +++ b/packages/webview_flutter/example/lib/main.dart @@ -62,11 +62,9 @@ class _WebViewExampleState extends State { onWebViewCreated: (WebViewController webViewController) { _controller.complete(webViewController); }, - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannels: [ + javascriptChannels: { _toasterJavascriptChannel(context), - ].toSet(), + }, navigationDelegate: (NavigationRequest request) { if (request.url.startsWith('https://www.youtube.com/')) { print('blocking navigation to $request}'); diff --git a/packages/webview_flutter/example/pubspec.yaml b/packages/webview_flutter/example/pubspec.yaml index 44c740ae9739..543e7fd86971 100644 --- a/packages/webview_flutter/example/pubspec.yaml +++ b/packages/webview_flutter/example/pubspec.yaml @@ -23,3 +23,4 @@ flutter: uses-material-design: true assets: - assets/sample_audio.ogg + - assets/sample_video.mp4 diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index 969e010913f3..ed3cf44424e8 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -332,6 +332,9 @@ - (NSString*)applySettings:(NSDictionary*)settings { } else if ([key isEqualToString:@"userAgent"]) { NSString* userAgent = settings[key]; [self updateUserAgent:[userAgent isEqual:[NSNull null]] ? nil : userAgent]; + } else if ([key isEqualToString:@"allowsInlineMediaPlayback"]) { + NSNumber* allowsInlineMediaPlayback = settings[key]; + _webView.configuration.allowsInlineMediaPlayback = [allowsInlineMediaPlayback boolValue]; } else { [unknownKeys addObject:key]; } diff --git a/packages/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/lib/platform_interface.dart index f162e58cf0f9..a840c0036fb3 100644 --- a/packages/webview_flutter/lib/platform_interface.dart +++ b/packages/webview_flutter/lib/platform_interface.dart @@ -390,6 +390,7 @@ class WebSettings { this.hasNavigationDelegate, this.debuggingEnabled, this.gestureNavigationEnabled, + this.allowsInlineMediaPlayback, required this.userAgent, }) : assert(userAgent != null); @@ -404,6 +405,11 @@ class WebSettings { /// See also: [WebView.debuggingEnabled]. final bool? debuggingEnabled; + /// Whether to play HTML5 videos inline or use the native full-screen controller on iOS. + /// + /// This will have no effect on Android. + final bool? allowsInlineMediaPlayback; + /// The value used for the HTTP `User-Agent:` request header. /// /// If [userAgent.value] is null the platform's default user agent should be used. @@ -421,7 +427,7 @@ class WebSettings { @override String toString() { - return 'WebSettings(javascriptMode: $javascriptMode, hasNavigationDelegate: $hasNavigationDelegate, debuggingEnabled: $debuggingEnabled, gestureNavigationEnabled: $gestureNavigationEnabled, userAgent: $userAgent)'; + return 'WebSettings(javascriptMode: $javascriptMode, hasNavigationDelegate: $hasNavigationDelegate, debuggingEnabled: $debuggingEnabled, gestureNavigationEnabled: $gestureNavigationEnabled, userAgent: $userAgent, allowsInlineMediaPlayback: $allowsInlineMediaPlayback)'; } } diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart index 1c666d7686ef..b38d65acb486 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -185,6 +185,8 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { _addIfNonNull('debuggingEnabled', settings.debuggingEnabled); _addIfNonNull( 'gestureNavigationEnabled', settings.gestureNavigationEnabled); + _addIfNonNull( + 'allowsInlineMediaPlayback', settings.allowsInlineMediaPlayback); _addSettingIfPresent('userAgent', settings.userAgent); return map; } diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 4327c789afbe..6853d39555c3 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -223,8 +223,10 @@ class WebView extends StatefulWidget { this.userAgent, this.initialMediaPlaybackPolicy = AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + this.allowsInlineMediaPlayback = false, }) : assert(javascriptMode != null), assert(initialMediaPlaybackPolicy != null), + assert(allowsInlineMediaPlayback != null), super(key: key); static WebViewPlatform? _platform; @@ -333,6 +335,13 @@ class WebView extends StatefulWidget { /// * When a navigationDelegate is set HTTP requests do not include the HTTP referer header. final NavigationDelegate? navigationDelegate; + /// Controls whether inline playback of HTML5 videos is allowed on iOS. + /// + /// This field is ignored on Android because Android allows it by default. + /// + /// By default `allowsInlineMediaPlayback` is false. + final bool allowsInlineMediaPlayback; + /// Invoked when a page starts loading. final PageStartedCallback? onPageStarted; @@ -469,6 +478,7 @@ WebSettings _webSettingsFromWidget(WebView widget) { hasNavigationDelegate: widget.navigationDelegate != null, debuggingEnabled: widget.debuggingEnabled, gestureNavigationEnabled: widget.gestureNavigationEnabled, + allowsInlineMediaPlayback: widget.allowsInlineMediaPlayback, userAgent: WebSetting.of(widget.userAgent), ); } diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index de62a50ada17..75910dfe02aa 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 2.0.0-nullsafety +version: 2.0.0-nullsafety.1 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: diff --git a/packages/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/test/webview_flutter_test.dart index 662a2f7f976a..162b1932e49d 100644 --- a/packages/webview_flutter/test/webview_flutter_test.dart +++ b/packages/webview_flutter/test/webview_flutter_test.dart @@ -423,14 +423,12 @@ void main() { await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannels: [ + javascriptChannels: { JavascriptChannel( name: 'Tts', onMessageReceived: (JavascriptMessage msg) {}), JavascriptChannel( name: 'Alarm', onMessageReceived: (JavascriptMessage msg) {}), - ].toSet(), + }, ), ); @@ -463,14 +461,12 @@ void main() { await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannels: [ + javascriptChannels: { JavascriptChannel( name: 'Alarm', onMessageReceived: (JavascriptMessage msg) {}), JavascriptChannel( name: 'Alarm', onMessageReceived: (JavascriptMessage msg) {}), - ].toSet(), + }, ), ); expect(tester.takeException(), isNot(null)); @@ -480,30 +476,26 @@ void main() { await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannels: [ + javascriptChannels: { JavascriptChannel( name: 'Tts', onMessageReceived: (JavascriptMessage msg) {}), JavascriptChannel( name: 'Alarm', onMessageReceived: (JavascriptMessage msg) {}), - ].toSet(), + }, ), ); await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannels: [ + javascriptChannels: { JavascriptChannel( name: 'Tts', onMessageReceived: (JavascriptMessage msg) {}), JavascriptChannel( name: 'Alarm2', onMessageReceived: (JavascriptMessage msg) {}), JavascriptChannel( name: 'Alarm3', onMessageReceived: (JavascriptMessage msg) {}), - ].toSet(), + }, ), ); @@ -523,12 +515,10 @@ void main() { await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannels: [ + javascriptChannels: { JavascriptChannel( name: 'Tts', onMessageReceived: (JavascriptMessage msg) {}), - ].toSet(), + }, ), ); @@ -541,12 +531,10 @@ void main() { await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannels: [ + javascriptChannels: { JavascriptChannel( name: 'Tts', onMessageReceived: (JavascriptMessage msg) {}), - ].toSet(), + }, ), ); @@ -563,9 +551,7 @@ void main() { await tester.pumpWidget( WebView( initialUrl: 'https://youtube.com', - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // ignore: prefer_collection_literals - javascriptChannels: [ + javascriptChannels: { JavascriptChannel( name: 'Tts', onMessageReceived: (JavascriptMessage msg) { @@ -576,7 +562,7 @@ void main() { onMessageReceived: (JavascriptMessage msg) { alarmMessagesReceived.add(msg.message); }), - ].toSet(), + }, ), ); From 5482d9a4cb2d172dadb767888be978493675b987 Mon Sep 17 00:00:00 2001 From: Amir Hardon Date: Wed, 16 Dec 2020 11:33:04 -0800 Subject: [PATCH 050/924] Remove custom null safety analysis_options files (#3339) --- .../connectivity/analysis_options.yaml | 4 ---- .../connectivity/example/pubspec.yaml | 2 +- .../test_driver/test/integration_test.dart | 4 ++++ .../analysis_options.yaml | 4 ---- .../device_info/analysis_options.yaml | 4 ---- .../analysis_options.yaml | 4 ---- .../analysis_options.yaml | 4 ---- .../ios/Runner.xcodeproj/project.pbxproj | 19 ------------------- .../url_launcher/analysis_options.yaml | 4 ---- .../url_launcher/example/pubspec.yaml | 2 +- .../analysis_options.yaml | 4 ---- .../video_player/analysis_options.yaml | 4 ---- .../integration_test/video_player_test.dart | 7 ++++++- .../video_player/example/pubspec.yaml | 2 +- .../analysis_options.yaml | 4 ---- .../video_player_web/analysis_options.yaml | 12 ------------ script/incremental_build.sh | 11 +---------- 17 files changed, 14 insertions(+), 81 deletions(-) delete mode 100644 packages/connectivity/connectivity/analysis_options.yaml delete mode 100644 packages/connectivity/connectivity_platform_interface/analysis_options.yaml delete mode 100644 packages/device_info/device_info/analysis_options.yaml delete mode 100644 packages/device_info/device_info_platform_interface/analysis_options.yaml delete mode 100644 packages/plugin_platform_interface/analysis_options.yaml delete mode 100644 packages/url_launcher/url_launcher/analysis_options.yaml delete mode 100644 packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml delete mode 100644 packages/video_player/video_player/analysis_options.yaml delete mode 100644 packages/video_player/video_player_platform_interface/analysis_options.yaml delete mode 100644 packages/video_player/video_player_web/analysis_options.yaml diff --git a/packages/connectivity/connectivity/analysis_options.yaml b/packages/connectivity/connectivity/analysis_options.yaml deleted file mode 100644 index 3d64bb57fe49..000000000000 --- a/packages/connectivity/connectivity/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: ../../../analysis_options.yaml -analyzer: - enable-experiment: - - non-nullable diff --git a/packages/connectivity/connectivity/example/pubspec.yaml b/packages/connectivity/connectivity/example/pubspec.yaml index 94c8505c8096..682f0a2dd08a 100644 --- a/packages/connectivity/connectivity/example/pubspec.yaml +++ b/packages/connectivity/connectivity/example/pubspec.yaml @@ -19,5 +19,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart b/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart index c0cbdcab2fb6..33421c335bdd 100644 --- a/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart +++ b/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(amirh): Remove this once flutter_driver supports null safety. +// https://github.com/flutter/flutter/issues/71379 +// @dart = 2.9 + import 'dart:convert'; import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; diff --git a/packages/connectivity/connectivity_platform_interface/analysis_options.yaml b/packages/connectivity/connectivity_platform_interface/analysis_options.yaml deleted file mode 100644 index 3d64bb57fe49..000000000000 --- a/packages/connectivity/connectivity_platform_interface/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: ../../../analysis_options.yaml -analyzer: - enable-experiment: - - non-nullable diff --git a/packages/device_info/device_info/analysis_options.yaml b/packages/device_info/device_info/analysis_options.yaml deleted file mode 100644 index 3d64bb57fe49..000000000000 --- a/packages/device_info/device_info/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: ../../../analysis_options.yaml -analyzer: - enable-experiment: - - non-nullable diff --git a/packages/device_info/device_info_platform_interface/analysis_options.yaml b/packages/device_info/device_info_platform_interface/analysis_options.yaml deleted file mode 100644 index 3d64bb57fe49..000000000000 --- a/packages/device_info/device_info_platform_interface/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: ../../../analysis_options.yaml -analyzer: - enable-experiment: - - non-nullable diff --git a/packages/plugin_platform_interface/analysis_options.yaml b/packages/plugin_platform_interface/analysis_options.yaml deleted file mode 100644 index f4819cd5c313..000000000000 --- a/packages/plugin_platform_interface/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: ../../analysis_options.yaml -analyzer: - enable-experiment: - - non-nullable diff --git a/packages/share/example/ios/Runner.xcodeproj/project.pbxproj b/packages/share/example/ios/Runner.xcodeproj/project.pbxproj index 639666b2865c..d03ef3e65776 100644 --- a/packages/share/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/share/example/ios/Runner.xcodeproj/project.pbxproj @@ -197,7 +197,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 12A149CFB1B2610A83692801 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -268,24 +267,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 12A149CFB1B2610A83692801 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../Flutter/Flutter.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/packages/url_launcher/url_launcher/analysis_options.yaml b/packages/url_launcher/url_launcher/analysis_options.yaml deleted file mode 100644 index 3d64bb57fe49..000000000000 --- a/packages/url_launcher/url_launcher/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: ../../../analysis_options.yaml -analyzer: - enable-experiment: - - non-nullable diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml index 1fdb73cef666..7caea27744db 100644 --- a/packages/url_launcher/url_launcher/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher/example/pubspec.yaml @@ -20,5 +20,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml b/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml deleted file mode 100644 index 3d64bb57fe49..000000000000 --- a/packages/url_launcher/url_launcher_platform_interface/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: ../../../analysis_options.yaml -analyzer: - enable-experiment: - - non-nullable diff --git a/packages/video_player/video_player/analysis_options.yaml b/packages/video_player/video_player/analysis_options.yaml deleted file mode 100644 index 3d64bb57fe49..000000000000 --- a/packages/video_player/video_player/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: ../../../analysis_options.yaml -analyzer: - enable-experiment: - - non-nullable diff --git a/packages/video_player/video_player/example/integration_test/video_player_test.dart b/packages/video_player/video_player/example/integration_test/video_player_test.dart index d2f38367ce9a..7ef1cf64065c 100644 --- a/packages/video_player/video_player/example/integration_test/video_player_test.dart +++ b/packages/video_player/video_player/example/integration_test/video_player_test.dart @@ -2,6 +2,11 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. + +// TODO(amirh): Remove this once flutter_driver supports null safety. +// https://github.com/flutter/flutter/issues/71379 +// @dart = 2.9 + import 'package:flutter/material.dart'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -11,7 +16,7 @@ const Duration _playDuration = Duration(seconds: 1); void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - late VideoPlayerController _controller; + VideoPlayerController _controller; tearDown(() async => _controller.dispose()); group('asset videos', () { diff --git a/packages/video_player/video_player/example/pubspec.yaml b/packages/video_player/video_player/example/pubspec.yaml index 6cfa93213afb..fb18d8b75efa 100644 --- a/packages/video_player/video_player/example/pubspec.yaml +++ b/packages/video_player/video_player/example/pubspec.yaml @@ -27,5 +27,5 @@ flutter: - assets/bumble_bee_captions.srt environment: - sdk: ">=2.8.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/video_player/video_player_platform_interface/analysis_options.yaml b/packages/video_player/video_player_platform_interface/analysis_options.yaml deleted file mode 100644 index 3d64bb57fe49..000000000000 --- a/packages/video_player/video_player_platform_interface/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: ../../../analysis_options.yaml -analyzer: - enable-experiment: - - non-nullable diff --git a/packages/video_player/video_player_web/analysis_options.yaml b/packages/video_player/video_player_web/analysis_options.yaml deleted file mode 100644 index 7e5b7b306a83..000000000000 --- a/packages/video_player/video_player_web/analysis_options.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# This is a temporary file to allow us to unblock the flutter/plugins repo CI. -# It disables some of lints that were disabled inline. Disabling lints inline -# is no longer possible, so this file is required. -# TODO(ditman) https://github.com/flutter/flutter/issues/55000 (clean this up) - -include: ../../../analysis_options.yaml - -analyzer: - enable-experiment: - - non-nullable - errors: - undefined_prefixed_name: ignore diff --git a/script/incremental_build.sh b/script/incremental_build.sh index 95e42c4cfcee..f54f90b0669c 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -29,17 +29,8 @@ fi # # TODO(mklim): Remove everything from this list. https://github.com/flutter/flutter/issues/45440 CUSTOM_ANALYSIS_PLUGINS=( - "plugin_platform_interface" - "video_player/video_player" - "video_player/video_player_platform_interface" - "video_player/video_player_web" - "url_launcher/url_launcher_platform_interface" - "url_launcher/url_launcher" - "device_info/device_info_platform_interface" - "device_info/device_info" - "connectivity/connectivity_platform_interface" - "connectivity/connectivity" ) + # Comma-separated string of the list above readonly CUSTOM_FLAG=$(IFS=, ; echo "${CUSTOM_ANALYSIS_PLUGINS[*]}") # Set some default actions if run without arguments. From 05879a3a4d8e582702227731ccdcf8b115f6b83d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Wed, 16 Dec 2020 20:34:18 +0100 Subject: [PATCH 051/924] [camera] Ios support documentation (#3335) * updated README.md to notify about no < iOS10 support * Version bump * Improved explanation Co-authored-by: Maurits van Beusekom Co-authored-by: Maurits van Beusekom --- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/README.md | 2 ++ packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index cb8dfedd1d9a..8a7c979c3b72 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.0+1 + +Updated README to inform users that iOS 10.0+ is needed for use + ## 0.6.0 As part of implementing federated architecture and making the interface compatible with the web this version contains the following **breaking changes**: diff --git a/packages/camera/camera/README.md b/packages/camera/camera/README.md index 39d3ed88abea..f8a4b05211fd 100644 --- a/packages/camera/camera/README.md +++ b/packages/camera/camera/README.md @@ -19,6 +19,8 @@ First, add `camera` as a [dependency in your pubspec.yaml file](https://flutter. ### iOS +iOS 10.0 of higher is needed to use the camera plugin. If compiling for any version lower than 10.0 make sure to check the iOS version before using the camera plugin. For example, using the [device_info](https://pub.dev/packages/device_info) plugin. + Add two rows to the `ios/Runner/Info.plist`: * one with the key `Privacy - Camera Usage Description` and a usage description. diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 64d5bba61159..cc25133f95f9 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.0 +version: 0.6.0+1 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From b2e9ca5c52995edea0d32b045a0df831d1aca192 Mon Sep 17 00:00:00 2001 From: Harry Cheng Date: Fri, 18 Dec 2020 03:34:05 +0800 Subject: [PATCH 052/924] fix(video_player): buffering state events missing on Android & Web (fixes flutter/flutter#28494) (#2563) --- .../video_player/video_player/CHANGELOG.md | 4 ++ .../plugins/videoplayer/VideoPlayer.java | 16 ++++++ .../integration_test/video_player_test.dart | 56 ++++++++++++++++++- .../video_player/video_player/pubspec.yaml | 2 +- .../video_player_web/CHANGELOG.md | 4 ++ .../lib/video_player_web.dart | 27 +++++++++ .../video_player_web/pubspec.yaml | 2 +- 7 files changed, 107 insertions(+), 4 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 14eaae381756..e2bca40531da 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.4 + +* Fixed an issue where `isBuffering` was not updating on Android. + ## 2.0.0-nullsafety.3 * Dart null safety requires `2.12`. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java index 33c2f42afe1e..65657509b49f 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java @@ -169,10 +169,21 @@ public void onCancel(Object o) { exoPlayer.addListener( new EventListener() { + private boolean isBuffering = false; + + public void setBuffering(boolean buffering) { + if (isBuffering != buffering) { + isBuffering = buffering; + Map event = new HashMap<>(); + event.put("event", isBuffering ? "bufferingStart" : "bufferingEnd"); + eventSink.success(event); + } + } @Override public void onPlaybackStateChanged(final int playbackState) { if (playbackState == Player.STATE_BUFFERING) { + setBuffering(true); sendBufferingUpdate(); } else if (playbackState == Player.STATE_READY) { if (!isInitialized) { @@ -184,10 +195,15 @@ public void onPlaybackStateChanged(final int playbackState) { event.put("event", "completed"); eventSink.success(event); } + + if (playbackState != Player.STATE_BUFFERING) { + setBuffering(false); + } } @Override public void onPlayerError(final ExoPlaybackException error) { + setBuffering(false); if (eventSink != null) { eventSink.error("VideoError", "Video player had error " + error, null); } diff --git a/packages/video_player/video_player/example/integration_test/video_player_test.dart b/packages/video_player/video_player/example/integration_test/video_player_test.dart index 7ef1cf64065c..9e273e02dc4d 100644 --- a/packages/video_player/video_player/example/integration_test/video_player_test.dart +++ b/packages/video_player/video_player/example/integration_test/video_player_test.dart @@ -2,11 +2,12 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. - // TODO(amirh): Remove this once flutter_driver supports null safety. // https://github.com/flutter/flutter/issues/71379 // @dart = 2.9 +import 'dart:async'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -34,10 +35,58 @@ void main() { const Duration(seconds: 7, milliseconds: 540)); }); + testWidgets( + 'reports buffering status', + (WidgetTester tester) async { + VideoPlayerController networkController = VideoPlayerController.network( + 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4', + ); + await networkController.initialize(); + // Mute to allow playing without DOM interaction on Web. + // See https://developers.google.com/web/updates/2017/09/autoplay-policy-changes + await networkController.setVolume(0); + final Completer started = Completer(); + final Completer ended = Completer(); + bool startedBuffering = false; + bool endedBuffering = false; + networkController.addListener(() { + if (networkController.value.isBuffering && !startedBuffering) { + startedBuffering = true; + started.complete(); + } + if (startedBuffering && + !networkController.value.isBuffering && + !endedBuffering) { + endedBuffering = true; + ended.complete(); + } + }); + + await networkController.play(); + await networkController.seekTo(const Duration(seconds: 5)); + await tester.pumpAndSettle(_playDuration); + await networkController.pause(); + + expect(networkController.value.isPlaying, false); + expect(networkController.value.position, + (Duration position) => position > const Duration(seconds: 0)); + + await started; + expect(startedBuffering, true); + + await ended; + expect(endedBuffering, true); + }, + skip: !(kIsWeb || defaultTargetPlatform == TargetPlatform.android), + ); + testWidgets( 'can be played', (WidgetTester tester) async { await _controller.initialize(); + // Mute to allow playing without DOM interaction on Web. + // See https://developers.google.com/web/updates/2017/09/autoplay-policy-changes + await _controller.setVolume(0); await _controller.play(); await tester.pumpAndSettle(_playDuration); @@ -63,6 +112,9 @@ void main() { 'can be paused', (WidgetTester tester) async { await _controller.initialize(); + // Mute to allow playing without DOM interaction on Web. + // See https://developers.google.com/web/updates/2017/09/autoplay-policy-changes + await _controller.setVolume(0); // Play for a second, then pause, and then wait a second. await _controller.play(); @@ -109,6 +161,6 @@ void main() { await tester.pumpAndSettle(); expect(_controller.value.isPlaying, true); - }); + }, skip: kIsWeb); // Web does not support local assets. }); } diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index cfbc4c65c1de..6e483324e499 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for displaying inline video with other Flutter # 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 2.0.0-nullsafety.3 +version: 2.0.0-nullsafety.4 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: diff --git a/packages/video_player/video_player_web/CHANGELOG.md b/packages/video_player/video_player_web/CHANGELOG.md index 52c2042d1e95..2becf5b85e0a 100644 --- a/packages/video_player/video_player_web/CHANGELOG.md +++ b/packages/video_player/video_player_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.2 + +* Fixed an issue where `isBuffering` was not updating on Web. + ## 2.0.0-nullsafety.1 * Bump Dart SDK to support null safety. diff --git a/packages/video_player/video_player_web/lib/video_player_web.dart b/packages/video_player/video_player_web/lib/video_player_web.dart index de8f6a7e4cf7..9132a08437da 100644 --- a/packages/video_player/video_player_web/lib/video_player_web.dart +++ b/packages/video_player/video_player_web/lib/video_player_web.dart @@ -156,6 +156,17 @@ class _VideoPlayer { final int textureId; late VideoElement videoElement; bool isInitialized = false; + bool isBuffering = false; + + void setBuffering(bool buffering) { + if (isBuffering != buffering) { + isBuffering = buffering; + eventController.add(VideoEvent( + eventType: isBuffering + ? VideoEventType.bufferingStart + : VideoEventType.bufferingEnd)); + } + } void initialize() { videoElement = VideoElement() @@ -176,10 +187,25 @@ class _VideoPlayer { isInitialized = true; sendInitialized(); } + setBuffering(false); + }); + + videoElement.onCanPlayThrough.listen((dynamic _) { + setBuffering(false); + }); + + videoElement.onPlaying.listen((dynamic _) { + setBuffering(false); + }); + + videoElement.onWaiting.listen((dynamic _) { + setBuffering(true); + sendBufferingUpdate(); }); // The error event fires when some form of error occurs while attempting to load or perform the media. videoElement.onError.listen((Event _) { + setBuffering(false); // The Event itself (_) doesn't contain info about the actual error. // We need to look at the HTMLMediaElement.error. // See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/error @@ -192,6 +218,7 @@ class _VideoPlayer { }); videoElement.onEnded.listen((dynamic _) { + setBuffering(false); eventController.add(VideoEvent(eventType: VideoEventType.completed)); }); } diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml index dc1af16c5d94..9333ac0ac6f0 100644 --- a/packages/video_player/video_player_web/pubspec.yaml +++ b/packages/video_player/video_player_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/v # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 2.0.0-nullsafety.1 +version: 2.0.0-nullsafety.2 flutter: plugin: From 41b4486333507e48fec7677e6344f81898f42d2e Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Thu, 17 Dec 2020 16:39:29 -0800 Subject: [PATCH 053/924] Upgrade CocoaPods in Cirrus (#3347) --- .cirrus.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cirrus.yml b/.cirrus.yml index 98cd6276e0e6..453a2ce0ac2c 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -132,6 +132,7 @@ task: osx_instance: image: catalina-xcode-11.3.1-flutter upgrade_script: + - sudo gem install cocoapods - flutter channel stable - flutter upgrade - flutter channel master @@ -190,6 +191,7 @@ task: setup_script: - flutter config --enable-macos-desktop upgrade_script: + - sudo gem install cocoapods - flutter channel master - flutter upgrade - git fetch origin master From 73eeb30c9819ab8f88109c1de232f47830ab7966 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 17 Dec 2020 18:16:56 -0800 Subject: [PATCH 054/924] [image_picker] use LocalizedString to fix lint error. (#3349) --- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 6 +++--- packages/image_picker/image_picker/pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 70a1cb21b354..a1f7608ac7ac 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+17 + +* iOS: fix `User-facing text should use localized string macro` warning. + ## 0.6.7+16 * Update Flutter SDK constraint. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 00fdec245aaf..8d260f31b055 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -146,10 +146,10 @@ - (void)showCamera { animated:YES completion:nil]; } else { - [[[UIAlertView alloc] initWithTitle:@"Error" - message:@"Camera not available." + [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil) + message:NSLocalizedString(@"Camera not available.", nil) delegate:nil - cancelButtonTitle:@"OK" + cancelButtonTitle:NSLocalizedString(@"OK", nil) otherButtonTitles:nil] show]; self.result(nil); self.result = nil; diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 4eb16beec641..7b4972578e98 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+16 +version: 0.6.7+17 flutter: plugin: From b6af039a969bbb5a0d68fd407fc608d4e1313c5b Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 18 Dec 2020 18:35:32 +0000 Subject: [PATCH 055/924] [connectivity] Clear networkCallback object as soon as stream is cancelled (#3303) Set networkCallback back to null when event stream is cancelled --- packages/connectivity/connectivity/CHANGELOG.md | 4 ++++ .../plugins/connectivity/ConnectivityBroadcastReceiver.java | 1 + packages/connectivity/connectivity/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index 60765d14c080..f215449eb72f 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.0-nullsafety.2 + +* Android: Cleanup the NetworkCallback object when a connectivity stream is cancelled + ## 3.0.0-nullsafety.1 * Bump Dart SDK to support null safety. diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java index ca3ccff82d2d..dbf96bda9fe8 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java @@ -64,6 +64,7 @@ public void onCancel(Object arguments) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (networkCallback != null) { connectivity.getConnectivityManager().unregisterNetworkCallback(networkCallback); + networkCallback = null; } } else { context.unregisterReceiver(this); diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index 2f6d78134796..916fa08908b5 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -2,7 +2,7 @@ name: connectivity description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity -version: 3.0.0-nullsafety.1 +version: 3.0.0-nullsafety.2 flutter: plugin: From b1ab21a63152cb6769e8c1b09056ffaa6357aaff Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Fri, 18 Dec 2020 13:04:02 -0800 Subject: [PATCH 056/924] [local_auth] Update README for Android Integration (#3348) --- packages/local_auth/CHANGELOG.md | 6 ++++- packages/local_auth/README.md | 38 +++++++++++++++++++++++++++++++- packages/local_auth/pubspec.yaml | 2 +- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index d83798ad4889..48d8df4f0fd9 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0-nullsafety.1 + +* Update README for Android Integration. + ## 1.0.0-nullsafety * Migrate to null safety. @@ -182,4 +186,4 @@ ## 0.0.1 -* Initial release of local authentication plugin. +* Initial release of local authentication plugin. \ No newline at end of file diff --git a/packages/local_auth/README.md b/packages/local_auth/README.md index ca2aa49bed23..98dcdcf0bffa 100644 --- a/packages/local_auth/README.md +++ b/packages/local_auth/README.md @@ -142,6 +142,42 @@ opposed to Activity. This can be easily done by switching to use `FlutterFragmentActivity` as opposed to `FlutterActivity` in your manifest (or your own Activity class if you are extending the base class). +Update your MainActivity.java: + +```java +import android.os.Bundle; +import io.flutter.app.FlutterFragmentActivity; +import io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin; +import io.flutter.plugins.localauth.LocalAuthPlugin; + +public class MainActivity extends FlutterFragmentActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + FlutterAndroidLifecyclePlugin.registerWith( + registrarFor( + "io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin")); + LocalAuthPlugin.registerWith(registrarFor("io.flutter.plugins.localauth.LocalAuthPlugin")); + } +} +``` + +OR + +Update your MainActivity.kt: + +```kotlin +import io.flutter.embedding.android.FlutterFragmentActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugins.GeneratedPluginRegistrant + +class MainActivity: FlutterFragmentActivity() { + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { + GeneratedPluginRegistrant.registerWith(flutterEngine) + } +} +``` + Update your project's `AndroidManifest.xml` file to include the `USE_FINGERPRINT` permissions: @@ -172,4 +208,4 @@ app resumes. For help getting started with Flutter, view our online [documentation](http://flutter.io/). -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). +For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). \ No newline at end of file diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index f61f8b3ca4a7..30acd7264314 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth description: Flutter plugin for Android and iOS device authentication sensors such as Fingerprint Reader and Touch ID. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 1.0.0-nullsafety +version: 1.0.0-nullsafety.1 flutter: plugin: From debfbecb53a556013e77195272c8a12a3fafa0da Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 18 Dec 2020 14:49:03 -0800 Subject: [PATCH 057/924] Fix outdated links across a number of markdown files (#3276) --- CONTRIBUTING.md | 9 ++++----- packages/android_alarm_manager/CHANGELOG.md | 4 ++++ packages/android_alarm_manager/README.md | 6 +++--- packages/android_alarm_manager/pubspec.yaml | 2 +- packages/android_intent/CHANGELOG.md | 4 ++++ packages/android_intent/README.md | 8 ++++---- packages/android_intent/pubspec.yaml | 2 +- packages/battery/battery/CHANGELOG.md | 4 ++++ packages/battery/battery/README.md | 4 ++-- packages/battery/battery/pubspec.yaml | 2 +- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/README.md | 4 ++-- packages/camera/camera/pubspec.yaml | 2 +- packages/connectivity/connectivity/CHANGELOG.md | 4 ++++ packages/connectivity/connectivity/README.md | 4 ++-- packages/connectivity/connectivity/pubspec.yaml | 2 +- packages/cross_file/CHANGELOG.md | 4 ++++ packages/cross_file/README.md | 2 +- packages/cross_file/pubspec.yaml | 2 +- packages/device_info/device_info/CHANGELOG.md | 4 ++++ packages/device_info/device_info/README.md | 6 +++--- packages/device_info/device_info/pubspec.yaml | 2 +- packages/flutter_plugin_android_lifecycle/CHANGELOG.md | 4 ++++ packages/flutter_plugin_android_lifecycle/README.md | 4 ++-- packages/flutter_plugin_android_lifecycle/pubspec.yaml | 2 +- .../google_maps_flutter/google_maps_flutter/CHANGELOG.md | 4 ++++ .../google_maps_flutter/google_maps_flutter/README.md | 4 ++-- .../google_maps_flutter/google_maps_flutter/pubspec.yaml | 2 +- .../CHANGELOG.md | 4 ++++ .../example/README.md | 2 +- .../pubspec.yaml | 2 +- packages/google_sign_in/google_sign_in/CHANGELOG.md | 4 ++++ packages/google_sign_in/google_sign_in/README.md | 4 ++-- packages/google_sign_in/google_sign_in/pubspec.yaml | 2 +- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ packages/image_picker/image_picker/README.md | 4 ++-- packages/image_picker/image_picker/pubspec.yaml | 2 +- packages/in_app_purchase/CHANGELOG.md | 4 ++++ packages/in_app_purchase/README.md | 2 +- packages/in_app_purchase/pubspec.yaml | 2 +- packages/local_auth/CHANGELOG.md | 4 ++++ packages/local_auth/README.md | 4 ++-- packages/local_auth/pubspec.yaml | 2 +- packages/path_provider/path_provider/CHANGELOG.md | 4 ++++ packages/path_provider/path_provider/README.md | 4 ++-- packages/path_provider/path_provider/pubspec.yaml | 2 +- packages/quick_actions/CHANGELOG.md | 4 ++++ packages/quick_actions/README.md | 4 ++-- packages/quick_actions/pubspec.yaml | 2 +- packages/sensors/CHANGELOG.md | 4 ++++ packages/sensors/README.md | 2 +- packages/sensors/pubspec.yaml | 2 +- packages/share/CHANGELOG.md | 4 ++++ packages/share/README.md | 4 ++-- packages/share/pubspec.yaml | 2 +- .../shared_preferences/shared_preferences/CHANGELOG.md | 4 ++++ packages/shared_preferences/shared_preferences/README.md | 4 ++-- .../shared_preferences/shared_preferences/pubspec.yaml | 2 +- packages/url_launcher/url_launcher/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher/README.md | 6 +++--- packages/url_launcher/url_launcher/pubspec.yaml | 2 +- packages/url_launcher/url_launcher_linux/CHANGELOG.md | 4 ++++ .../url_launcher/url_launcher_linux/example/README.md | 2 +- packages/url_launcher/url_launcher_linux/pubspec.yaml | 2 +- packages/video_player/video_player/CHANGELOG.md | 4 ++++ packages/video_player/video_player/README.md | 4 ++-- packages/video_player/video_player/pubspec.yaml | 2 +- packages/webview_flutter/CHANGELOG.md | 4 ++++ packages/webview_flutter/README.md | 4 ++-- packages/webview_flutter/pubspec.yaml | 2 +- 70 files changed, 165 insertions(+), 74 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b278b43e524f..b763320b67c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ [![Build Status](https://api.cirrus-ci.com/github/flutter/plugins.svg)](https://cirrus-ci.com/github/flutter/plugins/master) -_See also: [Flutter's code of conduct](https://flutter.io/design-principles/#code-of-conduct)_ +_See also: [Flutter's code of conduct](https://github.com/flutter/flutter/blob/master/CODE_OF_CONDUCT.md)_ ## Things you will need @@ -131,9 +131,8 @@ pub global run flutter_plugin_tools xctest --target RunnerUITests --skip ` * Hack away. - * Verify changes with [flutter_plugin_tools](https://pub.dartlang.org/packages/flutter_plugin_tools) + * Verify changes with [flutter_plugin_tools](https://pub.dev/packages/flutter_plugin_tools) ``` pub global activate flutter_plugin_tools pub global run flutter_plugin_tools format --plugins plugin_name diff --git a/packages/android_alarm_manager/CHANGELOG.md b/packages/android_alarm_manager/CHANGELOG.md index e0c436d79eea..1b6a7b749e66 100644 --- a/packages/android_alarm_manager/CHANGELOG.md +++ b/packages/android_alarm_manager/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.5+19 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 0.4.5+18 * Update Flutter SDK constraint. diff --git a/packages/android_alarm_manager/README.md b/packages/android_alarm_manager/README.md index 9d245e5edc20..cf02bf66ff11 100644 --- a/packages/android_alarm_manager/README.md +++ b/packages/android_alarm_manager/README.md @@ -1,6 +1,6 @@ # android_alarm_manager -[![pub package](https://img.shields.io/pub/v/android_alarm_manager.svg)](https://pub.dartlang.org/packages/android_alarm_manager) +[![pub package](https://img.shields.io/pub/v/android_alarm_manager.svg)](https://pub.dev/packages/android_alarm_manager) A Flutter plugin for accessing the Android AlarmManager service, and running Dart code in the background when alarms fire. @@ -121,6 +121,6 @@ register plugins. This can be resolved by running `flutter upgrade` to upgrade to the latest Flutter version.** For help getting started with Flutter, view our online -[documentation](http://flutter.io/). +[documentation](https://flutter.dev/). -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). +For help on editing plugin code, view the [documentation](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin). diff --git a/packages/android_alarm_manager/pubspec.yaml b/packages/android_alarm_manager/pubspec.yaml index 5b6780b4b14a..b055823c2db3 100644 --- a/packages/android_alarm_manager/pubspec.yaml +++ b/packages/android_alarm_manager/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for accessing the Android AlarmManager service, and # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.5+18 +version: 0.4.5+19 homepage: https://github.com/flutter/plugins/tree/master/packages/android_alarm_manager dependencies: diff --git a/packages/android_intent/CHANGELOG.md b/packages/android_intent/CHANGELOG.md index 65c991c6f7b2..113e4464c947 100644 --- a/packages/android_intent/CHANGELOG.md +++ b/packages/android_intent/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.1 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 2.0.0-nullsafety * Migrate to null safety. diff --git a/packages/android_intent/README.md b/packages/android_intent/README.md index f7dfdfed9860..aabf059ea336 100644 --- a/packages/android_intent/README.md +++ b/packages/android_intent/README.md @@ -53,13 +53,13 @@ if (platform.isAndroid) { Feel free to add support for additional Android intents. The Dart values supported for the arguments parameter, and their corresponding -Android values, are listed [here](https://flutter.io/platform-channels/#codec). +Android values, are listed [here](https://flutter.dev/docs/development/platform-integration/platform-channels#codec). On the Android side, the arguments are used to populate an Android `Bundle` instance. This process currently restricts the use of lists to homogeneous lists of integers or strings. > Note that a similar method does not currently exist for iOS. Instead, the -[url_launcher](https://pub.dartlang.org/packages/url_launcher) plugin +[url_launcher](https://pub.dev/packages/url_launcher) plugin can be used for deep linking. Url launcher can also be used for creating ACTION_VIEW intents for Android, however this intent plugin also allows clients to set extra parameters for the intent. @@ -67,6 +67,6 @@ clients to set extra parameters for the intent. ## Getting Started For help getting started with Flutter, view our online -[documentation](http://flutter.io/). +[documentation](https://flutter.dev/). -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). +For help on editing plugin code, view the [documentation](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin). diff --git a/packages/android_intent/pubspec.yaml b/packages/android_intent/pubspec.yaml index aec7ad0d5a18..52928f08093f 100644 --- a/packages/android_intent/pubspec.yaml +++ b/packages/android_intent/pubspec.yaml @@ -1,7 +1,7 @@ name: android_intent description: Flutter plugin for launching Android Intents. Not supported on iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/android_intent -version: 2.0.0-nullsafety +version: 2.0.0-nullsafety.1 flutter: plugin: diff --git a/packages/battery/battery/CHANGELOG.md b/packages/battery/battery/CHANGELOG.md index c9bf41a81baf..c9268d4d4e3c 100644 --- a/packages/battery/battery/CHANGELOG.md +++ b/packages/battery/battery/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.10 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 1.0.9 * Update Flutter SDK constraint. diff --git a/packages/battery/battery/README.md b/packages/battery/battery/README.md index 22ce5007acd7..358dee6f8f27 100644 --- a/packages/battery/battery/README.md +++ b/packages/battery/battery/README.md @@ -1,11 +1,11 @@ # Battery -[![pub package](https://img.shields.io/pub/v/battery.svg)](https://pub.dartlang.org/packages/battery) +[![pub package](https://img.shields.io/pub/v/battery.svg)](https://pub.dev/packages/battery) A Flutter plugin to access various information about the battery of the device the app is running on. ## Usage -To use this plugin, add `battery` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/). +To use this plugin, add `battery` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels). ### Example diff --git a/packages/battery/battery/pubspec.yaml b/packages/battery/battery/pubspec.yaml index c7d4f0a9f5c2..d3c823d73ad2 100644 --- a/packages/battery/battery/pubspec.yaml +++ b/packages/battery/battery/pubspec.yaml @@ -2,7 +2,7 @@ name: battery description: Flutter plugin for accessing information about the battery state (full, charging, discharging) on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/battery/battery -version: 1.0.9 +version: 1.0.10 flutter: plugin: diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 8a7c979c3b72..a11579d528a4 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.0+2 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 0.6.0+1 Updated README to inform users that iOS 10.0+ is needed for use diff --git a/packages/camera/camera/README.md b/packages/camera/camera/README.md index f8a4b05211fd..f7163818aae3 100644 --- a/packages/camera/camera/README.md +++ b/packages/camera/camera/README.md @@ -1,6 +1,6 @@ # Camera Plugin -[![pub package](https://img.shields.io/pub/v/camera.svg)](https://pub.dartlang.org/packages/camera) +[![pub package](https://img.shields.io/pub/v/camera.svg)](https://pub.dev/packages/camera) A Flutter plugin for iOS and Android allowing access to the device cameras. @@ -15,7 +15,7 @@ A Flutter plugin for iOS and Android allowing access to the device cameras. ## Installation -First, add `camera` as a [dependency in your pubspec.yaml file](https://flutter.io/using-packages/). +First, add `camera` as a [dependency in your pubspec.yaml file](https://flutter.dev/using-packages/). ### iOS diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index cc25133f95f9..3c3e0cea3565 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.0+1 +version: 0.6.0+2 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index f215449eb72f..a1d0231a5bd4 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.0-nullsafety.3 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 3.0.0-nullsafety.2 * Android: Cleanup the NetworkCallback object when a connectivity stream is cancelled diff --git a/packages/connectivity/connectivity/README.md b/packages/connectivity/connectivity/README.md index a6a1dcc2838a..6c608d3d8e16 100644 --- a/packages/connectivity/connectivity/README.md +++ b/packages/connectivity/connectivity/README.md @@ -55,6 +55,6 @@ Note that connectivity changes are no longer communicated to Android apps in the ## Getting Started For help getting started with Flutter, view our online -[documentation](http://flutter.io/). +[documentation](https://flutter.dev/). -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). +For help on editing plugin code, view the [documentation](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin). diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index 916fa08908b5..7ae03553a26c 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -2,7 +2,7 @@ name: connectivity description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity -version: 3.0.0-nullsafety.2 +version: 3.0.0-nullsafety.3 flutter: plugin: diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md index b5d8a5695c5e..1716cb5ade7f 100644 --- a/packages/cross_file/CHANGELOG.md +++ b/packages/cross_file/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0+2 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 0.1.0+1 - Update Flutter SDK constraint. diff --git a/packages/cross_file/README.md b/packages/cross_file/README.md index f1ab89bc52f1..65bd41896184 100644 --- a/packages/cross_file/README.md +++ b/packages/cross_file/README.md @@ -24,7 +24,7 @@ final fileContent = await file.readAsString(); print('Content of the file: ${fileContent}'); // e.g. "Moto G (4)" ``` -You will find links to the API docs on the [pub page](https://pub.dartlang.org/packages/cross_file). +You will find links to the API docs on the [pub page](https://pub.dev/packages/cross_file). ## Getting Started diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml index 495a0ced5eee..0c7f30677aba 100644 --- a/packages/cross_file/pubspec.yaml +++ b/packages/cross_file/pubspec.yaml @@ -1,7 +1,7 @@ name: cross_file description: An abstraction to allow working with files across multiple platforms. homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file -version: 0.1.0+1 +version: 0.1.0+2 dependencies: flutter: diff --git a/packages/device_info/device_info/CHANGELOG.md b/packages/device_info/device_info/CHANGELOG.md index cee321742843..910d265b7c3e 100644 --- a/packages/device_info/device_info/CHANGELOG.md +++ b/packages/device_info/device_info/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.2 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 2.0.0-nullsafety.1 * Bump Dart SDK to support null safety. diff --git a/packages/device_info/device_info/README.md b/packages/device_info/device_info/README.md index 128bea5c2a17..98bfc15c7156 100644 --- a/packages/device_info/device_info/README.md +++ b/packages/device_info/device_info/README.md @@ -21,11 +21,11 @@ IosDeviceInfo iosInfo = await deviceInfo.iosInfo; print('Running on ${iosInfo.utsname.machine}'); // e.g. "iPod7,1" ``` -You will find links to the API docs on the [pub page](https://pub.dartlang.org/packages/device_info). +You will find links to the API docs on the [pub page](https://pub.dev/packages/device_info). ## Getting Started For help getting started with Flutter, view our online -[documentation](http://flutter.io/). +[documentation](https://flutter.dev/). -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). +For help on editing plugin code, view the [documentation](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin). diff --git a/packages/device_info/device_info/pubspec.yaml b/packages/device_info/device_info/pubspec.yaml index 57c1741270c2..1a222869a632 100644 --- a/packages/device_info/device_info/pubspec.yaml +++ b/packages/device_info/device_info/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/device_info # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 2.0.0-nullsafety.1 +version: 2.0.0-nullsafety.2 flutter: plugin: diff --git a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md index 6403638b02d4..e1804c5cc7f5 100644 --- a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md +++ b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.2 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 2.0.0-nullsafety.1 * Fix example app SDK. diff --git a/packages/flutter_plugin_android_lifecycle/README.md b/packages/flutter_plugin_android_lifecycle/README.md index 25f4d9efd056..3290140f4e5e 100644 --- a/packages/flutter_plugin_android_lifecycle/README.md +++ b/packages/flutter_plugin_android_lifecycle/README.md @@ -1,6 +1,6 @@ # Flutter Android Lifecycle Plugin -[![pub package](https://img.shields.io/pub/v/flutter_plugin_android_lifecycle.svg)](https://pub.dartlang.org/packages/flutter_plugin_android_lifecycle) +[![pub package](https://img.shields.io/pub/v/flutter_plugin_android_lifecycle.svg)](https://pub.dev/packages/flutter_plugin_android_lifecycle) A Flutter plugin for Android to allow other Flutter plugins to access Android `Lifecycle` objects in the plugin's binding. @@ -11,7 +11,7 @@ major version of the Android `Lifecycle` API they expect. ## Installation -Add `flutter_plugin_android_lifecycle` as a [dependency in your pubspec.yaml file](https://flutter.io/using-packages/). +Add `flutter_plugin_android_lifecycle` as a [dependency in your pubspec.yaml file](https://flutter.dev/using-packages/). ## Example diff --git a/packages/flutter_plugin_android_lifecycle/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/pubspec.yaml index 66b3eba5cb94..d94237c2101a 100644 --- a/packages/flutter_plugin_android_lifecycle/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_plugin_android_lifecycle description: Flutter plugin for accessing an Android Lifecycle within other plugins. -version: 2.0.0-nullsafety.1 +version: 2.0.0-nullsafety.2 homepage: https://github.com/flutter/plugins/tree/master/packages/flutter_plugin_android_lifecycle environment: diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index 75788a5d97fe..7783f3042dde 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.9 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 1.0.8 * Update Flutter SDK constraint. diff --git a/packages/google_maps_flutter/google_maps_flutter/README.md b/packages/google_maps_flutter/google_maps_flutter/README.md index cbc0ccbf62b8..6bb11a8da793 100644 --- a/packages/google_maps_flutter/google_maps_flutter/README.md +++ b/packages/google_maps_flutter/google_maps_flutter/README.md @@ -1,12 +1,12 @@ # Google Maps for Flutter -[![pub package](https://img.shields.io/pub/v/google_maps_flutter.svg)](https://pub.dartlang.org/packages/google_maps_flutter) +[![pub package](https://img.shields.io/pub/v/google_maps_flutter.svg)](https://pub.dev/packages/google_maps_flutter) A Flutter plugin that provides a [Google Maps](https://developers.google.com/maps/) widget. ## Usage -To use this plugin, add `google_maps_flutter` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/). +To use this plugin, add `google_maps_flutter` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels). ## Getting Started diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index b2f23805d863..7d480ebf74f2 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 1.0.8 +version: 1.0.9 dependencies: flutter: diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md index b2e5e7920db3..25539436f8fa 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.3 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 1.0.2 * Update Flutter SDK constraint. diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md index 689071dcfe8d..a7ad235b71d5 100755 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md @@ -5,4 +5,4 @@ Demonstrates how to use the google_sign_in plugin with the `googleapis` package. ## Getting Started For help getting started with Flutter, view our online -[documentation](http://flutter.io/). +[documentation](https://flutter.dev/). diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml index 39243e719b8a..aecd5a9569be 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml @@ -6,7 +6,7 @@ name: extension_google_sign_in_as_googleapis_auth description: A bridge package between google_sign_in and googleapis_auth, to create Authenticated Clients from google_sign_in user credentials. -version: 1.0.2 +version: 1.0.3 homepage: https://github.com/flutter/plugins/google_sign_in/extension_google_sign_in_as_googleapis_auth dependencies: diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md index 3c9605eb9752..8a4dd6bc817e 100644 --- a/packages/google_sign_in/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.5.8 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 4.5.7 * Update Flutter SDK constraint. diff --git a/packages/google_sign_in/google_sign_in/README.md b/packages/google_sign_in/google_sign_in/README.md index fc877171c4d2..61c4380cdcb7 100755 --- a/packages/google_sign_in/google_sign_in/README.md +++ b/packages/google_sign_in/google_sign_in/README.md @@ -1,6 +1,6 @@ # google_sign_in -[![pub package](https://img.shields.io/pub/v/google_sign_in.svg)](https://pub.dartlang.org/packages/google_sign_in) +[![pub package](https://img.shields.io/pub/v/google_sign_in.svg)](https://pub.dev/packages/google_sign_in) A Flutter plugin for [Google Sign In](https://developers.google.com/identity/). @@ -63,7 +63,7 @@ plugin could be an option. ## Usage ### Import the package -To use this plugin, follow the [plugin installation instructions](https://pub.dartlang.org/packages/google_sign_in#pub-pkg-tab-installing). +To use this plugin, follow the [plugin installation instructions](https://pub.dev/packages/google_sign_in#pub-pkg-tab-installing). ### Use the plugin Add the following import to your Dart code: diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index ea1218543d83..b99b231adb9d 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in -version: 4.5.7 +version: 4.5.8 flutter: plugin: diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index a1f7608ac7ac..4c1553a8ccaf 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+18 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 0.6.7+17 * iOS: fix `User-facing text should use localized string macro` warning. diff --git a/packages/image_picker/image_picker/README.md b/packages/image_picker/image_picker/README.md index 2e062a024597..106d78b630b9 100755 --- a/packages/image_picker/image_picker/README.md +++ b/packages/image_picker/image_picker/README.md @@ -1,13 +1,13 @@ # Image Picker plugin for Flutter -[![pub package](https://img.shields.io/pub/v/image_picker.svg)](https://pub.dartlang.org/packages/image_picker) +[![pub package](https://img.shields.io/pub/v/image_picker.svg)](https://pub.dev/packages/image_picker) A Flutter plugin for iOS and Android for picking images from the image library, and taking new pictures with the camera. ## Installation -First, add `image_picker` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/). +First, add `image_picker` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels). ### iOS diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 7b4972578e98..29baaa0de5d5 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+17 +version: 0.6.7+18 flutter: plugin: diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index 7b3301cf41cf..0a5794f931a8 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.4+18 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 0.3.4+17 * Update Flutter SDK constraint. diff --git a/packages/in_app_purchase/README.md b/packages/in_app_purchase/README.md index 021811842b2f..431f2810c165 100644 --- a/packages/in_app_purchase/README.md +++ b/packages/in_app_purchase/README.md @@ -181,7 +181,7 @@ WARNING! Failure to call `InAppPurchaseConnection.completePurchase` and get a su ## Development This plugin uses -[json_serializable](https://pub.dartlang.org/packages/json_serializable) for the +[json_serializable](https://pub.dev/packages/json_serializable) for the many data structs passed between the underlying platform layers and Dart. After editing any of the serialized data structs, rebuild the serializers by running `flutter packages pub run build_runner build --delete-conflicting-outputs`. diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 4b009b1383fd..5e5ef2447278 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.3.4+17 +version: 0.3.4+18 dependencies: async: ^2.0.8 diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index 48d8df4f0fd9..863d72ed1da4 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0-nullsafety.2 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 1.0.0-nullsafety.1 * Update README for Android Integration. diff --git a/packages/local_auth/README.md b/packages/local_auth/README.md index 98dcdcf0bffa..516561be4230 100644 --- a/packages/local_auth/README.md +++ b/packages/local_auth/README.md @@ -206,6 +206,6 @@ app resumes. ## Getting Started For help getting started with Flutter, view our online -[documentation](http://flutter.io/). +[documentation](https://flutter.dev/). -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). \ No newline at end of file +For help on editing plugin code, view the [documentation](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin). diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 30acd7264314..444eec2efa53 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth description: Flutter plugin for Android and iOS device authentication sensors such as Fingerprint Reader and Touch ID. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 1.0.0-nullsafety.1 +version: 1.0.0-nullsafety.2 flutter: plugin: diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index 551e040f0488..f0e3cd9bfde8 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.26 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 1.6.25 * Update Flutter SDK constraint. diff --git a/packages/path_provider/path_provider/README.md b/packages/path_provider/path_provider/README.md index e8d97e0106a3..0c80a5b34075 100644 --- a/packages/path_provider/path_provider/README.md +++ b/packages/path_provider/path_provider/README.md @@ -1,13 +1,13 @@ # path_provider -[![pub package](https://img.shields.io/pub/v/path_provider.svg)](https://pub.dartlang.org/packages/path_provider) +[![pub package](https://img.shields.io/pub/v/path_provider.svg)](https://pub.dev/packages/path_provider) A Flutter plugin for finding commonly used locations on the filesystem. Supports iOS, Android, Linux and MacOS. Not all methods are supported on all platforms. ## Usage -To use this plugin, add `path_provider` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/). +To use this plugin, add `path_provider` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels). ### Example diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index 4be15fad09ff..15f9c57a0c98 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 1.6.25 +version: 1.6.26 flutter: plugin: diff --git a/packages/quick_actions/CHANGELOG.md b/packages/quick_actions/CHANGELOG.md index 8126f08ae3a8..a0c1b1f43c66 100644 --- a/packages/quick_actions/CHANGELOG.md +++ b/packages/quick_actions/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.0+12 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 0.4.0+11 * Update Flutter SDK constraint. diff --git a/packages/quick_actions/README.md b/packages/quick_actions/README.md index 21e7cfb619cb..4573523a5e36 100644 --- a/packages/quick_actions/README.md +++ b/packages/quick_actions/README.md @@ -43,6 +43,6 @@ quick action. ## Getting Started For help getting started with Flutter, view our online -[documentation](http://flutter.io/). +[documentation](https://flutter.dev/). -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). +For help on editing plugin code, view the [documentation](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin). diff --git a/packages/quick_actions/pubspec.yaml b/packages/quick_actions/pubspec.yaml index ea363e842f08..e76cd9ce8bd2 100644 --- a/packages/quick_actions/pubspec.yaml +++ b/packages/quick_actions/pubspec.yaml @@ -2,7 +2,7 @@ name: quick_actions description: Flutter plugin for creating shortcuts on home screen, also known as Quick Actions on iOS and App Shortcuts on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/quick_actions -version: 0.4.0+11 +version: 0.4.0+12 flutter: plugin: diff --git a/packages/sensors/CHANGELOG.md b/packages/sensors/CHANGELOG.md index 82500ae4edda..8970f1e76e5d 100644 --- a/packages/sensors/CHANGELOG.md +++ b/packages/sensors/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.2+8 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 0.4.2+7 * Update Flutter SDK constraint. diff --git a/packages/sensors/README.md b/packages/sensors/README.md index e3c80b2b2947..08a9b2ea2b8c 100644 --- a/packages/sensors/README.md +++ b/packages/sensors/README.md @@ -13,7 +13,7 @@ A Flutter plugin to access the accelerometer and gyroscope sensors. ## Usage To use this plugin, add `sensors` as a [dependency in your pubspec.yaml -file](https://flutter.io/platform-plugins/). +file](https://flutter.dev/docs/development/platform-integration/platform-channels). This will expose three classes of sensor events, through three different streams. diff --git a/packages/sensors/pubspec.yaml b/packages/sensors/pubspec.yaml index e1abc05a8496..35feb4b1ed56 100644 --- a/packages/sensors/pubspec.yaml +++ b/packages/sensors/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/sensors # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.2+7 +version: 0.4.2+8 flutter: plugin: diff --git a/packages/share/CHANGELOG.md b/packages/share/CHANGELOG.md index 86906bbd56be..eef22bfcc76e 100644 --- a/packages/share/CHANGELOG.md +++ b/packages/share/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.1 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 2.0.0-nullsafety * Migrate to null safety. diff --git a/packages/share/README.md b/packages/share/README.md index 750fca6a5b18..6ca38b416f03 100644 --- a/packages/share/README.md +++ b/packages/share/README.md @@ -1,6 +1,6 @@ # Share plugin -[![pub package](https://img.shields.io/pub/v/share.svg)](https://pub.dartlang.org/packages/share) +[![pub package](https://img.shields.io/pub/v/share.svg)](https://pub.dev/packages/share) A Flutter plugin to share content from your Flutter app via the platform's share dialog. @@ -17,7 +17,7 @@ For more details see: https://github.com/flutter/flutter/wiki/Package-migration- ## Usage -To use this plugin, add `share` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/). +To use this plugin, add `share` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels). ## Example diff --git a/packages/share/pubspec.yaml b/packages/share/pubspec.yaml index 69d0fdbd5eb8..07ead8f3f659 100644 --- a/packages/share/pubspec.yaml +++ b/packages/share/pubspec.yaml @@ -2,7 +2,7 @@ name: share description: Flutter plugin for sharing content via the platform share UI, using the ACTION_SEND intent on Android and UIActivityViewController on iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/share -version: 2.0.0-nullsafety +version: 2.0.0-nullsafety.1 flutter: plugin: diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 407cf0ccdda4..5e09b3f87fb0 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.13+2 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 0.5.13+1 * Update Flutter SDK constraint. diff --git a/packages/shared_preferences/shared_preferences/README.md b/packages/shared_preferences/shared_preferences/README.md index 9ccac0ac49ae..516d7a91b848 100644 --- a/packages/shared_preferences/shared_preferences/README.md +++ b/packages/shared_preferences/shared_preferences/README.md @@ -1,6 +1,6 @@ # Shared preferences plugin -[![pub package](https://img.shields.io/pub/v/shared_preferences.svg)](https://pub.dartlang.org/packages/shared_preferences) +[![pub package](https://img.shields.io/pub/v/shared_preferences.svg)](https://pub.dev/packages/shared_preferences) Wraps platform-specific persistent storage for simple data (NSUserDefaults on iOS and macOS, SharedPreferences on Android, etc.). Data may be persisted to disk asynchronously, @@ -16,7 +16,7 @@ Please use `shared_preferences: '>=0.5.y+x <2.0.0'` as your dependency constrain For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 ## Usage -To use this plugin, add `shared_preferences` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/). +To use this plugin, add `shared_preferences` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels). ### Example diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 492027ac0e42..69689c738b8e 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/shared_prefere # 0.5.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.5.13+1 +version: 0.5.13+2 flutter: plugin: diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index aaf958a52624..9df2d27a2b57 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.0.0-nullsafety.2 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 6.0.0-nullsafety.1 * Bump Dart SDK to support null safety. diff --git a/packages/url_launcher/url_launcher/README.md b/packages/url_launcher/url_launcher/README.md index f29b5327a611..573624fa18eb 100644 --- a/packages/url_launcher/url_launcher/README.md +++ b/packages/url_launcher/url_launcher/README.md @@ -1,6 +1,6 @@ # url_launcher -[![pub package](https://img.shields.io/pub/v/url_launcher.svg)](https://pub.dartlang.org/packages/url_launcher) +[![pub package](https://img.shields.io/pub/v/url_launcher.svg)](https://pub.dev/packages/url_launcher) A Flutter plugin for launching a URL in the mobile platform. Supports iOS, Android, web, Windows, macOS, and Linux. @@ -35,7 +35,7 @@ void _launchURL() async => ## Supported URL schemes -The [`launch`](https://www.dartdocs.org/documentation/url_launcher/latest/url_launcher/launch.html) method +The [`launch`](https://pub.dev/documentation/url_launcher/latest/url_launcher/launch.html) method takes a string argument containing a URL. This URL can be formatted using a number of different URL schemes. The supported URL schemes depend on the underlying platform and installed apps. @@ -80,7 +80,7 @@ launching a URL using the `sms` scheme, or a device may not have an email app and thus no support for launching a URL using the `email` scheme. We recommend checking which URL schemes are supported using the -[`canLaunch`](https://www.dartdocs.org/documentation/url_launcher/latest/url_launcher/canLaunch.html) +[`canLaunch`](https://pub.dev/documentation/url_launcher/latest/url_launcher/canLaunch.html) method prior to calling `launch`. If the `canLaunch` method returns false, as a best practice we suggest adjusting the application UI so that the unsupported URL is never triggered; for example, if the `email` scheme is not supported, a diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index d0abd941a9c2..e2d7a161e1ea 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 6.0.0-nullsafety.1 +version: 6.0.0-nullsafety.2 flutter: plugin: diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md index bad287a7a744..cc3ee456c938 100644 --- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0-nullsafety.2 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 0.1.0-nullsafety.1 * Migrate to null safety. diff --git a/packages/url_launcher/url_launcher_linux/example/README.md b/packages/url_launcher/url_launcher_linux/example/README.md index 28dd90d71700..c200da8974d1 100644 --- a/packages/url_launcher/url_launcher_linux/example/README.md +++ b/packages/url_launcher/url_launcher_linux/example/README.md @@ -5,4 +5,4 @@ Demonstrates how to use the url_launcher plugin. ## Getting Started For help getting started with Flutter, view our online -[documentation](http://flutter.io/). +[documentation](https://flutter.dev/). diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml index e2fb5fc52e69..41366a1d4f1e 100644 --- a/packages/url_launcher/url_launcher_linux/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: url_launcher_linux description: Linux implementation of the url_launcher plugin. -version: 0.1.0-nullsafety.1 +version: 0.1.0-nullsafety.2 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux flutter: diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index e2bca40531da..4e2826262eaf 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.5 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 2.0.0-nullsafety.4 * Fixed an issue where `isBuffering` was not updating on Android. diff --git a/packages/video_player/video_player/README.md b/packages/video_player/video_player/README.md index 5eff770b87a2..e64ce152f85b 100644 --- a/packages/video_player/video_player/README.md +++ b/packages/video_player/video_player/README.md @@ -1,6 +1,6 @@ # Video Player plugin for Flutter -[![pub package](https://img.shields.io/pub/v/video_player.svg)](https://pub.dartlang.org/packages/video_player) +[![pub package](https://img.shields.io/pub/v/video_player.svg)](https://pub.dev/packages/video_player) A Flutter plugin for iOS, Android and Web for playing back video on a Widget surface. @@ -12,7 +12,7 @@ A Flutter plugin for iOS, Android and Web for playing back video on a Widget sur ## Installation -First, add `video_player` as a [dependency in your pubspec.yaml file](https://flutter.io/using-packages/). +First, add `video_player` as a [dependency in your pubspec.yaml file](https://flutter.dev/using-packages/). ### iOS diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 6e483324e499..603f2358cd55 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for displaying inline video with other Flutter # 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 2.0.0-nullsafety.4 +version: 2.0.0-nullsafety.5 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index a10c28dc20b7..19cacb6a6e90 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.2 + +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) + ## 2.0.0-nullsafety.1 * Added `allowsInlineMediaPlayback` property. diff --git a/packages/webview_flutter/README.md b/packages/webview_flutter/README.md index 6852ebb34522..df554eb5123c 100644 --- a/packages/webview_flutter/README.md +++ b/packages/webview_flutter/README.md @@ -1,6 +1,6 @@ # WebView for Flutter -[![pub package](https://img.shields.io/pub/v/webview_flutter.svg)](https://pub.dartlang.org/packages/webview_flutter) +[![pub package](https://img.shields.io/pub/v/webview_flutter.svg)](https://pub.dev/packages/webview_flutter) A Flutter plugin that provides a WebView widget. @@ -8,7 +8,7 @@ On iOS the WebView widget is backed by a [WKWebView](https://developer.apple.com On Android the WebView widget is backed by a [WebView](https://developer.android.com/reference/android/webkit/WebView). ## Usage -Add `webview_flutter` as a [dependency in your pubspec.yaml file](https://flutter.io/platform-plugins/). +Add `webview_flutter` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels). You can now include a WebView widget in your widget tree. See the [WebView](https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebView-class.html) diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 75910dfe02aa..b2fbfc1110c5 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 2.0.0-nullsafety.1 +version: 2.0.0-nullsafety.2 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: From 22422af71d792e62f439fb8a278b1c23fa940993 Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Sat, 19 Dec 2020 11:08:30 +0100 Subject: [PATCH 058/924] [camera] Flash functionality for Android and iOS (#3314) * Move camera to camera/camera * Fix relative path after move * First suggestion for camera platform interface * Remove test coverage folder * Update the version to 1.0.0 * Remove redundant analysis overrides * Renamed onLatestImageAvailableHandler definition * Split CameraEvents into separate streams * Updated platform interface to have recording methods return XFile instances. * Update documentation and unit tests to match platform interface changes * Make file input optional for recording methods in platform interface. Update docs. * Add missing full stop in docs. * Run dartfmt. Wrapped docs after max 80 cols. Added missing full stop. * Implemented & tested first parts of method channel implementation * Remove unused EventChannelMock class * Add missing unit tests * Add availableCameras to method channel implementation * Updated platform interface * Update packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart Co-authored-by: Maurits van Beusekom * Update packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart Co-authored-by: Maurits van Beusekom * Added placeholders in default method channel implementation * Add missing implementations to default method channel implementation * Fix formatting * Fix PR feedback * Add unit test for availableCameras * Expand availableCameras unit test. Added unit test for takePicture. * Add unit test for startVideoRecording * Add unit test for prepareForVideoRecording * Add unit test for stopVideoRecording * Add unit test for pauseVideoRecording * Add unit test for buildView * Remove TODO comment * Update packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart Co-authored-by: Maurits van Beusekom * Update packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart Co-authored-by: Maurits van Beusekom * Update packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart Co-authored-by: Maurits van Beusekom * WIP: Dart and Android implementation * Have resolution stream replay last value on subscription. Replace stream_transform with rxdart. * Added reverse method channel to replace event channel. Updated initialise and takePicture implementations for android. WIP implementation for startVideoRecording * Fixed example app for Android. Removed isRecordingVideo and isStreamingImages from buildView method. * iOS implementation: Removed standard event channel. Added reverse method channel. Updated initialize method. Added resolution changed event. Updated error reporting to use new method channel. * Added some first tests for camera/camera * Started splitting initialize method * More tests and some feedback * Finish splitting up initialize for iOS * Update unit tests * Remove unused listener in plugin * Fix takePicture method on iOS * Fix video recording on iOS. Updated platform interface. * Update unit tests * Update error handling of video methods in iOS code. Make iOS code more consistent. * Split initialize method on Android * Updated startVideoRecording documentation * Make sure file is returned by stopVideoRecording * Change cast * Use correct event-type after initializing * Fix DartMessenger unit-tests * Fix formatting * Fixed tests, formatting and analysis warnings * Added missing documentation public APIs * Added missing license to Dart files * Fix formatting issues * Updated CHANGELOG and version * Added more tests * Formatted code * Added additional unit-tests to platform_interface * Fix formatting issues * Re-added the CameraPreview widget * Refactored CameraException not to use * Use import/export instead of part implementation * fixed formatting * Resolved additional feedback * Resolved additional feedback * Flash WIP * Implement flash modes for Android * Update dependency to git repo * Add missing PictureCaptureRequest class * Add PR feedback * Move enums out of Camera.java * Expanded platform interface so support setting flash mode * Formatted dart code * Manually serialize flash mode enum rather than relying on stringification. * Add default to flash mode serialization * Fix for unit tests and reformatting * Fixed CHANGELOG and remove redundant iOS files * Expose FlashMode through camera package * Add reqeusted unit tests * Clean up new tests * Add unit tests for Android implementation * Update platform interface dependency to point to pub.dev release. Co-authored-by: Maurits van Beusekom Co-authored-by: Maurits van Beusekom Co-authored-by: daniel --- packages/camera/camera/CHANGELOG.md | 4 + .../io/flutter/plugins/camera/Camera.java | 191 ++++++++++++++---- .../flutter/plugins/camera/CameraUtils.java | 2 +- .../plugins/camera/MethodCallHandlerImpl.java | 16 ++ .../plugins/camera/PictureCaptureRequest.java | 49 +++++ .../plugins/camera/types/FlashMode.java | 16 ++ .../camera/types/ResolutionPreset.java | 11 + .../camera/PictureCaptureRequestTest.java | 93 +++++++++ .../plugins/camera/types/FlashModeTest.java | 26 +++ .../android/app/src/main/AndroidManifest.xml | 1 + packages/camera/camera/example/lib/main.dart | 54 +++++ .../camera/camera/ios/Classes/CameraPlugin.m | 48 +++++ packages/camera/camera/lib/camera.dart | 1 + .../camera/lib/src/camera_controller.dart | 20 +- packages/camera/camera/pubspec.yaml | 4 +- packages/camera/camera/test/camera_test.dart | 45 +++++ .../camera/camera/test/camera_value_test.dart | 6 +- 17 files changed, 542 insertions(+), 45 deletions(-) create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index a11579d528a4..9789e9e80b69 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.1 + +* Add flash support for Android and iOS implementations. + ## 0.6.0+2 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 306dd447cfb9..27f1355319c1 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -17,6 +17,8 @@ import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; @@ -34,6 +36,8 @@ import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.camera.media.MediaRecorderBuilder; +import io.flutter.plugins.camera.types.FlashMode; +import io.flutter.plugins.camera.types.ResolutionPreset; import io.flutter.view.TextureRegistry.SurfaceTextureEntry; import java.io.File; import java.io.FileOutputStream; @@ -69,16 +73,8 @@ public class Camera { private CamcorderProfile recordingProfile; private int currentOrientation = ORIENTATION_UNKNOWN; private Context applicationContext; - - // Mirrors camera.dart - public enum ResolutionPreset { - low, - medium, - high, - veryHigh, - ultraHigh, - max, - } + private FlashMode flashMode; + private PictureCaptureRequest pictureCaptureRequest; public Camera( final Activity activity, @@ -97,6 +93,7 @@ public Camera( this.dartMessenger = dartMessenger; this.cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); this.applicationContext = activity.getApplicationContext(); + this.flashMode = FlashMode.auto; orientationEventListener = new OrientationEventListener(activity.getApplicationContext()) { @Override @@ -220,58 +217,125 @@ SurfaceTextureEntry getFlutterTexture() { } public void takePicture(@NonNull final Result result) { + // Only take 1 picture at a time + if (pictureCaptureRequest != null && !pictureCaptureRequest.isFinished()) { + result.error("captureAlreadyActive", "Picture is currently already being captured", null); + return; + } + // Store the result + this.pictureCaptureRequest = new PictureCaptureRequest(result); + + // Create temporary file final File outputDir = applicationContext.getCacheDir(); final File file; try { file = File.createTempFile("CAP", ".jpg", outputDir); } catch (IOException | SecurityException e) { - result.error("cannotCreateFile", e.getMessage(), null); + pictureCaptureRequest.error("cannotCreateFile", e.getMessage(), null); return; } + // Listen for picture being taken pictureImageReader.setOnImageAvailableListener( reader -> { try (Image image = reader.acquireLatestImage()) { ByteBuffer buffer = image.getPlanes()[0].getBuffer(); writeToFile(buffer, file); - result.success(file.getAbsolutePath()); + pictureCaptureRequest.finish(file.getAbsolutePath()); } catch (IOException e) { - result.error("IOError", "Failed saving image", null); + pictureCaptureRequest.error("IOError", "Failed saving image", null); } }, null); + runPicturePreCapture(); + } + + private final CameraCaptureSession.CaptureCallback pictureCaptureCallback = + new CameraCaptureSession.CaptureCallback() { + @Override + public void onCaptureCompleted( + @NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, + @NonNull TotalCaptureResult result) { + assert (pictureCaptureRequest != null); + switch (pictureCaptureRequest.getState()) { + case awaitingPreCapture: + Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); + // Some devices might return null here, in which case we will also continue. + if (aeState == null + || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED + || aeState == CaptureRequest.CONTROL_AE_STATE_CONVERGED) { + runPictureCapture(); + } + break; + } + } + + @Override + public void onCaptureFailed( + @NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, + @NonNull CaptureFailure failure) { + assert (pictureCaptureRequest != null); + String reason; + switch (failure.getReason()) { + case CaptureFailure.REASON_ERROR: + reason = "An error happened in the framework"; + break; + case CaptureFailure.REASON_FLUSHED: + reason = "The capture has failed due to an abortCaptures() call"; + break; + default: + reason = "Unknown reason"; + } + pictureCaptureRequest.error("captureFailure", reason, null); + } + }; + + private void runPicturePreCapture() { + assert (pictureCaptureRequest != null); + pictureCaptureRequest.setState(PictureCaptureRequest.State.awaitingPreCapture); + + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); + try { + cameraCaptureSession.capture(captureRequestBuilder.build(), pictureCaptureCallback, null); + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); + } catch (CameraAccessException e) { + pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); + } + } + + private void runPictureCapture() { + assert (pictureCaptureRequest != null); + pictureCaptureRequest.setState(PictureCaptureRequest.State.capturing); try { final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(pictureImageReader.getSurface()); captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getMediaOrientation()); - - cameraCaptureSession.capture( - captureBuilder.build(), - new CameraCaptureSession.CaptureCallback() { - @Override - public void onCaptureFailed( - @NonNull CameraCaptureSession session, - @NonNull CaptureRequest request, - @NonNull CaptureFailure failure) { - String reason; - switch (failure.getReason()) { - case CaptureFailure.REASON_ERROR: - reason = "An error happened in the framework"; - break; - case CaptureFailure.REASON_FLUSHED: - reason = "The capture has failed due to an abortCaptures() call"; - break; - default: - reason = "Unknown reason"; - } - result.error("captureFailure", reason, null); - } - }, - null); + switch (flashMode) { + case off: + captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); + captureBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + break; + case auto: + captureBuilder.set( + CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); + break; + case always: + default: + captureBuilder.set( + CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); + break; + } + cameraCaptureSession.capture(captureBuilder.build(), pictureCaptureCallback, null); } catch (CameraAccessException e) { - result.error("cameraAccess", e.getMessage(), null); + pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); } } @@ -314,8 +378,7 @@ public void onConfigured(@NonNull CameraCaptureSession session) { return; } cameraCaptureSession = session; - captureRequestBuilder.set( - CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); + initPreviewCaptureBuilder(); cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); if (onSuccessCallback != null) { onSuccessCallback.run(); @@ -452,6 +515,54 @@ public void resumeVideoRecording(@NonNull final Result result) { result.success(null); } + public void setFlashMode(@NonNull final Result result, FlashMode mode) + throws CameraAccessException { + // Get the flash availability + Boolean flashAvailable; + try { + flashAvailable = + cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.FLASH_INFO_AVAILABLE); + } catch (CameraAccessException e) { + result.error("setFlashModeFailed", e.getMessage(), null); + return; + } + // Check if flash is available. + if (flashAvailable == null || !flashAvailable) { + result.error("setFlashModeFailed", "Device does not have flash capabilities", null); + return; + } + // Get flash + + this.flashMode = mode; + initPreviewCaptureBuilder(); + this.cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); + result.success(null); + } + + private void initPreviewCaptureBuilder() { + captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); + switch (flashMode) { + case off: + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); + captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + break; + case auto: + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); + captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + break; + case always: + default: + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); + captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + break; + } + } + public void startPreview() throws CameraAccessException { if (pictureImageReader == null || pictureImageReader.getSurface() == null) return; diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java index a7bb3b7d4914..3b665d6b24f2 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java @@ -10,7 +10,7 @@ import android.hardware.camera2.params.StreamConfigurationMap; import android.media.CamcorderProfile; import android.util.Size; -import io.flutter.plugins.camera.Camera.ResolutionPreset; +import io.flutter.plugins.camera.types.ResolutionPreset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 6c2e65e76f9e..12b99b72f642 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -10,6 +10,7 @@ import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.camera.CameraPermissions.PermissionsRegistry; +import io.flutter.plugins.camera.types.FlashMode; import io.flutter.view.TextureRegistry; import java.util.HashMap; import java.util.Map; @@ -122,6 +123,21 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) camera.resumeVideoRecording(result); break; } + case "setFlashMode": + { + String modeStr = call.argument("mode"); + FlashMode mode = FlashMode.getValueForString(modeStr); + if (mode == null) { + result.error("setFlashModeFailed", "Unknown flash mode " + modeStr, null); + return; + } + try { + camera.setFlashMode(result, mode); + } catch (Exception e) { + handleException(e, result); + } + break; + } case "startImageStream": { try { diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java new file mode 100644 index 000000000000..e365f071d9a8 --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java @@ -0,0 +1,49 @@ +package io.flutter.plugins.camera; + +import androidx.annotation.Nullable; +import io.flutter.plugin.common.MethodChannel; + +class PictureCaptureRequest { + + enum State { + idle, + awaitingPreCapture, + capturing, + finished, + error, + } + + private final MethodChannel.Result result; + private State state; + + public PictureCaptureRequest(MethodChannel.Result result) { + this.result = result; + state = State.idle; + } + + public void setState(State state) { + if (isFinished()) throw new IllegalStateException("Request has already been finished"); + this.state = state; + } + + public State getState() { + return state; + } + + public boolean isFinished() { + return state == State.finished || state == State.error; + } + + public void finish(String absolutePath) { + if (isFinished()) throw new IllegalStateException("Request has already been finished"); + result.success(absolutePath); + state = State.finished; + } + + public void error( + String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { + if (isFinished()) throw new IllegalStateException("Request has already been finished"); + result.error(errorCode, errorMessage, errorDetails); + state = State.error; + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java new file mode 100644 index 000000000000..eddeddc47eab --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java @@ -0,0 +1,16 @@ +package io.flutter.plugins.camera.types; + +// Mirrors flash_mode.dart +public enum FlashMode { + off, + auto, + always; + + public static FlashMode getValueForString(String modeStr) { + try { + return valueOf(modeStr); + } catch (IllegalArgumentException | NullPointerException e) { + return null; + } + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java new file mode 100644 index 000000000000..ffbe2e62095d --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java @@ -0,0 +1,11 @@ +package io.flutter.plugins.camera.types; + +// Mirrors camera.dart +public enum ResolutionPreset { + low, + medium, + high, + veryHigh, + ultraHigh, + max, +} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java new file mode 100644 index 000000000000..2b6aa0f25fcf --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java @@ -0,0 +1,93 @@ +package io.flutter.plugins.camera; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import io.flutter.plugin.common.MethodChannel; +import org.junit.Test; + +public class PictureCaptureRequestTest { + + @Test + public void state_is_idle_by_default() { + PictureCaptureRequest req = new PictureCaptureRequest(null); + assertEquals("Default state is idle", req.getState(), PictureCaptureRequest.State.idle); + } + + @Test + public void setState_sets_state() { + PictureCaptureRequest req = new PictureCaptureRequest(null); + req.setState(PictureCaptureRequest.State.awaitingPreCapture); + assertEquals( + "State is awaitingPreCapture", + req.getState(), + PictureCaptureRequest.State.awaitingPreCapture); + req.setState(PictureCaptureRequest.State.capturing); + assertEquals( + "State is awaitingPreCapture", req.getState(), PictureCaptureRequest.State.capturing); + } + + @Test + public void finish_sets_result_and_state() { + // Setup + MethodChannel.Result mockResult = mock(MethodChannel.Result.class); + PictureCaptureRequest req = new PictureCaptureRequest(mockResult); + // Act + req.finish("/test/path"); + // Test + verify(mockResult).success("/test/path"); + assertEquals("State is finished", req.getState(), PictureCaptureRequest.State.finished); + } + + @Test + public void isFinished_is_true_When_state_is_finished_or_error() { + // Setup + PictureCaptureRequest req = new PictureCaptureRequest(null); + // Test false states + req.setState(PictureCaptureRequest.State.idle); + assertFalse(req.isFinished()); + req.setState(PictureCaptureRequest.State.awaitingPreCapture); + assertFalse(req.isFinished()); + req.setState(PictureCaptureRequest.State.capturing); + assertFalse(req.isFinished()); + // Test true states + req.setState(PictureCaptureRequest.State.finished); + assertTrue(req.isFinished()); + req = new PictureCaptureRequest(null); // Refresh + req.setState(PictureCaptureRequest.State.error); + assertTrue(req.isFinished()); + } + + @Test(expected = IllegalStateException.class) + public void finish_throws_When_already_finished() { + // Setup + PictureCaptureRequest req = new PictureCaptureRequest(null); + req.setState(PictureCaptureRequest.State.finished); + // Act + req.finish("/test/path"); + } + + @Test + public void error_sets_result_and_state() { + // Setup + MethodChannel.Result mockResult = mock(MethodChannel.Result.class); + PictureCaptureRequest req = new PictureCaptureRequest(mockResult); + // Act + req.error("ERROR_CODE", "Error Message", null); + // Test + verify(mockResult).error("ERROR_CODE", "Error Message", null); + assertEquals("State is error", req.getState(), PictureCaptureRequest.State.error); + } + + @Test(expected = IllegalStateException.class) + public void error_throws_When_already_finished() { + // Setup + PictureCaptureRequest req = new PictureCaptureRequest(null); + req.setState(PictureCaptureRequest.State.finished); + // Act + req.error(null, null, null); + } +} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java new file mode 100644 index 000000000000..0549e4fc750e --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java @@ -0,0 +1,26 @@ +package io.flutter.plugins.camera.types; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class FlashModeTest { + + @Test + public void getValueForString_returns_correct_values() { + assertEquals( + "Returns FlashMode.off for 'off'", FlashMode.getValueForString("off"), FlashMode.off); + assertEquals( + "Returns FlashMode.auto for 'auto'", FlashMode.getValueForString("auto"), FlashMode.auto); + assertEquals( + "Returns FlashMode.always for 'always'", + FlashMode.getValueForString("always"), + FlashMode.always); + } + + @Test + public void getValueForString_returns_null_for_nonexistant_value() { + assertEquals( + "Returns null for 'nonexistant'", FlashMode.getValueForString("nonexistant"), null); + } +} diff --git a/packages/camera/camera/example/android/app/src/main/AndroidManifest.xml b/packages/camera/camera/example/android/app/src/main/AndroidManifest.xml index f37f82306024..f216a7251bcf 100644 --- a/packages/camera/camera/example/android/app/src/main/AndroidManifest.xml +++ b/packages/camera/camera/example/android/app/src/main/AndroidManifest.xml @@ -37,4 +37,5 @@ android:required="true"/> + diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index e1edc1b06386..847779dade09 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -101,6 +101,7 @@ class _CameraExampleHomeState extends State ), ), _captureControlRowWidget(), + _flashModeRowWidget(), _toggleAudioWidget(), Padding( padding: const EdgeInsets.all(5.0), @@ -191,6 +192,43 @@ class _CameraExampleHomeState extends State ); } + /// Display a bar with buttons to change the flash mode + Widget _flashModeRowWidget() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisSize: MainAxisSize.max, + children: [ + IconButton( + icon: const Icon(Icons.flash_off), + color: controller?.value?.flashMode == FlashMode.off + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => onFlashModeButtonPressed(FlashMode.off) + : null, + ), + IconButton( + icon: const Icon(Icons.flash_auto), + color: controller?.value?.flashMode == FlashMode.auto + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => onFlashModeButtonPressed(FlashMode.auto) + : null, + ), + IconButton( + icon: const Icon(Icons.flash_on), + color: controller?.value?.flashMode == FlashMode.always + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => onFlashModeButtonPressed(FlashMode.always) + : null, + ), + ], + ); + } + /// Display the control bar with buttons to take pictures and record videos. Widget _captureControlRowWidget() { return Row( @@ -317,6 +355,13 @@ class _CameraExampleHomeState extends State }); } + void onFlashModeButtonPressed(FlashMode mode) { + setFlashMode(mode).then((_) { + if (mounted) setState(() {}); + showInSnackBar('Flash mode set to ${mode.toString().split('.').last}'); + }); + } + void onVideoRecordButtonPressed() { startVideoRecording().then((_) { if (mounted) setState(() {}); @@ -406,6 +451,15 @@ class _CameraExampleHomeState extends State } } + Future setFlashMode(FlashMode mode) async { + try { + await controller.setFlashMode(mode); + } on CameraException catch (e) { + _showCameraException(e); + rethrow; + } + } + Future _startVideoPlayer() async { final VideoPlayerController vController = VideoPlayerController.file(File(videoFile.path)); diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index 9455375b8524..cc70ddf209ce 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -114,6 +114,24 @@ - (UIImageOrientation)getImageRotation { } @end +static AVCaptureFlashMode getFlashModeForString(NSString *mode) { + if ([mode isEqualToString:@"off"]) { + return AVCaptureFlashModeOff; + } else if ([mode isEqualToString:@"auto"]) { + return AVCaptureFlashModeAuto; + } else if ([mode isEqualToString:@"always"]) { + return AVCaptureFlashModeOn; + } else { + NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:NSURLErrorUnknown + userInfo:@{ + NSLocalizedDescriptionKey : [NSString + stringWithFormat:@"Unknown flash mode %@", mode] + }]; + @throw error; + } +} + // Mirrors ResolutionPreset in camera.dart typedef enum { veryLow, @@ -181,6 +199,7 @@ @interface FLTCam : NSObject *)messenger { if (!_isStreamingImages) { FlutterEventChannel *eventChannel = @@ -910,6 +956,8 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re [_camera pauseVideoRecordingWithResult:result]; } else if ([@"resumeVideoRecording" isEqualToString:call.method]) { [_camera resumeVideoRecordingWithResult:result]; + } else if ([@"setFlashMode" isEqualToString:call.method]) { + [_camera setFlashModeWithResult:result mode:call.arguments[@"mode"]]; } else { result(FlutterMethodNotImplemented); } diff --git a/packages/camera/camera/lib/camera.dart b/packages/camera/camera/lib/camera.dart index 6c6d90b9bcee..6c6214e96951 100644 --- a/packages/camera/camera/lib/camera.dart +++ b/packages/camera/camera/lib/camera.dart @@ -11,5 +11,6 @@ export 'package:camera_platform_interface/camera_platform_interface.dart' CameraDescription, CameraException, CameraLensDirection, + FlashMode, ResolutionPreset, XFile; diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index fcf00245ce7f..2c2ce3b633f1 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -36,6 +36,7 @@ class CameraValue { this.isTakingPicture, this.isStreamingImages, bool isRecordingPaused, + this.flashMode, }) : _isRecordingPaused = isRecordingPaused; /// Creates a new camera controller state for an uninitialized controller. @@ -46,6 +47,7 @@ class CameraValue { isTakingPicture: false, isStreamingImages: false, isRecordingPaused: false, + flashMode: FlashMode.auto, ); /// True after [CameraController.initialize] has completed successfully. @@ -86,6 +88,9 @@ class CameraValue { /// When true [errorDescription] describes the error. bool get hasError => errorDescription != null; + /// The flash mode the camera is currently set to. + final FlashMode flashMode; + /// Creates a modified copy of the object. /// /// Explicitly specified fields get the specified value, all other fields get @@ -98,6 +103,7 @@ class CameraValue { String errorDescription, Size previewSize, bool isRecordingPaused, + FlashMode flashMode, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -107,6 +113,7 @@ class CameraValue { isTakingPicture: isTakingPicture ?? this.isTakingPicture, isStreamingImages: isStreamingImages ?? this.isStreamingImages, isRecordingPaused: isRecordingPaused ?? _isRecordingPaused, + flashMode: flashMode ?? this.flashMode, ); } @@ -117,7 +124,8 @@ class CameraValue { 'isInitialized: $isInitialized, ' 'errorDescription: $errorDescription, ' 'previewSize: $previewSize, ' - 'isStreamingImages: $isStreamingImages)'; + 'isStreamingImages: $isStreamingImages, ' + 'flashMode: $flashMode)'; } } @@ -468,6 +476,16 @@ class CameraController extends ValueNotifier { } } + /// Sets the flash mode for taking pictures. + Future setFlashMode(FlashMode mode) async { + try { + await CameraPlatform.instance.setFlashMode(_cameraId, mode); + value = value.copyWith(flashMode: mode); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + /// Releases the resources of this camera. @override Future dispose() async { diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 3c3e0cea3565..3194fff33684 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,13 +2,13 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.0+2 +version: 0.6.1 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: flutter: sdk: flutter - camera_platform_interface: ^1.0.0 + camera_platform_interface: ^1.0.4 dev_dependencies: path_provider: ^0.5.0 diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index b129849cd141..c19aa9718f47 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -310,6 +310,51 @@ void main() { 'startVideoRecording was called while a camera was streaming images.', ))); }); + + test('setFlashMode() calls $CameraPlatform', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.setFlashMode(FlashMode.always); + + verify(CameraPlatform.instance + .setFlashMode(cameraController.cameraId, FlashMode.always)) + .called(1); + }); + + test('setFlashMode() throws $CameraException on $PlatformException', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .setFlashMode(cameraController.cameraId, FlashMode.always)) + .thenThrow( + PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error message', + details: null, + ), + ); + + expect( + cameraController.setFlashMode(FlashMode.always), + throwsA(isA().having( + (error) => error.description, + 'TEST_ERROR', + 'This is a test error message', + ))); + }); }); } diff --git a/packages/camera/camera/test/camera_value_test.dart b/packages/camera/camera/test/camera_value_test.dart index 28255eb0a568..06b327cb1c29 100644 --- a/packages/camera/camera/test/camera_value_test.dart +++ b/packages/camera/camera/test/camera_value_test.dart @@ -5,6 +5,7 @@ import 'dart:ui'; import 'package:camera/camera.dart'; +import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -19,6 +20,7 @@ void main() { isRecordingVideo: false, isTakingPicture: false, isStreamingImages: false, + flashMode: FlashMode.auto, ); expect(cameraValue, isA()); @@ -56,6 +58,7 @@ void main() { expect(cameraValue.isRecordingVideo, isFalse); expect(cameraValue.isTakingPicture, isFalse); expect(cameraValue.isStreamingImages, isFalse); + expect(cameraValue.flashMode, FlashMode.auto); }); test('Has aspectRatio after setting size', () { @@ -93,10 +96,11 @@ void main() { isRecordingVideo: false, isTakingPicture: false, isStreamingImages: false, + flashMode: FlashMode.auto, ); expect(cameraValue.toString(), - 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false)'); + 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false, flashMode: FlashMode.auto)'); }); }); } From 0c6ed0418bdee30610f70bb60ae1bf8eaa97456c Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Sat, 19 Dec 2020 11:46:28 +0100 Subject: [PATCH 059/924] Add implementation of didFinishProcessingPhoto callback (#3337) --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../camera/camera/ios/Classes/CameraPlugin.m | 20 +++++++++++++++++++ packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 9789e9e80b69..24b1365d1252 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.1+1 + +* Added implementation of the `didFinishProcessingPhoto` on iOS which allows saving image metadata (EXIF) on iOS 11 and up. + ## 0.6.1 * Add flash support for Android and iOS implementations. diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index cc70ddf209ce..4e5c37ed67a9 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -76,6 +76,7 @@ - (void)captureOutput:(AVCapturePhotoOutput *)output UIImage *image = [UIImage imageWithCGImage:[UIImage imageWithData:data].CGImage scale:1.0 orientation:[self getImageRotation]]; + // TODO(sigurdm): Consider writing file asynchronously. bool success = [UIImageJPEGRepresentation(image, 1.0) writeToFile:_path atomically:YES]; if (!success) { @@ -85,6 +86,25 @@ - (void)captureOutput:(AVCapturePhotoOutput *)output _result(_path); } +- (void)captureOutput:(AVCapturePhotoOutput *)output + didFinishProcessingPhoto:(AVCapturePhoto *)photo + error:(NSError *)error API_AVAILABLE(ios(11.0)) { + selfReference = nil; + if (error) { + _result(getFlutterError(error)); + return; + } + + NSData *photoData = [photo fileDataRepresentation]; + + bool success = [photoData writeToFile:_path atomically:YES]; + if (!success) { + _result([FlutterError errorWithCode:@"IOError" message:@"Unable to write file" details:nil]); + return; + } + _result(_path); +} + - (UIImageOrientation)getImageRotation { float const threshold = 45.0; BOOL (^isNearValue)(float value1, float value2) = ^BOOL(float value1, float value2) { diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 3194fff33684..587e6f752971 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.1 +version: 0.6.1+1 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From b289e1a4fb1b6fe574a50408e066030bd1eb911c Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Sat, 19 Dec 2020 23:59:27 +0100 Subject: [PATCH 060/924] [camera] Zoom functionality for Android and iOS (#3315) * Refactored and tested zoom on Android * Fix merge conflict --- packages/camera/camera/CHANGELOG.md | 4 + packages/camera/camera/android/build.gradle | 10 +- .../io/flutter/plugins/camera/Camera.java | 55 +++- .../io/flutter/plugins/camera/CameraZoom.java | 48 ++++ .../plugins/camera/MethodCallHandlerImpl.java | 43 +++ .../plugins/camera/CameraZoomTest.java | 121 +++++++++ .../camera/example/android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- packages/camera/camera/example/lib/main.dart | 35 ++- .../camera/camera/ios/Classes/CameraPlugin.m | 61 +++++ .../camera/lib/src/camera_controller.dart | 52 ++++ packages/camera/camera/pubspec.yaml | 2 +- packages/camera/camera/test/camera_test.dart | 248 ++++++++++++++++++ 13 files changed, 662 insertions(+), 21 deletions(-) create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 24b1365d1252..168ed5557123 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.2 + +* Add zoom support for Android and iOS implementations. + ## 0.6.1+1 * Added implementation of the `didFinishProcessingPhoto` on iOS which allows saving image metadata (EXIF) on iOS 11 and up. diff --git a/packages/camera/camera/android/build.gradle b/packages/camera/camera/android/build.gradle index d19d6df7b447..0b88fd10fb71 100644 --- a/packages/camera/camera/android/build.gradle +++ b/packages/camera/camera/android/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.5.0' } } @@ -40,16 +40,16 @@ android { sourceCompatibility = '1.8' targetCompatibility = '1.8' } - dependencies { - implementation 'androidx.annotation:annotation:1.0.0' - implementation 'androidx.core:core:1.0.0' - } testOptions { + unitTests.includeAndroidResources = true unitTests.returnDefaultValues = true } } dependencies { + compileOnly 'androidx.annotation:annotation:1.1.0' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:3.5.13' + testImplementation 'androidx.test:core:1.3.0' + testImplementation 'org.robolectric:robolectric:4.3' } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 27f1355319c1..3e8bbc7b295b 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -8,6 +8,7 @@ import android.app.Activity; import android.content.Context; import android.graphics.ImageFormat; +import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; @@ -21,7 +22,6 @@ import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.params.SessionConfiguration; -import android.hardware.camera2.params.StreamConfigurationMap; import android.media.CamcorderProfile; import android.media.Image; import android.media.ImageReader; @@ -47,6 +47,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.Executors; @@ -60,19 +61,20 @@ public class Camera { private final Size captureSize; private final Size previewSize; private final boolean enableAudio; + private final Context applicationContext; + private final CamcorderProfile recordingProfile; + private final DartMessenger dartMessenger; + private final CameraZoom cameraZoom; private CameraDevice cameraDevice; private CameraCaptureSession cameraCaptureSession; private ImageReader pictureImageReader; private ImageReader imageStreamReader; - private DartMessenger dartMessenger; private CaptureRequest.Builder captureRequestBuilder; private MediaRecorder mediaRecorder; private boolean recordingVideo; private File videoRecordingFile; - private CamcorderProfile recordingProfile; private int currentOrientation = ORIENTATION_UNKNOWN; - private Context applicationContext; private FlashMode flashMode; private PictureCaptureRequest pictureCaptureRequest; @@ -108,11 +110,7 @@ public void onOrientationChanged(int i) { orientationEventListener.enable(); CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraName); - StreamConfigurationMap streamConfigurationMap = - characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); - //noinspection ConstantConditions sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); - //noinspection ConstantConditions isFrontFacing = characteristics.get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_FRONT; ResolutionPreset preset = ResolutionPreset.valueOf(resolutionPreset); @@ -120,6 +118,10 @@ public void onOrientationChanged(int i) { CameraUtils.getBestAvailableCamcorderProfileForResolutionPreset(cameraName, preset); captureSize = new Size(recordingProfile.videoFrameWidth, recordingProfile.videoFrameHeight); previewSize = computeBestPreviewSize(cameraName, preset); + cameraZoom = + new CameraZoom( + characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE), + characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)); } private void prepareMediaRecorder(String outputFilePath) throws IOException { @@ -212,10 +214,6 @@ private void writeToFile(ByteBuffer buffer, File file) throws IOException { } } - SurfaceTextureEntry getFlutterTexture() { - return flutterTexture; - } - public void takePicture(@NonNull final Result result) { // Only take 1 picture at a time if (pictureCaptureRequest != null && !pictureCaptureRequest.isFinished()) { @@ -620,6 +618,39 @@ private void setImageStreamImageAvailableListener(final EventChannel.EventSink i null); } + public float getMaxZoomLevel() { + return cameraZoom.maxZoom; + } + + public float getMinZoomLevel() { + return CameraZoom.DEFAULT_ZOOM_FACTOR; + } + + public void setZoomLevel(@NonNull final Result result, float zoom) throws CameraAccessException { + float maxZoom = cameraZoom.maxZoom; + float minZoom = CameraZoom.DEFAULT_ZOOM_FACTOR; + + if (zoom > maxZoom || zoom < minZoom) { + String errorMessage = + String.format( + Locale.ENGLISH, + "Zoom level out of bounds (zoom level should be between %f and %f).", + minZoom, + maxZoom); + result.error("ZOOM_ERROR", errorMessage, null); + return; + } + + //Zoom area is calculated relative to sensor area (activeRect) + if (captureRequestBuilder != null) { + final Rect computedZoom = cameraZoom.computeZoom(zoom); + captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom); + cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); + } + + result.success(null); + } + private void closeCaptureSession() { if (cameraCaptureSession != null) { cameraCaptureSession.close(); diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java new file mode 100644 index 000000000000..a179f12db224 --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java @@ -0,0 +1,48 @@ +package io.flutter.plugins.camera; + +import android.graphics.Rect; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.math.MathUtils; + +public final class CameraZoom { + public static final float DEFAULT_ZOOM_FACTOR = 1.0f; + + @NonNull private final Rect cropRegion = new Rect(); + @Nullable private final Rect sensorSize; + + public final float maxZoom; + public final boolean hasSupport; + + public CameraZoom(@Nullable final Rect sensorArraySize, final Float maxZoom) { + this.sensorSize = sensorArraySize; + + if (this.sensorSize == null) { + this.maxZoom = DEFAULT_ZOOM_FACTOR; + this.hasSupport = false; + return; + } + + this.maxZoom = + ((maxZoom == null) || (maxZoom < DEFAULT_ZOOM_FACTOR)) ? DEFAULT_ZOOM_FACTOR : maxZoom; + + this.hasSupport = (Float.compare(this.maxZoom, DEFAULT_ZOOM_FACTOR) > 0); + } + + public Rect computeZoom(final float zoom) { + if (sensorSize == null || !this.hasSupport) { + return null; + } + + final float newZoom = MathUtils.clamp(zoom, DEFAULT_ZOOM_FACTOR, this.maxZoom); + + final int centerX = this.sensorSize.width() / 2; + final int centerY = this.sensorSize.height() / 2; + final int deltaX = (int) ((0.5f * this.sensorSize.width()) / newZoom); + final int deltaY = (int) ((0.5f * this.sensorSize.height()) / newZoom); + + this.cropRegion.set(centerX - deltaX, centerY - deltaY, centerX + deltaX, centerY + deltaY); + + return cropRegion; + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 12b99b72f642..704504176518 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -158,6 +158,49 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) } break; } + case "getMaxZoomLevel": + { + assert camera != null; + + try { + float maxZoomLevel = camera.getMaxZoomLevel(); + result.success(maxZoomLevel); + } catch (Exception e) { + handleException(e, result); + } + break; + } + case "getMinZoomLevel": + { + assert camera != null; + + try { + float minZoomLevel = camera.getMinZoomLevel(); + result.success(minZoomLevel); + } catch (Exception e) { + handleException(e, result); + } + break; + } + case "setZoomLevel": + { + assert camera != null; + + Double zoom = call.argument("zoom"); + + if (zoom == null) { + result.error( + "ZOOM_ERROR", "setZoomLevel is called without specifying a zoom level.", null); + return; + } + + try { + camera.setZoomLevel(result, zoom.floatValue()); + } catch (Exception e) { + handleException(e, result); + } + break; + } case "dispose": { if (camera != null) { diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java new file mode 100644 index 000000000000..93aaa5d926b4 --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java @@ -0,0 +1,121 @@ +package io.flutter.plugins.camera; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.graphics.Rect; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class CameraZoomTest { + + @Test + public void ctor_when_parameters_are_valid() { + final Rect sensorSize = new Rect(0, 0, 0, 0); + final Float maxZoom = 4.0f; + final CameraZoom cameraZoom = new CameraZoom(sensorSize, maxZoom); + + assertNotNull(cameraZoom); + assertTrue(cameraZoom.hasSupport); + assertEquals(4.0f, cameraZoom.maxZoom, 0); + assertEquals(1.0f, CameraZoom.DEFAULT_ZOOM_FACTOR, 0); + } + + @Test + public void ctor_when_sensor_size_is_null() { + final Rect sensorSize = null; + final Float maxZoom = 4.0f; + final CameraZoom cameraZoom = new CameraZoom(sensorSize, maxZoom); + + assertNotNull(cameraZoom); + assertFalse(cameraZoom.hasSupport); + assertEquals(cameraZoom.maxZoom, 1.0f, 0); + } + + @Test + public void ctor_when_max_zoom_is_null() { + final Rect sensorSize = new Rect(0, 0, 0, 0); + final Float maxZoom = null; + final CameraZoom cameraZoom = new CameraZoom(sensorSize, maxZoom); + + assertNotNull(cameraZoom); + assertFalse(cameraZoom.hasSupport); + assertEquals(cameraZoom.maxZoom, 1.0f, 0); + } + + @Test + public void ctor_when_max_zoom_is_smaller_then_default_zoom_factor() { + final Rect sensorSize = new Rect(0, 0, 0, 0); + final Float maxZoom = 0.5f; + final CameraZoom cameraZoom = new CameraZoom(sensorSize, maxZoom); + + assertNotNull(cameraZoom); + assertFalse(cameraZoom.hasSupport); + assertEquals(cameraZoom.maxZoom, 1.0f, 0); + } + + @Test + public void setZoom_when_no_support_should_not_set_scaler_crop_region() { + final CameraZoom cameraZoom = new CameraZoom(null, null); + final Rect computedZoom = cameraZoom.computeZoom(2f); + + assertNull(computedZoom); + } + + @Test + public void setZoom_when_sensor_size_equals_zero_should_return_crop_region_of_zero() { + final Rect sensorSize = new Rect(0, 0, 0, 0); + final CameraZoom cameraZoom = new CameraZoom(sensorSize, 20f); + final Rect computedZoom = cameraZoom.computeZoom(18f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 0); + assertEquals(computedZoom.top, 0); + assertEquals(computedZoom.right, 0); + assertEquals(computedZoom.bottom, 0); + } + + @Test + public void setZoom_when_sensor_size_is_valid_should_return_crop_region() { + final Rect sensorSize = new Rect(0, 0, 100, 100); + final CameraZoom cameraZoom = new CameraZoom(sensorSize, 20f); + final Rect computedZoom = cameraZoom.computeZoom(18f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 48); + assertEquals(computedZoom.top, 48); + assertEquals(computedZoom.right, 52); + assertEquals(computedZoom.bottom, 52); + } + + @Test + public void setZoom_when_zoom_is_greater_then_max_zoom_clamp_to_max_zoom() { + final Rect sensorSize = new Rect(0, 0, 100, 100); + final CameraZoom cameraZoom = new CameraZoom(sensorSize, 10f); + final Rect computedZoom = cameraZoom.computeZoom(25f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 45); + assertEquals(computedZoom.top, 45); + assertEquals(computedZoom.right, 55); + assertEquals(computedZoom.bottom, 55); + } + + @Test + public void setZoom_when_zoom_is_smaller_then_min_zoom_clamp_to_min_zoom() { + final Rect sensorSize = new Rect(0, 0, 100, 100); + final CameraZoom cameraZoom = new CameraZoom(sensorSize, 10f); + final Rect computedZoom = cameraZoom.computeZoom(0.5f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 0); + assertEquals(computedZoom.top, 0); + assertEquals(computedZoom.right, 100); + assertEquals(computedZoom.bottom, 100); + } +} diff --git a/packages/camera/camera/example/android/build.gradle b/packages/camera/camera/example/android/build.gradle index 112aa2a87c27..498448e78692 100644 --- a/packages/camera/camera/example/android/build.gradle +++ b/packages/camera/camera/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.5.0' } } diff --git a/packages/camera/camera/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/camera/camera/example/android/gradle/wrapper/gradle-wrapper.properties index 019065d1d650..01a286e96a21 100644 --- a/packages/camera/camera/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/camera/camera/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 847779dade09..049141d3935e 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -42,6 +42,13 @@ class _CameraExampleHomeState extends State VideoPlayerController videoController; VoidCallback videoPlayerListener; bool enableAudio = true; + double _minAvailableZoom; + double _maxAvailableZoom; + double _currentScale = 1.0; + double _baseScale = 1.0; + + // Counting pointers (number of user fingers on screen) + int _pointers = 0; @override void initState() { @@ -132,11 +139,35 @@ class _CameraExampleHomeState extends State } else { return AspectRatio( aspectRatio: controller.value.aspectRatio, - child: CameraPreview(controller), + child: Listener( + onPointerDown: (_) => _pointers++, + onPointerUp: (_) => _pointers--, + child: GestureDetector( + onScaleStart: _handleScaleStart, + onScaleUpdate: _handleScaleUpdate, + child: CameraPreview(controller), + ), + ), ); } } + void _handleScaleStart(ScaleStartDetails details) { + _baseScale = _currentScale; + } + + Future _handleScaleUpdate(ScaleUpdateDetails details) async { + // When there are not exactly two fingers on screen don't scale + if (_pointers != 2) { + return; + } + + _currentScale = (_baseScale * details.scale) + .clamp(_minAvailableZoom, _maxAvailableZoom); + + await controller.setZoomLevel(_currentScale); + } + /// Toggle recording audio Widget _toggleAudioWidget() { return Padding( @@ -333,6 +364,8 @@ class _CameraExampleHomeState extends State try { await controller.initialize(); + _maxAvailableZoom = await controller.getMaxZoomLevel(); + _minAvailableZoom = await controller.getMinZoomLevel(); } on CameraException catch (e) { _showCameraException(e); } diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index 4e5c37ed67a9..c13ff60abd0a 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -743,6 +743,60 @@ - (void)stopImageStream { } } +- (void)getMaxZoomLevelWithResult:(FlutterResult)result { + CGFloat maxZoomFactor = [self getMaxAvailableZoomFactor]; + + result([NSNumber numberWithFloat:maxZoomFactor]); +} + +- (void)getMinZoomLevelWithResult:(FlutterResult)result { + CGFloat minZoomFactor = [self getMinAvailableZoomFactor]; + + result([NSNumber numberWithFloat:minZoomFactor]); +} + +- (void)setZoomLevel:(CGFloat)zoom Result:(FlutterResult)result { + CGFloat maxAvailableZoomFactor = [self getMaxAvailableZoomFactor]; + CGFloat minAvailableZoomFactor = [self getMinAvailableZoomFactor]; + + if (maxAvailableZoomFactor < zoom || minAvailableZoomFactor > zoom) { + NSString *errorMessage = [NSString + stringWithFormat:@"Zoom level out of bounds (zoom level should be between %f and %f).", + minAvailableZoomFactor, maxAvailableZoomFactor]; + FlutterError *error = [FlutterError errorWithCode:@"ZOOM_ERROR" + message:errorMessage + details:nil]; + result(error); + return; + } + + NSError *error = nil; + if (![_captureDevice lockForConfiguration:&error]) { + result(getFlutterError(error)); + return; + } + [_captureDevice rampToVideoZoomFactor:zoom withRate:1]; + [_captureDevice unlockForConfiguration]; + + result(nil); +} + +- (CGFloat)getMinAvailableZoomFactor { + if (@available(iOS 11.0, *)) { + return _captureDevice.minAvailableVideoZoomFactor; + } else { + return 1.0; + } +} + +- (CGFloat)getMaxAvailableZoomFactor { + if (@available(iOS 11.0, *)) { + return _captureDevice.maxAvailableVideoZoomFactor; + } else { + return _captureDevice.activeFormat.videoMaxZoomFactor; + } +} + - (BOOL)setupWriterForPath:(NSString *)path { NSError *error = nil; NSURL *outputURL; @@ -976,6 +1030,13 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re [_camera pauseVideoRecordingWithResult:result]; } else if ([@"resumeVideoRecording" isEqualToString:call.method]) { [_camera resumeVideoRecordingWithResult:result]; + } else if ([@"getMaxZoomLevel" isEqualToString:call.method]) { + [_camera getMaxZoomLevelWithResult:result]; + } else if ([@"getMinZoomLevel" isEqualToString:call.method]) { + [_camera getMinZoomLevelWithResult:result]; + } else if ([@"setZoomLevel" isEqualToString:call.method]) { + CGFloat zoom = ((NSNumber *)argsMap[@"zoom"]).floatValue; + [_camera setZoomLevel:zoom Result:result]; } else if ([@"setFlashMode" isEqualToString:call.method]) { [_camera setFlashModeWithResult:result mode:call.arguments[@"mode"]]; } else { diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index 2c2ce3b633f1..b79975fbad8e 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -476,6 +476,58 @@ class CameraController extends ValueNotifier { } } + /// Gets the maximum supported zoom level for the selected camera. + Future getMaxZoomLevel() { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'getMaxZoomLevel was called on uninitialized CameraController', + ); + } + + try { + return CameraPlatform.instance.getMaxZoomLevel(_cameraId); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Gets the minimum supported zoom level for the selected camera. + Future getMinZoomLevel() { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'getMinZoomLevel was called on uninitialized CameraController', + ); + } + + try { + return CameraPlatform.instance.getMinZoomLevel(_cameraId); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Set the zoom level for the selected camera. + /// + /// The supplied [zoom] value should be between 1.0 and the maximum supported + /// zoom level returned by the `getMaxZoomLevel`. Throws an `CameraException` + /// when an illegal zoom level is suplied. + Future setZoomLevel(double zoom) { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'setZoomLevel was called on uninitialized CameraController', + ); + } + + try { + return CameraPlatform.instance.setZoomLevel(_cameraId, zoom); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + /// Sets the flash mode for taking pictures. Future setFlashMode(FlashMode mode) async { try { diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 587e6f752971..d823dd383281 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.1+1 +version: 0.6.2 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index c19aa9718f47..43dec7374901 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -311,6 +311,254 @@ void main() { ))); }); + test('getMaxZoomLevel() throws $CameraException when uninitialized', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + expect( + cameraController.getMaxZoomLevel, + throwsA(isA().having( + (error) => error.description, + 'Uninitialized CameraController', + 'getMaxZoomLevel was called on uninitialized CameraController', + ))); + }); + + test('getMaxZoomLevel() throws $CameraException when disposed', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + await cameraController.dispose(); + + expect( + cameraController.getMaxZoomLevel, + throwsA(isA().having( + (error) => error.description, + 'Uninitialized CameraController', + 'getMaxZoomLevel was called on uninitialized CameraController', + ))); + }); + + test( + 'getMaxZoomLevel() throws $CameraException when a platform exception occured.', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + when(CameraPlatform.instance.getMaxZoomLevel(mockInitializeCamera)) + .thenThrow(PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error messge', + details: null)); + + expect( + cameraController.getMaxZoomLevel, + throwsA(isA() + .having((error) => error.code, 'code', 'TEST_ERROR') + .having( + (error) => error.description, + 'description', + 'This is a test error messge', + ))); + }); + + test('getMaxZoomLevel() returns max zoom level.', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + when(CameraPlatform.instance.getMaxZoomLevel(mockInitializeCamera)) + .thenAnswer((_) => Future.value(42.0)); + + final maxZoomLevel = await cameraController.getMaxZoomLevel(); + expect(maxZoomLevel, 42.0); + }); + + test('getMinZoomLevel() throws $CameraException when uninitialized', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + expect( + cameraController.getMinZoomLevel, + throwsA(isA().having( + (error) => error.description, + 'Uninitialized CameraController', + 'getMinZoomLevel was called on uninitialized CameraController', + ))); + }); + + test('getMinZoomLevel() throws $CameraException when disposed', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + await cameraController.dispose(); + + expect( + cameraController.getMinZoomLevel, + throwsA(isA().having( + (error) => error.description, + 'Uninitialized CameraController', + 'getMinZoomLevel was called on uninitialized CameraController', + ))); + }); + + test( + 'getMinZoomLevel() throws $CameraException when a platform exception occured.', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + when(CameraPlatform.instance.getMinZoomLevel(mockInitializeCamera)) + .thenThrow(PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error messge', + details: null)); + + expect( + cameraController.getMinZoomLevel, + throwsA(isA() + .having((error) => error.code, 'code', 'TEST_ERROR') + .having( + (error) => error.description, + 'description', + 'This is a test error messge', + ))); + }); + + test('getMinZoomLevel() returns max zoom level.', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + when(CameraPlatform.instance.getMinZoomLevel(mockInitializeCamera)) + .thenAnswer((_) => Future.value(42.0)); + + final maxZoomLevel = await cameraController.getMinZoomLevel(); + expect(maxZoomLevel, 42.0); + }); + + test('setZoomLevel() throws $CameraException when uninitialized', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + expect( + () => cameraController.setZoomLevel(42.0), + throwsA(isA().having( + (error) => error.description, + 'Uninitialized CameraController', + 'setZoomLevel was called on uninitialized CameraController', + ))); + }); + + test('setZoomLevel() throws $CameraException when disposed', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + await cameraController.dispose(); + + expect( + () => cameraController.setZoomLevel(42.0), + throwsA(isA().having( + (error) => error.description, + 'Uninitialized CameraController', + 'setZoomLevel was called on uninitialized CameraController', + ))); + }); + + test( + 'setZoomLevel() throws $CameraException when a platform exception occured.', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + when(CameraPlatform.instance.setZoomLevel(mockInitializeCamera, 42.0)) + .thenThrow(PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error messge', + details: null)); + + expect( + () => cameraController.setZoomLevel(42), + throwsA(isA() + .having((error) => error.code, 'code', 'TEST_ERROR') + .having( + (error) => error.description, + 'description', + 'This is a test error messge', + ))); + + reset(CameraPlatform.instance); + }); + + test( + 'setZoomLevel() completes and calls method channel with correct value.', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + await cameraController.setZoomLevel(42.0); + + verify(CameraPlatform.instance.setZoomLevel(mockInitializeCamera, 42.0)) + .called(1); + }); + test('setFlashMode() calls $CameraPlatform', () async { CameraController cameraController = CameraController( CameraDescription( From b4466e7c7feab95d277b8ddafbebbde8357ad44c Mon Sep 17 00:00:00 2001 From: Amir Hardon Date: Sat, 19 Dec 2020 19:55:13 -0800 Subject: [PATCH 061/924] Fix test exclusion logic for nnbd plugins (#3342) --- .cirrus.yml | 12 +++++++ .../test/android_intent_test.dart | 5 ++- ...flutter_plugin_android_lifecycle_test.dart | 2 ++ .../example/lib/main.dart | 4 +++ .../example/pubspec.yaml | 14 ++++---- ....java => FlutterFragmentActivityTest.java} | 0 packages/local_auth/example/lib/main.dart | 10 +++--- packages/local_auth/example/pubspec.yaml | 2 +- .../integration_test/local_auth_test.dart | 6 ++++ .../share/integration_test/share_test.dart | 2 ++ packages/share/test/share_test.dart | 4 ++- packages/webview_flutter/CHANGELOG.md | 4 +++ .../webview_flutter_test.dart | 32 +++++++++++-------- .../webview_flutter/example/lib/main.dart | 16 +++++----- packages/webview_flutter/example/pubspec.yaml | 2 +- .../example/test_driver/integration_test.dart | 2 ++ .../lib/src/webview_method_channel.dart | 3 +- packages/webview_flutter/pubspec.yaml | 2 +- script/build_all_plugins_app.sh | 9 +++++- script/incremental_build.sh | 2 +- 20 files changed, 91 insertions(+), 42 deletions(-) rename packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/{MainActivityTest.java => FlutterFragmentActivityTest.java} (100%) diff --git a/.cirrus.yml b/.cirrus.yml index 453a2ce0ac2c..4ec73ea3f24c 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -39,8 +39,16 @@ task: - flutter channel $CHANNEL - ./script/incremental_build.sh test - name: analyze + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" script: ./script/incremental_build.sh analyze - name: build_all_plugins_apk + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" script: # TODO(jackson): Allow web plugins once supported on stable # https://github.com/flutter/flutter/issues/42864 @@ -144,6 +152,10 @@ task: - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot matrix: - name: build_all_plugins_ipa + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" script: # TODO(jackson): Allow web plugins once supported on stable # https://github.com/flutter/flutter/issues/42864 diff --git a/packages/android_intent/test/android_intent_test.dart b/packages/android_intent/test/android_intent_test.dart index b0fa48e22fee..ad0eae3b662d 100644 --- a/packages/android_intent/test/android_intent_test.dart +++ b/packages/android_intent/test/android_intent_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 + import 'package:android_intent/flag.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -11,7 +13,8 @@ import 'package:platform/platform.dart'; void main() { AndroidIntent androidIntent; - late MockMethodChannel mockChannel; + MockMethodChannel mockChannel; + setUp(() { mockChannel = MockMethodChannel(); when(mockChannel.invokeMethod('canResolveActivity', any)) diff --git a/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart b/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart index 1405ab69153c..ba67043bcf43 100644 --- a/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart +++ b/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_plugin_android_lifecycle_example/main.dart'; diff --git a/packages/flutter_plugin_android_lifecycle/example/lib/main.dart b/packages/flutter_plugin_android_lifecycle/example/lib/main.dart index 6dfe523a0ae1..eb82aacd0237 100644 --- a/packages/flutter_plugin_android_lifecycle/example/lib/main.dart +++ b/packages/flutter_plugin_android_lifecycle/example/lib/main.dart @@ -1,3 +1,7 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + // ignore_for_file: public_member_api_docs import 'package:flutter/material.dart'; diff --git a/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml index 2532ab047dcc..4643317c1951 100644 --- a/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml @@ -1,23 +1,21 @@ name: flutter_plugin_android_lifecycle_example description: Demonstrates how to use the flutter_plugin_android_lifecycle plugin. -publish_to: 'none' - -environment: - sdk: ">=2.12.0-0 <3.0.0" dependencies: flutter: sdk: flutter - integration_test: - path: ../../integration_test + flutter_plugin_android_lifecycle: + path: ../ dev_dependencies: + integration_test: + path: ../../integration_test flutter_test: sdk: flutter pedantic: ^1.8.0 - flutter_plugin_android_lifecycle: - path: ../ +environment: + sdk: ">=2.12.0-0 <3.0.0" flutter: uses-material-design: true diff --git a/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/MainActivityTest.java b/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java similarity index 100% rename from packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/MainActivityTest.java rename to packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java diff --git a/packages/local_auth/example/lib/main.dart b/packages/local_auth/example/lib/main.dart index 06e33b9853be..241593a08b6a 100644 --- a/packages/local_auth/example/lib/main.dart +++ b/packages/local_auth/example/lib/main.dart @@ -21,16 +21,17 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { final LocalAuthentication auth = LocalAuthentication(); - bool _canCheckBiometrics; - List _availableBiometrics; + late bool _canCheckBiometrics; + late List _availableBiometrics; String _authorized = 'Not Authorized'; bool _isAuthenticating = false; Future _checkBiometrics() async { - bool canCheckBiometrics; + late bool canCheckBiometrics; try { canCheckBiometrics = await auth.canCheckBiometrics; } on PlatformException catch (e) { + canCheckBiometrics = false; print(e); } if (!mounted) return; @@ -41,10 +42,11 @@ class _MyAppState extends State { } Future _getAvailableBiometrics() async { - List availableBiometrics; + late List availableBiometrics; try { availableBiometrics = await auth.getAvailableBiometrics(); } on PlatformException catch (e) { + availableBiometrics = []; print(e); } if (!mounted) return; diff --git a/packages/local_auth/example/pubspec.yaml b/packages/local_auth/example/pubspec.yaml index 0861c51adbc6..9c7b91e672e6 100644 --- a/packages/local_auth/example/pubspec.yaml +++ b/packages/local_auth/example/pubspec.yaml @@ -18,5 +18,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/local_auth/integration_test/local_auth_test.dart b/packages/local_auth/integration_test/local_auth_test.dart index 47e5dfa67912..c09810032461 100644 --- a/packages/local_auth/integration_test/local_auth_test.dart +++ b/packages/local_auth/integration_test/local_auth_test.dart @@ -1,3 +1,9 @@ +// 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. + +// @dart = 2.9 + import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/share/integration_test/share_test.dart b/packages/share/integration_test/share_test.dart index 08a19ce2c27b..7b66480d0681 100644 --- a/packages/share/integration_test/share_test.dart +++ b/packages/share/integration_test/share_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'package:flutter_test/flutter_test.dart'; import 'package:share/share.dart'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/share/test/share_test.dart b/packages/share/test/share_test.dart index fa9f980beae3..d00867b19452 100644 --- a/packages/share/test/share_test.dart +++ b/packages/share/test/share_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 + import 'dart:io'; import 'dart:ui'; @@ -15,7 +17,7 @@ import 'package:flutter/services.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - late MockMethodChannel mockChannel; + MockMethodChannel mockChannel; setUp(() { mockChannel = MockMethodChannel(); diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 19cacb6a6e90..867ea1757985 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.3 + +* Fix `onWebResourceError` on iOS. + ## 2.0.0-nullsafety.2 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index 86cf8ab73e05..5f39cc3d86d2 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -358,12 +360,12 @@ void main() { videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest)); }); - test('Auto media playback', () async { + testWidgets('Auto media playback', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -390,7 +392,7 @@ void main() { pageLoaded = Completer(); // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -414,15 +416,16 @@ void main() { isPaused = await controller.evaluateJavascript('isPaused();'); expect(isPaused, _webviewBool(true)); - }); + }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - test('Changes to initialMediaPlaybackPolicy are ignored', () async { + testWidgets('Changes to initialMediaPlaybackPolicy are ignored', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); final GlobalKey key = GlobalKey(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -447,7 +450,7 @@ void main() { pageLoaded = Completer(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -472,14 +475,15 @@ void main() { isPaused = await controller.evaluateJavascript('isPaused();'); expect(isPaused, _webviewBool(false)); - }); + }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - test('Video plays inline when allowsInlineMediaPlayback is true', () async { + testWidgets('Video plays inline when allowsInlineMediaPlayback is true', + (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -507,7 +511,7 @@ void main() { controllerCompleter = Completer(); pageLoaded = Completer(); - await pumpWidget( + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( @@ -531,7 +535,7 @@ void main() { isFullScreen = await controller.evaluateJavascript('isFullScreen();'); expect(isFullScreen, _webviewBool(true)); - }); + }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); }); group('Audio playback policy', () { @@ -631,7 +635,7 @@ void main() { isPaused = await controller.evaluateJavascript('isPaused();'); expect(isPaused, _webviewBool(true)); - }); + }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); testWidgets('Changes to initialMediaPlaybackPolocy are ignored', (WidgetTester tester) async { @@ -700,7 +704,7 @@ void main() { isPaused = await controller.evaluateJavascript('isPaused();'); expect(isPaused, _webviewBool(false)); - }); + }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); }); testWidgets('getTitle', (WidgetTester tester) async { diff --git a/packages/webview_flutter/example/lib/main.dart b/packages/webview_flutter/example/lib/main.dart index 2a4b652d2658..c7f42ac2bf66 100644 --- a/packages/webview_flutter/example/lib/main.dart +++ b/packages/webview_flutter/example/lib/main.dart @@ -105,7 +105,7 @@ class _WebViewExampleState extends State { if (controller.hasData) { return FloatingActionButton( onPressed: () async { - final String url = await controller.data.currentUrl(); + final String url = (await controller.data!.currentUrl())!; // ignore: deprecated_member_use Scaffold.of(context).showSnackBar( SnackBar(content: Text('Favorited $url')), @@ -145,25 +145,25 @@ class SampleMenu extends StatelessWidget { onSelected: (MenuOptions value) { switch (value) { case MenuOptions.showUserAgent: - _onShowUserAgent(controller.data, context); + _onShowUserAgent(controller.data!, context); break; case MenuOptions.listCookies: - _onListCookies(controller.data, context); + _onListCookies(controller.data!, context); break; case MenuOptions.clearCookies: _onClearCookies(context); break; case MenuOptions.addToCache: - _onAddToCache(controller.data, context); + _onAddToCache(controller.data!, context); break; case MenuOptions.listCache: - _onListCache(controller.data, context); + _onListCache(controller.data!, context); break; case MenuOptions.clearCache: - _onClearCache(controller.data, context); + _onClearCache(controller.data!, context); break; case MenuOptions.navigationDelegate: - _onNavigationDelegateExample(controller.data, context); + _onNavigationDelegateExample(controller.data!, context); break; } }, @@ -299,7 +299,7 @@ class NavigationControls extends StatelessWidget { (BuildContext context, AsyncSnapshot snapshot) { final bool webViewReady = snapshot.connectionState == ConnectionState.done; - final WebViewController controller = snapshot.data; + final WebViewController controller = snapshot.data!; return Row( children: [ IconButton( diff --git a/packages/webview_flutter/example/pubspec.yaml b/packages/webview_flutter/example/pubspec.yaml index 543e7fd86971..1ace8afe400f 100644 --- a/packages/webview_flutter/example/pubspec.yaml +++ b/packages/webview_flutter/example/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_example description: Demonstrates how to use the webview_flutter plugin. environment: - sdk: ">=2.0.0-dev.68.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" dependencies: flutter: diff --git a/packages/webview_flutter/example/test_driver/integration_test.dart b/packages/webview_flutter/example/test_driver/integration_test.dart index 7a2c21338786..a8a56aa90f6a 100644 --- a/packages/webview_flutter/example/test_driver/integration_test.dart +++ b/packages/webview_flutter/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart index b38d65acb486..54ab647cdc04 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -48,7 +48,8 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { WebResourceError( errorCode: call.arguments['errorCode']!, description: call.arguments['description']!, - failingUrl: call.arguments['failingUrl']!, + // iOS doesn't support `failingUrl`. + failingUrl: call.arguments['failingUrl'], domain: call.arguments['domain'], errorType: call.arguments['errorType'] == null ? null diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index b2fbfc1110c5..8bdd790e5e36 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 2.0.0-nullsafety.2 +version: 2.0.0-nullsafety.3 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index f2897f8aa9a2..ca97c05f8ee4 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -1,10 +1,16 @@ #!/bin/bash +# Usage: +# +# ./script/build_all_plugins_app.sh apk +# ./script/build_all_plugins_app.sh ios + # This script builds the app in flutter/plugins/example/all_plugins to make # sure all first party plugins can be compiled together. # So that users can run this script from anywhere and it will work as expected. readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd)" + readonly REPO_DIR="$(dirname "$SCRIPT_DIR")" source "$SCRIPT_DIR/common.sh" @@ -23,6 +29,7 @@ readonly EXCLUDED_PLUGINS_LIST=( "google_sign_in_platform_interface" "google_sign_in_web" "image_picker_platform_interface" + "local_auth" # flutter_plugin_android_lifecycle conflict "instrumentation_adapter" "path_provider_linux" "path_provider_macos" @@ -46,7 +53,7 @@ readonly EXCLUDED=$(IFS=, ; echo "${EXCLUDED_PLUGINS_LIST[*]}") ALL_EXCLUDED=($EXCLUDED) # Exclude nnbd plugins from stable. -if [[ "$CHANNEL" -eq "stable" ]]; then +if [ "$CHANNEL" == "stable" ]; then ALL_EXCLUDED=("$EXCLUDED,$EXCLUDED_PLUGINS_FROM_STABLE") fi diff --git a/script/incremental_build.sh b/script/incremental_build.sh index f54f90b0669c..3911f0a6e9c8 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -16,7 +16,7 @@ fi # Plugins that are excluded from this task. ALL_EXCLUDED=("") # Exclude nnbd plugins from stable. -if [[ "$CHANNEL" -eq "stable" ]]; then +if [ "$CHANNEL" == "stable" ]; then ALL_EXCLUDED=($EXCLUDED_PLUGINS_FROM_STABLE) echo "Excluding the following plugins: $ALL_EXCLUDED" fi From c986058e301c1eda2c8d388b28c4eb9b736d854b Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Mon, 21 Dec 2020 12:38:48 -0800 Subject: [PATCH 062/924] [video_player] Fix video player test (#3361) --- packages/video_player/video_player/CHANGELOG.md | 4 ++++ packages/video_player/video_player/pubspec.yaml | 2 +- .../video_player/video_player/test/video_player_test.dart | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 4e2826262eaf..c79b0a02bc98 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.6 + +* Fix `VideoPlayerValue toString()` test. + ## 2.0.0-nullsafety.5 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 603f2358cd55..a8066e129608 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for displaying inline video with other Flutter # 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 2.0.0-nullsafety.5 +version: 2.0.0-nullsafety.6 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart index 3e9800f2b68e..f3f2b5e8faf1 100644 --- a/packages/video_player/video_player/test/video_player_test.dart +++ b/packages/video_player/video_player/test/video_player_test.dart @@ -567,7 +567,7 @@ void main() { 'VideoPlayerValue(duration: 0:00:05.000000, ' 'size: Size(400.0, 300.0), ' 'position: 0:00:01.000000, ' - 'caption: Caption(number: null, start: null, end: null, text: foo), ' + 'caption: Caption(number: 0, start: 0:00:00.000000, end: 0:00:00.000000, text: foo), ' 'buffered: [DurationRange(start: 0:00:00.000000, end: 0:00:04.000000)], ' 'isInitialized: true, ' 'isPlaying: true, ' From 8980d79446d3196bbd0c1366ab67ab2a5f39da9d Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Mon, 21 Dec 2020 14:33:17 -0800 Subject: [PATCH 063/924] [image_picker] Do not copy a static field into another static field (#3353) --- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ .../image_picker/lib/image_picker.dart | 2 +- packages/image_picker/image_picker/pubspec.yaml | 4 +++- .../image_picker/test/image_picker_test.dart | 16 ++++++++++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 4c1553a8ccaf..32d61cc79607 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+19 + +* Do not copy static field to another static field. + ## 0.6.7+18 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/image_picker/image_picker/lib/image_picker.dart b/packages/image_picker/image_picker/lib/image_picker.dart index 82c199e007f4..5c0683c3f29f 100755 --- a/packages/image_picker/image_picker/lib/image_picker.dart +++ b/packages/image_picker/image_picker/lib/image_picker.dart @@ -27,7 +27,7 @@ export 'package:image_picker_platform_interface/image_picker_platform_interface. class ImagePicker { /// The platform interface that drives this plugin @visibleForTesting - static ImagePickerPlatform platform = ImagePickerPlatform.instance; + static ImagePickerPlatform get platform => ImagePickerPlatform.instance; /// Returns a [File] object pointing to the image that was picked. /// diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 29baaa0de5d5..377c3840c2d1 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+18 +version: 0.6.7+19 flutter: plugin: @@ -25,7 +25,9 @@ dev_dependencies: sdk: flutter integration_test: path: ../../integration_test + mockito: ^4.1.3 pedantic: ^1.8.0 + plugin_platform_interface: ^1.0.3 environment: sdk: ">=2.1.0 <3.0.0" diff --git a/packages/image_picker/image_picker/test/image_picker_test.dart b/packages/image_picker/image_picker/test/image_picker_test.dart index 0ada1b261363..7172975ded5d 100644 --- a/packages/image_picker/image_picker/test/image_picker_test.dart +++ b/packages/image_picker/image_picker/test/image_picker_test.dart @@ -5,6 +5,9 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -26,6 +29,15 @@ void main() { log.clear(); }); + test('ImagePicker platform instance overrides the actual platform used', + () { + final ImagePickerPlatform savedPlatform = ImagePickerPlatform.instance; + final MockPlatform mockPlatform = MockPlatform(); + ImagePickerPlatform.instance = mockPlatform; + expect(ImagePicker.platform, mockPlatform); + ImagePickerPlatform.instance = savedPlatform; + }); + group('#pickImage', () { test('passes the image source argument correctly', () async { await picker.getImage(source: ImageSource.camera); @@ -336,3 +348,7 @@ void main() { }); }); } + +class MockPlatform extends Mock + with MockPlatformInterfaceMixin + implements ImagePickerPlatform {} From 0f1c20dd25c070a4b1349bfcbfe0f284ee205150 Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Mon, 21 Dec 2020 14:38:22 -0800 Subject: [PATCH 064/924] [url_launcher] forceSafariVC should be nullable to avoid breaking change (#3354) --- packages/url_launcher/url_launcher/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher/lib/url_launcher.dart | 4 ++-- packages/url_launcher/url_launcher/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 9df2d27a2b57..eb08455c4785 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.0.0-nullsafety.3 + +* forceSafariVC should be nullable. + ## 6.0.0-nullsafety.2 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/url_launcher/url_launcher/lib/url_launcher.dart b/packages/url_launcher/url_launcher/lib/url_launcher.dart index 6138fff2e3d9..35833de18738 100644 --- a/packages/url_launcher/url_launcher/lib/url_launcher.dart +++ b/packages/url_launcher/url_launcher/lib/url_launcher.dart @@ -62,7 +62,7 @@ import 'package:url_launcher_platform_interface/url_launcher_platform_interface. /// is set to true and the universal link failed to launch. Future launch( String urlString, { - bool forceSafariVC = true, + bool? forceSafariVC, bool forceWebView = false, bool enableJavaScript = false, bool enableDomStorage = false, @@ -95,7 +95,7 @@ Future launch( final bool result = await UrlLauncherPlatform.instance.launch( urlString, - useSafariVC: forceSafariVC, + useSafariVC: forceSafariVC ?? isWebURL, useWebView: forceWebView, enableJavaScript: enableJavaScript, enableDomStorage: enableDomStorage, diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index e2d7a161e1ea..0ab2d410c000 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 6.0.0-nullsafety.2 +version: 6.0.0-nullsafety.3 flutter: plugin: From 57087311b64246a0e56b82f918605334e326294d Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 22 Dec 2020 18:56:02 +0100 Subject: [PATCH 065/924] Fix documentation (#3362) --- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/lib/src/camera_controller.dart | 8 +------- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 168ed5557123..2811384a7d3b 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.2+1 + +* Fix the API documentation for the `CameraController.takePicture` method. + ## 0.6.2 * Add zoom support for Android and iOS implementations. diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index b79975fbad8e..1d7aed755f42 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -226,13 +226,7 @@ class CameraController extends ValueNotifier { await CameraPlatform.instance.prepareForVideoRecording(); } - /// Captures an image and saves it to [path]. - /// - /// A path can for example be obtained using - /// [path_provider](https://pub.dartlang.org/packages/path_provider). - /// - /// If a file already exists at the provided path an error will be thrown. - /// The file can be read as this function returns. + /// Captures an image and returns the file where it was saved. /// /// Throws a [CameraException] if the capture fails. Future takePicture() async { diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index d823dd383281..4f6ade284e29 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.2 +version: 0.6.2+1 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 7bc9aa215f885e0ac384082aa8286103329a2d6a Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 22 Dec 2020 19:02:49 +0100 Subject: [PATCH 066/924] Make sure saveTo returns a Future (#3363) --- packages/cross_file/CHANGELOG.md | 4 ++++ packages/cross_file/lib/src/types/base.dart | 2 +- packages/cross_file/lib/src/types/html.dart | 2 +- packages/cross_file/lib/src/types/io.dart | 2 +- packages/cross_file/pubspec.yaml | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md index 1716cb5ade7f..5ad91979dc89 100644 --- a/packages/cross_file/CHANGELOG.md +++ b/packages/cross_file/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.0 + +* **breaking change** Make sure the `saveTo` method returns a `Future` so it can be awaited and users are sure the file has been written to disk. + ## 0.1.0+2 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/cross_file/lib/src/types/base.dart b/packages/cross_file/lib/src/types/base.dart index 6dc2d51b08b1..1a1b5694d58f 100644 --- a/packages/cross_file/lib/src/types/base.dart +++ b/packages/cross_file/lib/src/types/base.dart @@ -18,7 +18,7 @@ abstract class XFileBase { XFileBase(String path); /// Save the CrossFile at the indicated file path. - void saveTo(String path) async { + Future saveTo(String path) { throw UnimplementedError('saveTo has not been implemented.'); } diff --git a/packages/cross_file/lib/src/types/html.dart b/packages/cross_file/lib/src/types/html.dart index 269f2a8d9412..646939612d75 100644 --- a/packages/cross_file/lib/src/types/html.dart +++ b/packages/cross_file/lib/src/types/html.dart @@ -108,7 +108,7 @@ class XFile extends XFileBase { /// Saves the data of this CrossFile at the location indicated by path. /// For the web implementation, the path variable is ignored. - void saveTo(String path) async { + Future saveTo(String path) async { // Create a DOM container where we can host the anchor. _target = ensureInitialized('__x_file_dom_element'); diff --git a/packages/cross_file/lib/src/types/io.dart b/packages/cross_file/lib/src/types/io.dart index 81b8cdd84d67..d9a93559b507 100644 --- a/packages/cross_file/lib/src/types/io.dart +++ b/packages/cross_file/lib/src/types/io.dart @@ -57,7 +57,7 @@ class XFile extends XFileBase { } @override - void saveTo(String path) async { + Future saveTo(String path) async { File fileToSave = File(path); await fileToSave.writeAsBytes(_bytes ?? (await readAsBytes())); await fileToSave.create(); diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml index 0c7f30677aba..4c9acf9b008a 100644 --- a/packages/cross_file/pubspec.yaml +++ b/packages/cross_file/pubspec.yaml @@ -1,7 +1,7 @@ name: cross_file description: An abstraction to allow working with files across multiple platforms. homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file -version: 0.1.0+2 +version: 0.2.0 dependencies: flutter: From 622ba57c3960e511bdd4adabe800aef844e263fc Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Tue, 22 Dec 2020 23:28:30 +0100 Subject: [PATCH 067/924] [camera] Add implementations for the torch flash mode. (#3338) * Added torch mode functionality for Android and iOS. * Format objective c code --- packages/camera/camera/CHANGELOG.md | 4 + .../io/flutter/plugins/camera/Camera.java | 8 +- .../plugins/camera/types/FlashMode.java | 3 +- .../plugins/camera/types/FlashModeTest.java | 4 + packages/camera/camera/example/lib/main.dart | 9 ++ .../camera/camera/ios/Classes/CameraPlugin.m | 99 +++++++++++++++---- packages/camera/camera/pubspec.yaml | 2 +- .../method_channel_camera_test.dart | 3 + 8 files changed, 108 insertions(+), 24 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 2811384a7d3b..b407b83e35db 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.3 + +* Adds torch mode as a flash mode for Android and iOS implementations. + ## 0.6.2+1 * Fix the API documentation for the `CameraController.takePicture` method. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 3e8bbc7b295b..cae666d6742a 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -532,7 +532,6 @@ public void setFlashMode(@NonNull final Result result, FlashMode mode) return; } // Get flash - this.flashMode = mode; initPreviewCaptureBuilder(); this.cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); @@ -553,11 +552,16 @@ private void initPreviewCaptureBuilder() { captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; case always: - default: captureRequestBuilder.set( CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; + case torch: + default: + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); + captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); + break; } } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java index eddeddc47eab..99d4915b3a6a 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java @@ -4,7 +4,8 @@ public enum FlashMode { off, auto, - always; + always, + torch; public static FlashMode getValueForString(String modeStr) { try { diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java index 0549e4fc750e..d2674e8c7e06 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java @@ -16,6 +16,10 @@ public void getValueForString_returns_correct_values() { "Returns FlashMode.always for 'always'", FlashMode.getValueForString("always"), FlashMode.always); + assertEquals( + "Returns FlashMode.torch for 'torch'", + FlashMode.getValueForString("torch"), + FlashMode.torch); } @Test diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 049141d3935e..ee8e2c259b3d 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -256,6 +256,15 @@ class _CameraExampleHomeState extends State ? () => onFlashModeButtonPressed(FlashMode.always) : null, ), + IconButton( + icon: const Icon(Icons.highlight), + color: controller?.value?.flashMode == FlashMode.torch + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => onFlashModeButtonPressed(FlashMode.torch) + : null, + ), ], ); } diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index c13ff60abd0a..d54695233bdb 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -134,13 +134,23 @@ - (UIImageOrientation)getImageRotation { } @end -static AVCaptureFlashMode getFlashModeForString(NSString *mode) { +// Mirrors FlashMode in flash_mode.dart +typedef enum { + FlashModeOff, + FlashModeAuto, + FlashModeAlways, + FlashModeTorch, +} FlashMode; + +static FlashMode getFlashModeForString(NSString *mode) { if ([mode isEqualToString:@"off"]) { - return AVCaptureFlashModeOff; + return FlashModeOff; } else if ([mode isEqualToString:@"auto"]) { - return AVCaptureFlashModeAuto; + return FlashModeAuto; } else if ([mode isEqualToString:@"always"]) { - return AVCaptureFlashModeOn; + return FlashModeAlways; + } else if ([mode isEqualToString:@"torch"]) { + return FlashModeTorch; } else { NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSURLErrorUnknown @@ -152,6 +162,20 @@ static AVCaptureFlashMode getFlashModeForString(NSString *mode) { } } +static AVCaptureFlashMode getAVCaptureFlashModeForFlashMode(FlashMode mode) { + switch (mode) { + case FlashModeOff: + return AVCaptureFlashModeOff; + case FlashModeAuto: + return AVCaptureFlashModeAuto; + case FlashModeAlways: + return AVCaptureFlashModeOn; + case FlashModeTorch: + default: + return -1; + } +} + // Mirrors ResolutionPreset in camera.dart typedef enum { veryLow, @@ -219,7 +243,7 @@ @interface FLTCam : NSObject [ + isMethodCall('setFlashMode', + arguments: {'cameraId': cameraId, 'mode': 'torch'}), isMethodCall('setFlashMode', arguments: {'cameraId': cameraId, 'mode': 'always'}), isMethodCall('setFlashMode', From a9513d592101555eaab8f26315d161ac84f3d066 Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Thu, 24 Dec 2020 17:20:43 +0100 Subject: [PATCH 068/924] [camera] Fix flash/torch not working on some Android devices. (#3367) * Wait pre capture to finish * Add autofocus stage to capture * Fixed autofocus stage * Make sure torch is turned off * Format & structure improvements * Update changelog and pubspec * Update packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java Co-authored-by: Maurits van Beusekom * Update packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java Co-authored-by: Maurits van Beusekom * Update packages/camera/camera/CHANGELOG.md Co-authored-by: Maurits van Beusekom * Update packages/camera/camera/pubspec.yaml Co-authored-by: Maurits van Beusekom * Remove unnecessary import. * Updated unit tests Co-authored-by: Maurits van Beusekom Co-authored-by: Maurits van Beusekom --- packages/camera/camera/CHANGELOG.md | 4 + .../io/flutter/plugins/camera/Camera.java | 176 ++++++++++++++++-- .../plugins/camera/PictureCaptureRequest.java | 4 +- .../camera/PictureCaptureRequestTest.java | 12 +- packages/camera/camera/pubspec.yaml | 2 +- 5 files changed, 173 insertions(+), 25 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index b407b83e35db..225601054fb9 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.3+1 + +* Fixes flash & torch modes not working on some Android devices. + ## 0.6.3 * Adds torch mode as a flash mode for Android and iOS implementations. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index cae666d6742a..0116ce3c0e4d 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -12,6 +12,7 @@ import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCaptureSession.CaptureCallback; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; @@ -29,12 +30,15 @@ import android.os.Build; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; +import android.os.Handler; +import android.os.Looper; import android.util.Size; import android.view.OrientationEventListener; import android.view.Surface; import androidx.annotation.NonNull; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugins.camera.PictureCaptureRequest.State; import io.flutter.plugins.camera.media.MediaRecorderBuilder; import io.flutter.plugins.camera.types.FlashMode; import io.flutter.plugins.camera.types.ResolutionPreset; @@ -246,7 +250,7 @@ public void takePicture(@NonNull final Result result) { }, null); - runPicturePreCapture(); + runPictureAutoFocus(); } private final CameraCaptureSession.CaptureCallback pictureCaptureCallback = @@ -256,18 +260,15 @@ public void onCaptureCompleted( @NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { - assert (pictureCaptureRequest != null); - switch (pictureCaptureRequest.getState()) { - case awaitingPreCapture: - Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); - // Some devices might return null here, in which case we will also continue. - if (aeState == null - || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED - || aeState == CaptureRequest.CONTROL_AE_STATE_CONVERGED) { - runPictureCapture(); - } - break; - } + processCapture(result); + } + + @Override + public void onCaptureProgressed( + @NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, + @NonNull CaptureResult partialResult) { + processCapture(partialResult); } @Override @@ -289,11 +290,54 @@ public void onCaptureFailed( } pictureCaptureRequest.error("captureFailure", reason, null); } + + private void processCapture(CaptureResult result) { + if (pictureCaptureRequest == null) { + return; + } + + Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); + Integer afState = result.get(CaptureResult.CONTROL_AF_STATE); + switch (pictureCaptureRequest.getState()) { + case focusing: + if (afState == null) { + return; + } else if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED + || afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) { + // Some devices might return null here, in which case we will also continue. + if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) { + runPictureCapture(); + } else { + runPicturePreCapture(); + } + } + break; + case preCapture: + // Some devices might return null here, in which case we will also continue. + if (aeState == null + || aeState == CaptureRequest.CONTROL_AE_STATE_PRECAPTURE + || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED + || aeState == CaptureRequest.CONTROL_AE_STATE_CONVERGED) { + pictureCaptureRequest.setState(State.waitingPreCaptureReady); + } + break; + case waitingPreCaptureReady: + if (aeState == null || aeState != CaptureRequest.CONTROL_AE_STATE_PRECAPTURE) { + runPictureCapture(); + } + } + } }; + private void runPictureAutoFocus() { + assert (pictureCaptureRequest != null); + pictureCaptureRequest.setState(PictureCaptureRequest.State.focusing); + lockAutoFocus(); + } + private void runPicturePreCapture() { assert (pictureCaptureRequest != null); - pictureCaptureRequest.setState(PictureCaptureRequest.State.awaitingPreCapture); + pictureCaptureRequest.setState(PictureCaptureRequest.State.preCapture); captureRequestBuilder.set( CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, @@ -331,7 +375,47 @@ private void runPictureCapture() { CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); break; } - cameraCaptureSession.capture(captureBuilder.build(), pictureCaptureCallback, null); + cameraCaptureSession.stopRepeating(); + cameraCaptureSession.capture( + captureBuilder.build(), + new CameraCaptureSession.CaptureCallback() { + @Override + public void onCaptureCompleted( + @NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, + @NonNull TotalCaptureResult result) { + unlockAutoFocus(); + } + }, + null); + } catch (CameraAccessException e) { + pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); + } + } + + private void lockAutoFocus() { + captureRequestBuilder.set( + CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); + try { + cameraCaptureSession.capture(captureRequestBuilder.build(), pictureCaptureCallback, null); + } catch (CameraAccessException e) { + pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); + } + } + + private void unlockAutoFocus() { + captureRequestBuilder.set( + CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL); + initPreviewCaptureBuilder(); + try { + cameraCaptureSession.capture(captureRequestBuilder.build(), null, null); + } catch (CameraAccessException ignored) { + } + captureRequestBuilder.set( + CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE); + try { + cameraCaptureSession.setRepeatingRequest( + captureRequestBuilder.build(), pictureCaptureCallback, null); } catch (CameraAccessException e) { pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); } @@ -377,7 +461,10 @@ public void onConfigured(@NonNull CameraCaptureSession session) { } cameraCaptureSession = session; initPreviewCaptureBuilder(); - cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); + cameraCaptureSession.setRepeatingRequest( + captureRequestBuilder.build(), + pictureCaptureCallback, + new Handler(Looper.getMainLooper())); if (onSuccessCallback != null) { onSuccessCallback.run(); } @@ -531,11 +618,60 @@ public void setFlashMode(@NonNull final Result result, FlashMode mode) result.error("setFlashModeFailed", "Device does not have flash capabilities", null); return; } + + // If switching directly from torch to auto or on, make sure we turn off the torch. + if (flashMode == FlashMode.torch && mode != FlashMode.torch && mode != FlashMode.off) { + this.flashMode = FlashMode.off; + initPreviewCaptureBuilder(); + this.cameraCaptureSession.setRepeatingRequest( + captureRequestBuilder.build(), + new CaptureCallback() { + private boolean isFinished = false; + + @Override + public void onCaptureCompleted( + @NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, + @NonNull TotalCaptureResult captureResult) { + if (isFinished) { + return; + } + + updateFlash(mode); + result.success(null); + isFinished = true; + } + + @Override + public void onCaptureFailed( + @NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, + @NonNull CaptureFailure failure) { + if (isFinished) { + return; + } + + result.error("setFlashModeFailed", "Could not set flash mode.", null); + isFinished = true; + } + }, + null); + } else { + updateFlash(mode); + result.success(null); + } + } + + private void updateFlash(FlashMode mode) { // Get flash - this.flashMode = mode; + flashMode = mode; initPreviewCaptureBuilder(); - this.cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); - result.success(null); + try { + cameraCaptureSession.setRepeatingRequest( + captureRequestBuilder.build(), pictureCaptureCallback, null); + } catch (CameraAccessException e) { + pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); + } } private void initPreviewCaptureBuilder() { @@ -563,6 +699,8 @@ private void initPreviewCaptureBuilder() { captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); break; } + captureRequestBuilder.set( + CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); } public void startPreview() throws CameraAccessException { diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java index e365f071d9a8..1103b8583ad6 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java @@ -7,7 +7,9 @@ class PictureCaptureRequest { enum State { idle, - awaitingPreCapture, + focusing, + preCapture, + waitingPreCaptureReady, capturing, finished, error, diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java index 2b6aa0f25fcf..2356b306c6c4 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java @@ -20,11 +20,15 @@ public void state_is_idle_by_default() { @Test public void setState_sets_state() { PictureCaptureRequest req = new PictureCaptureRequest(null); - req.setState(PictureCaptureRequest.State.awaitingPreCapture); + req.setState(PictureCaptureRequest.State.focusing); + assertEquals("State is focusing", req.getState(), PictureCaptureRequest.State.focusing); + req.setState(PictureCaptureRequest.State.preCapture); + assertEquals("State is preCapture", req.getState(), PictureCaptureRequest.State.preCapture); + req.setState(PictureCaptureRequest.State.waitingPreCaptureReady); assertEquals( - "State is awaitingPreCapture", + "State is waitingPreCaptureReady", req.getState(), - PictureCaptureRequest.State.awaitingPreCapture); + PictureCaptureRequest.State.waitingPreCaptureReady); req.setState(PictureCaptureRequest.State.capturing); assertEquals( "State is awaitingPreCapture", req.getState(), PictureCaptureRequest.State.capturing); @@ -49,7 +53,7 @@ public void isFinished_is_true_When_state_is_finished_or_error() { // Test false states req.setState(PictureCaptureRequest.State.idle); assertFalse(req.isFinished()); - req.setState(PictureCaptureRequest.State.awaitingPreCapture); + req.setState(PictureCaptureRequest.State.preCapture); assertFalse(req.isFinished()); req.setState(PictureCaptureRequest.State.capturing); assertFalse(req.isFinished()); diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 1bccbd4d45df..43a5fca3da21 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.3 +version: 0.6.3+1 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 7eff06206d5ff76097656b9b0f9b148a748c649e Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Sun, 27 Dec 2020 16:02:53 +0100 Subject: [PATCH 069/924] [camera] Fix video recording exception on Android (#3375) * Fixed video recording * Update changelog and pubspec version * Update packages/camera/camera/CHANGELOG.md Co-authored-by: Maurits van Beusekom Co-authored-by: Maurits van Beusekom --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../src/main/java/io/flutter/plugins/camera/Camera.java | 4 +++- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 225601054fb9..461b2d927eda 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.3+2 + +* Fixes crash on Android which occurs after video recording has stopped just before taking a picture. + ## 0.6.3+1 * Fixes flash & torch modes not working on some Android devices. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 0116ce3c0e4d..3c28d6655e48 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -276,7 +276,9 @@ public void onCaptureFailed( @NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { - assert (pictureCaptureRequest != null); + if (pictureCaptureRequest == null || pictureCaptureRequest.isFinished()) { + return; + } String reason; switch (failure.getReason()) { case CaptureFailure.REASON_ERROR: diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 43a5fca3da21..1f5d06eecbe3 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.3+1 +version: 0.6.3+2 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 3ec0d64a5b65b9a27863c553fff1ca54687f5431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Mon, 28 Dec 2020 11:14:26 +0100 Subject: [PATCH 070/924] [camera] Added maxVideoDuration to startVideoRecording (#3365) * Added maxVideoDuration to startVideoRecording * updated documentation Co-authored-by: Maurits van Beusekom * updated documentation Co-authored-by: Maurits van Beusekom * Fixed long line in docs * Formatting Co-authored-by: Maurits van Beusekom --- .../camera_platform_interface/CHANGELOG.md | 4 ++++ .../method_channel/method_channel_camera.dart | 8 +++++-- .../platform_interface/camera_platform.dart | 5 ++++- .../camera_platform_interface/pubspec.yaml | 2 +- .../method_channel_camera_test.dart | 22 +++++++++++++++++++ 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index ea9821e841f9..d117e1c0eba4 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.0 + +- Added an optional `maxVideoDuration` parameter to the `startVideoRecording` method, which allows implementations to limit the duration of a video recording. + ## 1.0.4 - Added the torch option to the FlashMode enum, which when implemented indicates the flash light should be turned on continuously. diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index 3bf996fedb19..bf2b3d3bd70a 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -146,10 +146,14 @@ class MethodChannelCamera extends CameraPlatform { _channel.invokeMethod('prepareForVideoRecording'); @override - Future startVideoRecording(int cameraId) async { + Future startVideoRecording(int cameraId, + {Duration maxVideoDuration}) async { await _channel.invokeMethod( 'startVideoRecording', - {'cameraId': cameraId}, + { + 'cameraId': cameraId, + 'maxVideoDuration': maxVideoDuration?.inMilliseconds, + }, ); } diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 6f96079dc55c..6c8e200c75c2 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -88,8 +88,11 @@ abstract class CameraPlatform extends PlatformInterface { /// Starts a video recording. /// + /// The length of the recording can be limited by specifying the [maxVideoDuration]. + /// By default no maximum duration is specified, + /// meaning the recording will continue until manually stopped. /// The video is returned as a [XFile] after calling [stopVideoRecording]. - Future startVideoRecording(int cameraId) { + Future startVideoRecording(int cameraId, {Duration maxVideoDuration}) { throw UnimplementedError('startVideoRecording() is not implemented.'); } diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index 8cb643e84ca6..b6933314d41d 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.0.4 +version: 1.1.0 dependencies: flutter: diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index 82b01015e4f4..12f5d6e8ecf8 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -411,10 +411,32 @@ void main() { expect(channel.log, [ isMethodCall('startVideoRecording', arguments: { 'cameraId': cameraId, + 'maxVideoDuration': null, }), ]); }); + test('Should pass maxVideoDuration when starting recording a video', + () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'startVideoRecording': null}, + ); + + // Act + await camera.startVideoRecording( + cameraId, + maxVideoDuration: Duration(seconds: 10), + ); + + // Assert + expect(channel.log, [ + isMethodCall('startVideoRecording', + arguments: {'cameraId': cameraId, 'maxVideoDuration': 10000}), + ]); + }); + test('Should stop a video recording and return the file', () async { // Arrange MethodChannelMock channel = MethodChannelMock( From 1c0090511fc84c2a64b275d7c3aea70e9222f220 Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Mon, 28 Dec 2020 20:00:47 +0100 Subject: [PATCH 071/924] [camera_platform_interface] Add platform interface methods for setting auto exposure. (#3345) * Added platform interface methods for setting auto exposure. * Added platform interface methods for setting auto exposure. * Remove workspace files --- .../camera_platform_interface/CHANGELOG.md | 4 + .../lib/src/events/camera_event.dart | 24 ++- .../method_channel/method_channel_camera.dart | 59 ++++++ .../platform_interface/camera_platform.dart | 46 ++++- .../lib/src/types/exposure_mode.dart | 36 ++++ .../lib/src/types/types.dart | 1 + .../camera_platform_interface/pubspec.yaml | 2 +- .../test/camera_platform_interface_test.dart | 78 ++++++++ .../test/events/camera_event_test.dart | 67 +++++-- .../method_channel_camera_test.dart | 172 +++++++++++++++++- .../test/types/exposure_mode_test.dart | 32 ++++ 11 files changed, 494 insertions(+), 27 deletions(-) create mode 100644 packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart create mode 100644 packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index d117e1c0eba4..8e316054f2b1 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.2.0 + +- Added interface to support automatic exposure. + ## 1.1.0 - Added an optional `maxVideoDuration` parameter to the `startVideoRecording` method, which allows implementations to limit the duration of a video recording. diff --git a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart index ab3d45545f23..590713d04e8b 100644 --- a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart +++ b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import '../../camera_platform_interface.dart'; + /// Generic Event coming from the native side of Camera. /// /// All [CameraEvent]s contain the `cameraId` that originated the event. This @@ -45,6 +47,12 @@ class CameraInitializedEvent extends CameraEvent { /// The height of the preview in pixels. final double previewHeight; + /// The default exposure mode + final ExposureMode exposureMode; + + /// Whether setting exposure points is supported. + final bool exposurePointSupported; + /// Build a CameraInitialized event triggered from the camera represented by /// `cameraId`. /// @@ -54,6 +62,8 @@ class CameraInitializedEvent extends CameraEvent { int cameraId, this.previewWidth, this.previewHeight, + this.exposureMode, + this.exposurePointSupported, ) : super(cameraId); /// Converts the supplied [Map] to an instance of the [CameraInitializedEvent] @@ -61,6 +71,8 @@ class CameraInitializedEvent extends CameraEvent { CameraInitializedEvent.fromJson(Map json) : previewWidth = json['previewWidth'], previewHeight = json['previewHeight'], + exposureMode = deserializeExposureMode(json['exposureMode']), + exposurePointSupported = json['exposurePointSupported'], super(json['cameraId']); /// Converts the [CameraInitializedEvent] instance into a [Map] instance that @@ -69,6 +81,8 @@ class CameraInitializedEvent extends CameraEvent { 'cameraId': cameraId, 'previewWidth': previewWidth, 'previewHeight': previewHeight, + 'exposureMode': serializeExposureMode(exposureMode), + 'exposurePointSupported': exposurePointSupported, }; @override @@ -78,11 +92,17 @@ class CameraInitializedEvent extends CameraEvent { other is CameraInitializedEvent && runtimeType == other.runtimeType && previewWidth == other.previewWidth && - previewHeight == other.previewHeight; + previewHeight == other.previewHeight && + exposureMode == other.exposureMode && + exposurePointSupported == other.exposurePointSupported; @override int get hashCode => - super.hashCode ^ previewWidth.hashCode ^ previewHeight.hashCode; + super.hashCode ^ + previewWidth.hashCode ^ + previewHeight.hashCode ^ + exposureMode.hashCode ^ + exposurePointSupported.hashCode; } /// An event fired when the resolution preset of the camera has changed. diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index bf2b3d3bd70a..6a73031111df 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:math'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:camera_platform_interface/src/utils/utils.dart'; @@ -189,6 +190,62 @@ class MethodChannelCamera extends CameraPlatform { }, ); + @override + Future setExposureMode(int cameraId, ExposureMode mode) => + _channel.invokeMethod( + 'setExposureMode', + { + 'cameraId': cameraId, + 'mode': serializeExposureMode(mode), + }, + ); + + @override + Future setExposurePoint(int cameraId, Point point) { + assert(point == null || point.x >= 0 && point.x <= 1); + assert(point == null || point.y >= 0 && point.y <= 1); + return _channel.invokeMethod( + 'setExposurePoint', + { + 'cameraId': cameraId, + 'reset': point == null, + 'x': point?.x, + 'y': point?.y, + }, + ); + } + + @override + Future getMinExposureOffset(int cameraId) => + _channel.invokeMethod( + 'getMinExposureOffset', + {'cameraId': cameraId}, + ); + + @override + Future getMaxExposureOffset(int cameraId) => + _channel.invokeMethod( + 'getMaxExposureOffset', + {'cameraId': cameraId}, + ); + + @override + Future getExposureOffsetStepSize(int cameraId) => + _channel.invokeMethod( + 'getExposureOffsetStepSize', + {'cameraId': cameraId}, + ); + + @override + Future setExposureOffset(int cameraId, double offset) => + _channel.invokeMethod( + 'setExposureOffset', + { + 'cameraId': cameraId, + 'offset': offset, + }, + ); + @override Future getMaxZoomLevel(int cameraId) => _channel.invokeMethod( 'getMaxZoomLevel', @@ -269,6 +326,8 @@ class MethodChannelCamera extends CameraPlatform { cameraId, call.arguments['previewWidth'], call.arguments['previewHeight'], + deserializeExposureMode(call.arguments['exposureMode']), + call.arguments['exposurePointSupported'], )); break; case 'resolution_changed': diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 6c8e200c75c2..c7a603228ce2 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -3,9 +3,11 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:math'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; +import 'package:camera_platform_interface/src/types/exposure_mode.dart'; import 'package:cross_file/cross_file.dart'; import 'package:flutter/widgets.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -116,6 +118,48 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('setFlashMode() is not implemented.'); } + /// Sets the exposure mode for taking pictures. + Future setExposureMode(int cameraId, ExposureMode mode) { + throw UnimplementedError('setExposureMode() is not implemented.'); + } + + /// Sets the exposure point for automatically determining the exposure value. + Future setExposurePoint(int cameraId, Point point) { + throw UnimplementedError('setExposurePoint() is not implemented.'); + } + + /// Gets the minimum supported exposure offset for the selected camera in EV units. + Future getMinExposureOffset(int cameraId) { + throw UnimplementedError('getMinExposureOffset() is not implemented.'); + } + + /// Gets the maximum supported exposure offset for the selected camera in EV units. + Future getMaxExposureOffset(int cameraId) { + throw UnimplementedError('getMaxExposureOffset() is not implemented.'); + } + + /// Gets the supported step size for exposure offset for the selected camera in EV units. + /// + /// Returns 0 when the camera supports using a free value without stepping. + Future getExposureOffsetStepSize(int cameraId) { + throw UnimplementedError('getMinExposureOffset() is not implemented.'); + } + + /// Sets the exposure offset for the selected camera. + /// + /// The supplied [offset] value should be in EV units. 1 EV unit represents a + /// doubling in brightness. It should be between the minimum and maximum offsets + /// obtained through `getMinExposureOffset` and `getMaxExposureOffset` respectively. + /// Throws a `CameraException` when an illegal offset is supplied. + /// + /// When the supplied [offset] value does not align with the step size obtained + /// through `getExposureStepSize`, it will automatically be rounded to the nearest step. + /// + /// Returns the (rounded) offset value that was set. + Future setExposureOffset(int cameraId, double offset) { + throw UnimplementedError('setExposureOffset() is not implemented.'); + } + /// Gets the maximum supported zoom level for the selected camera. Future getMaxZoomLevel(int cameraId) { throw UnimplementedError('getMaxZoomLevel() is not implemented.'); @@ -129,7 +173,7 @@ abstract class CameraPlatform extends PlatformInterface { /// Set the zoom level for the selected camera. /// /// The supplied [zoom] value should be between 1.0 and the maximum supported - /// zoom level returned by the `getMaxZoomLevel`. Throws an `CameraException` + /// zoom level returned by the `getMaxZoomLevel`. Throws a `CameraException` /// when an illegal zoom level is supplied. Future setZoomLevel(int cameraId, double zoom) { throw UnimplementedError('setZoomLevel() is not implemented.'); diff --git a/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart new file mode 100644 index 000000000000..836f53826479 --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart @@ -0,0 +1,36 @@ +// Copyright 2019 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. + +/// The possible exposure modes that can be set for a camera. +enum ExposureMode { + /// Automatically determine exposure settings. + auto, + + /// Lock the currently determined exposure settings. + locked, +} + +/// Returns the exposure mode as a String. +String serializeExposureMode(ExposureMode exposureMode) { + switch (exposureMode) { + case ExposureMode.locked: + return 'locked'; + case ExposureMode.auto: + return 'auto'; + default: + throw ArgumentError('Unknown ExposureMode value'); + } +} + +/// Returns the exposure mode for a given String. +ExposureMode deserializeExposureMode(String str) { + switch (str) { + case "locked": + return ExposureMode.locked; + case "auto": + return ExposureMode.auto; + default: + throw ArgumentError('"$str" is not a valid ExposureMode value'); + } +} diff --git a/packages/camera/camera_platform_interface/lib/src/types/types.dart b/packages/camera/camera_platform_interface/lib/src/types/types.dart index 3a89a1021e95..bab430eb5a69 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/types.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/types.dart @@ -6,3 +6,4 @@ export 'camera_description.dart'; export 'resolution_preset.dart'; export 'camera_exception.dart'; export 'flash_mode.dart'; +export 'exposure_mode.dart'; diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index b6933314d41d..b8301d289cc6 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.0 +version: 1.2.0 dependencies: flutter: diff --git a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart index 7a6fc344503f..574fa45e7b81 100644 --- a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart +++ b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart @@ -186,6 +186,84 @@ void main() { ); }); + test( + 'Default implementation of setExposureMode() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.setExposureMode(1, null), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of setExposurePoint() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.setExposurePoint(1, null), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of getMinExposureOffset() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.getMinExposureOffset(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of getMaxExposureOffset() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.getMaxExposureOffset(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of getExposureOffsetStepSize() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.getExposureOffsetStepSize(1), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of setExposureOffset() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.setExposureOffset(1, null), + throwsUnimplementedError, + ); + }); + test( 'Default implementation of startVideoRecording() should throw unimplemented error', () { diff --git a/packages/camera/camera_platform_interface/test/events/camera_event_test.dart b/packages/camera/camera_platform_interface/test/events/camera_event_test.dart index 01b03b8e93a0..1e28fa689383 100644 --- a/packages/camera/camera_platform_interface/test/events/camera_event_test.dart +++ b/packages/camera/camera_platform_interface/test/events/camera_event_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/types/exposure_mode.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -10,11 +11,14 @@ void main() { group('CameraInitializedEvent tests', () { test('Constructor should initialize all properties', () { - final event = CameraInitializedEvent(1, 1024, 640); + final event = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); expect(event.cameraId, 1); expect(event.previewWidth, 1024); expect(event.previewHeight, 640); + expect(event.exposureMode, ExposureMode.auto); + expect(event.exposurePointSupported, true); }); test('fromJson should initialize all properties', () { @@ -22,57 +26,92 @@ void main() { 'cameraId': 1, 'previewWidth': 1024.0, 'previewHeight': 640.0, + 'exposureMode': 'auto' }); expect(event.cameraId, 1); expect(event.previewWidth, 1024); expect(event.previewHeight, 640); + expect(event.exposureMode, ExposureMode.auto); }); test('toJson should return a map with all fields', () { - final event = CameraInitializedEvent(1, 1024, 640); + final event = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); final jsonMap = event.toJson(); - expect(jsonMap.length, 3); + expect(jsonMap.length, 5); expect(jsonMap['cameraId'], 1); expect(jsonMap['previewWidth'], 1024); expect(jsonMap['previewHeight'], 640); + expect(jsonMap['exposureMode'], 'auto'); + expect(jsonMap['exposurePointSupported'], true); }); test('equals should return true if objects are the same', () { - final firstEvent = CameraInitializedEvent(1, 1024, 640); - final secondEvent = CameraInitializedEvent(1, 1024, 640); + final firstEvent = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); + final secondEvent = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); expect(firstEvent == secondEvent, true); }); test('equals should return false if cameraId is different', () { - final firstEvent = CameraInitializedEvent(1, 1024, 640); - final secondEvent = CameraInitializedEvent(2, 1024, 640); + final firstEvent = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); + final secondEvent = + CameraInitializedEvent(2, 1024, 640, ExposureMode.auto, true); expect(firstEvent == secondEvent, false); }); test('equals should return false if previewWidth is different', () { - final firstEvent = CameraInitializedEvent(1, 1024, 640); - final secondEvent = CameraInitializedEvent(1, 2048, 640); + final firstEvent = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); + final secondEvent = + CameraInitializedEvent(1, 2048, 640, ExposureMode.auto, true); expect(firstEvent == secondEvent, false); }); test('equals should return false if previewHeight is different', () { - final firstEvent = CameraInitializedEvent(1, 1024, 640); - final secondEvent = CameraInitializedEvent(1, 1024, 980); + final firstEvent = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); + final secondEvent = + CameraInitializedEvent(1, 1024, 980, ExposureMode.auto, true); + + expect(firstEvent == secondEvent, false); + }); + + test('equals should return false if exposureMode is different', () { + final firstEvent = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); + final secondEvent = + CameraInitializedEvent(1, 1024, 640, ExposureMode.locked, true); + + expect(firstEvent == secondEvent, false); + }); + + test('equals should return false if exposurePointSupported is different', + () { + final firstEvent = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); + final secondEvent = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, false); expect(firstEvent == secondEvent, false); }); test('hashCode should match hashCode of all properties', () { - final event = CameraInitializedEvent(1, 1024, 640); - final expectedHashCode = event.cameraId.hashCode ^ + final event = + CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); + final expectedHashCode = event.cameraId ^ event.previewWidth.hashCode ^ - event.previewHeight.hashCode; + event.previewHeight.hashCode ^ + event.exposureMode.hashCode ^ + event.exposurePointSupported.hashCode; expect(event.hashCode, expectedHashCode); }); diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index 12f5d6e8ecf8..b916513ef0de 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:math'; import 'package:async/async.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; @@ -118,8 +119,13 @@ void main() { // Act Future initializeFuture = camera.initializeCamera(cameraId); - camera.cameraEventStreamController - .add(CameraInitializedEvent(cameraId, 1920, 1080)); + camera.cameraEventStreamController.add(CameraInitializedEvent( + cameraId, + 1920, + 1080, + ExposureMode.auto, + true, + )); await initializeFuture; // Assert @@ -151,8 +157,13 @@ void main() { ResolutionPreset.high, ); Future initializeFuture = camera.initializeCamera(cameraId); - camera.cameraEventStreamController - .add(CameraInitializedEvent(cameraId, 1920, 1080)); + camera.cameraEventStreamController.add(CameraInitializedEvent( + cameraId, + 1920, + 1080, + ExposureMode.auto, + true, + )); await initializeFuture; // Act @@ -188,8 +199,13 @@ void main() { ResolutionPreset.high, ); Future initializeFuture = camera.initializeCamera(cameraId); - camera.cameraEventStreamController - .add(CameraInitializedEvent(cameraId, 1920, 1080)); + camera.cameraEventStreamController.add(CameraInitializedEvent( + cameraId, + 1920, + 1080, + ExposureMode.auto, + true, + )); await initializeFuture; }); @@ -200,7 +216,13 @@ void main() { final streamQueue = StreamQueue(eventStream); // Emit test events - final event = CameraInitializedEvent(cameraId, 3840, 2160); + final event = CameraInitializedEvent( + cameraId, + 3840, + 2160, + ExposureMode.auto, + true, + ); await camera.handleMethodCall( MethodCall('initialized', event.toJson()), cameraId); @@ -304,8 +326,15 @@ void main() { ResolutionPreset.high, ); Future initializeFuture = camera.initializeCamera(cameraId); - camera.cameraEventStreamController - .add(CameraInitializedEvent(cameraId, 1920, 1080)); + camera.cameraEventStreamController.add( + CameraInitializedEvent( + cameraId, + 1920, + 1080, + ExposureMode.auto, + true, + ), + ); await initializeFuture; }); @@ -518,6 +547,131 @@ void main() { ]); }); + test('Should set the exposure mode', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'setExposureMode': null}, + ); + + // Act + await camera.setExposureMode(cameraId, ExposureMode.auto); + await camera.setExposureMode(cameraId, ExposureMode.locked); + + // Assert + expect(channel.log, [ + isMethodCall('setExposureMode', + arguments: {'cameraId': cameraId, 'mode': 'auto'}), + isMethodCall('setExposureMode', + arguments: {'cameraId': cameraId, 'mode': 'locked'}), + ]); + }); + + test('Should set the exposure point', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'setExposurePoint': null}, + ); + + // Act + await camera.setExposurePoint(cameraId, Point(0.5, 0.5)); + await camera.setExposurePoint(cameraId, null); + + // Assert + expect(channel.log, [ + isMethodCall('setExposurePoint', arguments: { + 'cameraId': cameraId, + 'x': 0.5, + 'y': 0.5, + 'reset': false + }), + isMethodCall('setExposurePoint', arguments: { + 'cameraId': cameraId, + 'x': null, + 'y': null, + 'reset': true + }), + ]); + }); + + test('Should get the min exposure offset', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'getMinExposureOffset': 2.0}, + ); + + // Act + final minExposureOffset = await camera.getMinExposureOffset(cameraId); + + // Assert + expect(minExposureOffset, 2.0); + expect(channel.log, [ + isMethodCall('getMinExposureOffset', arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test('Should get the max exposure offset', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'getMaxExposureOffset': 2.0}, + ); + + // Act + final maxExposureOffset = await camera.getMaxExposureOffset(cameraId); + + // Assert + expect(maxExposureOffset, 2.0); + expect(channel.log, [ + isMethodCall('getMaxExposureOffset', arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test('Should get the exposure offset step size', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'getExposureOffsetStepSize': 0.25}, + ); + + // Act + final stepSize = await camera.getExposureOffsetStepSize(cameraId); + + // Assert + expect(stepSize, 0.25); + expect(channel.log, [ + isMethodCall('getExposureOffsetStepSize', arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test('Should set the exposure offset', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'setExposureOffset': 0.6}, + ); + + // Act + final actualOffset = await camera.setExposureOffset(cameraId, 0.5); + + // Assert + expect(actualOffset, 0.6); + expect(channel.log, [ + isMethodCall('setExposureOffset', arguments: { + 'cameraId': cameraId, + 'offset': 0.5, + }), + ]); + }); + test('Should build a texture widget as preview widget', () async { // Act Widget widget = camera.buildPreview(cameraId); diff --git a/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart b/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart new file mode 100644 index 000000000000..c34c1d7b4157 --- /dev/null +++ b/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart @@ -0,0 +1,32 @@ +// Copyright 2019 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 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/types/exposure_mode.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('ExposureMode should contain 2 options', () { + final values = ExposureMode.values; + + expect(values.length, 2); + }); + + test("ExposureMode enum should have items in correct index", () { + final values = ExposureMode.values; + + expect(values[0], ExposureMode.auto); + expect(values[1], ExposureMode.locked); + }); + + test("serializeExposureMode() should serialize correctly", () { + expect(serializeExposureMode(ExposureMode.auto), "auto"); + expect(serializeExposureMode(ExposureMode.locked), "locked"); + }); + + test("deserializeExposureMode() should deserialize correctly", () { + expect(deserializeExposureMode('auto'), ExposureMode.auto); + expect(deserializeExposureMode('locked'), ExposureMode.locked); + }); +} From 65d041fd9adce6d350e7c063fd6a8a2e13d478f0 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 29 Dec 2020 02:29:03 +0100 Subject: [PATCH 072/924] Update camera_platform_interface to 1.2.0 (#3376) --- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/pubspec.yaml | 4 ++-- packages/camera/camera/test/camera_test.dart | 6 ++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 461b2d927eda..9a5fe7c209af 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.3+3 + +* Updated dependency on camera_platform_interface to ^1.2.0. + ## 0.6.3+2 * Fixes crash on Android which occurs after video recording has stopped just before taking a picture. diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 1f5d06eecbe3..2a32734485d4 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,13 +2,13 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.3+2 +version: 0.6.3+3 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: flutter: sdk: flutter - camera_platform_interface: ^1.0.4 + camera_platform_interface: ^1.2.0 dev_dependencies: path_provider: ^0.5.0 diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 43dec7374901..0029e56bf566 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -26,7 +26,8 @@ get mockAvailableCameras => [ get mockInitializeCamera => 13; -get mockOnCameraInitializedEvent => CameraInitializedEvent(13, 75, 75); +get mockOnCameraInitializedEvent => + CameraInitializedEvent(13, 75, 75, ExposureMode.auto, false); get mockOnCameraClosingEvent => null; @@ -641,7 +642,8 @@ class MockCameraPlatform extends Mock : Future.value(mockTakePicture); @override - Future startVideoRecording(int cameraId) => + Future startVideoRecording(int cameraId, + {Duration maxVideoDuration}) => Future.value(mockVideoRecordingXFile); } From 72cc8e2197733c73c9974205b2c473982f4e0b78 Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Tue, 29 Dec 2020 15:04:03 +0100 Subject: [PATCH 073/924] Change platform interface dependency (#3377) --- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/pubspec.yaml | 4 ++-- packages/camera/camera/test/camera_test.dart | 6 ++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 9a5fe7c209af..df543c74efcf 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.3+4 + +* Revert previous dependency update: Changed dependency on camera_platform_interface to >=1.04 <1.1.0. + ## 0.6.3+3 * Updated dependency on camera_platform_interface to ^1.2.0. diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 2a32734485d4..fa40ad03ae89 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,13 +2,13 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.3+3 +version: 0.6.3+4 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: flutter: sdk: flutter - camera_platform_interface: ^1.2.0 + camera_platform_interface: ">=1.0.4 <1.1.0" dev_dependencies: path_provider: ^0.5.0 diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 0029e56bf566..43dec7374901 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -26,8 +26,7 @@ get mockAvailableCameras => [ get mockInitializeCamera => 13; -get mockOnCameraInitializedEvent => - CameraInitializedEvent(13, 75, 75, ExposureMode.auto, false); +get mockOnCameraInitializedEvent => CameraInitializedEvent(13, 75, 75); get mockOnCameraClosingEvent => null; @@ -642,8 +641,7 @@ class MockCameraPlatform extends Mock : Future.value(mockTakePicture); @override - Future startVideoRecording(int cameraId, - {Duration maxVideoDuration}) => + Future startVideoRecording(int cameraId) => Future.value(mockVideoRecordingXFile); } From 96e2328fe6338f429da4dec18998dce42e837d8b Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Wed, 30 Dec 2020 20:35:55 +0100 Subject: [PATCH 074/924] [camera] Add iOS and Android implementations for managing auto exposure. (#3346) * Added platform interface methods for setting auto exposure. * Added platform interface methods for setting auto exposure. * Remove workspace files * Added auto exposure implementations for Android and iOS * iOS fix for setting the exposure point * Removed unnecessary check * Update platform interface dependency * Implement PR feedback * Restore test * Small improvements for exposure point resetting --- packages/camera/camera/CHANGELOG.md | 4 + .../io/flutter/plugins/camera/Camera.java | 175 +++++++- .../flutter/plugins/camera/CameraRegions.java | 59 +++ .../flutter/plugins/camera/DartMessenger.java | 17 +- .../plugins/camera/MethodCallHandlerImpl.java | 68 +++ .../plugins/camera/types/ExposureMode.java | 25 ++ .../plugins/camera/types/FlashMode.java | 26 +- .../plugins/camera/CameraRegionsTest.java | 105 +++++ .../plugins/camera/DartMessengerTest.java | 5 +- .../camera/types/ExposureModeTest.java | 33 ++ .../plugins/camera/types/FlashModeTest.java | 8 + packages/camera/camera/example/lib/main.dart | 316 +++++++++++--- .../camera/camera/ios/Classes/CameraPlugin.m | 121 +++++- packages/camera/camera/lib/camera.dart | 1 + .../camera/lib/src/camera_controller.dart | 176 +++++++- packages/camera/camera/pubspec.yaml | 6 +- packages/camera/camera/test/camera_test.dart | 399 +++++++++++++++++- .../camera/camera/test/camera_value_test.dart | 30 +- 18 files changed, 1453 insertions(+), 121 deletions(-) create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index df543c74efcf..f576ee524ca1 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.4 + +* Adds auto exposure support for Android and iOS implementations. + ## 0.6.3+4 * Revert previous dependency update: Changed dependency on camera_platform_interface to >=1.04 <1.1.0. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 3c28d6655e48..d57a737c09f6 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -21,6 +21,7 @@ import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.MeteringRectangle; import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.params.SessionConfiguration; import android.media.CamcorderProfile; @@ -32,6 +33,8 @@ import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.Looper; +import android.util.Range; +import android.util.Rational; import android.util.Size; import android.view.OrientationEventListener; import android.view.Surface; @@ -40,6 +43,7 @@ import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.camera.PictureCaptureRequest.State; import io.flutter.plugins.camera.media.MediaRecorderBuilder; +import io.flutter.plugins.camera.types.ExposureMode; import io.flutter.plugins.camera.types.FlashMode; import io.flutter.plugins.camera.types.ResolutionPreset; import io.flutter.view.TextureRegistry.SurfaceTextureEntry; @@ -80,7 +84,10 @@ public class Camera { private File videoRecordingFile; private int currentOrientation = ORIENTATION_UNKNOWN; private FlashMode flashMode; + private ExposureMode exposureMode; private PictureCaptureRequest pictureCaptureRequest; + private CameraRegions cameraRegions; + private int exposureOffset; public Camera( final Activity activity, @@ -100,6 +107,8 @@ public Camera( this.cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); this.applicationContext = activity.getApplicationContext(); this.flashMode = FlashMode.auto; + this.exposureMode = ExposureMode.auto; + this.exposureOffset = 0; orientationEventListener = new OrientationEventListener(activity.getApplicationContext()) { @Override @@ -158,15 +167,17 @@ public void open() throws CameraAccessException { public void onOpened(@NonNull CameraDevice device) { cameraDevice = device; try { + cameraRegions = new CameraRegions(getRegionBoundaries()); startPreview(); + dartMessenger.sendCameraInitializedEvent( + previewSize.getWidth(), + previewSize.getHeight(), + exposureMode, + isExposurePointSupported()); } catch (CameraAccessException e) { dartMessenger.sendCameraErrorEvent(e.getMessage()); close(); - return; } - - dartMessenger.sendCameraInitializedEvent( - previewSize.getWidth(), previewSize.getHeight()); } @Override @@ -605,16 +616,11 @@ public void resumeVideoRecording(@NonNull final Result result) { public void setFlashMode(@NonNull final Result result, FlashMode mode) throws CameraAccessException { // Get the flash availability - Boolean flashAvailable; - try { - flashAvailable = - cameraManager - .getCameraCharacteristics(cameraDevice.getId()) - .get(CameraCharacteristics.FLASH_INFO_AVAILABLE); - } catch (CameraAccessException e) { - result.error("setFlashModeFailed", e.getMessage(), null); - return; - } + Boolean flashAvailable = + cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.FLASH_INFO_AVAILABLE); + // Check if flash is available. if (flashAvailable == null || !flashAvailable) { result.error("setFlashModeFailed", "Device does not have flash capabilities", null); @@ -676,8 +682,133 @@ private void updateFlash(FlashMode mode) { } } + public void setExposureMode(@NonNull final Result result, ExposureMode mode) + throws CameraAccessException { + this.exposureMode = mode; + initPreviewCaptureBuilder(); + cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); + result.success(null); + } + + public void setExposurePoint(@NonNull final Result result, Double x, Double y) + throws CameraAccessException { + // Check if exposure point functionality is available. + if (!isExposurePointSupported()) { + result.error( + "setExposurePointFailed", "Device does not have exposure point capabilities", null); + return; + } + // Check if we are doing a reset or not + if (x == null || y == null) { + x = 0.5; + y = 0.5; + } + // Get the current region boundaries. + Size maxBoundaries = getRegionBoundaries(); + if (maxBoundaries == null) { + result.error("setExposurePointFailed", "Could not determine max region boundaries", null); + return; + } + // Set the metering rectangle + cameraRegions.setAutoExposureMeteringRectangleFromPoint(x, y); + // Apply it + initPreviewCaptureBuilder(); + this.cameraCaptureSession.setRepeatingRequest( + captureRequestBuilder.build(), pictureCaptureCallback, null); + result.success(null); + } + + @TargetApi(VERSION_CODES.P) + private boolean supportsDistortionCorrection() throws CameraAccessException { + int[] availableDistortionCorrectionModes = + cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES); + if (availableDistortionCorrectionModes == null) availableDistortionCorrectionModes = new int[0]; + long nonOffModesSupported = + Arrays.stream(availableDistortionCorrectionModes) + .filter((value) -> value != CaptureRequest.DISTORTION_CORRECTION_MODE_OFF) + .count(); + return nonOffModesSupported > 0; + } + + private Size getRegionBoundaries() throws CameraAccessException { + // No distortion correction support + if (android.os.Build.VERSION.SDK_INT < VERSION_CODES.P || !supportsDistortionCorrection()) { + return cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); + } + // Get the current distortion correction mode + Integer distortionCorrectionMode = + captureRequestBuilder.get(CaptureRequest.DISTORTION_CORRECTION_MODE); + // Return the correct boundaries depending on the mode + android.graphics.Rect rect; + if (distortionCorrectionMode == null + || distortionCorrectionMode == CaptureRequest.DISTORTION_CORRECTION_MODE_OFF) { + rect = + cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); + } else { + rect = + cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); + } + return rect == null ? null : new Size(rect.width(), rect.height()); + } + + private boolean isExposurePointSupported() throws CameraAccessException { + Integer supportedRegions = + cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE); + return supportedRegions != null && supportedRegions > 0; + } + + public double getMinExposureOffset() throws CameraAccessException { + Range range = + cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE); + double minStepped = range == null ? 0 : range.getLower(); + double stepSize = getExposureOffsetStepSize(); + return minStepped * stepSize; + } + + public double getMaxExposureOffset() throws CameraAccessException { + Range range = + cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE); + double maxStepped = range == null ? 0 : range.getUpper(); + double stepSize = getExposureOffsetStepSize(); + return maxStepped * stepSize; + } + + public double getExposureOffsetStepSize() throws CameraAccessException { + Rational stepSize = + cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP); + return stepSize == null ? 0.0 : stepSize.doubleValue(); + } + + public void setExposureOffset(@NonNull final Result result, double offset) + throws CameraAccessException { + // Set the exposure offset + double stepSize = getExposureOffsetStepSize(); + exposureOffset = (int) (offset / stepSize); + // Apply it + initPreviewCaptureBuilder(); + this.cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); + result.success(offset); + } + private void initPreviewCaptureBuilder() { captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); + // Applying flash modes switch (flashMode) { case off: captureRequestBuilder.set( @@ -701,6 +832,22 @@ private void initPreviewCaptureBuilder() { captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); break; } + // Applying auto exposure + MeteringRectangle aeRect = cameraRegions.getAEMeteringRectangle(); + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_REGIONS, + aeRect == null ? null : new MeteringRectangle[] {cameraRegions.getAEMeteringRectangle()}); + switch (exposureMode) { + case locked: + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true); + break; + case auto: + default: + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false); + break; + } + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureOffset); + // Applying auto focus captureRequestBuilder.set( CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java new file mode 100644 index 000000000000..2285f67ad25c --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java @@ -0,0 +1,59 @@ +package io.flutter.plugins.camera; + +import android.hardware.camera2.params.MeteringRectangle; +import android.util.Size; + +public final class CameraRegions { + private MeteringRectangle aeMeteringRectangle; + private Size maxBoundaries; + + public CameraRegions(Size maxBoundaries) { + assert (maxBoundaries == null || maxBoundaries.getWidth() > 0); + assert (maxBoundaries == null || maxBoundaries.getHeight() > 0); + this.maxBoundaries = maxBoundaries; + } + + public MeteringRectangle getAEMeteringRectangle() { + return aeMeteringRectangle; + } + + public Size getMaxBoundaries() { + return this.maxBoundaries; + } + + public void resetAutoExposureMeteringRectangle() { + this.aeMeteringRectangle = null; + } + + public void setAutoExposureMeteringRectangleFromPoint(double x, double y) { + this.aeMeteringRectangle = getMeteringRectangleForPoint(maxBoundaries, x, y); + } + + public MeteringRectangle getMeteringRectangleForPoint(Size maxBoundaries, double x, double y) { + assert (x >= 0 && x <= 1); + assert (y >= 0 && y <= 1); + if (maxBoundaries == null) + throw new IllegalStateException( + "Functionality for managing metering rectangles is unavailable as this CameraRegions instance was initialized with null boundaries."); + + // Interpolate the target coordinate + int targetX = (int) Math.round(x * ((double) (maxBoundaries.getWidth() - 1))); + int targetY = (int) Math.round(y * ((double) (maxBoundaries.getHeight() - 1))); + // Determine the dimensions of the metering triangle (10th of the viewport) + int targetWidth = (int) Math.round(((double) maxBoundaries.getWidth()) / 10d); + int targetHeight = (int) Math.round(((double) maxBoundaries.getHeight()) / 10d); + // Adjust target coordinate to represent top-left corner of metering rectangle + targetX -= targetWidth / 2; + targetY -= targetHeight / 2; + // Adjust target coordinate as to not fall out of bounds + if (targetX < 0) targetX = 0; + if (targetY < 0) targetY = 0; + int maxTargetX = maxBoundaries.getWidth() - 1 - targetWidth; + int maxTargetY = maxBoundaries.getHeight() - 1 - targetHeight; + if (targetX > maxTargetX) targetX = maxTargetX; + if (targetY > maxTargetY) targetY = maxTargetY; + + // Build the metering rectangle + return new MeteringRectangle(targetX, targetY, targetWidth, targetHeight, 1); + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java index 49f9d9a76de0..2fee13816b51 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java @@ -4,6 +4,7 @@ import androidx.annotation.Nullable; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugins.camera.types.ExposureMode; import java.util.HashMap; import java.util.Map; @@ -20,13 +21,23 @@ enum EventType { channel = new MethodChannel(messenger, "flutter.io/cameraPlugin/camera" + cameraId); } - void sendCameraInitializedEvent(Integer previewWidth, Integer previewHeight) { + void sendCameraInitializedEvent( + Integer previewWidth, + Integer previewHeight, + ExposureMode exposureMode, + Boolean exposurePointSupported) { + assert (previewWidth != null); + assert (previewHeight != null); + assert (exposureMode != null); + assert (exposurePointSupported != null); this.send( EventType.INITIALIZED, new HashMap() { { - if (previewWidth != null) put("previewWidth", previewWidth.doubleValue()); - if (previewHeight != null) put("previewHeight", previewHeight.doubleValue()); + put("previewWidth", previewWidth.doubleValue()); + put("previewHeight", previewHeight.doubleValue()); + put("exposureMode", exposureMode.toString()); + put("exposurePointSupported", exposurePointSupported); } }); } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 704504176518..78a10010f90b 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -10,6 +10,7 @@ import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.camera.CameraPermissions.PermissionsRegistry; +import io.flutter.plugins.camera.types.ExposureMode; import io.flutter.plugins.camera.types.FlashMode; import io.flutter.view.TextureRegistry; import java.util.HashMap; @@ -138,6 +139,73 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) } break; } + case "setExposureMode": + { + String modeStr = call.argument("mode"); + ExposureMode mode = ExposureMode.getValueForString(modeStr); + if (mode == null) { + result.error("setExposureModeFailed", "Unknown exposure mode " + modeStr, null); + return; + } + try { + camera.setExposureMode(result, mode); + } catch (Exception e) { + handleException(e, result); + } + break; + } + case "setExposurePoint": + { + Boolean reset = call.argument("reset"); + Double x = null; + Double y = null; + if (reset == null || !reset) { + x = call.argument("x"); + y = call.argument("y"); + } + try { + camera.setExposurePoint(result, x, y); + } catch (Exception e) { + handleException(e, result); + } + break; + } + case "getMinExposureOffset": + { + try { + result.success(camera.getMinExposureOffset()); + } catch (Exception e) { + handleException(e, result); + } + break; + } + case "getMaxExposureOffset": + { + try { + result.success(camera.getMaxExposureOffset()); + } catch (Exception e) { + handleException(e, result); + } + break; + } + case "getExposureOffsetStepSize": + { + try { + result.success(camera.getExposureOffsetStepSize()); + } catch (Exception e) { + handleException(e, result); + } + break; + } + case "setExposureOffset": + { + try { + camera.setExposureOffset(result, call.argument("offset")); + } catch (Exception e) { + handleException(e, result); + } + break; + } case "startImageStream": { try { diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java new file mode 100644 index 000000000000..8066f59d2b14 --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java @@ -0,0 +1,25 @@ +package io.flutter.plugins.camera.types; + +// Mirrors exposure_mode.dart +public enum ExposureMode { + auto("auto"), + locked("locked"); + + private final String strValue; + + ExposureMode(String strValue) { + this.strValue = strValue; + } + + public static ExposureMode getValueForString(String modeStr) { + for (ExposureMode value : values()) { + if (value.strValue.equals(modeStr)) return value; + } + return null; + } + + @Override + public String toString() { + return strValue; + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java index 99d4915b3a6a..ee6fe489511f 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java @@ -2,16 +2,26 @@ // Mirrors flash_mode.dart public enum FlashMode { - off, - auto, - always, - torch; + off("off"), + auto("auto"), + always("always"), + torch("torch"); + + private final String strValue; + + FlashMode(String strValue) { + this.strValue = strValue; + } public static FlashMode getValueForString(String modeStr) { - try { - return valueOf(modeStr); - } catch (IllegalArgumentException | NullPointerException e) { - return null; + for (FlashMode value : values()) { + if (value.strValue.equals(modeStr)) return value; } + return null; + } + + @Override + public String toString() { + return strValue; } } diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java new file mode 100644 index 000000000000..ca66918e2493 --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java @@ -0,0 +1,105 @@ +package io.flutter.plugins.camera; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import android.hardware.camera2.params.MeteringRectangle; +import android.util.Size; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class CameraRegionsTest { + + CameraRegions cameraRegions; + + @Before + public void setUp() { + this.cameraRegions = new CameraRegions(new Size(100, 50)); + } + + @Test(expected = AssertionError.class) + public void getMeteringRectangleForPoint_should_throw_for_x_upper_bound() { + cameraRegions.getMeteringRectangleForPoint(new Size(10, 10), 1.5, 0); + } + + @Test(expected = AssertionError.class) + public void getMeteringRectangleForPoint_should_throw_for_x_lower_bound() { + cameraRegions.getMeteringRectangleForPoint(new Size(10, 10), -0.5, 0); + } + + @Test(expected = AssertionError.class) + public void getMeteringRectangleForPoint_should_throw_for_y_upper_bound() { + cameraRegions.getMeteringRectangleForPoint(new Size(10, 10), 0, 1.5); + } + + @Test(expected = AssertionError.class) + public void getMeteringRectangleForPoint_should_throw_for_y_lower_bound() { + cameraRegions.getMeteringRectangleForPoint(new Size(10, 10), 0, -0.5); + } + + @Test(expected = IllegalStateException.class) + public void getMeteringRectangleForPoint_should_throw_for_null_boundaries() { + cameraRegions.getMeteringRectangleForPoint(null, 0, -0); + } + + @Test + public void getMeteringRectangleForPoint_should_return_valid_MeteringRectangle() { + MeteringRectangle r; + // Center + r = cameraRegions.getMeteringRectangleForPoint(cameraRegions.getMaxBoundaries(), 0.5, 0.5); + assertEquals(new MeteringRectangle(45, 23, 10, 5, 1), r); + + // Top left + r = cameraRegions.getMeteringRectangleForPoint(cameraRegions.getMaxBoundaries(), 0.0, 0.0); + assertEquals(new MeteringRectangle(0, 0, 10, 5, 1), r); + + // Bottom right + r = cameraRegions.getMeteringRectangleForPoint(cameraRegions.getMaxBoundaries(), 1.0, 1.0); + assertEquals(new MeteringRectangle(89, 44, 10, 5, 1), r); + + // Top left + r = cameraRegions.getMeteringRectangleForPoint(cameraRegions.getMaxBoundaries(), 0.0, 1.0); + assertEquals(new MeteringRectangle(0, 44, 10, 5, 1), r); + + // Top right + r = cameraRegions.getMeteringRectangleForPoint(cameraRegions.getMaxBoundaries(), 1.0, 0.0); + assertEquals(new MeteringRectangle(89, 0, 10, 5, 1), r); + } + + @Test(expected = AssertionError.class) + public void constructor_should_throw_for_0_width_boundary() { + new CameraRegions(new Size(0, 50)); + } + + @Test(expected = AssertionError.class) + public void constructor_should_throw_for_0_height_boundary() { + new CameraRegions(new Size(100, 0)); + } + + @Test + public void constructor_should_initialize() { + CameraRegions cr = new CameraRegions(new Size(100, 50)); + assertEquals(new Size(100, 50), cr.getMaxBoundaries()); + assertNull(cr.getAEMeteringRectangle()); + } + + @Test + public void setAutoExposureMeteringRectangleFromPoint_should_set_aeMeteringRectangle_for_point() { + CameraRegions cr = new CameraRegions(new Size(100, 50)); + cr.setAutoExposureMeteringRectangleFromPoint(0, 0); + assertEquals(new MeteringRectangle(0, 0, 10, 5, 1), cr.getAEMeteringRectangle()); + } + + @Test + public void resetAutoExposureMeteringRectangle_should_reset_aeMeteringRectangle() { + CameraRegions cr = new CameraRegions(new Size(100, 50)); + cr.setAutoExposureMeteringRectangleFromPoint(0, 0); + assertNotNull(cr.getAEMeteringRectangle()); + cr.resetAutoExposureMeteringRectangle(); + assertNull(cr.getAEMeteringRectangle()); + } +} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java index a689f2b6128f..f91bf82c7063 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java @@ -7,6 +7,7 @@ import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.StandardMethodCodec; +import io.flutter.plugins.camera.types.ExposureMode; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -58,7 +59,7 @@ public void sendCameraErrorEvent_includesErrorDescriptions() { @Test public void sendCameraInitializedEvent_includesPreviewSize() { - dartMessenger.sendCameraInitializedEvent(0, 0); + dartMessenger.sendCameraInitializedEvent(0, 0, ExposureMode.auto, true); List sentMessages = fakeBinaryMessenger.getMessages(); assertEquals(1, sentMessages.size()); @@ -66,6 +67,8 @@ public void sendCameraInitializedEvent_includesPreviewSize() { assertEquals("initialized", call.method); assertEquals(0, (double) call.argument("previewWidth"), 0); assertEquals(0, (double) call.argument("previewHeight"), 0); + assertEquals("ExposureMode auto", call.argument("exposureMode"), "auto"); + assertEquals("exposurePointSupported", call.argument("exposurePointSupported"), true); } @Test diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java new file mode 100644 index 000000000000..28d2343cedcd --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java @@ -0,0 +1,33 @@ +package io.flutter.plugins.camera.types; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class ExposureModeTest { + + @Test + public void getValueForString_returns_correct_values() { + assertEquals( + "Returns ExposureMode.auto for 'auto'", + ExposureMode.getValueForString("auto"), + ExposureMode.auto); + assertEquals( + "Returns ExposureMode.locked for 'locked'", + ExposureMode.getValueForString("locked"), + ExposureMode.locked); + } + + @Test + public void getValueForString_returns_null_for_nonexistant_value() { + assertEquals( + "Returns null for 'nonexistant'", ExposureMode.getValueForString("nonexistant"), null); + } + + @Test + public void toString_returns_correct_value() { + assertEquals("Returns 'auto' for ExposureMode.auto", ExposureMode.auto.toString(), "auto"); + assertEquals( + "Returns 'locked' for ExposureMode.locked", ExposureMode.locked.toString(), "locked"); + } +} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java index d2674e8c7e06..bba01836545a 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java @@ -27,4 +27,12 @@ public void getValueForString_returns_null_for_nonexistant_value() { assertEquals( "Returns null for 'nonexistant'", FlashMode.getValueForString("nonexistant"), null); } + + @Test + public void toString_returns_correct_value() { + assertEquals("Returns 'off' for FlashMode.off", FlashMode.off.toString(), "off"); + assertEquals("Returns 'auto' for FlashMode.auto", FlashMode.auto.toString(), "auto"); + assertEquals("Returns 'always' for FlashMode.always", FlashMode.always.toString(), "always"); + assertEquals("Returns 'torch' for FlashMode.torch", FlashMode.torch.toString(), "torch"); + } } diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index ee8e2c259b3d..c4fa1c5ed01e 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -35,13 +35,20 @@ void logError(String code, String message) => print('Error: $code\nError Message: $message'); class _CameraExampleHomeState extends State - with WidgetsBindingObserver { + with WidgetsBindingObserver, TickerProviderStateMixin { CameraController controller; XFile imageFile; XFile videoFile; VideoPlayerController videoController; VoidCallback videoPlayerListener; bool enableAudio = true; + double _minAvailableExposureOffset = 0.0; + double _maxAvailableExposureOffset = 0.0; + double _currentExposureOffset = 0.0; + AnimationController _flashModeControlRowAnimationController; + Animation _flashModeControlRowAnimation; + AnimationController _exposureModeControlRowAnimationController; + Animation _exposureModeControlRowAnimation; double _minAvailableZoom; double _maxAvailableZoom; double _currentScale = 1.0; @@ -54,11 +61,29 @@ class _CameraExampleHomeState extends State void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); + _flashModeControlRowAnimationController = AnimationController( + duration: const Duration(milliseconds: 300), + vsync: this, + ); + _flashModeControlRowAnimation = CurvedAnimation( + parent: _flashModeControlRowAnimationController, + curve: Curves.easeInCubic, + ); + _exposureModeControlRowAnimationController = AnimationController( + duration: const Duration(milliseconds: 300), + vsync: this, + ); + _exposureModeControlRowAnimation = CurvedAnimation( + parent: _exposureModeControlRowAnimationController, + curve: Curves.easeInCubic, + ); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); + _flashModeControlRowAnimationController.dispose(); + _exposureModeControlRowAnimationController.dispose(); super.dispose(); } @@ -108,8 +133,7 @@ class _CameraExampleHomeState extends State ), ), _captureControlRowWidget(), - _flashModeRowWidget(), - _toggleAudioWidget(), + _modeControlRowWidget(), Padding( padding: const EdgeInsets.all(5.0), child: Row( @@ -142,11 +166,15 @@ class _CameraExampleHomeState extends State child: Listener( onPointerDown: (_) => _pointers++, onPointerUp: (_) => _pointers--, - child: GestureDetector( - onScaleStart: _handleScaleStart, - onScaleUpdate: _handleScaleUpdate, - child: CameraPreview(controller), - ), + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return GestureDetector( + onScaleStart: _handleScaleStart, + onScaleUpdate: _handleScaleUpdate, + onTapDown: (details) => onViewFinderTap(details, constraints), + child: CameraPreview(controller), + ); + }), ), ); } @@ -168,27 +196,6 @@ class _CameraExampleHomeState extends State await controller.setZoomLevel(_currentScale); } - /// Toggle recording audio - Widget _toggleAudioWidget() { - return Padding( - padding: const EdgeInsets.only(left: 25), - child: Row( - children: [ - const Text('Enable Audio:'), - Switch( - value: enableAudio, - onChanged: (bool value) { - enableAudio = value; - if (controller != null) { - onNewCameraSelected(controller.description); - } - }, - ), - ], - ), - ); - } - /// Display the thumbnail of the captured image or video. Widget _thumbnailWidget() { return Expanded( @@ -223,49 +230,156 @@ class _CameraExampleHomeState extends State ); } - /// Display a bar with buttons to change the flash mode - Widget _flashModeRowWidget() { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - mainAxisSize: MainAxisSize.max, - children: [ - IconButton( - icon: const Icon(Icons.flash_off), - color: controller?.value?.flashMode == FlashMode.off - ? Colors.orange - : Colors.blue, - onPressed: controller != null - ? () => onFlashModeButtonPressed(FlashMode.off) - : null, - ), - IconButton( - icon: const Icon(Icons.flash_auto), - color: controller?.value?.flashMode == FlashMode.auto - ? Colors.orange - : Colors.blue, - onPressed: controller != null - ? () => onFlashModeButtonPressed(FlashMode.auto) - : null, + /// Display a bar with buttons to change the flash and exposure modes + Widget _modeControlRowWidget() { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisSize: MainAxisSize.max, + children: [ + IconButton( + icon: Icon(Icons.flash_on), + color: Colors.blue, + onPressed: controller != null ? onFlashModeButtonPressed : null, + ), + IconButton( + icon: Icon(Icons.exposure), + color: Colors.blue, + onPressed: + controller != null ? onExposureModeButtonPressed : null, + ), + IconButton( + icon: Icon(enableAudio ? Icons.volume_up : Icons.volume_mute), + color: Colors.blue, + onPressed: controller != null ? onAudioModeButtonPressed : null, + ), + ], ), - IconButton( - icon: const Icon(Icons.flash_on), - color: controller?.value?.flashMode == FlashMode.always - ? Colors.orange - : Colors.blue, - onPressed: controller != null - ? () => onFlashModeButtonPressed(FlashMode.always) - : null, + _flashModeControlRowWidget(), + _exposureModeControlRowWidget(), + ], + ); + } + + Widget _flashModeControlRowWidget() { + return SizeTransition( + sizeFactor: _flashModeControlRowAnimation, + child: ClipRect( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisSize: MainAxisSize.max, + children: [ + IconButton( + icon: Icon(Icons.flash_off), + color: controller?.value?.flashMode == FlashMode.off + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => onSetFlashModeButtonPressed(FlashMode.off) + : null, + ), + IconButton( + icon: Icon(Icons.flash_auto), + color: controller?.value?.flashMode == FlashMode.auto + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => onSetFlashModeButtonPressed(FlashMode.auto) + : null, + ), + IconButton( + icon: Icon(Icons.flash_on), + color: controller?.value?.flashMode == FlashMode.always + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => onSetFlashModeButtonPressed(FlashMode.always) + : null, + ), + IconButton( + icon: Icon(Icons.highlight), + color: controller?.value?.flashMode == FlashMode.torch + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => onSetFlashModeButtonPressed(FlashMode.torch) + : null, + ), + ], ), - IconButton( - icon: const Icon(Icons.highlight), - color: controller?.value?.flashMode == FlashMode.torch - ? Colors.orange - : Colors.blue, - onPressed: controller != null - ? () => onFlashModeButtonPressed(FlashMode.torch) - : null, + ), + ); + } + + Widget _exposureModeControlRowWidget() { + return SizeTransition( + sizeFactor: _exposureModeControlRowAnimation, + child: ClipRect( + child: Container( + color: Colors.grey.shade50, + child: Column( + children: [ + Center( + child: Text("Exposure Mode"), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisSize: MainAxisSize.max, + children: [ + FlatButton( + child: Text('AUTO'), + textColor: + controller?.value?.exposureMode == ExposureMode.auto + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => + onSetExposureModeButtonPressed(ExposureMode.auto) + : null, + onLongPress: () { + if (controller != null) controller.setExposurePoint(null); + showInSnackBar('Resetting exposure point'); + }, + ), + FlatButton( + child: Text('LOCKED'), + textColor: + controller?.value?.exposureMode == ExposureMode.locked + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => + onSetExposureModeButtonPressed(ExposureMode.locked) + : null, + ), + ], + ), + Center( + child: Text("Exposure Offset"), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisSize: MainAxisSize.max, + children: [ + Text(_minAvailableExposureOffset.toString()), + Slider( + value: _currentExposureOffset, + min: _minAvailableExposureOffset, + max: _maxAvailableExposureOffset, + label: _currentExposureOffset.toString(), + onChanged: _minAvailableExposureOffset == + _maxAvailableExposureOffset + ? null + : setExposureOffset, + ), + Text(_maxAvailableExposureOffset.toString()), + ], + ), + ], + ), ), - ], + ), ); } @@ -353,6 +467,13 @@ class _CameraExampleHomeState extends State _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message))); } + void onViewFinderTap(TapDownDetails details, BoxConstraints constraints) { + controller.setExposurePoint(Offset( + details.localPosition.dx / constraints.maxWidth, + details.localPosition.dy / constraints.maxHeight, + )); + } + void onNewCameraSelected(CameraDescription cameraDescription) async { if (controller != null) { await controller.dispose(); @@ -373,6 +494,8 @@ class _CameraExampleHomeState extends State try { await controller.initialize(); + _minAvailableExposureOffset = await controller.getMinExposureOffset(); + _maxAvailableExposureOffset = await controller.getMaxExposureOffset(); _maxAvailableZoom = await controller.getMaxZoomLevel(); _minAvailableZoom = await controller.getMinZoomLevel(); } on CameraException catch (e) { @@ -397,13 +520,45 @@ class _CameraExampleHomeState extends State }); } - void onFlashModeButtonPressed(FlashMode mode) { + void onFlashModeButtonPressed() { + if (_flashModeControlRowAnimationController.value == 1) { + _flashModeControlRowAnimationController.reverse(); + } else { + _flashModeControlRowAnimationController.forward(); + _exposureModeControlRowAnimationController.reverse(); + } + } + + void onExposureModeButtonPressed() { + if (_exposureModeControlRowAnimationController.value == 1) { + _exposureModeControlRowAnimationController.reverse(); + } else { + _exposureModeControlRowAnimationController.forward(); + _flashModeControlRowAnimationController.reverse(); + } + } + + void onAudioModeButtonPressed() { + enableAudio = !enableAudio; + if (controller != null) { + onNewCameraSelected(controller.description); + } + } + + void onSetFlashModeButtonPressed(FlashMode mode) { setFlashMode(mode).then((_) { if (mounted) setState(() {}); showInSnackBar('Flash mode set to ${mode.toString().split('.').last}'); }); } + void onSetExposureModeButtonPressed(ExposureMode mode) { + setExposureMode(mode).then((_) { + if (mounted) setState(() {}); + showInSnackBar('Exposure mode set to ${mode.toString().split('.').last}'); + }); + } + void onVideoRecordButtonPressed() { startVideoRecording().then((_) { if (mounted) setState(() {}); @@ -502,6 +657,27 @@ class _CameraExampleHomeState extends State } } + Future setExposureMode(ExposureMode mode) async { + try { + await controller.setExposureMode(mode); + } on CameraException catch (e) { + _showCameraException(e); + rethrow; + } + } + + Future setExposureOffset(double offset) async { + setState(() { + _currentExposureOffset = offset; + }); + try { + offset = await controller.setExposureOffset(offset); + } on CameraException catch (e) { + _showCameraException(e); + rethrow; + } + } + Future _startVideoPlayer() async { final VideoPlayerController vController = VideoPlayerController.file(File(videoFile.path)); diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index d54695233bdb..816792e2fc1d 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -176,6 +176,45 @@ static AVCaptureFlashMode getAVCaptureFlashModeForFlashMode(FlashMode mode) { } } +// Mirrors ExposureMode in camera.dart +typedef enum { + ExposureModeAuto, + ExposureModeLocked, + +} ExposureMode; + +static NSString *getStringForExposureMode(ExposureMode mode) { + switch (mode) { + case ExposureModeAuto: + return @"auto"; + case ExposureModeLocked: + return @"locked"; + } + NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:NSURLErrorUnknown + userInfo:@{ + NSLocalizedDescriptionKey : [NSString + stringWithFormat:@"Unknown string for exposure mode"] + }]; + @throw error; +} + +static ExposureMode getExposureModeForString(NSString *mode) { + if ([mode isEqualToString:@"auto"]) { + return ExposureModeAuto; + } else if ([mode isEqualToString:@"locked"]) { + return ExposureModeLocked; + } else { + NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:NSURLErrorUnknown + userInfo:@{ + NSLocalizedDescriptionKey : [NSString + stringWithFormat:@"Unknown exposure mode %@", mode] + }]; + @throw error; + } +} + // Mirrors ResolutionPreset in camera.dart typedef enum { veryLow, @@ -243,6 +282,7 @@ @interface FLTCam : NSObject *)messenger { if (!_isStreamingImages) { FlutterEventChannel *eventChannel = @@ -1063,7 +1159,10 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re [methodChannel invokeMethod:@"initialized" arguments:@{ @"previewWidth" : @(_camera.previewSize.width), - @"previewHeight" : @(_camera.previewSize.height) + @"previewHeight" : @(_camera.previewSize.height), + @"exposureMode" : getStringForExposureMode([_camera exposureMode]), + @"exposurePointSupported" : + @([_camera.captureDevice isExposurePointOfInterestSupported]), }]; [_camera start]; result(nil); @@ -1098,6 +1197,26 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re [_camera setZoomLevel:zoom Result:result]; } else if ([@"setFlashMode" isEqualToString:call.method]) { [_camera setFlashModeWithResult:result mode:call.arguments[@"mode"]]; + } else if ([@"setExposureMode" isEqualToString:call.method]) { + [_camera setExposureModeWithResult:result mode:call.arguments[@"mode"]]; + } else if ([@"setExposurePoint" isEqualToString:call.method]) { + BOOL reset = ((NSNumber *)call.arguments[@"reset"]).boolValue; + double x = 0.5; + double y = 0.5; + if (!reset) { + x = ((NSNumber *)call.arguments[@"x"]).doubleValue; + y = ((NSNumber *)call.arguments[@"y"]).doubleValue; + } + [_camera setExposurePointWithResult:result x:x y:y]; + } else if ([@"getMinExposureOffset" isEqualToString:call.method]) { + result(@(_camera.captureDevice.minExposureTargetBias)); + } else if ([@"getMaxExposureOffset" isEqualToString:call.method]) { + result(@(_camera.captureDevice.maxExposureTargetBias)); + } else if ([@"getExposureOffsetStepSize" isEqualToString:call.method]) { + result(@(0.0)); + } else if ([@"setExposureOffset" isEqualToString:call.method]) { + [_camera setExposureOffsetWithResult:result + offset:((NSNumber *)call.arguments[@"offset"]).doubleValue]; } else { result(FlutterMethodNotImplemented); } diff --git a/packages/camera/camera/lib/camera.dart b/packages/camera/camera/lib/camera.dart index 6c6214e96951..55e7aa9444aa 100644 --- a/packages/camera/camera/lib/camera.dart +++ b/packages/camera/camera/lib/camera.dart @@ -12,5 +12,6 @@ export 'package:camera_platform_interface/camera_platform_interface.dart' CameraException, CameraLensDirection, FlashMode, + ExposureMode, ResolutionPreset, XFile; diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index 1d7aed755f42..c1f44bc9630a 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -3,12 +3,14 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:math'; import 'package:camera/camera.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:pedantic/pedantic.dart'; final MethodChannel _channel = const MethodChannel('plugins.flutter.io/camera'); @@ -37,6 +39,8 @@ class CameraValue { this.isStreamingImages, bool isRecordingPaused, this.flashMode, + this.exposureMode, + this.exposurePointSupported, }) : _isRecordingPaused = isRecordingPaused; /// Creates a new camera controller state for an uninitialized controller. @@ -48,6 +52,7 @@ class CameraValue { isStreamingImages: false, isRecordingPaused: false, flashMode: FlashMode.auto, + exposurePointSupported: false, ); /// True after [CameraController.initialize] has completed successfully. @@ -91,6 +96,12 @@ class CameraValue { /// The flash mode the camera is currently set to. final FlashMode flashMode; + /// The exposure mode the camera is currently set to. + final ExposureMode exposureMode; + + /// Whether setting the exposure point is supported. + final bool exposurePointSupported; + /// Creates a modified copy of the object. /// /// Explicitly specified fields get the specified value, all other fields get @@ -104,6 +115,8 @@ class CameraValue { Size previewSize, bool isRecordingPaused, FlashMode flashMode, + ExposureMode exposureMode, + bool exposurePointSupported, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -114,6 +127,9 @@ class CameraValue { isStreamingImages: isStreamingImages ?? this.isStreamingImages, isRecordingPaused: isRecordingPaused ?? _isRecordingPaused, flashMode: flashMode ?? this.flashMode, + exposureMode: exposureMode ?? this.exposureMode, + exposurePointSupported: + exposurePointSupported ?? this.exposurePointSupported, ); } @@ -125,7 +141,9 @@ class CameraValue { 'errorDescription: $errorDescription, ' 'previewSize: $previewSize, ' 'isStreamingImages: $isStreamingImages, ' - 'flashMode: $flashMode)'; + 'flashMode: $flashMode, ' + 'exposureMode: $exposureMode, ' + 'exposurePointSupported: $exposurePointSupported)'; } } @@ -184,25 +202,34 @@ class CameraController extends ValueNotifier { ); } try { + Completer _initializeCompleter = Completer(); + _cameraId = await CameraPlatform.instance.createCamera( description, resolutionPreset, enableAudio: enableAudio, ); - final previewSize = - CameraPlatform.instance.onCameraInitialized(_cameraId).map((event) { - return Size( - event.previewWidth, - event.previewHeight, - ); - }).first; + unawaited(CameraPlatform.instance + .onCameraInitialized(_cameraId) + .first + .then((event) { + _initializeCompleter.complete(event); + })); await CameraPlatform.instance.initializeCamera(_cameraId); value = value.copyWith( isInitialized: true, - previewSize: await previewSize, + previewSize: await _initializeCompleter.future + .then((CameraInitializedEvent event) => Size( + event.previewWidth, + event.previewHeight, + )), + exposureMode: await _initializeCompleter.future + .then((event) => event.exposureMode), + exposurePointSupported: await _initializeCompleter.future + .then((event) => event.exposurePointSupported), ); } on PlatformException catch (e) { throw CameraException(e.code, e.message); @@ -532,6 +559,137 @@ class CameraController extends ValueNotifier { } } + /// Sets the exposure mode for taking pictures. + Future setExposureMode(ExposureMode mode) async { + try { + await CameraPlatform.instance.setExposureMode(_cameraId, mode); + value = value.copyWith(exposureMode: mode); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Sets the exposure point for automatically determining the exposure value. + Future setExposurePoint(Offset point) async { + if (point != null && + (point.dx < 0 || point.dx > 1 || point.dy < 0 || point.dy > 1)) { + throw ArgumentError( + 'The values of point should be anywhere between (0,0) and (1,1).'); + } + try { + await CameraPlatform.instance.setExposurePoint( + _cameraId, + point == null + ? null + : Point( + point.dx, + point.dy, + ), + ); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Gets the minimum supported exposure offset for the selected camera in EV units. + Future getMinExposureOffset() async { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'getMinExposureOffset was called on uninitialized CameraController', + ); + } + + try { + return CameraPlatform.instance.getMinExposureOffset(_cameraId); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Gets the maximum supported exposure offset for the selected camera in EV units. + Future getMaxExposureOffset() async { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'getMaxExposureOffset was called on uninitialized CameraController', + ); + } + + try { + return CameraPlatform.instance.getMaxExposureOffset(_cameraId); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Gets the supported step size for exposure offset for the selected camera in EV units. + /// + /// Returns 0 when the camera supports using a free value without stepping. + Future getExposureOffsetStepSize() async { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'getExposureOffsetStepSize was called on uninitialized CameraController', + ); + } + + try { + return CameraPlatform.instance.getExposureOffsetStepSize(_cameraId); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Sets the exposure offset for the selected camera. + /// + /// The supplied [offset] value should be in EV units. 1 EV unit represents a + /// doubling in brightness. It should be between the minimum and maximum offsets + /// obtained through `getMinExposureOffset` and `getMaxExposureOffset` respectively. + /// Throws a `CameraException` when an illegal offset is supplied. + /// + /// When the supplied [offset] value does not align with the step size obtained + /// through `getExposureStepSize`, it will automatically be rounded to the nearest step. + /// + /// Returns the (rounded) offset value that was set. + Future setExposureOffset(double offset) async { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'setExposureOffset was called on uninitialized CameraController', + ); + } + + // Check if offset is in range + List range = + await Future.wait([getMinExposureOffset(), getMaxExposureOffset()]); + if (offset < range[0] || offset > range[1]) { + throw CameraException( + "exposureOffsetOutOfBounds", + "The provided exposure offset was outside the supported range for this device.", + ); + } + + // Round to the closest step if needed + double stepSize = await getExposureOffsetStepSize(); + if (stepSize > 0) { + double inv = 1.0 / stepSize; + double roundedOffset = (offset * inv).roundToDouble() / inv; + if (roundedOffset > range[1]) { + roundedOffset = (offset * inv).floorToDouble() / inv; + } else if (roundedOffset < range[0]) { + roundedOffset = (offset * inv).ceilToDouble() / inv; + } + offset = roundedOffset; + } + + try { + return CameraPlatform.instance.setExposureOffset(_cameraId, offset); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + /// Releases the resources of this camera. @override Future dispose() async { diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index fa40ad03ae89..0811ac442852 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,13 +2,14 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.3+4 +version: 0.6.4 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: flutter: sdk: flutter - camera_platform_interface: ">=1.0.4 <1.1.0" + camera_platform_interface: ^1.2.0 + pedantic: ^1.8.0 dev_dependencies: path_provider: ^0.5.0 @@ -17,7 +18,6 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - pedantic: ^1.8.0 mockito: ^4.1.3 plugin_platform_interface: ^1.0.3 diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 43dec7374901..5a4a7fc8771b 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:math'; import 'dart:ui'; import 'package:camera/camera.dart'; @@ -26,7 +27,8 @@ get mockAvailableCameras => [ get mockInitializeCamera => 13; -get mockOnCameraInitializedEvent => CameraInitializedEvent(13, 75, 75); +get mockOnCameraInitializedEvent => + CameraInitializedEvent(13, 75, 75, ExposureMode.auto, true); get mockOnCameraClosingEvent => null; @@ -603,6 +605,398 @@ void main() { 'This is a test error message', ))); }); + + test('setExposureMode() calls $CameraPlatform', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.setExposureMode(ExposureMode.auto); + + verify(CameraPlatform.instance + .setExposureMode(cameraController.cameraId, ExposureMode.auto)) + .called(1); + }); + + test('setExposureMode() throws $CameraException on $PlatformException', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .setExposureMode(cameraController.cameraId, ExposureMode.auto)) + .thenThrow( + PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error message', + details: null, + ), + ); + + expect( + cameraController.setExposureMode(ExposureMode.auto), + throwsA(isA().having( + (error) => error.description, + 'TEST_ERROR', + 'This is a test error message', + ))); + }); + + test('setExposurePoint() calls $CameraPlatform', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.setExposurePoint(Offset(0.5, 0.5)); + + verify(CameraPlatform.instance.setExposurePoint( + cameraController.cameraId, Point(0.5, 0.5))) + .called(1); + }); + + test('setExposurePoint() throws $CameraException on $PlatformException', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance.setExposurePoint( + cameraController.cameraId, Point(0.5, 0.5))) + .thenThrow( + PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error message', + details: null, + ), + ); + + expect( + cameraController.setExposurePoint(Offset(0.5, 0.5)), + throwsA(isA().having( + (error) => error.description, + 'TEST_ERROR', + 'This is a test error message', + ))); + }); + + test('getMinExposureOffset() calls $CameraPlatform', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.getMinExposureOffset(); + + verify(CameraPlatform.instance + .getMinExposureOffset(cameraController.cameraId)) + .called(1); + }); + + test('getMinExposureOffset() throws $CameraException on $PlatformException', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getMinExposureOffset(cameraController.cameraId)) + .thenThrow( + PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error message', + details: null, + ), + ); + + expect( + cameraController.getMinExposureOffset(), + throwsA(isA().having( + (error) => error.description, + 'TEST_ERROR', + 'This is a test error message', + ))); + }); + + test('getMaxExposureOffset() calls $CameraPlatform', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.getMaxExposureOffset(); + + verify(CameraPlatform.instance + .getMaxExposureOffset(cameraController.cameraId)) + .called(1); + }); + + test('getMaxExposureOffset() throws $CameraException on $PlatformException', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getMaxExposureOffset(cameraController.cameraId)) + .thenThrow( + PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error message', + details: null, + ), + ); + + expect( + cameraController.getMaxExposureOffset(), + throwsA(isA().having( + (error) => error.description, + 'TEST_ERROR', + 'This is a test error message', + ))); + }); + + test('getExposureOffsetStepSize() calls $CameraPlatform', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.getExposureOffsetStepSize(); + + verify(CameraPlatform.instance + .getMinExposureOffset(cameraController.cameraId)) + .called(1); + }); + + test( + 'getExposureOffsetStepSize() throws $CameraException on $PlatformException', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getExposureOffsetStepSize(cameraController.cameraId)) + .thenThrow( + PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error message', + details: null, + ), + ); + + expect( + cameraController.getExposureOffsetStepSize(), + throwsA(isA().having( + (error) => error.description, + 'TEST_ERROR', + 'This is a test error message', + ))); + }); + + test('setExposureOffset() calls $CameraPlatform', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + when(CameraPlatform.instance + .getMinExposureOffset(cameraController.cameraId)) + .thenAnswer((_) async => -1.0); + when(CameraPlatform.instance + .getMaxExposureOffset(cameraController.cameraId)) + .thenAnswer((_) async => 2.0); + when(CameraPlatform.instance + .getExposureOffsetStepSize(cameraController.cameraId)) + .thenAnswer((_) async => 1.0); + + await cameraController.setExposureOffset(1.0); + + verify(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 1.0)) + .called(1); + }); + + test('setExposureOffset() throws $CameraException on $PlatformException', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + when(CameraPlatform.instance + .getMinExposureOffset(cameraController.cameraId)) + .thenAnswer((_) async => -1.0); + when(CameraPlatform.instance + .getMaxExposureOffset(cameraController.cameraId)) + .thenAnswer((_) async => 2.0); + when(CameraPlatform.instance + .getExposureOffsetStepSize(cameraController.cameraId)) + .thenAnswer((_) async => 1.0); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 1.0)) + .thenThrow( + PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error message', + details: null, + ), + ); + + expect( + cameraController.setExposureOffset(1.0), + throwsA(isA().having( + (error) => error.description, + 'TEST_ERROR', + 'This is a test error message', + ))); + }); + + test( + 'setExposureOffset() throws $CameraException when offset is out of bounds', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + when(CameraPlatform.instance + .getMinExposureOffset(cameraController.cameraId)) + .thenAnswer((_) async => -1.0); + when(CameraPlatform.instance + .getMaxExposureOffset(cameraController.cameraId)) + .thenAnswer((_) async => 2.0); + when(CameraPlatform.instance + .getExposureOffsetStepSize(cameraController.cameraId)) + .thenAnswer((_) async => 1.0); + + expect( + cameraController.setExposureOffset(3.0), + throwsA(isA().having( + (error) => error.description, + 'exposureOffsetOutOfBounds', + 'The provided exposure offset was outside the supported range for this device.', + ))); + expect( + cameraController.setExposureOffset(-2.0), + throwsA(isA().having( + (error) => error.description, + 'exposureOffsetOutOfBounds', + 'The provided exposure offset was outside the supported range for this device.', + ))); + + await cameraController.setExposureOffset(2.0); + await cameraController.setExposureOffset(-1.0); + await cameraController.setExposureOffset(-0.0); + verify(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 2.0)) + .called(1); + verify(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, -1.0)) + .called(1); + verify(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 0.0)) + .called(1); + }); + + test('setExposureOffset() rounds offset to nearest step', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + when(CameraPlatform.instance + .getMinExposureOffset(cameraController.cameraId)) + .thenAnswer((_) async => -1.0); + when(CameraPlatform.instance + .getMaxExposureOffset(cameraController.cameraId)) + .thenAnswer((_) async => 1.0); + when(CameraPlatform.instance + .getExposureOffsetStepSize(cameraController.cameraId)) + .thenAnswer((_) async => 0.4); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 1.0)) + .thenAnswer((_) async => 1.0); + + await cameraController.setExposureOffset(1.0); + await cameraController.setExposureOffset(-1.0); + await cameraController.setExposureOffset(0.1); + await cameraController.setExposureOffset(0.2); + await cameraController.setExposureOffset(0.3); + await cameraController.setExposureOffset(0.4); + await cameraController.setExposureOffset(0.5); + await cameraController.setExposureOffset(0.6); + await cameraController.setExposureOffset(0.7); + await cameraController.setExposureOffset(-0.1); + await cameraController.setExposureOffset(-0.2); + await cameraController.setExposureOffset(-0.3); + await cameraController.setExposureOffset(-0.4); + await cameraController.setExposureOffset(-0.5); + await cameraController.setExposureOffset(-0.6); + await cameraController.setExposureOffset(-0.7); + + verify(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 0.8)) + .called(3); + verify(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, -0.8)) + .called(3); + verify(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 0.0)) + .called(2); + verify(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 0.4)) + .called(4); + verify(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, -0.4)) + .called(4); + }); }); } @@ -641,7 +1035,8 @@ class MockCameraPlatform extends Mock : Future.value(mockTakePicture); @override - Future startVideoRecording(int cameraId) => + Future startVideoRecording(int cameraId, + {Duration maxVideoDuration}) => Future.value(mockVideoRecordingXFile); } diff --git a/packages/camera/camera/test/camera_value_test.dart b/packages/camera/camera/test/camera_value_test.dart index 06b327cb1c29..d9193e212ea9 100644 --- a/packages/camera/camera/test/camera_value_test.dart +++ b/packages/camera/camera/test/camera_value_test.dart @@ -13,15 +13,16 @@ void main() { group('camera_value', () { test('Can be created', () { var cameraValue = const CameraValue( - isInitialized: false, - errorDescription: null, - previewSize: Size(10, 10), - isRecordingPaused: false, - isRecordingVideo: false, - isTakingPicture: false, - isStreamingImages: false, - flashMode: FlashMode.auto, - ); + isInitialized: false, + errorDescription: null, + previewSize: Size(10, 10), + isRecordingPaused: false, + isRecordingVideo: false, + isTakingPicture: false, + isStreamingImages: false, + flashMode: FlashMode.auto, + exposureMode: ExposureMode.auto, + exposurePointSupported: true); expect(cameraValue, isA()); expect(cameraValue.isInitialized, isFalse); @@ -31,6 +32,9 @@ void main() { expect(cameraValue.isRecordingVideo, isFalse); expect(cameraValue.isTakingPicture, isFalse); expect(cameraValue.isStreamingImages, isFalse); + expect(cameraValue.flashMode, FlashMode.auto); + expect(cameraValue.exposureMode, ExposureMode.auto); + expect(cameraValue.exposurePointSupported, true); }); test('Can be created as uninitialized', () { @@ -44,6 +48,9 @@ void main() { expect(cameraValue.isRecordingVideo, isFalse); expect(cameraValue.isTakingPicture, isFalse); expect(cameraValue.isStreamingImages, isFalse); + expect(cameraValue.flashMode, FlashMode.auto); + expect(cameraValue.exposureMode, null); + expect(cameraValue.exposurePointSupported, false); }); test('Can be copied with isInitialized', () { @@ -59,6 +66,8 @@ void main() { expect(cameraValue.isTakingPicture, isFalse); expect(cameraValue.isStreamingImages, isFalse); expect(cameraValue.flashMode, FlashMode.auto); + expect(cameraValue.exposureMode, null); + expect(cameraValue.exposurePointSupported, false); }); test('Has aspectRatio after setting size', () { @@ -97,10 +106,11 @@ void main() { isTakingPicture: false, isStreamingImages: false, flashMode: FlashMode.auto, + exposurePointSupported: true, ); expect(cameraValue.toString(), - 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false, flashMode: FlashMode.auto)'); + 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false, flashMode: FlashMode.auto, exposureMode: null, exposurePointSupported: true)'); }); }); } From cfa709835ab85702ee8a9ed24bbe7a3fe736c3f5 Mon Sep 17 00:00:00 2001 From: Anniek Date: Thu, 31 Dec 2020 13:27:56 +0100 Subject: [PATCH 075/924] Added closeCaptureSession() to stopVideoRecording in Camera.java to fix an Android 6 crash (#3336) Co-authored-by: Maurits van Beusekom --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../src/main/java/io/flutter/plugins/camera/Camera.java | 1 + packages/camera/camera/pubspec.yaml | 2 +- .../example/android/gradle/wrapper/gradle-wrapper.properties | 5 +++++ 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 packages/camera/example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index f576ee524ca1..3bb1b0639c97 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.4+1 + +* Added closeCaptureSession() to stopVideoRecording in Camera.java to fix an Android 6 crash + ## 0.6.4 * Adds auto exposure support for Android and iOS implementations. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index d57a737c09f6..a3ae3f275213 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -560,6 +560,7 @@ public void stopVideoRecording(@NonNull final Result result) { try { recordingVideo = false; + closeCaptureSession(); mediaRecorder.stop(); mediaRecorder.reset(); startPreview(); diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 0811ac442852..2b392f17bf82 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.4 +version: 0.6.4+1 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: diff --git a/packages/camera/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/camera/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000000..be52383ef49c --- /dev/null +++ b/packages/camera/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists From 16f37e9a814e3f84927dcc8c3f991b5c7203f1bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Tue, 5 Jan 2021 09:00:53 +0100 Subject: [PATCH 076/924] [camera_platform_interface] Added imageFormatGroup to initialize (#3364) * Added imageFormatGroup to initialize * Apply suggestions from code review Co-authored-by: Maurits van Beusekom * Added period to sentence * Moved ImageFormatGroup to platform_interface; Added extension to convert ImageFormatGroup to name; Changed int to ImageFormatGroup for initializeCamera * Fixed test * Separated Android and iOS in name extension * Clarified returns on name extension * Export image_format_group.dart in types.dart * Changed enum values to lowercase * Added ImageFormatGroup test * Fixed formatting * Removed target platform switch. * Fixed formatting Co-authored-by: Maurits van Beusekom --- .../camera_platform_interface/CHANGELOG.md | 4 ++ .../method_channel/method_channel_camera.dart | 5 +- .../platform_interface/camera_platform.dart | 8 ++- .../lib/src/types/image_format_group.dart | 50 +++++++++++++++++++ .../lib/src/types/types.dart | 1 + .../camera_platform_interface/pubspec.yaml | 4 +- .../method_channel_camera_test.dart | 11 +++- .../test/types/image_group_test.dart | 13 +++++ 8 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart create mode 100644 packages/camera/camera_platform_interface/test/types/image_group_test.dart diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index 8e316054f2b1..d264d6c6f9ce 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.3.0 + +- Introduces an option to set the image format when initializing. + ## 1.2.0 - Added interface to support automatic exposure. diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index 6a73031111df..0ccc59939610 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:math'; import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/types/image_format_group.dart'; import 'package:camera_platform_interface/src/utils/utils.dart'; import 'package:cross_file/cross_file.dart'; import 'package:flutter/services.dart'; @@ -76,7 +77,8 @@ class MethodChannelCamera extends CameraPlatform { } @override - Future initializeCamera(int cameraId) { + Future initializeCamera(int cameraId, + {ImageFormatGroup imageFormatGroup}) { _channels.putIfAbsent(cameraId, () { final channel = MethodChannel('flutter.io/cameraPlugin/camera$cameraId'); channel.setMethodCallHandler( @@ -94,6 +96,7 @@ class MethodChannelCamera extends CameraPlatform { 'initialize', { 'cameraId': cameraId, + 'imageFormatGroup': imageFormatGroup.name(), }, ); diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index c7a603228ce2..d95d957e4862 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -8,6 +8,7 @@ import 'dart:math'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; import 'package:camera_platform_interface/src/types/exposure_mode.dart'; +import 'package:camera_platform_interface/src/types/image_format_group.dart'; import 'package:cross_file/cross_file.dart'; import 'package:flutter/widgets.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -54,7 +55,12 @@ abstract class CameraPlatform extends PlatformInterface { } /// Initializes the camera on the device. - Future initializeCamera(int cameraId) { + /// + /// [imageFormatGroup] is used to specify the image formatting used. + /// On Android this defaults to ImageFormat.YUV_420_888 and applies only to the imageStream. + /// On iOS this defaults to kCVPixelFormatType_32BGRA. + Future initializeCamera(int cameraId, + {ImageFormatGroup imageFormatGroup}) { throw UnimplementedError('initializeCamera() is not implemented.'); } diff --git a/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart b/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart new file mode 100644 index 000000000000..3d2c0180fe65 --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart @@ -0,0 +1,50 @@ +/// Group of image formats that are comparable across Android and iOS platforms. +enum ImageFormatGroup { + /// The image format does not fit into any specific group. + unknown, + + /// Multi-plane YUV 420 format. + /// + /// This format is a generic YCbCr format, capable of describing any 4:2:0 + /// chroma-subsampled planar or semiplanar buffer (but not fully interleaved), + /// with 8 bits per color sample. + /// + /// On Android, this is `android.graphics.ImageFormat.YUV_420_888`. See + /// https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888 + /// + /// On iOS, this is `kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange`. See + /// https://developer.apple.com/documentation/corevideo/1563591-pixel_format_identifiers/kcvpixelformattype_420ypcbcr8biplanarvideorange?language=objc + yuv420, + + /// 32-bit BGRA. + /// + /// On iOS, this is `kCVPixelFormatType_32BGRA`. See + /// https://developer.apple.com/documentation/corevideo/1563591-pixel_format_identifiers/kcvpixelformattype_32bgra?language=objc + bgra8888, + + /// 32-big RGB image encoded into JPEG bytes. + /// + /// On Android, this is `android.graphics.ImageFormat.JPEG`. See + /// https://developer.android.com/reference/android/graphics/ImageFormat#JPEG + jpeg, +} + +/// Extension on [ImageFormatGroup] to stringify the enum +extension ImageFormatGroupName on ImageFormatGroup { + /// returns a String value for [ImageFormatGroup] + /// returns 'unknown' if platform is not supported + /// or if [ImageFormatGroup] is not supported for the platform + String name() { + switch (this) { + case ImageFormatGroup.bgra8888: + return 'bgra8888'; + case ImageFormatGroup.yuv420: + return 'yuv420'; + case ImageFormatGroup.jpeg: + return 'jpeg'; + case ImageFormatGroup.unknown: + default: + return 'unknown'; + } + } +} diff --git a/packages/camera/camera_platform_interface/lib/src/types/types.dart b/packages/camera/camera_platform_interface/lib/src/types/types.dart index bab430eb5a69..eaadc5c14061 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/types.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/types.dart @@ -6,4 +6,5 @@ export 'camera_description.dart'; export 'resolution_preset.dart'; export 'camera_exception.dart'; export 'flash_mode.dart'; +export 'image_format_group.dart'; export 'exposure_mode.dart'; diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index b8301d289cc6..7a4fa49ce052 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.2.0 +version: 1.3.0 dependencies: flutter: @@ -21,5 +21,5 @@ dev_dependencies: pedantic: ^1.8.0 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.7.0 <3.0.0" flutter: ">=1.22.0" diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index b916513ef0de..e8136fb051ad 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -25,7 +25,10 @@ void main() { MethodChannelMock cameraMockChannel = MethodChannelMock( channelName: 'plugins.flutter.io/camera', methods: { - 'create': {'cameraId': 1} + 'create': { + 'cameraId': 1, + 'imageFormatGroup': 'unknown', + } }); final camera = MethodChannelCamera(); @@ -108,7 +111,10 @@ void main() { MethodChannelMock cameraMockChannel = MethodChannelMock( channelName: 'plugins.flutter.io/camera', methods: { - 'create': {'cameraId': 1}, + 'create': { + 'cameraId': 1, + 'imageFormatGroup': 'unknown', + }, 'initialize': null }); final camera = MethodChannelCamera(); @@ -136,6 +142,7 @@ void main() { 'initialize', arguments: { 'cameraId': 1, + 'imageFormatGroup': 'unknown', }, ), ]); diff --git a/packages/camera/camera_platform_interface/test/types/image_group_test.dart b/packages/camera/camera_platform_interface/test/types/image_group_test.dart new file mode 100644 index 000000000000..c49b2f03a7a0 --- /dev/null +++ b/packages/camera/camera_platform_interface/test/types/image_group_test.dart @@ -0,0 +1,13 @@ +import 'package:camera_platform_interface/src/types/types.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('$ImageFormatGroup tests', () { + test('ImageFormatGroupName extension returns correct values', () { + expect(ImageFormatGroup.bgra8888.name(), 'bgra8888'); + expect(ImageFormatGroup.yuv420.name(), 'yuv420'); + expect(ImageFormatGroup.jpeg.name(), 'jpeg'); + expect(ImageFormatGroup.unknown.name(), 'unknown'); + }); + }); +} From 03941830fea4281ef90c878e99073da323bbed4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Tue, 5 Jan 2021 11:46:06 +0100 Subject: [PATCH 077/924] [camera] Fixed stale images in imageStream subscriptions (#3344) * Fixed stale images in imageStream subscriptions * Implemented feedback * Fixed format exception * added null-check for imageStreamReader * Removed setOnImageAvailableListener from onCancel * fixed formatting --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../src/main/java/io/flutter/plugins/camera/Camera.java | 7 +++++++ .../io/flutter/plugins/camera/MethodCallHandlerImpl.java | 2 +- packages/camera/camera/pubspec.yaml | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 3bb1b0639c97..d38016a471e6 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.4+2 + +* Set ImageStreamReader listener to null to prevent stale images when streaming images. + ## 0.6.4+1 * Added closeCaptureSession() to stopVideoRecording in Camera.java to fix an Android 6 crash diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index a3ae3f275213..b7da94a613ba 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -943,6 +943,13 @@ public void setZoomLevel(@NonNull final Result result, float zoom) throws Camera result.success(null); } + public void stopImageStream() throws CameraAccessException { + if (imageStreamReader != null) { + imageStreamReader.setOnImageAvailableListener(null, null); + } + startPreview(); + } + private void closeCaptureSession() { if (cameraCaptureSession != null) { cameraCaptureSession.close(); diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 78a10010f90b..2ceff845ed4b 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -219,7 +219,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) case "stopImageStream": { try { - camera.startPreview(); + camera.stopImageStream(); result.success(null); } catch (Exception e) { handleException(e, result); diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 2b392f17bf82..02f874bf9ea3 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.4+1 +version: 0.6.4+2 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From b64bebff9743589a75d31b613b0d0af9040604df Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 5 Jan 2021 20:13:44 +0100 Subject: [PATCH 078/924] [camera] disable auto focus when using front facing camera on Android (#3383) * Refactured Camera and fix issue front facing camera * Update FPS range on Android to have correct brightness * Formatted files * Fix version conflict --- packages/camera/camera/CHANGELOG.md | 4 + .../io/flutter/plugins/camera/Camera.java | 480 ++++++++++-------- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 286 insertions(+), 200 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index d38016a471e6..55c7eb1fcfd2 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.4+3 + +* Detect if selected camera supports auto focus and act accordingly on Android. This solves a problem where front facing cameras are not capturing the picture because auto focus is not supported. + ## 0.6.4+2 * Set ImageStreamReader listener to null to prevent stale images when streaming images. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index b7da94a613ba..2db097ceadf7 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -33,12 +33,14 @@ import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.Looper; +import android.util.Log; import android.util.Range; import android.util.Rational; import android.util.Size; import android.view.OrientationEventListener; import android.view.Surface; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.camera.PictureCaptureRequest.State; @@ -59,6 +61,11 @@ import java.util.Map; import java.util.concurrent.Executors; +@FunctionalInterface +interface ErrorCallback { + void onError(String errorCode, String errorMessage); +} + public class Camera { private final SurfaceTextureEntry flutterTexture; private final CameraManager cameraManager; @@ -73,6 +80,7 @@ public class Camera { private final CamcorderProfile recordingProfile; private final DartMessenger dartMessenger; private final CameraZoom cameraZoom; + private final CameraCharacteristics cameraCharacteristics; private CameraDevice cameraDevice; private CameraCaptureSession cameraCaptureSession; @@ -88,6 +96,8 @@ public class Camera { private PictureCaptureRequest pictureCaptureRequest; private CameraRegions cameraRegions; private int exposureOffset; + private boolean useAutoFocus; + private Range fpsRange; public Camera( final Activity activity, @@ -122,10 +132,12 @@ public void onOrientationChanged(int i) { }; orientationEventListener.enable(); - CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraName); - sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); + cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraName); + initFps(cameraCharacteristics); + sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); isFrontFacing = - characteristics.get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_FRONT; + cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) + == CameraMetadata.LENS_FACING_FRONT; ResolutionPreset preset = ResolutionPreset.valueOf(resolutionPreset); recordingProfile = CameraUtils.getBestAvailableCamcorderProfileForResolutionPreset(cameraName, preset); @@ -133,8 +145,29 @@ public void onOrientationChanged(int i) { previewSize = computeBestPreviewSize(cameraName, preset); cameraZoom = new CameraZoom( - characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE), - characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)); + cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE), + cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)); + } + + private void initFps(CameraCharacteristics cameraCharacteristics) { + try { + Range[] ranges = + cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); + if (ranges != null) { + for (Range range : ranges) { + int upper = range.getUpper(); + Log.i("Camera", "[FPS Range Available] is:" + range); + if (upper >= 10) { + if (fpsRange == null || upper < fpsRange.getUpper()) { + fpsRange = range; + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + Log.i("Camera", "[FPS Range] is:" + fpsRange); } private void prepareMediaRecorder(String outputFilePath) throws IOException { @@ -221,6 +254,118 @@ public void onError(@NonNull CameraDevice cameraDevice, int errorCode) { null); } + private void createCaptureSession(int templateType, Surface... surfaces) + throws CameraAccessException { + createCaptureSession(templateType, null, surfaces); + } + + private void createCaptureSession( + int templateType, Runnable onSuccessCallback, Surface... surfaces) + throws CameraAccessException { + // Close any existing capture session. + closeCaptureSession(); + + // Create a new capture builder. + captureRequestBuilder = cameraDevice.createCaptureRequest(templateType); + + // Build Flutter surface to render to + SurfaceTexture surfaceTexture = flutterTexture.surfaceTexture(); + surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); + Surface flutterSurface = new Surface(surfaceTexture); + captureRequestBuilder.addTarget(flutterSurface); + + List remainingSurfaces = Arrays.asList(surfaces); + if (templateType != CameraDevice.TEMPLATE_PREVIEW) { + // If it is not preview mode, add all surfaces as targets. + for (Surface surface : remainingSurfaces) { + captureRequestBuilder.addTarget(surface); + } + } + + // Prepare the callback + CameraCaptureSession.StateCallback callback = + new CameraCaptureSession.StateCallback() { + @Override + public void onConfigured(@NonNull CameraCaptureSession session) { + if (cameraDevice == null) { + dartMessenger.sendCameraErrorEvent("The camera was closed during configuration."); + return; + } + cameraCaptureSession = session; + + updateFpsRange(); + updateAutoFocus(); + updateFlash(flashMode); + updateExposure(exposureMode); + + refreshPreviewCaptureSession( + onSuccessCallback, (code, message) -> dartMessenger.sendCameraErrorEvent(message)); + } + + @Override + public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { + dartMessenger.sendCameraErrorEvent("Failed to configure camera session."); + } + }; + + // Start the session + if (VERSION.SDK_INT >= VERSION_CODES.P) { + // Collect all surfaces we want to render to. + List configs = new ArrayList<>(); + configs.add(new OutputConfiguration(flutterSurface)); + for (Surface surface : remainingSurfaces) { + configs.add(new OutputConfiguration(surface)); + } + createCaptureSessionWithSessionConfig(configs, callback); + } else { + // Collect all surfaces we want to render to. + List surfaceList = new ArrayList<>(); + surfaceList.add(flutterSurface); + surfaceList.addAll(remainingSurfaces); + createCaptureSession(surfaceList, callback); + } + } + + @TargetApi(VERSION_CODES.P) + private void createCaptureSessionWithSessionConfig( + List outputConfigs, CameraCaptureSession.StateCallback callback) + throws CameraAccessException { + cameraDevice.createCaptureSession( + new SessionConfiguration( + SessionConfiguration.SESSION_REGULAR, + outputConfigs, + Executors.newSingleThreadExecutor(), + callback)); + } + + @TargetApi(VERSION_CODES.LOLLIPOP) + @SuppressWarnings("deprecation") + private void createCaptureSession( + List surfaces, CameraCaptureSession.StateCallback callback) + throws CameraAccessException { + cameraDevice.createCaptureSession(surfaces, callback, null); + } + + private void refreshPreviewCaptureSession( + @Nullable Runnable onSuccessCallback, @NonNull ErrorCallback onErrorCallback) { + if (cameraCaptureSession == null) { + return; + } + + try { + cameraCaptureSession.setRepeatingRequest( + captureRequestBuilder.build(), + pictureCaptureCallback, + new Handler(Looper.getMainLooper())); + + if (onSuccessCallback != null) { + onSuccessCallback.run(); + } + } catch (CameraAccessException | IllegalStateException | IllegalArgumentException e) { + onErrorCallback.onError("cameraAccess", e.getMessage()); + } + } + private void writeToFile(ByteBuffer buffer, File file) throws IOException { try (FileOutputStream outputStream = new FileOutputStream(file)) { while (0 < buffer.remaining()) { @@ -261,7 +406,11 @@ public void takePicture(@NonNull final Result result) { }, null); - runPictureAutoFocus(); + if (useAutoFocus) { + runPictureAutoFocus(); + } else { + runPicturePreCapture(); + } } private final CameraCaptureSession.CaptureCallback pictureCaptureCallback = @@ -344,6 +493,7 @@ private void processCapture(CaptureResult result) { private void runPictureAutoFocus() { assert (pictureCaptureRequest != null); + pictureCaptureRequest.setState(PictureCaptureRequest.State.focusing); lockAutoFocus(); } @@ -355,14 +505,13 @@ private void runPicturePreCapture() { captureRequestBuilder.set( CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); - try { - cameraCaptureSession.capture(captureRequestBuilder.build(), pictureCaptureCallback, null); - captureRequestBuilder.set( - CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, - CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); - } catch (CameraAccessException e) { - pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); - } + + refreshPreviewCaptureSession( + () -> + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE), + (code, message) -> pictureCaptureRequest.error(code, message, null)); } private void runPictureCapture() { @@ -409,125 +558,25 @@ public void onCaptureCompleted( private void lockAutoFocus() { captureRequestBuilder.set( CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); - try { - cameraCaptureSession.capture(captureRequestBuilder.build(), pictureCaptureCallback, null); - } catch (CameraAccessException e) { - pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); - } + + refreshPreviewCaptureSession( + null, (code, message) -> pictureCaptureRequest.error(code, message, null)); } private void unlockAutoFocus() { captureRequestBuilder.set( CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL); - initPreviewCaptureBuilder(); + updateAutoFocus(); try { cameraCaptureSession.capture(captureRequestBuilder.build(), null, null); } catch (CameraAccessException ignored) { } captureRequestBuilder.set( CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE); - try { - cameraCaptureSession.setRepeatingRequest( - captureRequestBuilder.build(), pictureCaptureCallback, null); - } catch (CameraAccessException e) { - pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); - } - } - private void createCaptureSession(int templateType, Surface... surfaces) - throws CameraAccessException { - createCaptureSession(templateType, null, surfaces); - } - - private void createCaptureSession( - int templateType, Runnable onSuccessCallback, Surface... surfaces) - throws CameraAccessException { - // Close any existing capture session. - closeCaptureSession(); - - // Create a new capture builder. - captureRequestBuilder = cameraDevice.createCaptureRequest(templateType); - - // Build Flutter surface to render to - SurfaceTexture surfaceTexture = flutterTexture.surfaceTexture(); - surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); - Surface flutterSurface = new Surface(surfaceTexture); - captureRequestBuilder.addTarget(flutterSurface); - - List remainingSurfaces = Arrays.asList(surfaces); - if (templateType != CameraDevice.TEMPLATE_PREVIEW) { - // If it is not preview mode, add all surfaces as targets. - for (Surface surface : remainingSurfaces) { - captureRequestBuilder.addTarget(surface); - } - } - - // Prepare the callback - CameraCaptureSession.StateCallback callback = - new CameraCaptureSession.StateCallback() { - @Override - public void onConfigured(@NonNull CameraCaptureSession session) { - try { - if (cameraDevice == null) { - dartMessenger.sendCameraErrorEvent("The camera was closed during configuration."); - return; - } - cameraCaptureSession = session; - initPreviewCaptureBuilder(); - cameraCaptureSession.setRepeatingRequest( - captureRequestBuilder.build(), - pictureCaptureCallback, - new Handler(Looper.getMainLooper())); - if (onSuccessCallback != null) { - onSuccessCallback.run(); - } - } catch (CameraAccessException | IllegalStateException | IllegalArgumentException e) { - dartMessenger.sendCameraErrorEvent(e.getMessage()); - } - } - - @Override - public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { - dartMessenger.sendCameraErrorEvent("Failed to configure camera session."); - } - }; - - // Start the session - if (VERSION.SDK_INT >= VERSION_CODES.P) { - // Collect all surfaces we want to render to. - List configs = new ArrayList<>(); - configs.add(new OutputConfiguration(flutterSurface)); - for (Surface surface : remainingSurfaces) { - configs.add(new OutputConfiguration(surface)); - } - createCaptureSessionWithSessionConfig(configs, callback); - } else { - // Collect all surfaces we want to render to. - List surfaceList = new ArrayList<>(); - surfaceList.add(flutterSurface); - surfaceList.addAll(remainingSurfaces); - createCaptureSession(surfaceList, callback); - } - } - - @TargetApi(VERSION_CODES.P) - private void createCaptureSessionWithSessionConfig( - List outputConfigs, CameraCaptureSession.StateCallback callback) - throws CameraAccessException { - cameraDevice.createCaptureSession( - new SessionConfiguration( - SessionConfiguration.SESSION_REGULAR, - outputConfigs, - Executors.newSingleThreadExecutor(), - callback)); - } - - @TargetApi(VERSION_CODES.LOLLIPOP) - @SuppressWarnings("deprecation") - private void createCaptureSession( - List surfaces, CameraCaptureSession.StateCallback callback) - throws CameraAccessException { - cameraDevice.createCaptureSession(surfaces, callback, null); + refreshPreviewCaptureSession( + null, + (errorCode, errorMessage) -> pictureCaptureRequest.error(errorCode, errorMessage, null)); } public void startVideoRecording(Result result) { @@ -560,8 +609,14 @@ public void stopVideoRecording(@NonNull final Result result) { try { recordingVideo = false; - closeCaptureSession(); - mediaRecorder.stop(); + + try { + cameraCaptureSession.abortCaptures(); + mediaRecorder.stop(); + } catch (CameraAccessException | IllegalStateException e) { + // Ignore exceptions and try to continue (changes are camera session already aborted capture) + } + mediaRecorder.reset(); startPreview(); result.success(videoRecordingFile.getAbsolutePath()); @@ -630,8 +685,8 @@ public void setFlashMode(@NonNull final Result result, FlashMode mode) // If switching directly from torch to auto or on, make sure we turn off the torch. if (flashMode == FlashMode.torch && mode != FlashMode.torch && mode != FlashMode.off) { - this.flashMode = FlashMode.off; - initPreviewCaptureBuilder(); + updateFlash(FlashMode.off); + this.cameraCaptureSession.setRepeatingRequest( captureRequestBuilder.build(), new CaptureCallback() { @@ -647,8 +702,13 @@ public void onCaptureCompleted( } updateFlash(mode); - result.success(null); - isFinished = true; + refreshPreviewCaptureSession( + () -> { + result.success(null); + isFinished = true; + }, + (code, message) -> + result.error("setFlashModeFailed", "Could not set flash mode.", null)); } @Override @@ -667,26 +727,16 @@ public void onCaptureFailed( null); } else { updateFlash(mode); - result.success(null); - } - } - private void updateFlash(FlashMode mode) { - // Get flash - flashMode = mode; - initPreviewCaptureBuilder(); - try { - cameraCaptureSession.setRepeatingRequest( - captureRequestBuilder.build(), pictureCaptureCallback, null); - } catch (CameraAccessException e) { - pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); + refreshPreviewCaptureSession( + () -> result.success(null), + (code, message) -> result.error("setFlashModeFailed", "Could not set flash mode.", null)); } } public void setExposureMode(@NonNull final Result result, ExposureMode mode) throws CameraAccessException { - this.exposureMode = mode; - initPreviewCaptureBuilder(); + updateExposure(mode); cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); result.success(null); } @@ -713,10 +763,9 @@ public void setExposurePoint(@NonNull final Result result, Double x, Double y) // Set the metering rectangle cameraRegions.setAutoExposureMeteringRectangleFromPoint(x, y); // Apply it - initPreviewCaptureBuilder(); - this.cameraCaptureSession.setRepeatingRequest( - captureRequestBuilder.build(), pictureCaptureCallback, null); - result.success(null); + updateExposure(exposureMode); + refreshPreviewCaptureSession( + () -> result.success(null), (code, message) -> result.error("CameraAccess", message, null)); } @TargetApi(VERSION_CODES.P) @@ -802,13 +851,97 @@ public void setExposureOffset(@NonNull final Result result, double offset) double stepSize = getExposureOffsetStepSize(); exposureOffset = (int) (offset / stepSize); // Apply it - initPreviewCaptureBuilder(); + updateExposure(exposureMode); this.cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); result.success(offset); } - private void initPreviewCaptureBuilder() { - captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); + public float getMaxZoomLevel() { + return cameraZoom.maxZoom; + } + + public float getMinZoomLevel() { + return CameraZoom.DEFAULT_ZOOM_FACTOR; + } + + public void setZoomLevel(@NonNull final Result result, float zoom) throws CameraAccessException { + float maxZoom = cameraZoom.maxZoom; + float minZoom = CameraZoom.DEFAULT_ZOOM_FACTOR; + + if (zoom > maxZoom || zoom < minZoom) { + String errorMessage = + String.format( + Locale.ENGLISH, + "Zoom level out of bounds (zoom level should be between %f and %f).", + minZoom, + maxZoom); + result.error("ZOOM_ERROR", errorMessage, null); + return; + } + + //Zoom area is calculated relative to sensor area (activeRect) + if (captureRequestBuilder != null) { + final Rect computedZoom = cameraZoom.computeZoom(zoom); + captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom); + cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); + } + + result.success(null); + } + + private void updateFpsRange() { + if (fpsRange == null) { + return; + } + + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange); + } + + private void updateAutoFocus() { + if (useAutoFocus) { + int[] modes = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); + // Auto focus is not supported + if (modes == null + || modes.length == 0 + || (modes.length == 1 && modes[0] == CameraCharacteristics.CONTROL_AF_MODE_OFF)) { + useAutoFocus = false; + captureRequestBuilder.set( + CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); + } else { + captureRequestBuilder.set( + CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + } + } else { + captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); + } + } + + private void updateExposure(ExposureMode mode) { + exposureMode = mode; + + // Applying auto exposure + MeteringRectangle aeRect = cameraRegions.getAEMeteringRectangle(); + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_REGIONS, + aeRect == null ? null : new MeteringRectangle[] {cameraRegions.getAEMeteringRectangle()}); + + switch (mode) { + case locked: + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true); + break; + case auto: + default: + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false); + break; + } + + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureOffset); + } + + private void updateFlash(FlashMode mode) { + // Get flash + flashMode = mode; + // Applying flash modes switch (flashMode) { case off: @@ -833,24 +966,6 @@ private void initPreviewCaptureBuilder() { captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); break; } - // Applying auto exposure - MeteringRectangle aeRect = cameraRegions.getAEMeteringRectangle(); - captureRequestBuilder.set( - CaptureRequest.CONTROL_AE_REGIONS, - aeRect == null ? null : new MeteringRectangle[] {cameraRegions.getAEMeteringRectangle()}); - switch (exposureMode) { - case locked: - captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true); - break; - case auto: - default: - captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false); - break; - } - captureRequestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureOffset); - // Applying auto focus - captureRequestBuilder.set( - CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); } public void startPreview() throws CameraAccessException { @@ -910,39 +1025,6 @@ private void setImageStreamImageAvailableListener(final EventChannel.EventSink i null); } - public float getMaxZoomLevel() { - return cameraZoom.maxZoom; - } - - public float getMinZoomLevel() { - return CameraZoom.DEFAULT_ZOOM_FACTOR; - } - - public void setZoomLevel(@NonNull final Result result, float zoom) throws CameraAccessException { - float maxZoom = cameraZoom.maxZoom; - float minZoom = CameraZoom.DEFAULT_ZOOM_FACTOR; - - if (zoom > maxZoom || zoom < minZoom) { - String errorMessage = - String.format( - Locale.ENGLISH, - "Zoom level out of bounds (zoom level should be between %f and %f).", - minZoom, - maxZoom); - result.error("ZOOM_ERROR", errorMessage, null); - return; - } - - //Zoom area is calculated relative to sensor area (activeRect) - if (captureRequestBuilder != null) { - final Rect computedZoom = cameraZoom.computeZoom(zoom); - captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom); - cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); - } - - result.success(null); - } - public void stopImageStream() throws CameraAccessException { if (imageStreamReader != null) { imageStreamReader.setOnImageAvailableListener(null, null); diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 02f874bf9ea3..99f41fb165a5 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.4+2 +version: 0.6.4+3 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From dac4b6f3c692cc4aabe0e0430106e6ec2c061afe Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Wed, 6 Jan 2021 23:48:03 +0100 Subject: [PATCH 079/924] [camera_platform_interface] Add platform interface methods for setting auto focus. (#3369) * Added platform interface methods for setting auto exposure. * Added platform interface methods for setting auto exposure. * Remove workspace files * Added auto exposure implementations for Android and iOS * Added platform interface methods for managing auto focus. * Formatted code * Export focus mode * Update platform interface for changes to autofocus methods * Revert "Update platform interface for changes to autofocus methods" This reverts commit bdeed1d213a9f106d0bd80b8905c0ae3af29886e. * iOS fix for setting the exposure point * Removed unnecessary check * Updated changelog and pubspec.yaml * Update platform interface dependency * Implement PR feedback * Restore test * Revert test change * Update camera pubspec * Update platform interface to prevent breaking changes with current master Co-authored-by: Maurits van Beusekom --- .../camera_platform_interface/CHANGELOG.md | 4 + .../lib/src/events/camera_event.dart | 30 ++++-- .../method_channel/method_channel_camera.dart | 28 ++++++ .../platform_interface/camera_platform.dart | 13 ++- .../lib/src/types/exposure_mode.dart | 2 + .../lib/src/types/focus_mode.dart | 38 +++++++ .../lib/src/types/types.dart | 1 + .../camera_platform_interface/pubspec.yaml | 2 +- .../test/camera_platform_interface_test.dart | 26 +++++ .../test/events/camera_event_test.dart | 99 ++++++++++++------- .../method_channel_camera_test.dart | 59 +++++++++++ .../test/types/focus_mode_test.dart | 31 ++++++ 12 files changed, 291 insertions(+), 42 deletions(-) create mode 100644 packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart create mode 100644 packages/camera/camera_platform_interface/test/types/focus_mode_test.dart diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index d264d6c6f9ce..ae22f8a5f6a4 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.4.0 + +- Added interface methods to support auto focus. + ## 1.3.0 - Introduces an option to set the image format when initializing. diff --git a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart index 590713d04e8b..8ca445a2e06e 100644 --- a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart +++ b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:camera_platform_interface/src/types/focus_mode.dart'; + import '../../camera_platform_interface.dart'; /// Generic Event coming from the native side of Camera. @@ -50,9 +52,15 @@ class CameraInitializedEvent extends CameraEvent { /// The default exposure mode final ExposureMode exposureMode; + /// The default focus mode + final FocusMode focusMode; + /// Whether setting exposure points is supported. final bool exposurePointSupported; + /// Whether setting focus points is supported. + final bool focusPointSupported; + /// Build a CameraInitialized event triggered from the camera represented by /// `cameraId`. /// @@ -61,10 +69,12 @@ class CameraInitializedEvent extends CameraEvent { CameraInitializedEvent( int cameraId, this.previewWidth, - this.previewHeight, + this.previewHeight, [ this.exposureMode, - this.exposurePointSupported, - ) : super(cameraId); + this.exposurePointSupported = false, + this.focusMode, + this.focusPointSupported = false, + ]) : super(cameraId); /// Converts the supplied [Map] to an instance of the [CameraInitializedEvent] /// class. @@ -72,7 +82,9 @@ class CameraInitializedEvent extends CameraEvent { : previewWidth = json['previewWidth'], previewHeight = json['previewHeight'], exposureMode = deserializeExposureMode(json['exposureMode']), - exposurePointSupported = json['exposurePointSupported'], + exposurePointSupported = json['exposurePointSupported'] ?? false, + focusMode = deserializeFocusMode(json['focusMode']), + focusPointSupported = json['focusPointSupported'] ?? false, super(json['cameraId']); /// Converts the [CameraInitializedEvent] instance into a [Map] instance that @@ -83,6 +95,8 @@ class CameraInitializedEvent extends CameraEvent { 'previewHeight': previewHeight, 'exposureMode': serializeExposureMode(exposureMode), 'exposurePointSupported': exposurePointSupported, + 'focusMode': serializeFocusMode(focusMode), + 'focusPointSupported': focusPointSupported, }; @override @@ -94,7 +108,9 @@ class CameraInitializedEvent extends CameraEvent { previewWidth == other.previewWidth && previewHeight == other.previewHeight && exposureMode == other.exposureMode && - exposurePointSupported == other.exposurePointSupported; + exposurePointSupported == other.exposurePointSupported && + focusMode == other.focusMode && + focusPointSupported == other.focusPointSupported; @override int get hashCode => @@ -102,7 +118,9 @@ class CameraInitializedEvent extends CameraEvent { previewWidth.hashCode ^ previewHeight.hashCode ^ exposureMode.hashCode ^ - exposurePointSupported.hashCode; + exposurePointSupported.hashCode ^ + focusMode.hashCode ^ + focusPointSupported.hashCode; } /// An event fired when the resolution preset of the camera has changed. diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index 0ccc59939610..d23271e59844 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:math'; import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/types/focus_mode.dart'; import 'package:camera_platform_interface/src/types/image_format_group.dart'; import 'package:camera_platform_interface/src/utils/utils.dart'; import 'package:cross_file/cross_file.dart'; @@ -249,6 +250,31 @@ class MethodChannelCamera extends CameraPlatform { }, ); + @override + Future setFocusMode(int cameraId, FocusMode mode) => + _channel.invokeMethod( + 'setFocusMode', + { + 'cameraId': cameraId, + 'mode': serializeFocusMode(mode), + }, + ); + + @override + Future setFocusPoint(int cameraId, Point point) { + assert(point == null || point.x >= 0 && point.x <= 1); + assert(point == null || point.y >= 0 && point.y <= 1); + return _channel.invokeMethod( + 'setFocusPoint', + { + 'cameraId': cameraId, + 'reset': point == null, + 'x': point?.x, + 'y': point?.y, + }, + ); + } + @override Future getMaxZoomLevel(int cameraId) => _channel.invokeMethod( 'getMaxZoomLevel', @@ -331,6 +357,8 @@ class MethodChannelCamera extends CameraPlatform { call.arguments['previewHeight'], deserializeExposureMode(call.arguments['exposureMode']), call.arguments['exposurePointSupported'], + deserializeFocusMode(call.arguments['focusMode']), + call.arguments['focusPointSupported'], )); break; case 'resolution_changed': diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index d95d957e4862..fcd85436c365 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -8,6 +8,7 @@ import 'dart:math'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; import 'package:camera_platform_interface/src/types/exposure_mode.dart'; +import 'package:camera_platform_interface/src/types/focus_mode.dart'; import 'package:camera_platform_interface/src/types/image_format_group.dart'; import 'package:cross_file/cross_file.dart'; import 'package:flutter/widgets.dart'; @@ -129,7 +130,7 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('setExposureMode() is not implemented.'); } - /// Sets the exposure point for automatically determining the exposure value. + /// Sets the exposure point for automatically determining the exposure values. Future setExposurePoint(int cameraId, Point point) { throw UnimplementedError('setExposurePoint() is not implemented.'); } @@ -166,6 +167,16 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('setExposureOffset() is not implemented.'); } + /// Sets the focus mode for taking pictures. + Future setFocusMode(int cameraId, FocusMode mode) { + throw UnimplementedError('setFocusMode() is not implemented.'); + } + + /// Sets the focus point for automatically determining the focus values. + Future setFocusPoint(int cameraId, Point point) { + throw UnimplementedError('setFocusPoint() is not implemented.'); + } + /// Gets the maximum supported zoom level for the selected camera. Future getMaxZoomLevel(int cameraId) { throw UnimplementedError('getMaxZoomLevel() is not implemented.'); diff --git a/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart index 836f53826479..7fbfbaf5f4a9 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart @@ -13,6 +13,7 @@ enum ExposureMode { /// Returns the exposure mode as a String. String serializeExposureMode(ExposureMode exposureMode) { + if (exposureMode == null) return null; switch (exposureMode) { case ExposureMode.locked: return 'locked'; @@ -25,6 +26,7 @@ String serializeExposureMode(ExposureMode exposureMode) { /// Returns the exposure mode for a given String. ExposureMode deserializeExposureMode(String str) { + if (str == null) return null; switch (str) { case "locked": return ExposureMode.locked; diff --git a/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart new file mode 100644 index 000000000000..ad5e9a2d46f1 --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart @@ -0,0 +1,38 @@ +// Copyright 2019 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. + +/// The possible focus modes that can be set for a camera. +enum FocusMode { + /// Automatically determine focus settings. + auto, + + /// Lock the currently determined focus settings. + locked, +} + +/// Returns the focus mode as a String. +String serializeFocusMode(FocusMode focusMode) { + if (focusMode == null) return null; + switch (focusMode) { + case FocusMode.locked: + return 'locked'; + case FocusMode.auto: + return 'auto'; + default: + throw ArgumentError('Unknown FocusMode value'); + } +} + +/// Returns the focus mode for a given String. +FocusMode deserializeFocusMode(String str) { + if (str == null) return null; + switch (str) { + case "locked": + return FocusMode.locked; + case "auto": + return FocusMode.auto; + default: + throw ArgumentError('"$str" is not a valid FocusMode value'); + } +} diff --git a/packages/camera/camera_platform_interface/lib/src/types/types.dart b/packages/camera/camera_platform_interface/lib/src/types/types.dart index eaadc5c14061..256558dff3e7 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/types.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/types.dart @@ -8,3 +8,4 @@ export 'camera_exception.dart'; export 'flash_mode.dart'; export 'image_format_group.dart'; export 'exposure_mode.dart'; +export 'focus_mode.dart'; diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index 7a4fa49ce052..a6d0b815e660 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.3.0 +version: 1.4.0 dependencies: flutter: diff --git a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart index 574fa45e7b81..80316317e698 100644 --- a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart +++ b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart @@ -264,6 +264,32 @@ void main() { ); }); + test( + 'Default implementation of setFocusMode() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.setFocusMode(1, null), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of setFocusPoint() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.setFocusPoint(1, null), + throwsUnimplementedError, + ); + }); + test( 'Default implementation of startVideoRecording() should throw unimplemented error', () { diff --git a/packages/camera/camera_platform_interface/test/events/camera_event_test.dart b/packages/camera/camera_platform_interface/test/events/camera_event_test.dart index 1e28fa689383..f146b7e7e7bc 100644 --- a/packages/camera/camera_platform_interface/test/events/camera_event_test.dart +++ b/packages/camera/camera_platform_interface/test/events/camera_event_test.dart @@ -4,6 +4,7 @@ import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:camera_platform_interface/src/types/exposure_mode.dart'; +import 'package:camera_platform_interface/src/types/focus_mode.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -11,14 +12,16 @@ void main() { group('CameraInitializedEvent tests', () { test('Constructor should initialize all properties', () { - final event = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); + final event = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); expect(event.cameraId, 1); expect(event.previewWidth, 1024); expect(event.previewHeight, 640); expect(event.exposureMode, ExposureMode.auto); + expect(event.focusMode, FocusMode.auto); expect(event.exposurePointSupported, true); + expect(event.focusPointSupported, true); }); test('fromJson should initialize all properties', () { @@ -26,92 +29,120 @@ void main() { 'cameraId': 1, 'previewWidth': 1024.0, 'previewHeight': 640.0, - 'exposureMode': 'auto' + 'exposureMode': 'auto', + 'exposurePointSupported': true, + 'focusMode': 'auto', + 'focusPointSupported': true }); expect(event.cameraId, 1); expect(event.previewWidth, 1024); expect(event.previewHeight, 640); expect(event.exposureMode, ExposureMode.auto); + expect(event.exposurePointSupported, true); + expect(event.focusMode, FocusMode.auto); + expect(event.focusPointSupported, true); }); test('toJson should return a map with all fields', () { - final event = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); + final event = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); final jsonMap = event.toJson(); - expect(jsonMap.length, 5); + expect(jsonMap.length, 7); expect(jsonMap['cameraId'], 1); expect(jsonMap['previewWidth'], 1024); expect(jsonMap['previewHeight'], 640); expect(jsonMap['exposureMode'], 'auto'); expect(jsonMap['exposurePointSupported'], true); + expect(jsonMap['focusMode'], 'auto'); + expect(jsonMap['focusPointSupported'], true); }); test('equals should return true if objects are the same', () { - final firstEvent = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); - final secondEvent = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); + final firstEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); + final secondEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); expect(firstEvent == secondEvent, true); }); test('equals should return false if cameraId is different', () { - final firstEvent = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); - final secondEvent = - CameraInitializedEvent(2, 1024, 640, ExposureMode.auto, true); + final firstEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); + final secondEvent = CameraInitializedEvent( + 2, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); expect(firstEvent == secondEvent, false); }); test('equals should return false if previewWidth is different', () { - final firstEvent = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); - final secondEvent = - CameraInitializedEvent(1, 2048, 640, ExposureMode.auto, true); + final firstEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); + final secondEvent = CameraInitializedEvent( + 1, 2048, 640, ExposureMode.auto, true, FocusMode.auto, true); expect(firstEvent == secondEvent, false); }); test('equals should return false if previewHeight is different', () { - final firstEvent = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); - final secondEvent = - CameraInitializedEvent(1, 1024, 980, ExposureMode.auto, true); + final firstEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); + final secondEvent = CameraInitializedEvent( + 1, 1024, 980, ExposureMode.auto, true, FocusMode.auto, true); expect(firstEvent == secondEvent, false); }); test('equals should return false if exposureMode is different', () { - final firstEvent = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); - final secondEvent = - CameraInitializedEvent(1, 1024, 640, ExposureMode.locked, true); + final firstEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); + final secondEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.locked, true, FocusMode.auto, true); expect(firstEvent == secondEvent, false); }); test('equals should return false if exposurePointSupported is different', () { - final firstEvent = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); - final secondEvent = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, false); + final firstEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); + final secondEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, false, FocusMode.auto, true); + + expect(firstEvent == secondEvent, false); + }); + + test('equals should return false if focusMode is different', () { + final firstEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); + final secondEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.locked, true); + + expect(firstEvent == secondEvent, false); + }); + + test('equals should return false if focusPointSupported is different', () { + final firstEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); + final secondEvent = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, false); expect(firstEvent == secondEvent, false); }); test('hashCode should match hashCode of all properties', () { - final event = - CameraInitializedEvent(1, 1024, 640, ExposureMode.auto, true); - final expectedHashCode = event.cameraId ^ + final event = CameraInitializedEvent( + 1, 1024, 640, ExposureMode.auto, true, FocusMode.auto, true); + final expectedHashCode = event.cameraId.hashCode ^ event.previewWidth.hashCode ^ event.previewHeight.hashCode ^ event.exposureMode.hashCode ^ - event.exposurePointSupported.hashCode; + event.exposurePointSupported.hashCode ^ + event.focusMode.hashCode ^ + event.focusPointSupported.hashCode; expect(event.hashCode, expectedHashCode); }); diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index e8136fb051ad..550be358f7c9 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -8,6 +8,7 @@ import 'dart:math'; import 'package:async/async.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; +import 'package:camera_platform_interface/src/types/focus_mode.dart'; import 'package:camera_platform_interface/src/utils/utils.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -131,6 +132,8 @@ void main() { 1080, ExposureMode.auto, true, + FocusMode.auto, + true, )); await initializeFuture; @@ -170,6 +173,8 @@ void main() { 1080, ExposureMode.auto, true, + FocusMode.auto, + true, )); await initializeFuture; @@ -212,6 +217,8 @@ void main() { 1080, ExposureMode.auto, true, + FocusMode.auto, + true, )); await initializeFuture; }); @@ -229,6 +236,8 @@ void main() { 2160, ExposureMode.auto, true, + FocusMode.auto, + true, ); await camera.handleMethodCall( MethodCall('initialized', event.toJson()), cameraId); @@ -340,6 +349,8 @@ void main() { 1080, ExposureMode.auto, true, + FocusMode.auto, + true, ), ); await initializeFuture; @@ -679,6 +690,54 @@ void main() { ]); }); + test('Should set the focus mode', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'setFocusMode': null}, + ); + + // Act + await camera.setFocusMode(cameraId, FocusMode.auto); + await camera.setFocusMode(cameraId, FocusMode.locked); + + // Assert + expect(channel.log, [ + isMethodCall('setFocusMode', + arguments: {'cameraId': cameraId, 'mode': 'auto'}), + isMethodCall('setFocusMode', + arguments: {'cameraId': cameraId, 'mode': 'locked'}), + ]); + }); + + test('Should set the exposure point', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'setFocusPoint': null}, + ); + + // Act + await camera.setFocusPoint(cameraId, Point(0.5, 0.5)); + await camera.setFocusPoint(cameraId, null); + + // Assert + expect(channel.log, [ + isMethodCall('setFocusPoint', arguments: { + 'cameraId': cameraId, + 'x': 0.5, + 'y': 0.5, + 'reset': false + }), + isMethodCall('setFocusPoint', arguments: { + 'cameraId': cameraId, + 'x': null, + 'y': null, + 'reset': true + }), + ]); + }); + test('Should build a texture widget as preview widget', () async { // Act Widget widget = camera.buildPreview(cameraId); diff --git a/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart b/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart new file mode 100644 index 000000000000..ca7ad902820a --- /dev/null +++ b/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart @@ -0,0 +1,31 @@ +// Copyright 2019 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 'package:camera_platform_interface/src/types/focus_mode.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('FocusMode should contain 2 options', () { + final values = FocusMode.values; + + expect(values.length, 2); + }); + + test("FocusMode enum should have items in correct index", () { + final values = FocusMode.values; + + expect(values[0], FocusMode.auto); + expect(values[1], FocusMode.locked); + }); + + test("serializeFocusMode() should serialize correctly", () { + expect(serializeFocusMode(FocusMode.auto), "auto"); + expect(serializeFocusMode(FocusMode.locked), "locked"); + }); + + test("deserializeFocusMode() should deserialize correctly", () { + expect(deserializeFocusMode('auto'), FocusMode.auto); + expect(deserializeFocusMode('locked'), FocusMode.locked); + }); +} From 43ee609f0262ac3c74712971b2bf73160216f520 Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Thu, 7 Jan 2021 10:08:19 +0100 Subject: [PATCH 080/924] [camera_platform_interface] Add platform interface methods for locking capture orientation. (#3389) * Expand platform interface to support reporting device orientation * Switch to flutter DeviceOrientation enum * Add interface methods for (un)locking the capture orientation. * Update capture orientation interfaces and add unit tests. * Made device orientation mandatory for locking capture orientation in the platform interface. * Update comment * Update comment. * Update changelog and pubspec version * Update packages/camera/camera_platform_interface/lib/src/events/device_event.dart Co-authored-by: Maurits van Beusekom * Update packages/camera/camera_platform_interface/lib/src/events/device_event.dart Co-authored-by: Maurits van Beusekom * Update packages/camera/camera_platform_interface/lib/src/events/device_event.dart Co-authored-by: Maurits van Beusekom * Update packages/camera/camera_platform_interface/lib/src/events/device_event.dart Co-authored-by: Maurits van Beusekom * Update packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart Co-authored-by: Maurits van Beusekom * Update packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart Co-authored-by: Maurits van Beusekom Co-authored-by: Maurits van Beusekom Co-authored-by: Maurits van Beusekom --- .../camera_platform_interface/CHANGELOG.md | 5 ++ .../lib/camera_platform_interface.dart | 1 + .../lib/src/events/camera_event.dart | 3 +- .../lib/src/events/device_event.dart | 52 +++++++++++ .../method_channel/method_channel_camera.dart | 78 +++++++++++++++-- .../platform_interface/camera_platform.dart | 23 +++++ .../lib/src/utils/utils.dart | 33 +++++++ .../camera_platform_interface/pubspec.yaml | 2 +- .../test/camera_platform_interface_test.dart | 39 +++++++++ .../test/events/device_event_test.dart | 61 +++++++++++++ .../method_channel_camera_test.dart | 87 ++++++++++++++++--- .../test/utils/utils_test.dart | 23 +++++ 12 files changed, 384 insertions(+), 23 deletions(-) create mode 100644 packages/camera/camera_platform_interface/lib/src/events/device_event.dart create mode 100644 packages/camera/camera_platform_interface/test/events/device_event_test.dart diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index ae22f8a5f6a4..d7442d4ac931 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.5.0 + +- Introduces interface methods for locking and unlocking the capture orientation. +- Introduces interface method for listening to the device orientation. + ## 1.4.0 - Added interface methods to support auto focus. diff --git a/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart b/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart index eaa14da45a5e..d7e5fcd0834c 100644 --- a/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart +++ b/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. export 'src/events/camera_event.dart'; +export 'src/events/device_event.dart'; export 'src/platform_interface/camera_platform.dart'; export 'src/types/types.dart'; diff --git a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart index 8ca445a2e06e..d60a0a39f608 100644 --- a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart +++ b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart @@ -6,7 +6,8 @@ import 'package:camera_platform_interface/src/types/focus_mode.dart'; import '../../camera_platform_interface.dart'; -/// Generic Event coming from the native side of Camera. +/// Generic Event coming from the native side of Camera, +/// related to a specific camera module. /// /// All [CameraEvent]s contain the `cameraId` that originated the event. This /// should never be `null`. diff --git a/packages/camera/camera_platform_interface/lib/src/events/device_event.dart b/packages/camera/camera_platform_interface/lib/src/events/device_event.dart new file mode 100644 index 000000000000..82febcab2290 --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/events/device_event.dart @@ -0,0 +1,52 @@ +// Copyright 2019 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 'package:camera_platform_interface/src/utils/utils.dart'; +import 'package:flutter/services.dart'; + +/// Generic Event coming from the native side of Camera, +/// not related to a specific camera module. +/// +/// This class is used as a base class for all the events that might be +/// triggered from a device, but it is never used directly as an event type. +/// +/// Do NOT instantiate new events like `DeviceEvent()` directly, +/// use a specific class instead: +/// +/// Do `class NewEvent extend DeviceEvent` when creating your own events. +/// See below for examples: `DeviceOrientationChangedEvent`... +/// These events are more semantic and more pleasant to use than raw generics. +/// They can be (and in fact, are) filtered by the `instanceof`-operator. +abstract class DeviceEvent {} + +/// The [DeviceOrientationChangedEvent] is fired every time the user changes the +/// physical orientation of the device. +class DeviceOrientationChangedEvent extends DeviceEvent { + /// The new orientation of the device + final DeviceOrientation orientation; + + /// Build a new orientation changed event. + DeviceOrientationChangedEvent(this.orientation); + + /// Converts the supplied [Map] to an instance of the [DeviceOrientationChangedEvent] + /// class. + DeviceOrientationChangedEvent.fromJson(Map json) + : orientation = deserializeDeviceOrientation(json['orientation']); + + /// Converts the [DeviceOrientationChangedEvent] instance into a [Map] instance that + /// can be serialized to JSON. + Map toJson() => { + 'orientation': serializeDeviceOrientation(orientation), + }; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is DeviceOrientationChangedEvent && + runtimeType == other.runtimeType && + orientation == other.orientation; + + @override + int get hashCode => orientation.hashCode; +} diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index d23271e59844..e6f658c45365 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:math'; import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/events/device_event.dart'; import 'package:camera_platform_interface/src/types/focus_mode.dart'; import 'package:camera_platform_interface/src/types/image_format_group.dart'; import 'package:camera_platform_interface/src/utils/utils.dart'; @@ -22,7 +23,7 @@ class MethodChannelCamera extends CameraPlatform { final Map _channels = {}; /// The controller we need to broadcast the different events coming - /// from handleMethodCall. + /// from handleMethodCall, specific to camera events. /// /// It is a `broadcast` because multiple controllers will connect to /// different stream views of this Controller. @@ -32,10 +33,28 @@ class MethodChannelCamera extends CameraPlatform { final StreamController cameraEventStreamController = StreamController.broadcast(); - Stream _events(int cameraId) => + /// The controller we need to broadcast the different events coming + /// from handleMethodCall, specific to general device events. + /// + /// It is a `broadcast` because multiple controllers will connect to + /// different stream views of this Controller. + /// This is only exposed for test purposes. It shouldn't be used by clients of + /// the plugin as it may break or change at any time. + @visibleForTesting + final StreamController deviceEventStreamController = + StreamController.broadcast(); + + Stream _cameraEvents(int cameraId) => cameraEventStreamController.stream .where((event) => event.cameraId == cameraId); + /// Construct a new method channel camera instance. + MethodChannelCamera() { + final channel = MethodChannel('flutter.io/cameraPlugin/device'); + channel.setMethodCallHandler( + (MethodCall call) => handleDeviceMethodCall(call)); + } + @override Future> availableCameras() async { try { @@ -83,7 +102,7 @@ class MethodChannelCamera extends CameraPlatform { _channels.putIfAbsent(cameraId, () { final channel = MethodChannel('flutter.io/cameraPlugin/camera$cameraId'); channel.setMethodCallHandler( - (MethodCall call) => handleMethodCall(call, cameraId)); + (MethodCall call) => handleCameraMethodCall(call, cameraId)); return channel; }); @@ -119,22 +138,48 @@ class MethodChannelCamera extends CameraPlatform { @override Stream onCameraInitialized(int cameraId) { - return _events(cameraId).whereType(); + return _cameraEvents(cameraId).whereType(); } @override Stream onCameraResolutionChanged(int cameraId) { - return _events(cameraId).whereType(); + return _cameraEvents(cameraId).whereType(); } @override Stream onCameraClosing(int cameraId) { - return _events(cameraId).whereType(); + return _cameraEvents(cameraId).whereType(); } @override Stream onCameraError(int cameraId) { - return _events(cameraId).whereType(); + return _cameraEvents(cameraId).whereType(); + } + + @override + Stream onDeviceOrientationChanged() { + return deviceEventStreamController.stream + .whereType(); + } + + @override + Future lockCaptureOrientation( + int cameraId, DeviceOrientation orientation) async { + await _channel.invokeMethod( + 'lockCaptureOrientation', + { + 'cameraId': cameraId, + 'orientation': serializeDeviceOrientation(orientation) + }, + ); + } + + @override + Future unlockCaptureOrientation(int cameraId) async { + await _channel.invokeMethod( + 'unlockCaptureOrientation', + {'cameraId': cameraId}, + ); } @override @@ -343,12 +388,27 @@ class MethodChannelCamera extends CameraPlatform { } } - /// Converts messages received from the native platform into events. + /// Converts messages received from the native platform into device events. + /// + /// This is only exposed for test purposes. It shouldn't be used by clients of + /// the plugin as it may break or change at any time. + Future handleDeviceMethodCall(MethodCall call) async { + switch (call.method) { + case 'orientation_changed': + deviceEventStreamController.add(DeviceOrientationChangedEvent( + deserializeDeviceOrientation(call.arguments['orientation']))); + break; + default: + throw MissingPluginException(); + } + } + + /// Converts messages received from the native platform into camera events. /// /// This is only exposed for test purposes. It shouldn't be used by clients of /// the plugin as it may break or change at any time. @visibleForTesting - Future handleMethodCall(MethodCall call, int cameraId) async { + Future handleCameraMethodCall(MethodCall call, int cameraId) async { switch (call.method) { case 'initialized': cameraEventStreamController.add(CameraInitializedEvent( diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index fcd85436c365..c1d6e09c3263 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -6,11 +6,13 @@ import 'dart:async'; import 'dart:math'; import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/events/device_event.dart'; import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; import 'package:camera_platform_interface/src/types/exposure_mode.dart'; import 'package:camera_platform_interface/src/types/focus_mode.dart'; import 'package:camera_platform_interface/src/types/image_format_group.dart'; import 'package:cross_file/cross_file.dart'; +import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -85,6 +87,27 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('onCameraError() is not implemented.'); } + /// The device orientation changed. + /// + /// Implementations for this: + /// - Should support all 4 orientations. + /// - Should not emit new values when the screen orientation is locked. + Stream onDeviceOrientationChanged() { + throw UnimplementedError( + 'onDeviceOrientationChanged() is not implemented.'); + } + + /// Locks the capture orientation. + Future lockCaptureOrientation( + int cameraId, DeviceOrientation orientation) { + throw UnimplementedError('lockCaptureOrientation() is not implemented.'); + } + + /// Unlocks the capture orientation. + Future unlockCaptureOrientation(int cameraId) { + throw UnimplementedError('unlockCaptureOrientation() is not implemented.'); + } + /// Captures an image and returns the file where it was saved. Future takePicture(int cameraId) { throw UnimplementedError('takePicture() is not implemented.'); diff --git a/packages/camera/camera_platform_interface/lib/src/utils/utils.dart b/packages/camera/camera_platform_interface/lib/src/utils/utils.dart index f94d8e69c07e..5413f25bb8b7 100644 --- a/packages/camera/camera_platform_interface/lib/src/utils/utils.dart +++ b/packages/camera/camera_platform_interface/lib/src/utils/utils.dart @@ -1,4 +1,5 @@ import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter/services.dart'; /// Parses a string into a corresponding CameraLensDirection. CameraLensDirection parseCameraLensDirection(String string) { @@ -12,3 +13,35 @@ CameraLensDirection parseCameraLensDirection(String string) { } throw ArgumentError('Unknown CameraLensDirection value'); } + +/// Returns the device orientation as a String. +String serializeDeviceOrientation(DeviceOrientation orientation) { + switch (orientation) { + case DeviceOrientation.portraitUp: + return 'portraitUp'; + case DeviceOrientation.portraitDown: + return 'portraitDown'; + case DeviceOrientation.landscapeRight: + return 'landscapeRight'; + case DeviceOrientation.landscapeLeft: + return 'landscapeLeft'; + default: + throw ArgumentError('Unknown DeviceOrientation value'); + } +} + +/// Returns the device orientation for a given String. +DeviceOrientation deserializeDeviceOrientation(String str) { + switch (str) { + case "portraitUp": + return DeviceOrientation.portraitUp; + case "portraitDown": + return DeviceOrientation.portraitDown; + case "landscapeRight": + return DeviceOrientation.landscapeRight; + case "landscapeLeft": + return DeviceOrientation.landscapeLeft; + default: + throw ArgumentError('"$str" is not a valid DeviceOrientation value'); + } +} diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index a6d0b815e660..2a8d7ce9abe1 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.4.0 +version: 1.5.0 dependencies: flutter: diff --git a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart index 80316317e698..8baf5da34159 100644 --- a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart +++ b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart @@ -96,6 +96,45 @@ void main() { ); }); + test( + 'Default implementation of onDeviceOrientationChanged() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.onDeviceOrientationChanged(), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of lockCaptureOrientation() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.lockCaptureOrientation(1, null), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of unlockCaptureOrientation() should throw unimplemented error', + () { + // Arrange + final cameraPlatform = ExtendsCameraPlatform(); + + // Act & Assert + expect( + () => cameraPlatform.unlockCaptureOrientation(1), + throwsUnimplementedError, + ); + }); + test('Default implementation of dispose() should throw unimplemented error', () { // Arrange diff --git a/packages/camera/camera_platform_interface/test/events/device_event_test.dart b/packages/camera/camera_platform_interface/test/events/device_event_test.dart new file mode 100644 index 000000000000..c2fef49be04f --- /dev/null +++ b/packages/camera/camera_platform_interface/test/events/device_event_test.dart @@ -0,0 +1,61 @@ +// Copyright 2019 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 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('DeviceOrientationChangedEvent tests', () { + test('Constructor should initialize all properties', () { + final event = DeviceOrientationChangedEvent(DeviceOrientation.portraitUp); + + expect(event.orientation, DeviceOrientation.portraitUp); + }); + + test('fromJson should initialize all properties', () { + final event = DeviceOrientationChangedEvent.fromJson({ + 'orientation': 'portraitUp', + }); + + expect(event.orientation, DeviceOrientation.portraitUp); + }); + + test('toJson should return a map with all fields', () { + final event = DeviceOrientationChangedEvent(DeviceOrientation.portraitUp); + + final jsonMap = event.toJson(); + + expect(jsonMap.length, 1); + expect(jsonMap['orientation'], 'portraitUp'); + }); + + test('equals should return true if objects are the same', () { + final firstEvent = + DeviceOrientationChangedEvent(DeviceOrientation.portraitUp); + final secondEvent = + DeviceOrientationChangedEvent(DeviceOrientation.portraitUp); + + expect(firstEvent == secondEvent, true); + }); + + test('equals should return false if orientation is different', () { + final firstEvent = + DeviceOrientationChangedEvent(DeviceOrientation.portraitUp); + final secondEvent = + DeviceOrientationChangedEvent(DeviceOrientation.landscapeLeft); + + expect(firstEvent == secondEvent, false); + }); + + test('hashCode should match hashCode of all properties', () { + final event = DeviceOrientationChangedEvent(DeviceOrientation.portraitUp); + final expectedHashCode = event.orientation.hashCode; + + expect(event.hashCode, expectedHashCode); + }); + }); +} diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index 550be358f7c9..7e9146344206 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -7,9 +7,11 @@ import 'dart:math'; import 'package:async/async.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:camera_platform_interface/src/events/device_event.dart'; import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; import 'package:camera_platform_interface/src/types/focus_mode.dart'; import 'package:camera_platform_interface/src/utils/utils.dart'; +import 'package:flutter/services.dart' hide DeviceOrientation; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -239,7 +241,7 @@ void main() { FocusMode.auto, true, ); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('initialized', event.toJson()), cameraId); // Assert @@ -258,13 +260,13 @@ void main() { // Emit test events final fhdEvent = CameraResolutionChangedEvent(cameraId, 1920, 1080); final uhdEvent = CameraResolutionChangedEvent(cameraId, 3840, 2160); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('resolution_changed', fhdEvent.toJson()), cameraId); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('resolution_changed', uhdEvent.toJson()), cameraId); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('resolution_changed', fhdEvent.toJson()), cameraId); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('resolution_changed', uhdEvent.toJson()), cameraId); // Assert @@ -285,11 +287,11 @@ void main() { // Emit test events final event = CameraClosingEvent(cameraId); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('camera_closing', event.toJson()), cameraId); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('camera_closing', event.toJson()), cameraId); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('camera_closing', event.toJson()), cameraId); // Assert @@ -308,11 +310,11 @@ void main() { // Emit test events final event = CameraErrorEvent(cameraId, 'Error Description'); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('error', event.toJson()), cameraId); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('error', event.toJson()), cameraId); - await camera.handleMethodCall( + await camera.handleCameraMethodCall( MethodCall('error', event.toJson()), cameraId); // Assert @@ -323,6 +325,30 @@ void main() { // Clean up await streamQueue.cancel(); }); + + test('Should receive device orientation change events', () async { + // Act + final eventStream = camera.onDeviceOrientationChanged(); + final streamQueue = StreamQueue(eventStream); + + // Emit test events + final event = + DeviceOrientationChangedEvent(DeviceOrientation.portraitUp); + await camera.handleDeviceMethodCall( + MethodCall('orientation_changed', event.toJson())); + await camera.handleDeviceMethodCall( + MethodCall('orientation_changed', event.toJson())); + await camera.handleDeviceMethodCall( + MethodCall('orientation_changed', event.toJson())); + + // Assert + expect(await streamQueue.next, event); + expect(await streamQueue.next, event); + expect(await streamQueue.next, event); + + // Clean up + await streamQueue.cancel(); + }); }); group('Function Tests', () { @@ -751,7 +777,9 @@ void main() { () { final camera = MethodChannelCamera(); - expect(() => camera.handleMethodCall(MethodCall('unknown_method'), 1), + expect( + () => + camera.handleCameraMethodCall(MethodCall('unknown_method'), 1), throwsA(isA())); }); @@ -832,6 +860,41 @@ void main() { .having((e) => e.description, 'description', 'Illegal zoom error'))); }); + + test('Should lock the capture orientation', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'lockCaptureOrientation': null}, + ); + + // Act + await camera.lockCaptureOrientation( + cameraId, DeviceOrientation.portraitUp); + + // Assert + expect(channel.log, [ + isMethodCall('lockCaptureOrientation', + arguments: {'cameraId': cameraId, 'orientation': 'portraitUp'}), + ]); + }); + + test('Should unlock the capture orientation', () async { + // Arrange + MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'unlockCaptureOrientation': null}, + ); + + // Act + await camera.unlockCaptureOrientation(cameraId); + + // Assert + expect(channel.log, [ + isMethodCall('unlockCaptureOrientation', + arguments: {'cameraId': cameraId}), + ]); + }); }); }); } diff --git a/packages/camera/camera_platform_interface/test/utils/utils_test.dart b/packages/camera/camera_platform_interface/test/utils/utils_test.dart index dccb30754f14..63e3baff265d 100644 --- a/packages/camera/camera_platform_interface/test/utils/utils_test.dart +++ b/packages/camera/camera_platform_interface/test/utils/utils_test.dart @@ -1,5 +1,6 @@ import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:camera_platform_interface/src/utils/utils.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -29,5 +30,27 @@ void main() { throwsA(isArgumentError), ); }); + + test("serializeDeviceOrientation() should serialize correctly", () { + expect(serializeDeviceOrientation(DeviceOrientation.portraitUp), + "portraitUp"); + expect(serializeDeviceOrientation(DeviceOrientation.portraitDown), + "portraitDown"); + expect(serializeDeviceOrientation(DeviceOrientation.landscapeRight), + "landscapeRight"); + expect(serializeDeviceOrientation(DeviceOrientation.landscapeLeft), + "landscapeLeft"); + }); + + test("deserializeDeviceOrientation() should deserialize correctly", () { + expect(deserializeDeviceOrientation('portraitUp'), + DeviceOrientation.portraitUp); + expect(deserializeDeviceOrientation('portraitDown'), + DeviceOrientation.portraitDown); + expect(deserializeDeviceOrientation('landscapeRight'), + DeviceOrientation.landscapeRight); + expect(deserializeDeviceOrientation('landscapeLeft'), + DeviceOrientation.landscapeLeft); + }); }); } From d026d07afea2fa29eacaff3589d8b11a33a402e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Filipovi=C4=87?= Date: Thu, 7 Jan 2021 19:24:24 +0100 Subject: [PATCH 081/924] [camera] set useAutoFocus to true by default (#3396) * set useAutoFocus to true by default there's no way to set useAutoFocus to `true` and it is `false` by default so the auto focus is not working. * Update pubspec.yaml * Update CHANGELOG.md --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../src/main/java/io/flutter/plugins/camera/Camera.java | 2 +- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 55c7eb1fcfd2..6557b8a8e0b3 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.4+4 + +* Set camera auto focus enabled by default. + ## 0.6.4+3 * Detect if selected camera supports auto focus and act accordingly on Android. This solves a problem where front facing cameras are not capturing the picture because auto focus is not supported. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 2db097ceadf7..40656cbabcf1 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -96,7 +96,7 @@ public class Camera { private PictureCaptureRequest pictureCaptureRequest; private CameraRegions cameraRegions; private int exposureOffset; - private boolean useAutoFocus; + private boolean useAutoFocus = true; private Range fpsRange; public Camera( diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 99f41fb165a5..6c6d5159800d 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.4+3 +version: 0.6.4+4 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From d0fd4b188719f9cd867c82f01cd39bf2828acea1 Mon Sep 17 00:00:00 2001 From: Aman Verma Date: Fri, 8 Jan 2021 01:24:04 +0530 Subject: [PATCH 082/924] [image_picker] Update README.md (#3098) --- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ packages/image_picker/image_picker/README.md | 4 ++-- packages/image_picker/image_picker/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 32d61cc79607..90cf80f9aee6 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+20 + +* Updated README.md to show the new Android API requirements. + ## 0.6.7+19 * Do not copy static field to another static field. diff --git a/packages/image_picker/image_picker/README.md b/packages/image_picker/image_picker/README.md index 106d78b630b9..ca8ad763c553 100755 --- a/packages/image_picker/image_picker/README.md +++ b/packages/image_picker/image_picker/README.md @@ -19,10 +19,10 @@ Add the following keys to your _Info.plist_ file, located in `/ios ### Android -#### API 29+ +#### API < 29 No configuration required - the plugin should work out of the box. -#### API < 29 +#### API 29+ Add `android:requestLegacyExternalStorage="true"` as an attribute to the `` tag in AndroidManifest.xml. The [attribute](https://developer.android.com/training/data-storage/compatibility) is `false` by default on apps targeting Android Q. diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 377c3840c2d1..af409fd1c5b3 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+19 +version: 0.6.7+20 flutter: plugin: From 1b7afc52353c53b153176a899f51fc3198ec7f95 Mon Sep 17 00:00:00 2001 From: Andrew Zuo Date: Thu, 7 Jan 2021 14:59:03 -0500 Subject: [PATCH 083/924] [in_app_purchase] Added serviceTimeout code (#3287) --- packages/in_app_purchase/CHANGELOG.md | 4 ++++ .../billing_client_wrapper.dart | 5 +++++ .../enum_converters.g.dart | 1 + packages/in_app_purchase/pubspec.yaml | 2 +- .../billing_client_wrapper_test.dart | 18 ++++++++++++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index 0a5794f931a8..d7124407d711 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.5 + +* [Android] Fixed: added support for the SERVICE_TIMEOUT (-3) response code. + ## 0.3.4+18 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart index 0c8b348f4cd0..2aa91d9f9225 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart @@ -314,6 +314,11 @@ enum BillingResponse { // WARNING: Changes to this class need to be reflected in our generated code. // Run `flutter packages pub run build_runner watch` to rebuild and watch for // further changes. + + /// The request has reached the maximum timeout before Google Play responds. + @JsonValue(-3) + serviceTimeout, + /// The requested feature is not supported by Play Store on the current device. @JsonValue(-2) featureNotSupported, diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart index 899304b08273..947700df64df 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart @@ -43,6 +43,7 @@ T _$enumDecode( } const _$BillingResponseEnumMap = { + BillingResponse.serviceTimeout: -3, BillingResponse.featureNotSupported: -2, BillingResponse.serviceDisconnected: -1, BillingResponse.ok: 0, diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 5e5ef2447278..883f8c39c273 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.3.4+18 +version: 0.3.5 dependencies: async: ^2.0.8 diff --git a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart index 54f7c3eda77f..eee33a698237 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart @@ -39,6 +39,24 @@ void main() { }); }); + // Make sure that the enum values are supported and that the converter call + // does not fail + test('response states', () async { + BillingResponseConverter converter = BillingResponseConverter(); + converter.fromJson(-3); + converter.fromJson(-2); + converter.fromJson(-1); + converter.fromJson(0); + converter.fromJson(1); + converter.fromJson(2); + converter.fromJson(3); + converter.fromJson(4); + converter.fromJson(5); + converter.fromJson(6); + converter.fromJson(7); + converter.fromJson(8); + }); + group('startConnection', () { final String methodName = 'BillingClient#startConnection(BillingClientStateListener)'; From a7dd76950e5b240d2d878504a6f010ef24717e34 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Thu, 7 Jan 2021 14:47:38 -0800 Subject: [PATCH 084/924] Update obsolete button refs in plugin examples (#3395) --- packages/android_alarm_manager/CHANGELOG.md | 4 +++ .../example/lib/main.dart | 2 +- packages/android_alarm_manager/pubspec.yaml | 2 +- packages/android_intent/CHANGELOG.md | 4 +++ packages/android_intent/example/lib/main.dart | 20 ++++++------- packages/android_intent/pubspec.yaml | 2 +- packages/battery/battery/CHANGELOG.md | 4 +++ .../battery/battery/example/lib/main.dart | 2 +- packages/battery/battery/pubspec.yaml | 2 +- packages/camera/camera/CHANGELOG.md | 4 +++ packages/camera/camera/example/lib/main.dart | 24 ++++++++------- packages/camera/camera/pubspec.yaml | 2 +- .../file_selector/file_selector/CHANGELOG.md | 4 +++ .../example/lib/get_directory_page.dart | 10 ++++--- .../file_selector/example/lib/home_page.dart | 29 +++++++++--------- .../example/lib/open_image_page.dart | 10 ++++--- .../lib/open_multiple_images_page.dart | 10 ++++--- .../example/lib/open_text_page.dart | 10 ++++--- .../example/lib/save_text_page.dart | 8 +++-- .../file_selector/file_selector/pubspec.yaml | 2 +- .../google_maps_flutter/CHANGELOG.md | 4 +++ .../example/lib/animate_camera.dart | 20 ++++++------- .../example/lib/map_coordinates.dart | 2 +- .../example/lib/map_ui.dart | 30 +++++++++---------- .../example/lib/move_camera.dart | 20 ++++++------- .../example/lib/padding.dart | 4 +-- .../example/lib/place_circle.dart | 12 ++++---- .../example/lib/place_marker.dart | 28 ++++++++--------- .../example/lib/place_polygon.dart | 14 ++++----- .../example/lib/place_polyline.dart | 20 ++++++------- .../example/lib/snapshot.dart | 2 +- .../google_maps_flutter/pubspec.yaml | 2 +- .../CHANGELOG.md | 4 +++ .../example/lib/main.dart | 6 ++-- .../pubspec.yaml | 2 +- .../google_sign_in/CHANGELOG.md | 4 +++ .../google_sign_in/example/lib/main.dart | 6 ++-- .../google_sign_in/pubspec.yaml | 2 +- .../image_picker/image_picker/CHANGELOG.md | 4 +++ .../image_picker/example/lib/main.dart | 4 +-- packages/in_app_purchase/CHANGELOG.md | 4 +++ .../in_app_purchase/example/lib/main.dart | 8 +++-- packages/in_app_purchase/pubspec.yaml | 2 +- packages/local_auth/CHANGELOG.md | 4 +++ packages/local_auth/example/lib/main.dart | 6 ++-- packages/local_auth/pubspec.yaml | 2 +- .../path_provider/path_provider/CHANGELOG.md | 4 +++ .../path_provider/example/lib/main.dart | 14 ++++----- .../path_provider/path_provider/pubspec.yaml | 2 +- .../path_provider_macos/CHANGELOG.md | 4 +++ .../path_provider_macos/example/lib/main.dart | 10 +++---- .../path_provider_macos/pubspec.yaml | 2 +- packages/share/CHANGELOG.md | 4 +++ packages/share/example/lib/main.dart | 8 ++--- packages/share/pubspec.yaml | 2 +- .../url_launcher/url_launcher/CHANGELOG.md | 4 +++ .../url_launcher/example/lib/main.dart | 14 ++++----- .../test/url_launcher_example_test.dart | 2 +- .../url_launcher/lib/src/link.dart | 4 +-- .../url_launcher/url_launcher/pubspec.yaml | 2 +- .../url_launcher_linux/CHANGELOG.md | 4 +++ .../url_launcher_linux/example/lib/main.dart | 12 ++++---- .../url_launcher_linux/pubspec.yaml | 2 +- .../url_launcher_macos/CHANGELOG.md | 4 +++ .../url_launcher_macos/example/lib/main.dart | 12 ++++---- .../url_launcher_macos/pubspec.yaml | 2 +- .../url_launcher_windows/CHANGELOG.md | 4 +++ .../example/lib/main.dart | 2 +- .../url_launcher_windows/pubspec.yaml | 2 +- .../video_player/video_player/CHANGELOG.md | 4 +++ .../video_player/example/lib/main.dart | 4 +-- .../video_player/video_player/pubspec.yaml | 2 +- 72 files changed, 296 insertions(+), 205 deletions(-) diff --git a/packages/android_alarm_manager/CHANGELOG.md b/packages/android_alarm_manager/CHANGELOG.md index 1b6a7b749e66..df5b7a2fa752 100644 --- a/packages/android_alarm_manager/CHANGELOG.md +++ b/packages/android_alarm_manager/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.5+20 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 0.4.5+19 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/android_alarm_manager/example/lib/main.dart b/packages/android_alarm_manager/example/lib/main.dart index b4d907c127da..ac27fec2e4c6 100644 --- a/packages/android_alarm_manager/example/lib/main.dart +++ b/packages/android_alarm_manager/example/lib/main.dart @@ -131,7 +131,7 @@ class _AlarmHomePageState extends State<_AlarmHomePage> { ), ], ), - RaisedButton( + ElevatedButton( child: Text( 'Schedule OneShot Alarm', ), diff --git a/packages/android_alarm_manager/pubspec.yaml b/packages/android_alarm_manager/pubspec.yaml index b055823c2db3..d1771c0f0380 100644 --- a/packages/android_alarm_manager/pubspec.yaml +++ b/packages/android_alarm_manager/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for accessing the Android AlarmManager service, and # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.5+19 +version: 0.4.5+20 homepage: https://github.com/flutter/plugins/tree/master/packages/android_alarm_manager dependencies: diff --git a/packages/android_intent/CHANGELOG.md b/packages/android_intent/CHANGELOG.md index 113e4464c947..3e878a50aac2 100644 --- a/packages/android_intent/CHANGELOG.md +++ b/packages/android_intent/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.2 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 2.0.0-nullsafety.1 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/android_intent/example/lib/main.dart b/packages/android_intent/example/lib/main.dart index 45de9632e975..4fd2440285f3 100644 --- a/packages/android_intent/example/lib/main.dart +++ b/packages/android_intent/example/lib/main.dart @@ -59,12 +59,12 @@ class MyHomePage extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - RaisedButton( + ElevatedButton( child: const Text( 'Tap here to set an alarm\non weekdays at 9:30pm.'), onPressed: _createAlarm, ), - RaisedButton( + ElevatedButton( child: const Text('Tap here to test explicit intents.'), onPressed: () => _openExplicitIntentsView(context)), ], @@ -166,40 +166,40 @@ class ExplicitIntentsWidget extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - RaisedButton( + ElevatedButton( child: const Text( 'Tap here to display panorama\nimagery in Google Street View.'), onPressed: _openGoogleMapsStreetView, ), - RaisedButton( + ElevatedButton( child: const Text('Tap here to display\na map in Google Maps.'), onPressed: _displayMapInGoogleMaps, ), - RaisedButton( + ElevatedButton( child: const Text( 'Tap here to launch turn-by-turn\nnavigation in Google Maps.'), onPressed: _launchTurnByTurnNavigationInGoogleMaps, ), - RaisedButton( + ElevatedButton( child: const Text('Tap here to open link in Google Chrome.'), onPressed: _openLinkInGoogleChrome, ), - RaisedButton( + ElevatedButton( child: const Text('Tap here to start activity in new task.'), onPressed: _startActivityInNewTask, ), - RaisedButton( + ElevatedButton( child: const Text( 'Tap here to test explicit intent fallback to implicit.'), onPressed: _testExplicitIntentFallback, ), - RaisedButton( + ElevatedButton( child: const Text( 'Tap here to open Location Settings Configuration', ), onPressed: _openLocationSettingsConfiguration, ), - RaisedButton( + ElevatedButton( child: const Text( 'Tap here to open Application Details', ), diff --git a/packages/android_intent/pubspec.yaml b/packages/android_intent/pubspec.yaml index 52928f08093f..c61460718fc1 100644 --- a/packages/android_intent/pubspec.yaml +++ b/packages/android_intent/pubspec.yaml @@ -1,7 +1,7 @@ name: android_intent description: Flutter plugin for launching Android Intents. Not supported on iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/android_intent -version: 2.0.0-nullsafety.1 +version: 2.0.0-nullsafety.2 flutter: plugin: diff --git a/packages/battery/battery/CHANGELOG.md b/packages/battery/battery/CHANGELOG.md index c9268d4d4e3c..ca35c96fb569 100644 --- a/packages/battery/battery/CHANGELOG.md +++ b/packages/battery/battery/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.11 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 1.0.10 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/battery/battery/example/lib/main.dart b/packages/battery/battery/example/lib/main.dart index 1c1dfcf252b6..c84f5eec519b 100644 --- a/packages/battery/battery/example/lib/main.dart +++ b/packages/battery/battery/example/lib/main.dart @@ -71,7 +71,7 @@ class _MyHomePageState extends State { builder: (_) => AlertDialog( content: Text('Battery: $batteryLevel%'), actions: [ - FlatButton( + TextButton( child: const Text('OK'), onPressed: () { Navigator.pop(context); diff --git a/packages/battery/battery/pubspec.yaml b/packages/battery/battery/pubspec.yaml index d3c823d73ad2..9c2c2766c85f 100644 --- a/packages/battery/battery/pubspec.yaml +++ b/packages/battery/battery/pubspec.yaml @@ -2,7 +2,7 @@ name: battery description: Flutter plugin for accessing information about the battery state (full, charging, discharging) on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/battery/battery -version: 1.0.10 +version: 1.0.11 flutter: plugin: diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 6557b8a8e0b3..2f9b5399d6dd 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.4+5 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 0.6.4+4 * Set camera auto focus enabled by default. diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index c4fa1c5ed01e..5324e3d09383 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -313,6 +313,16 @@ class _CameraExampleHomeState extends State } Widget _exposureModeControlRowWidget() { + final ButtonStyle styleAuto = TextButton.styleFrom( + primary: controller?.value?.exposureMode == ExposureMode.auto + ? Colors.orange + : Colors.blue, + ); + final ButtonStyle styleLocked = TextButton.styleFrom( + primary: controller?.value?.exposureMode == ExposureMode.locked + ? Colors.orange + : Colors.blue, + ); return SizeTransition( sizeFactor: _exposureModeControlRowAnimation, child: ClipRect( @@ -327,12 +337,9 @@ class _CameraExampleHomeState extends State mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisSize: MainAxisSize.max, children: [ - FlatButton( + TextButton( child: Text('AUTO'), - textColor: - controller?.value?.exposureMode == ExposureMode.auto - ? Colors.orange - : Colors.blue, + style: styleAuto, onPressed: controller != null ? () => onSetExposureModeButtonPressed(ExposureMode.auto) @@ -342,12 +349,9 @@ class _CameraExampleHomeState extends State showInSnackBar('Resetting exposure point'); }, ), - FlatButton( + TextButton( child: Text('LOCKED'), - textColor: - controller?.value?.exposureMode == ExposureMode.locked - ? Colors.orange - : Colors.blue, + style: styleLocked, onPressed: controller != null ? () => onSetExposureModeButtonPressed(ExposureMode.locked) diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 6c6d5159800d..50f504a8d0e8 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.4+4 +version: 0.6.4+5 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: diff --git a/packages/file_selector/file_selector/CHANGELOG.md b/packages/file_selector/file_selector/CHANGELOG.md index 92136485a447..fe01ffec47b6 100644 --- a/packages/file_selector/file_selector/CHANGELOG.md +++ b/packages/file_selector/file_selector/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+2 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 0.7.0+1 * Update Flutter SDK constraint. diff --git a/packages/file_selector/file_selector/example/lib/get_directory_page.dart b/packages/file_selector/file_selector/example/lib/get_directory_page.dart index 2afc58f246a4..6463fb532957 100644 --- a/packages/file_selector/file_selector/example/lib/get_directory_page.dart +++ b/packages/file_selector/file_selector/example/lib/get_directory_page.dart @@ -24,9 +24,11 @@ class GetDirectoryPage extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - RaisedButton( - color: Colors.blue, - textColor: Colors.white, + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: Colors.blue, + onPrimary: Colors.white, + ), child: Text('Press to ask user to choose a directory'), onPressed: () => _getDirectoryPath(context), ), @@ -55,7 +57,7 @@ class TextDisplay extends StatelessWidget { ), ), actions: [ - FlatButton( + TextButton( child: const Text('Close'), onPressed: () => Navigator.pop(context), ), diff --git a/packages/file_selector/file_selector/example/lib/home_page.dart b/packages/file_selector/file_selector/example/lib/home_page.dart index c37d90170f6e..1cb7ef261e88 100644 --- a/packages/file_selector/file_selector/example/lib/home_page.dart +++ b/packages/file_selector/file_selector/example/lib/home_page.dart @@ -4,6 +4,10 @@ import 'package:flutter/material.dart'; class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { + final ButtonStyle style = ElevatedButton.styleFrom( + primary: Colors.blue, + onPrimary: Colors.white, + ); return Scaffold( appBar: AppBar( title: Text('File Selector Demo Home Page'), @@ -12,37 +16,32 @@ class HomePage extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - RaisedButton( - color: Colors.blue, - textColor: Colors.white, + ElevatedButton( + style: style, child: Text('Open a text file'), onPressed: () => Navigator.pushNamed(context, '/open/text'), ), SizedBox(height: 10), - RaisedButton( - color: Colors.blue, - textColor: Colors.white, + ElevatedButton( + style: style, child: Text('Open an image'), onPressed: () => Navigator.pushNamed(context, '/open/image'), ), SizedBox(height: 10), - RaisedButton( - color: Colors.blue, - textColor: Colors.white, + ElevatedButton( + style: style, child: Text('Open multiple images'), onPressed: () => Navigator.pushNamed(context, '/open/images'), ), SizedBox(height: 10), - RaisedButton( - color: Colors.blue, - textColor: Colors.white, + ElevatedButton( + style: style, child: Text('Save a file'), onPressed: () => Navigator.pushNamed(context, '/save/text'), ), SizedBox(height: 10), - RaisedButton( - color: Colors.blue, - textColor: Colors.white, + ElevatedButton( + style: style, child: Text('Open a get directory dialog'), onPressed: () => Navigator.pushNamed(context, '/directory'), ), diff --git a/packages/file_selector/file_selector/example/lib/open_image_page.dart b/packages/file_selector/file_selector/example/lib/open_image_page.dart index 2821635fb30b..593a1d60aed8 100644 --- a/packages/file_selector/file_selector/example/lib/open_image_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_image_page.dart @@ -31,9 +31,11 @@ class OpenImagePage extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - RaisedButton( - color: Colors.blue, - textColor: Colors.white, + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: Colors.blue, + onPrimary: Colors.white, + ), child: Text('Press to open an image file(png, jpg)'), onPressed: () => _openImageFile(context), ), @@ -63,7 +65,7 @@ class ImageDisplay extends StatelessWidget { // while on other platforms it is a system path. content: kIsWeb ? Image.network(filePath) : Image.file(File(filePath)), actions: [ - FlatButton( + TextButton( child: const Text('Close'), onPressed: () { Navigator.pop(context); diff --git a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart index 7a27a0c0715f..58b59cd91b03 100644 --- a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart @@ -34,9 +34,11 @@ class OpenMultipleImagesPage extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - RaisedButton( - color: Colors.blue, - textColor: Colors.white, + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: Colors.blue, + onPrimary: Colors.white, + ), child: Text('Press to open multiple images (png, jpg)'), onPressed: () => _openImageFile(context), ), @@ -74,7 +76,7 @@ class MultipleImagesDisplay extends StatelessWidget { ), ), actions: [ - FlatButton( + TextButton( child: const Text('Close'), onPressed: () { Navigator.pop(context); diff --git a/packages/file_selector/file_selector/example/lib/open_text_page.dart b/packages/file_selector/file_selector/example/lib/open_text_page.dart index 4cb3064046fd..299d0e2dc21a 100644 --- a/packages/file_selector/file_selector/example/lib/open_text_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_text_page.dart @@ -28,9 +28,11 @@ class OpenTextPage extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - RaisedButton( - color: Colors.blue, - textColor: Colors.white, + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: Colors.blue, + onPrimary: Colors.white, + ), child: Text('Press to open a text file (json, txt)'), onPressed: () => _openTextFile(context), ), @@ -62,7 +64,7 @@ class TextDisplay extends StatelessWidget { ), ), actions: [ - FlatButton( + TextButton( child: const Text('Close'), onPressed: () => Navigator.pop(context), ), diff --git a/packages/file_selector/file_selector/example/lib/save_text_page.dart b/packages/file_selector/file_selector/example/lib/save_text_page.dart index b70231f5a410..47408662ecee 100644 --- a/packages/file_selector/file_selector/example/lib/save_text_page.dart +++ b/packages/file_selector/file_selector/example/lib/save_text_page.dart @@ -51,9 +51,11 @@ class SaveTextPage extends StatelessWidget { ), ), SizedBox(height: 10), - RaisedButton( - color: Colors.blue, - textColor: Colors.white, + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: Colors.blue, + onPrimary: Colors.white, + ), child: Text('Press to save a text file'), onPressed: () => _saveFile(), ), diff --git a/packages/file_selector/file_selector/pubspec.yaml b/packages/file_selector/file_selector/pubspec.yaml index f095ba1f6a36..a55b7f4e06e7 100644 --- a/packages/file_selector/file_selector/pubspec.yaml +++ b/packages/file_selector/file_selector/pubspec.yaml @@ -1,7 +1,7 @@ name: file_selector description: Flutter plugin for opening and saving files. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector -version: 0.7.0+1 +version: 0.7.0+2 dependencies: flutter: diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index 7783f3042dde..b23ef79651e7 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.10 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 1.0.9 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart index 37c79d302733..ae5e9f6cee3a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart @@ -54,7 +54,7 @@ class AnimateCameraState extends State { children: [ Column( children: [ - FlatButton( + TextButton( onPressed: () { mapController.animateCamera( CameraUpdate.newCameraPosition( @@ -69,7 +69,7 @@ class AnimateCameraState extends State { }, child: const Text('newCameraPosition'), ), - FlatButton( + TextButton( onPressed: () { mapController.animateCamera( CameraUpdate.newLatLng( @@ -79,7 +79,7 @@ class AnimateCameraState extends State { }, child: const Text('newLatLng'), ), - FlatButton( + TextButton( onPressed: () { mapController.animateCamera( CameraUpdate.newLatLngBounds( @@ -93,7 +93,7 @@ class AnimateCameraState extends State { }, child: const Text('newLatLngBounds'), ), - FlatButton( + TextButton( onPressed: () { mapController.animateCamera( CameraUpdate.newLatLngZoom( @@ -104,7 +104,7 @@ class AnimateCameraState extends State { }, child: const Text('newLatLngZoom'), ), - FlatButton( + TextButton( onPressed: () { mapController.animateCamera( CameraUpdate.scrollBy(150.0, -225.0), @@ -116,7 +116,7 @@ class AnimateCameraState extends State { ), Column( children: [ - FlatButton( + TextButton( onPressed: () { mapController.animateCamera( CameraUpdate.zoomBy( @@ -127,7 +127,7 @@ class AnimateCameraState extends State { }, child: const Text('zoomBy with focus'), ), - FlatButton( + TextButton( onPressed: () { mapController.animateCamera( CameraUpdate.zoomBy(-0.5), @@ -135,7 +135,7 @@ class AnimateCameraState extends State { }, child: const Text('zoomBy'), ), - FlatButton( + TextButton( onPressed: () { mapController.animateCamera( CameraUpdate.zoomIn(), @@ -143,7 +143,7 @@ class AnimateCameraState extends State { }, child: const Text('zoomIn'), ), - FlatButton( + TextButton( onPressed: () { mapController.animateCamera( CameraUpdate.zoomOut(), @@ -151,7 +151,7 @@ class AnimateCameraState extends State { }, child: const Text('zoomOut'), ), - FlatButton( + TextButton( onPressed: () { mapController.animateCamera( CameraUpdate.zoomTo(16.0), diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart index efdbe016f7c4..f194f8cb3f3b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart @@ -83,7 +83,7 @@ class _MapCoordinatesBodyState extends State<_MapCoordinatesBody> { Widget _getVisibleRegionButton() { return Padding( padding: const EdgeInsets.all(8.0), - child: RaisedButton( + child: ElevatedButton( child: const Text('Get Visible Region Bounds'), onPressed: () async { final LatLngBounds visibleRegion = diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart index f117c3a48b22..61a62ac0cf6d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart @@ -70,7 +70,7 @@ class MapUiBodyState extends State { } Widget _compassToggler() { - return FlatButton( + return TextButton( child: Text('${_compassEnabled ? 'disable' : 'enable'} compass'), onPressed: () { setState(() { @@ -81,7 +81,7 @@ class MapUiBodyState extends State { } Widget _mapToolbarToggler() { - return FlatButton( + return TextButton( child: Text('${_mapToolbarEnabled ? 'disable' : 'enable'} map toolbar'), onPressed: () { setState(() { @@ -92,7 +92,7 @@ class MapUiBodyState extends State { } Widget _latLngBoundsToggler() { - return FlatButton( + return TextButton( child: Text( _cameraTargetBounds.bounds == null ? 'bound camera target' @@ -109,7 +109,7 @@ class MapUiBodyState extends State { } Widget _zoomBoundsToggler() { - return FlatButton( + return TextButton( child: Text(_minMaxZoomPreference.minZoom == null ? 'bound zoom' : 'release zoom'), @@ -126,7 +126,7 @@ class MapUiBodyState extends State { Widget _mapTypeCycler() { final MapType nextType = MapType.values[(_mapType.index + 1) % MapType.values.length]; - return FlatButton( + return TextButton( child: Text('change map type to $nextType'), onPressed: () { setState(() { @@ -137,7 +137,7 @@ class MapUiBodyState extends State { } Widget _rotateToggler() { - return FlatButton( + return TextButton( child: Text('${_rotateGesturesEnabled ? 'disable' : 'enable'} rotate'), onPressed: () { setState(() { @@ -148,7 +148,7 @@ class MapUiBodyState extends State { } Widget _scrollToggler() { - return FlatButton( + return TextButton( child: Text('${_scrollGesturesEnabled ? 'disable' : 'enable'} scroll'), onPressed: () { setState(() { @@ -159,7 +159,7 @@ class MapUiBodyState extends State { } Widget _tiltToggler() { - return FlatButton( + return TextButton( child: Text('${_tiltGesturesEnabled ? 'disable' : 'enable'} tilt'), onPressed: () { setState(() { @@ -170,7 +170,7 @@ class MapUiBodyState extends State { } Widget _zoomToggler() { - return FlatButton( + return TextButton( child: Text('${_zoomGesturesEnabled ? 'disable' : 'enable'} zoom'), onPressed: () { setState(() { @@ -181,7 +181,7 @@ class MapUiBodyState extends State { } Widget _zoomControlsToggler() { - return FlatButton( + return TextButton( child: Text('${_zoomControlsEnabled ? 'disable' : 'enable'} zoom controls'), onPressed: () { @@ -193,7 +193,7 @@ class MapUiBodyState extends State { } Widget _indoorViewToggler() { - return FlatButton( + return TextButton( child: Text('${_indoorViewEnabled ? 'disable' : 'enable'} indoor'), onPressed: () { setState(() { @@ -204,7 +204,7 @@ class MapUiBodyState extends State { } Widget _myLocationToggler() { - return FlatButton( + return TextButton( child: Text( '${_myLocationEnabled ? 'disable' : 'enable'} my location marker'), onPressed: () { @@ -216,7 +216,7 @@ class MapUiBodyState extends State { } Widget _myLocationButtonToggler() { - return FlatButton( + return TextButton( child: Text( '${_myLocationButtonEnabled ? 'disable' : 'enable'} my location button'), onPressed: () { @@ -228,7 +228,7 @@ class MapUiBodyState extends State { } Widget _myTrafficToggler() { - return FlatButton( + return TextButton( child: Text('${_myTrafficEnabled ? 'disable' : 'enable'} my traffic'), onPressed: () { setState(() { @@ -253,7 +253,7 @@ class MapUiBodyState extends State { if (!_isMapCreated) { return null; } - return FlatButton( + return TextButton( child: Text('${_nightMode ? 'disable' : 'enable'} night mode'), onPressed: () { if (_nightMode) { diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart index 514a315e03db..262d362d8c3e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart @@ -53,7 +53,7 @@ class MoveCameraState extends State { children: [ Column( children: [ - FlatButton( + TextButton( onPressed: () { mapController.moveCamera( CameraUpdate.newCameraPosition( @@ -68,7 +68,7 @@ class MoveCameraState extends State { }, child: const Text('newCameraPosition'), ), - FlatButton( + TextButton( onPressed: () { mapController.moveCamera( CameraUpdate.newLatLng( @@ -78,7 +78,7 @@ class MoveCameraState extends State { }, child: const Text('newLatLng'), ), - FlatButton( + TextButton( onPressed: () { mapController.moveCamera( CameraUpdate.newLatLngBounds( @@ -92,7 +92,7 @@ class MoveCameraState extends State { }, child: const Text('newLatLngBounds'), ), - FlatButton( + TextButton( onPressed: () { mapController.moveCamera( CameraUpdate.newLatLngZoom( @@ -103,7 +103,7 @@ class MoveCameraState extends State { }, child: const Text('newLatLngZoom'), ), - FlatButton( + TextButton( onPressed: () { mapController.moveCamera( CameraUpdate.scrollBy(150.0, -225.0), @@ -115,7 +115,7 @@ class MoveCameraState extends State { ), Column( children: [ - FlatButton( + TextButton( onPressed: () { mapController.moveCamera( CameraUpdate.zoomBy( @@ -126,7 +126,7 @@ class MoveCameraState extends State { }, child: const Text('zoomBy with focus'), ), - FlatButton( + TextButton( onPressed: () { mapController.moveCamera( CameraUpdate.zoomBy(-0.5), @@ -134,7 +134,7 @@ class MoveCameraState extends State { }, child: const Text('zoomBy'), ), - FlatButton( + TextButton( onPressed: () { mapController.moveCamera( CameraUpdate.zoomIn(), @@ -142,7 +142,7 @@ class MoveCameraState extends State { }, child: const Text('zoomIn'), ), - FlatButton( + TextButton( onPressed: () { mapController.moveCamera( CameraUpdate.zoomOut(), @@ -150,7 +150,7 @@ class MoveCameraState extends State { }, child: const Text('zoomOut'), ), - FlatButton( + TextButton( onPressed: () { mapController.moveCamera( CameraUpdate.zoomTo(16.0), diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart index 94b60b7758f9..934d4c647aa4 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart @@ -147,7 +147,7 @@ class MarkerIconsBodyState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - FlatButton( + TextButton( child: const Text("Set Padding"), onPressed: () { setState(() { @@ -159,7 +159,7 @@ class MarkerIconsBodyState extends State { }); }, ), - FlatButton( + TextButton( child: const Text("Reset Padding"), onPressed: () { setState(() { diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart index 954d8876d1d5..7f0447e9a279 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart @@ -165,15 +165,15 @@ class PlaceCircleBodyState extends State { children: [ Column( children: [ - FlatButton( + TextButton( child: const Text('add'), onPressed: _add, ), - FlatButton( + TextButton( child: const Text('remove'), onPressed: (selectedCircle == null) ? null : _remove, ), - FlatButton( + TextButton( child: const Text('toggle visible'), onPressed: (selectedCircle == null) ? null : _toggleVisible, @@ -182,19 +182,19 @@ class PlaceCircleBodyState extends State { ), Column( children: [ - FlatButton( + TextButton( child: const Text('change stroke width'), onPressed: (selectedCircle == null) ? null : _changeStrokeWidth, ), - FlatButton( + TextButton( child: const Text('change stroke color'), onPressed: (selectedCircle == null) ? null : _changeStrokeColor, ), - FlatButton( + TextButton( child: const Text('change fill color'), onPressed: (selectedCircle == null) ? null diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart index 6808e58c199e..2c5439590443 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart @@ -77,7 +77,7 @@ class PlaceMarkerBodyState extends State { builder: (BuildContext context) { return AlertDialog( actions: [ - FlatButton( + TextButton( child: const Text('OK'), onPressed: () => Navigator.of(context).pop(), ) @@ -313,19 +313,19 @@ class PlaceMarkerBodyState extends State { children: [ Column( children: [ - FlatButton( + TextButton( child: const Text('add'), onPressed: _add, ), - FlatButton( + TextButton( child: const Text('remove'), onPressed: _remove, ), - FlatButton( + TextButton( child: const Text('change info'), onPressed: _changeInfo, ), - FlatButton( + TextButton( child: const Text('change info anchor'), onPressed: _changeInfoAnchor, ), @@ -333,35 +333,35 @@ class PlaceMarkerBodyState extends State { ), Column( children: [ - FlatButton( + TextButton( child: const Text('change alpha'), onPressed: _changeAlpha, ), - FlatButton( + TextButton( child: const Text('change anchor'), onPressed: _changeAnchor, ), - FlatButton( + TextButton( child: const Text('toggle draggable'), onPressed: _toggleDraggable, ), - FlatButton( + TextButton( child: const Text('toggle flat'), onPressed: _toggleFlat, ), - FlatButton( + TextButton( child: const Text('change position'), onPressed: _changePosition, ), - FlatButton( + TextButton( child: const Text('change rotation'), onPressed: _changeRotation, ), - FlatButton( + TextButton( child: const Text('toggle visible'), onPressed: _toggleVisible, ), - FlatButton( + TextButton( child: const Text('change zIndex'), onPressed: _changeZIndex, ), @@ -371,7 +371,7 @@ class PlaceMarkerBodyState extends State { // TODO(amirh): uncomment this one the ImageStream API change makes it to stable. // https://github.com/flutter/flutter/issues/33438 // - // FlatButton( + // TextButton( // child: const Text('set marker icon'), // onPressed: () { // _getAssetIcon(context).then( diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart index 5713f9a099e6..af5ca16bea17 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart @@ -173,20 +173,20 @@ class PlacePolygonBodyState extends State { children: [ Column( children: [ - FlatButton( + TextButton( child: const Text('add'), onPressed: _add, ), - FlatButton( + TextButton( child: const Text('remove'), onPressed: (selectedPolygon == null) ? null : _remove, ), - FlatButton( + TextButton( child: const Text('toggle visible'), onPressed: (selectedPolygon == null) ? null : _toggleVisible, ), - FlatButton( + TextButton( child: const Text('toggle geodesic'), onPressed: (selectedPolygon == null) ? null @@ -196,18 +196,18 @@ class PlacePolygonBodyState extends State { ), Column( children: [ - FlatButton( + TextButton( child: const Text('change stroke width'), onPressed: (selectedPolygon == null) ? null : _changeWidth, ), - FlatButton( + TextButton( child: const Text('change stroke color'), onPressed: (selectedPolygon == null) ? null : _changeStrokeColor, ), - FlatButton( + TextButton( child: const Text('change fill color'), onPressed: (selectedPolygon == null) ? null diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart index 35ffd33a53c2..65201d5d1839 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart @@ -232,22 +232,22 @@ class PlacePolylineBodyState extends State { children: [ Column( children: [ - FlatButton( + TextButton( child: const Text('add'), onPressed: _add, ), - FlatButton( + TextButton( child: const Text('remove'), onPressed: (selectedPolyline == null) ? null : _remove, ), - FlatButton( + TextButton( child: const Text('toggle visible'), onPressed: (selectedPolyline == null) ? null : _toggleVisible, ), - FlatButton( + TextButton( child: const Text('toggle geodesic'), onPressed: (selectedPolyline == null) ? null @@ -257,29 +257,29 @@ class PlacePolylineBodyState extends State { ), Column( children: [ - FlatButton( + TextButton( child: const Text('change width'), onPressed: (selectedPolyline == null) ? null : _changeWidth, ), - FlatButton( + TextButton( child: const Text('change color'), onPressed: (selectedPolyline == null) ? null : _changeColor, ), - FlatButton( + TextButton( child: const Text('change start cap [Android only]'), onPressed: iOSorNotSelected ? null : _changeStartCap, ), - FlatButton( + TextButton( child: const Text('change end cap [Android only]'), onPressed: iOSorNotSelected ? null : _changeEndCap, ), - FlatButton( + TextButton( child: const Text('change joint type [Android only]'), onPressed: iOSorNotSelected ? null : _changeJointType, ), - FlatButton( + TextButton( child: const Text('change pattern [Android only]'), onPressed: iOSorNotSelected ? null : _changePattern, ), diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart index 872060d86039..f470a4f9783e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart @@ -47,7 +47,7 @@ class _SnapshotBodyState extends State<_SnapshotBody> { initialCameraPosition: _kInitialPosition, ), ), - FlatButton( + TextButton( child: Text('Take a snapshot'), onPressed: () async { final imageBytes = await _mapController?.takeSnapshot(); diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 7d480ebf74f2..4faadf4c2166 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 1.0.9 +version: 1.0.10 dependencies: flutter: diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md index 25539436f8fa..4afb1a0e98bf 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.4 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 1.0.3 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart index a238ca3bf8b5..597ab563ae5b 100755 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart @@ -111,11 +111,11 @@ class SignInDemoState extends State { ), const Text('Signed in successfully.'), Text(_contactText ?? ''), - RaisedButton( + ElevatedButton( child: const Text('SIGN OUT'), onPressed: _handleSignOut, ), - RaisedButton( + ElevatedButton( child: const Text('REFRESH'), onPressed: _handleGetContact, ), @@ -126,7 +126,7 @@ class SignInDemoState extends State { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ const Text('You are not currently signed in.'), - RaisedButton( + ElevatedButton( child: const Text('SIGN IN'), onPressed: _handleSignIn, ), diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml index aecd5a9569be..9da5f0baa848 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml @@ -6,7 +6,7 @@ name: extension_google_sign_in_as_googleapis_auth description: A bridge package between google_sign_in and googleapis_auth, to create Authenticated Clients from google_sign_in user credentials. -version: 1.0.3 +version: 1.0.4 homepage: https://github.com/flutter/plugins/google_sign_in/extension_google_sign_in_as_googleapis_auth dependencies: diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md index 8a4dd6bc817e..7f5b4f2bdd17 100644 --- a/packages/google_sign_in/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.5.9 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 4.5.8 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/google_sign_in/google_sign_in/example/lib/main.dart b/packages/google_sign_in/google_sign_in/example/lib/main.dart index 6c66d56085db..a738c248a4a4 100755 --- a/packages/google_sign_in/google_sign_in/example/lib/main.dart +++ b/packages/google_sign_in/google_sign_in/example/lib/main.dart @@ -120,11 +120,11 @@ class SignInDemoState extends State { ), const Text("Signed in successfully."), Text(_contactText ?? ''), - RaisedButton( + ElevatedButton( child: const Text('SIGN OUT'), onPressed: _handleSignOut, ), - RaisedButton( + ElevatedButton( child: const Text('REFRESH'), onPressed: _handleGetContact, ), @@ -135,7 +135,7 @@ class SignInDemoState extends State { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ const Text("You are not currently signed in."), - RaisedButton( + ElevatedButton( child: const Text('SIGN IN'), onPressed: _handleSignIn, ), diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index b99b231adb9d..6e0366c790bf 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in -version: 4.5.8 +version: 4.5.9 flutter: plugin: diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 90cf80f9aee6..1b3146d532fa 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+21 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 0.6.7+20 * Updated README.md to show the new Android API requirements. diff --git a/packages/image_picker/image_picker/example/lib/main.dart b/packages/image_picker/image_picker/example/lib/main.dart index 3047ac13f235..73327ef0caa6 100755 --- a/packages/image_picker/image_picker/example/lib/main.dart +++ b/packages/image_picker/image_picker/example/lib/main.dart @@ -327,13 +327,13 @@ class _MyHomePageState extends State { ], ), actions: [ - FlatButton( + TextButton( child: const Text('CANCEL'), onPressed: () { Navigator.of(context).pop(); }, ), - FlatButton( + TextButton( child: const Text('PICK'), onPressed: () { double width = maxWidthController.text.isNotEmpty diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index d7124407d711..3c77e0c313f5 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.5+1 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 0.3.5 * [Android] Fixed: added support for the SERVICE_TIMEOUT (-3) response code. diff --git a/packages/in_app_purchase/example/lib/main.dart b/packages/in_app_purchase/example/lib/main.dart index b285b6e2bb87..911edae98cfb 100644 --- a/packages/in_app_purchase/example/lib/main.dart +++ b/packages/in_app_purchase/example/lib/main.dart @@ -245,10 +245,12 @@ class _MyAppState extends State<_MyApp> { ), trailing: previousPurchase != null ? Icon(Icons.check) - : FlatButton( + : TextButton( child: Text(productDetails.price), - color: Colors.green[800], - textColor: Colors.white, + style: TextButton.styleFrom( + backgroundColor: Colors.green[800], + primary: Colors.white, + ), onPressed: () { PurchaseParam purchaseParam = PurchaseParam( productDetails: productDetails, diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 883f8c39c273..02240ea654db 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.3.5 +version: 0.3.5+1 dependencies: async: ^2.0.8 diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index 863d72ed1da4..b27ec83d41a7 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0-nullsafety.3 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 1.0.0-nullsafety.2 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/local_auth/example/lib/main.dart b/packages/local_auth/example/lib/main.dart index 241593a08b6a..0a07e2c4437d 100644 --- a/packages/local_auth/example/lib/main.dart +++ b/packages/local_auth/example/lib/main.dart @@ -99,17 +99,17 @@ class _MyAppState extends State { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Text('Can check biometrics: $_canCheckBiometrics\n'), - RaisedButton( + ElevatedButton( child: const Text('Check biometrics'), onPressed: _checkBiometrics, ), Text('Available biometrics: $_availableBiometrics\n'), - RaisedButton( + ElevatedButton( child: const Text('Get available biometrics'), onPressed: _getAvailableBiometrics, ), Text('Current State: $_authorized\n'), - RaisedButton( + ElevatedButton( child: Text(_isAuthenticating ? 'Cancel' : 'Authenticate'), onPressed: _isAuthenticating ? _cancelAuthentication : _authenticate, diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 444eec2efa53..050cedb5d7d0 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth description: Flutter plugin for Android and iOS device authentication sensors such as Fingerprint Reader and Touch ID. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 1.0.0-nullsafety.2 +version: 1.0.0-nullsafety.3 flutter: plugin: diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index f0e3cd9bfde8..bd6c0bc651f5 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.27 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 1.6.26 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/path_provider/path_provider/example/lib/main.dart b/packages/path_provider/path_provider/example/lib/main.dart index ce496e9d4e63..8e929a6882fe 100644 --- a/packages/path_provider/path_provider/example/lib/main.dart +++ b/packages/path_provider/path_provider/example/lib/main.dart @@ -129,7 +129,7 @@ class _MyHomePageState extends State { children: [ Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: const Text('Get Temporary Directory'), onPressed: _requestTempDirectory, ), @@ -138,7 +138,7 @@ class _MyHomePageState extends State { future: _tempDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: const Text('Get Application Documents Directory'), onPressed: _requestAppDocumentsDirectory, ), @@ -147,7 +147,7 @@ class _MyHomePageState extends State { future: _appDocumentsDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: const Text('Get Application Support Directory'), onPressed: _requestAppSupportDirectory, ), @@ -156,7 +156,7 @@ class _MyHomePageState extends State { future: _appSupportDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: const Text('Get Application Library Directory'), onPressed: _requestAppLibraryDirectory, ), @@ -165,7 +165,7 @@ class _MyHomePageState extends State { future: _appLibraryDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: Text( '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Storage Directory"}'), onPressed: @@ -177,7 +177,7 @@ class _MyHomePageState extends State { Column(children: [ Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: Text( '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Storage Directories"}'), onPressed: Platform.isIOS @@ -196,7 +196,7 @@ class _MyHomePageState extends State { Column(children: [ Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: Text( '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Cache Directories"}'), onPressed: diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index 15f9c57a0c98..649b3420d72f 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 1.6.26 +version: 1.6.27 flutter: plugin: diff --git a/packages/path_provider/path_provider_macos/CHANGELOG.md b/packages/path_provider/path_provider_macos/CHANGELOG.md index d9be6859e125..b082aefd9da6 100644 --- a/packages/path_provider/path_provider_macos/CHANGELOG.md +++ b/packages/path_provider/path_provider_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.4+8 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 0.0.4+7 * Update Flutter SDK constraint. diff --git a/packages/path_provider/path_provider_macos/example/lib/main.dart b/packages/path_provider/path_provider_macos/example/lib/main.dart index 473a989914f6..1c1c90b983c3 100644 --- a/packages/path_provider/path_provider_macos/example/lib/main.dart +++ b/packages/path_provider/path_provider_macos/example/lib/main.dart @@ -98,7 +98,7 @@ class _MyHomePageState extends State { children: [ Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: const Text('Get Temporary Directory'), onPressed: _requestTempDirectory, ), @@ -107,7 +107,7 @@ class _MyHomePageState extends State { future: _tempDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: const Text('Get Application Documents Directory'), onPressed: _requestAppDocumentsDirectory, ), @@ -116,7 +116,7 @@ class _MyHomePageState extends State { future: _appDocumentsDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: const Text('Get Application Support Directory'), onPressed: _requestAppSupportDirectory, ), @@ -125,7 +125,7 @@ class _MyHomePageState extends State { future: _appSupportDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: const Text('Get Application Library Directory'), onPressed: _requestAppLibraryDirectory, ), @@ -134,7 +134,7 @@ class _MyHomePageState extends State { future: _appLibraryDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), - child: RaisedButton( + child: ElevatedButton( child: const Text('Get Downlads Directory'), onPressed: _requestDownloadsDirectory, ), diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index 05f03a7930ba..0af1cfbf0aaa 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the path_provider plugin # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.4+7 +version: 0.0.4+8 homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_macos flutter: diff --git a/packages/share/CHANGELOG.md b/packages/share/CHANGELOG.md index eef22bfcc76e..855e737a1cd4 100644 --- a/packages/share/CHANGELOG.md +++ b/packages/share/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.2 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 2.0.0-nullsafety.1 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/share/example/lib/main.dart b/packages/share/example/lib/main.dart index 7ebce3ce5591..a9ebd6bb79fb 100644 --- a/packages/share/example/lib/main.dart +++ b/packages/share/example/lib/main.dart @@ -78,7 +78,7 @@ class DemoAppState extends State { const Padding(padding: EdgeInsets.only(top: 12.0)), Builder( builder: (BuildContext context) { - return RaisedButton( + return ElevatedButton( child: const Text('Share'), onPressed: text.isEmpty && imagePaths.isEmpty ? null @@ -89,7 +89,7 @@ class DemoAppState extends State { const Padding(padding: EdgeInsets.only(top: 12.0)), Builder( builder: (BuildContext context) { - return RaisedButton( + return ElevatedButton( child: const Text('Share With Empty Origin'), onPressed: () => _onShareWithEmptyOrigin(context), ); @@ -110,11 +110,11 @@ class DemoAppState extends State { _onShare(BuildContext context) async { // A builder is used to retrieve the context immediately - // surrounding the RaisedButton. + // surrounding the ElevatedButton. // // The context's `findRenderObject` returns the first // RenderObject in its descendent tree when it's not - // a RenderObjectWidget. The RaisedButton's RenderObject + // a RenderObjectWidget. The ElevatedButton's RenderObject // has its position and size after it's built. final RenderBox box = context.findRenderObject(); diff --git a/packages/share/pubspec.yaml b/packages/share/pubspec.yaml index 07ead8f3f659..ca9b506bf35c 100644 --- a/packages/share/pubspec.yaml +++ b/packages/share/pubspec.yaml @@ -2,7 +2,7 @@ name: share description: Flutter plugin for sharing content via the platform share UI, using the ACTION_SEND intent on Android and UIActivityViewController on iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/share -version: 2.0.0-nullsafety.1 +version: 2.0.0-nullsafety.2 flutter: plugin: diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index eb08455c4785..73852cdfea12 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.0.0-nullsafety.4 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 6.0.0-nullsafety.3 * forceSafariVC should be nullable. diff --git a/packages/url_launcher/url_launcher/example/lib/main.dart b/packages/url_launcher/url_launcher/example/lib/main.dart index b3e65f38a794..0b310490d0e9 100644 --- a/packages/url_launcher/url_launcher/example/lib/main.dart +++ b/packages/url_launcher/url_launcher/example/lib/main.dart @@ -141,7 +141,7 @@ class _MyHomePageState extends State { decoration: const InputDecoration( hintText: 'Input the phone number to launch')), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _makePhoneCall('tel:$_phone'); }), @@ -151,33 +151,33 @@ class _MyHomePageState extends State { padding: EdgeInsets.all(16.0), child: Text(toLaunch), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInBrowser(toLaunch); }), child: const Text('Launch in browser'), ), const Padding(padding: EdgeInsets.all(16.0)), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInWebViewOrVC(toLaunch); }), child: const Text('Launch in app'), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInWebViewWithJavaScript(toLaunch); }), child: const Text('Launch in app(JavaScript ON)'), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInWebViewWithDomStorage(toLaunch); }), child: const Text('Launch in app(DOM storage ON)'), ), const Padding(padding: EdgeInsets.all(16.0)), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchUniversalLinkIos(toLaunch); }), @@ -185,7 +185,7 @@ class _MyHomePageState extends State { 'Launch a universal link in a native app, fallback to Safari.(Youtube)'), ), const Padding(padding: EdgeInsets.all(16.0)), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInWebViewOrVC(toLaunch); Timer(const Duration(seconds: 5), () { diff --git a/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart b/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart index eddc126a8e66..a890be7f65f1 100644 --- a/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart +++ b/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart @@ -32,7 +32,7 @@ void main() { headers: defaultHeaders)); Finder browserlaunchBtn = - find.widgetWithText(RaisedButton, 'Launch in browser'); + find.widgetWithText(ElevatedButton, 'Launch in browser'); expect(browserlaunchBtn, findsOneWidget); await tester.tap(browserlaunchBtn); diff --git a/packages/url_launcher/url_launcher/lib/src/link.dart b/packages/url_launcher/url_launcher/lib/src/link.dart index f859bc4ad2cf..14fdc9055d7a 100644 --- a/packages/url_launcher/url_launcher/lib/src/link.dart +++ b/packages/url_launcher/url_launcher/lib/src/link.dart @@ -17,7 +17,7 @@ import 'package:url_launcher_platform_interface/url_launcher_platform_interface. /// ```dart /// Link( /// uri: Uri.parse('https://flutter.dev'), -/// builder: (BuildContext context, FollowLink followLink) => RaisedButton( +/// builder: (BuildContext context, FollowLink followLink) => ElevatedButton( /// onPressed: followLink, /// // ... other properties here ... /// )}, @@ -29,7 +29,7 @@ import 'package:url_launcher_platform_interface/url_launcher_platform_interface. /// ```dart /// Link( /// uri: Uri.parse('/home'), -/// builder: (BuildContext context, FollowLink followLink) => RaisedButton( +/// builder: (BuildContext context, FollowLink followLink) => ElevatedButton( /// onPressed: followLink, /// // ... other properties here ... /// )}, diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 0ab2d410c000..871c43ced733 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 6.0.0-nullsafety.3 +version: 6.0.0-nullsafety.4 flutter: plugin: diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md index cc3ee456c938..2d5a9a7d05af 100644 --- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0-nullsafety.3 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 0.1.0-nullsafety.2 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/url_launcher/url_launcher_linux/example/lib/main.dart b/packages/url_launcher/url_launcher_linux/example/lib/main.dart index b5cce7482d07..a45862012328 100644 --- a/packages/url_launcher/url_launcher_linux/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_linux/example/lib/main.dart @@ -140,7 +140,7 @@ class _MyHomePageState extends State { decoration: const InputDecoration( hintText: 'Input the phone number to launch')), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _makePhoneCall('tel:$_phone'); }), @@ -150,33 +150,33 @@ class _MyHomePageState extends State { padding: EdgeInsets.all(16.0), child: Text(toLaunch), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInBrowser(toLaunch); }), child: const Text('Launch in browser'), ), const Padding(padding: EdgeInsets.all(16.0)), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInWebViewOrVC(toLaunch); }), child: const Text('Launch in app'), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInWebViewWithJavaScript(toLaunch); }), child: const Text('Launch in app(JavaScript ON)'), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInWebViewWithDomStorage(toLaunch); }), child: const Text('Launch in app(DOM storage ON)'), ), const Padding(padding: EdgeInsets.all(16.0)), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchUniversalLinkIos(toLaunch); }), diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml index 41366a1d4f1e..c7aac06b88e5 100644 --- a/packages/url_launcher/url_launcher_linux/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: url_launcher_linux description: Linux implementation of the url_launcher plugin. -version: 0.1.0-nullsafety.2 +version: 0.1.0-nullsafety.3 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux flutter: diff --git a/packages/url_launcher/url_launcher_macos/CHANGELOG.md b/packages/url_launcher/url_launcher_macos/CHANGELOG.md index 8a0e6575b5f2..a5477a1b1501 100644 --- a/packages/url_launcher/url_launcher_macos/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.1.0-nullsafety.2 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + # 0.1.0-nullsafety.1 * Bump SDK to support null safety. diff --git a/packages/url_launcher/url_launcher_macos/example/lib/main.dart b/packages/url_launcher/url_launcher_macos/example/lib/main.dart index b5cce7482d07..a45862012328 100644 --- a/packages/url_launcher/url_launcher_macos/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_macos/example/lib/main.dart @@ -140,7 +140,7 @@ class _MyHomePageState extends State { decoration: const InputDecoration( hintText: 'Input the phone number to launch')), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _makePhoneCall('tel:$_phone'); }), @@ -150,33 +150,33 @@ class _MyHomePageState extends State { padding: EdgeInsets.all(16.0), child: Text(toLaunch), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInBrowser(toLaunch); }), child: const Text('Launch in browser'), ), const Padding(padding: EdgeInsets.all(16.0)), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInWebViewOrVC(toLaunch); }), child: const Text('Launch in app'), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInWebViewWithJavaScript(toLaunch); }), child: const Text('Launch in app(JavaScript ON)'), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInWebViewWithDomStorage(toLaunch); }), child: const Text('Launch in app(DOM storage ON)'), ), const Padding(padding: EdgeInsets.all(16.0)), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchUniversalLinkIos(toLaunch); }), diff --git a/packages/url_launcher/url_launcher_macos/pubspec.yaml b/packages/url_launcher/url_launcher_macos/pubspec.yaml index 9ce9c9c47ea9..be2dd2739298 100644 --- a/packages/url_launcher/url_launcher_macos/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the url_launcher plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.0-nullsafety.1 +version: 0.1.0-nullsafety.2 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos flutter: diff --git a/packages/url_launcher/url_launcher_windows/CHANGELOG.md b/packages/url_launcher/url_launcher_windows/CHANGELOG.md index e9649ff6fd1e..a1998c92e2e2 100644 --- a/packages/url_launcher/url_launcher_windows/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0-nullsafety.2 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 0.1.0-nullsafety.1 * Bump Dart SDK to support null safety. diff --git a/packages/url_launcher/url_launcher_windows/example/lib/main.dart b/packages/url_launcher/url_launcher_windows/example/lib/main.dart index db59af1e5b95..e6c9f477b5a4 100644 --- a/packages/url_launcher/url_launcher_windows/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_windows/example/lib/main.dart @@ -76,7 +76,7 @@ class _MyHomePageState extends State { padding: EdgeInsets.all(16.0), child: Text(toLaunch), ), - RaisedButton( + ElevatedButton( onPressed: () => setState(() { _launched = _launchInBrowser(toLaunch); }), diff --git a/packages/url_launcher/url_launcher_windows/pubspec.yaml b/packages/url_launcher/url_launcher_windows/pubspec.yaml index d2da4c534322..f7c96bf4a1bd 100644 --- a/packages/url_launcher/url_launcher_windows/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/pubspec.yaml @@ -3,7 +3,7 @@ description: Windows implementation of the url_launcher plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.0-nullsafety.1 +version: 0.1.0-nullsafety.2 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows flutter: diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index c79b0a02bc98..f9bae8dee6e1 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.7 + +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. + ## 2.0.0-nullsafety.6 * Fix `VideoPlayerValue toString()` test. diff --git a/packages/video_player/video_player/example/lib/main.dart b/packages/video_player/video_player/example/lib/main.dart index 42eaaa578fcf..c874f740eab2 100644 --- a/packages/video_player/video_player/example/lib/main.dart +++ b/packages/video_player/video_player/example/lib/main.dart @@ -124,13 +124,13 @@ class _ExampleCard extends StatelessWidget { ), ButtonBar( children: [ - FlatButton( + TextButton( child: const Text('BUY TICKETS'), onPressed: () { /* ... */ }, ), - FlatButton( + TextButton( child: const Text('SELL TICKETS'), onPressed: () { /* ... */ diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index a8066e129608..e4694195ebde 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for displaying inline video with other Flutter # 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 2.0.0-nullsafety.6 +version: 2.0.0-nullsafety.7 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: From 105c2bca87e97569aa63a491fdada81451b03850 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 8 Jan 2021 09:04:04 -0800 Subject: [PATCH 085/924] fix version (#3399) --- packages/image_picker/image_picker/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index af409fd1c5b3..789ca13d5bcb 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+20 +version: 0.6.7+21 flutter: plugin: From d01c84cb64d12c8f5e92fd9ed44e04b6350cd973 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Fri, 8 Jan 2021 09:09:05 -0800 Subject: [PATCH 086/924] Ignore deprecated_member_use analysis lint (#3400) --- .../lib/src/path_provider_windows_real.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart index 7ff448abf020..e1063957879e 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart @@ -123,7 +123,11 @@ class PathProviderWindows extends PathProviderPlatform { GUID knownFolderID = GUID.fromString(folderID); final hr = SHGetKnownFolderPath( - knownFolderID.addressOf, KF_FLAG_DEFAULT, NULL, pathPtrPtr); + knownFolderID.addressOf, // ignore: deprecated_member_use + KF_FLAG_DEFAULT, + NULL, + pathPtrPtr, + ); if (FAILED(hr)) { if (hr == E_INVALIDARG || hr == E_FAIL) { From b3bc1f2e246f78593b40c6d6cfbbd1ae36c9324b Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 8 Jan 2021 14:12:00 -0500 Subject: [PATCH 087/924] [battery] Migrate battery_plugin_interface to null safety (#3366) --- .../battery/battery_platform_interface/CHANGELOG.md | 4 ++++ .../lib/method_channel/method_channel_battery.dart | 9 +++++---- .../battery/battery_platform_interface/pubspec.yaml | 12 ++++++------ .../test/method_channel_battery_test.dart | 10 +++++----- script/nnbd_plugins.sh | 1 + 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/battery/battery_platform_interface/CHANGELOG.md b/packages/battery/battery_platform_interface/CHANGELOG.md index 09ac38cc5b4b..6fc7228a89f9 100644 --- a/packages/battery/battery_platform_interface/CHANGELOG.md +++ b/packages/battery/battery_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.0.1 - Update Flutter SDK constraint. diff --git a/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart b/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart index 4a3365cc2475..739812dc95e5 100644 --- a/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart +++ b/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart @@ -11,11 +11,11 @@ import '../battery_platform_interface.dart'; class MethodChannelBattery extends BatteryPlatform { /// The method channel used to interact with the native platform. @visibleForTesting - MethodChannel channel = MethodChannel('plugins.flutter.io/battery'); + final MethodChannel channel = MethodChannel('plugins.flutter.io/battery'); /// The event channel used to interact with the native platform. @visibleForTesting - EventChannel eventChannel = EventChannel('plugins.flutter.io/charging'); + final EventChannel eventChannel = EventChannel('plugins.flutter.io/charging'); /// Method channel for getting battery level. Future batteryLevel() async { @@ -23,7 +23,7 @@ class MethodChannelBattery extends BatteryPlatform { } /// Stream variable for storing battery state. - Stream _onBatteryStateChanged; + Stream? _onBatteryStateChanged; /// Event channel for getting battery change state. Stream onBatteryStateChanged() { @@ -32,7 +32,8 @@ class MethodChannelBattery extends BatteryPlatform { .receiveBroadcastStream() .map((dynamic event) => _parseBatteryState(event)); } - return _onBatteryStateChanged; + + return _onBatteryStateChanged!; } } diff --git a/packages/battery/battery_platform_interface/pubspec.yaml b/packages/battery/battery_platform_interface/pubspec.yaml index e88ef378be6e..c7c4f5e8395e 100644 --- a/packages/battery/battery_platform_interface/pubspec.yaml +++ b/packages/battery/battery_platform_interface/pubspec.yaml @@ -3,20 +3,20 @@ description: A common platform interface for the battery plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/battery # 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.0.1 +version: 2.0.0-nullsafety dependencies: flutter: sdk: flutter - meta: ^1.1.8 - plugin_platform_interface: ^1.0.2 + meta: ^1.3.0-nullsafety + plugin_platform_interface: ^1.1.0-nullsafety.1 dev_dependencies: flutter_test: sdk: flutter - mockito: ^4.1.1 - pedantic: ^1.8.0 + mockito: ^5.0.0-nullsafety.0 + pedantic: ^1.10.0-nullsafety environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.9.1+hotfix.4" diff --git a/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart b/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart index 65323e4044de..2b17cf97e711 100644 --- a/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart +++ b/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart @@ -12,8 +12,8 @@ import 'package:battery_platform_interface/method_channel/method_channel_battery void main() { TestWidgetsFlutterBinding.ensureInitialized(); - group("$MethodChannelBattery", () { - MethodChannelBattery methodChannelBattery; + group('$MethodChannelBattery', () { + late MethodChannelBattery methodChannelBattery; setUp(() async { methodChannelBattery = MethodChannelBattery(); @@ -32,7 +32,7 @@ void main() { .setMockMethodCallHandler((MethodCall methodCall) async { switch (methodCall.method) { case 'listen': - await ServicesBinding.instance.defaultBinaryMessenger + await ServicesBinding.instance!.defaultBinaryMessenger .handlePlatformMessage( methodChannelBattery.eventChannel.name, methodChannelBattery.eventChannel.codec @@ -48,13 +48,13 @@ void main() { }); /// Test for batetry level call. - test("getBatteryLevel", () async { + test('getBatteryLevel', () async { final int result = await methodChannelBattery.batteryLevel(); expect(result, 90); }); /// Test for battery changed state call. - test("onBatteryChanged", () async { + test('onBatteryChanged', () async { final BatteryState result = await methodChannelBattery.onBatteryStateChanged().first; expect(result, BatteryState.full); diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 0cab28abe2ab..7bc5ac35a3a5 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -6,6 +6,7 @@ readonly NNBD_PLUGINS_LIST=( "android_intent" + "battery" "connectivity" "device_info" "flutter_plugin_android_lifecycle" From 34faaafe507126c2ec636759df323b256cd6920f Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Fri, 8 Jan 2021 16:44:05 -0800 Subject: [PATCH 088/924] Sync the PR template to the new style (#3397) --- .github/PULL_REQUEST_TEMPLATE.md | 43 ++++++++++++++------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 083e125b32d2..741216982d35 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,37 +1,32 @@ -## Description +*Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.* -*Replace this paragraph with a description of what this PR is doing. If you're modifying existing behavior, describe the existing behavior, how this PR is changing it, and what motivated the change.* +*List which issues are fixed by this PR. You must list at least one issue.* -## Related Issues +*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* -*Replace this paragraph with a list of issues related to this PR from the [issue database](https://github.com/flutter/flutter/issues). Indicate, which of these issues are resolved or fixed by this PR. Note that you'll have to prefix the issue numbers with flutter/flutter#.* - -## Checklist - -Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (`[x]`). This will ensure a smooth and quick review process. +## Pre-launch Checklist +- [ ] The title of the PR starts with the name of the plugin surrounded by square brackets, e.g. `[shared_preferences]` - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. -- [ ] My PR includes unit or integration tests for *all* changed/updated/fixed behaviors (See [Contributor Guide]). -- [ ] All existing and new tests are passing. -- [ ] I updated/added relevant documentation (doc comments with `///`). -- [ ] The analyzer (`flutter analyze`) does not report any problems on my PR. -- [ ] I read and followed the [Flutter Style Guide]. -- [ ] The title of the PR starts with the name of the plugin surrounded by square brackets, e.g. [shared_preferences] +- [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. +- [ ] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. +- [ ] I listed at least one issue that this PR fixes in the description above. +- [ ] I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test exempt. - [ ] I updated pubspec.yaml with an appropriate new version according to the [pub versioning philosophy]. - [ ] I updated CHANGELOG.md to add a description of the change. +- [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I signed the [CLA]. -- [ ] I am willing to follow-up on review comments in a timely manner. - -## Breaking Change - -Does your PR require plugin users to manually update their apps to accommodate your change? +- [ ] All existing and new tests are passing. -- [ ] Yes, this is a breaking change (please indicate a breaking change in CHANGELOG.md and increment major revision). -- [ ] No, this is *not* a breaking change. +If you need help, consider asking for advice on the #hackers-new channel on [Discord]. -[issue database]: https://github.com/flutter/flutter/issues -[Contributor Guide]: https://github.com/flutter/plugins/blob/master/CONTRIBUTING.md +[Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview +[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo -[pub versioning philosophy]: https://www.dartlang.org/tools/pub/versioning +[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/master/CONTRIBUTING.md#style [CLA]: https://cla.developers.google.com/ +[flutter/tests]: https://github.com/flutter/tests +[breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes +[Discord]: https://github.com/flutter/flutter/wiki/Chat +[pub versioning philosophy]: https://dart.dev/tools/pub/versioning From da1b4638b750a5ff832d7be86a42831c42c6d6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Mon, 11 Jan 2021 14:56:10 +0100 Subject: [PATCH 089/924] [camera] Implemented ImageStream ImageFormat setting for Dart and Android (#3359) * Implemented ImageStream ImageFormat setting for Dart and Android * Fixed formatting and toString test * Apply suggestions from code review * Removed imageStreamImageFormat from CameraValue * Removed imageStreamImageFormat from CameraValue * Removed imageStreamImageFormat from CameraValue * fixed formatting * fixed formatting * fixed formatting * WIP: iOS implementation * Imaplemented suggested changes, added tests. * iOS switch case videoFormat * Added imageFormatGroup to initialize * Apply suggestions from code review Co-authored-by: Maurits van Beusekom * Added period to sentence * Moved ImageFormatGroup to platform_interface; Added extension to convert ImageFormatGroup to name; Changed int to ImageFormatGroup for initializeCamera * Fixed test * Separated Android and iOS in name extension * Clarified returns on name extension * updated Android implementation to support String output * removed getOrDefault * Updated camera implementation to use ImageFormatGroupName; Updated to Dart 2.7.0 to support extensions; * removed unused import * Export image_format_group.dart in types.dart * Changed enum values to lowercase * Added ImageFormatGroup test * Fixed formatting * made enum strings lowercase * Removed target platform switch. * Fixed formatting * Updated Android implementation * Updated iOS implementation * updated log message for unsupported ImageFormatGroup * Updated Android implementation * fixed period in docs * Switch change to if-statement * Moved switching videoFormat to method in iOS * Implemented feedback * fixed formatting * fixed mistakingly removed bracket * fixed formatting * Updated version * Updated version * fixed formatting * Define TAG correctly Co-authored-by: anniek Co-authored-by: Maurits van Beusekom Co-authored-by: Maurits van Beusekom --- packages/camera/camera/CHANGELOG.md | 5 ++- .../io/flutter/plugins/camera/Camera.java | 21 +++++++++-- .../plugins/camera/MethodCallHandlerImpl.java | 2 +- packages/camera/camera/example/lib/main.dart | 1 + packages/camera/camera/example/pubspec.yaml | 2 +- .../camera/camera/ios/Classes/CameraPlugin.m | 16 +++++++- packages/camera/camera/lib/camera.dart | 3 +- .../camera/lib/src/camera_controller.dart | 11 +++++- .../camera/camera/lib/src/camera_image.dart | 37 ++++--------------- packages/camera/camera/pubspec.yaml | 6 +-- .../camera/camera/test/camera_image_test.dart | 1 + packages/camera/camera/test/camera_test.dart | 21 +++++++++++ 12 files changed, 85 insertions(+), 41 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 2f9b5399d6dd..0ba77e5ee1d5 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.6.5 + +* Adds ImageFormat selection for ImageStream and Video(iOS only). ## 0.6.4+5 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. @@ -16,7 +19,7 @@ ## 0.6.4+1 -* Added closeCaptureSession() to stopVideoRecording in Camera.java to fix an Android 6 crash +* Added closeCaptureSession() to stopVideoRecording in Camera.java to fix an Android 6 crash. ## 0.6.4 diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 40656cbabcf1..fd7f4d67fa04 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -67,6 +67,8 @@ interface ErrorCallback { } public class Camera { + private static final String TAG = "Camera"; + private final SurfaceTextureEntry flutterTexture; private final CameraManager cameraManager; private final OrientationEventListener orientationEventListener; @@ -99,6 +101,14 @@ public class Camera { private boolean useAutoFocus = true; private Range fpsRange; + private static final HashMap supportedImageFormats; + // Current supported outputs + static { + supportedImageFormats = new HashMap<>(); + supportedImageFormats.put("yuv420", 35); + supportedImageFormats.put("jpeg", 256); + } + public Camera( final Activity activity, final SurfaceTextureEntry flutterTexture, @@ -183,15 +193,20 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException { } @SuppressLint("MissingPermission") - public void open() throws CameraAccessException { + public void open(String imageFormatGroup) throws CameraAccessException { pictureImageReader = ImageReader.newInstance( captureSize.getWidth(), captureSize.getHeight(), ImageFormat.JPEG, 2); + Integer imageFormat = supportedImageFormats.get(imageFormatGroup); + if (imageFormat == null) { + Log.w(TAG, "The selected imageFormatGroup is not supported by Android. Defaulting to yuv420"); + imageFormat = ImageFormat.YUV_420_888; + } + // Used to steam image byte data to dart side. imageStreamReader = - ImageReader.newInstance( - previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2); + ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(), imageFormat, 2); cameraManager.openCamera( cameraName, diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 2ceff845ed4b..95c0b198e43d 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -80,7 +80,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) { if (camera != null) { try { - camera.open(); + camera.open(call.argument("imageFormatGroup")); result.success(null); } catch (Exception e) { handleException(e, result); diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 5324e3d09383..6eaf66a256de 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -486,6 +486,7 @@ class _CameraExampleHomeState extends State cameraDescription, ResolutionPreset.medium, enableAudio: enableAudio, + imageFormatGroup: ImageFormatGroup.jpeg, ); // If the controller is updated then update the UI. diff --git a/packages/camera/camera/example/pubspec.yaml b/packages/camera/camera/example/pubspec.yaml index 0d1f03bef437..5d59ebf75c62 100644 --- a/packages/camera/camera/example/pubspec.yaml +++ b/packages/camera/camera/example/pubspec.yaml @@ -22,5 +22,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.0.0-dev.28.0 <3.0.0" + sdk: ">=2.7.0 <3.0.0" flutter: ">=1.9.1+hotfix.4 <2.0.0" diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index 816792e2fc1d..d1ef0e5c923e 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -162,6 +162,17 @@ static FlashMode getFlashModeForString(NSString *mode) { } } +static OSType getVideoFormatFromString(NSString *videoFormatString) { + if ([videoFormatString isEqualToString:@"bgra8888"]) { + return kCVPixelFormatType_32BGRA; + } else if ([videoFormatString isEqualToString:@"yuv420"]) { + return kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; + } else { + NSLog(@"The selected imageFormatGroup is not supported by iOS. Defaulting to brga8888"); + return kCVPixelFormatType_32BGRA; + } +} + static AVCaptureFlashMode getAVCaptureFlashModeForFlashMode(FlashMode mode) { switch (mode) { case FlashModeOff: @@ -296,7 +307,7 @@ @implementation FLTCam { dispatch_queue_t _dispatchQueue; } // Format used for video and image streaming. -FourCharCode const videoFormat = kCVPixelFormatType_32BGRA; +FourCharCode videoFormat = kCVPixelFormatType_32BGRA; NSString *const errorMethod = @"error"; - (instancetype)initWithCameraName:(NSString *)cameraName @@ -1147,6 +1158,9 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re NSDictionary *argsMap = call.arguments; NSUInteger cameraId = ((NSNumber *)argsMap[@"cameraId"]).unsignedIntegerValue; if ([@"initialize" isEqualToString:call.method]) { + NSString *videoFormatValue = ((NSString *)argsMap[@"imageFormatGroup"]); + videoFormat = getVideoFormatFromString(videoFormatValue); + __weak CameraPlugin *weakSelf = self; _camera.onFrameAvailable = ^{ [weakSelf.registry textureFrameAvailable:cameraId]; diff --git a/packages/camera/camera/lib/camera.dart b/packages/camera/camera/lib/camera.dart index 55e7aa9444aa..8058ea8f9cb1 100644 --- a/packages/camera/camera/lib/camera.dart +++ b/packages/camera/camera/lib/camera.dart @@ -14,4 +14,5 @@ export 'package:camera_platform_interface/camera_platform_interface.dart' FlashMode, ExposureMode, ResolutionPreset, - XFile; + XFile, + ImageFormatGroup; diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index c1f44bc9630a..53b990e783f3 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -160,6 +160,7 @@ class CameraController extends ValueNotifier { this.description, this.resolutionPreset, { this.enableAudio = true, + this.imageFormatGroup, }) : super(const CameraValue.uninitialized()); /// The properties of the camera device controlled by this controller. @@ -176,6 +177,11 @@ class CameraController extends ValueNotifier { /// Whether to include audio when recording a video. final bool enableAudio; + /// The [ImageFormatGroup] describes the output of the raw image format. + /// + /// When null the imageFormat will fallback to the platforms default. + final ImageFormatGroup imageFormatGroup; + int _cameraId; bool _isDisposed = false; StreamSubscription _imageStreamSubscription; @@ -217,7 +223,10 @@ class CameraController extends ValueNotifier { _initializeCompleter.complete(event); })); - await CameraPlatform.instance.initializeCamera(_cameraId); + await CameraPlatform.instance.initializeCamera( + _cameraId, + imageFormatGroup: imageFormatGroup, + ); value = value.copyWith( isInitialized: true, diff --git a/packages/camera/camera/lib/src/camera_image.dart b/packages/camera/camera/lib/src/camera_image.dart index ca8115eb758d..dffa5066d14f 100644 --- a/packages/camera/camera/lib/src/camera_image.dart +++ b/packages/camera/camera/lib/src/camera_image.dart @@ -6,6 +6,7 @@ import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:camera_platform_interface/camera_platform_interface.dart'; /// A single color plane of image data. /// @@ -41,32 +42,6 @@ class Plane { final int width; } -// TODO:(bmparr) Turn [ImageFormatGroup] to a class with int values. -/// Group of image formats that are comparable across Android and iOS platforms. -enum ImageFormatGroup { - /// The image format does not fit into any specific group. - unknown, - - /// Multi-plane YUV 420 format. - /// - /// This format is a generic YCbCr format, capable of describing any 4:2:0 - /// chroma-subsampled planar or semiplanar buffer (but not fully interleaved), - /// with 8 bits per color sample. - /// - /// On Android, this is `android.graphics.ImageFormat.YUV_420_888`. See - /// https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888 - /// - /// On iOS, this is `kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange`. See - /// https://developer.apple.com/documentation/corevideo/1563591-pixel_format_identifiers/kcvpixelformattype_420ypcbcr8biplanarvideorange?language=objc - yuv420, - - /// 32-bit BGRA. - /// - /// On iOS, this is `kCVPixelFormatType_32BGRA`. See - /// https://developer.apple.com/documentation/corevideo/1563591-pixel_format_identifiers/kcvpixelformattype_32bgra?language=objc - bgra8888, -} - /// Describes how pixels are represented in an image. class ImageFormat { ImageFormat._fromPlatformData(this.raw) : group = _asImageFormatGroup(raw); @@ -86,9 +61,13 @@ class ImageFormat { ImageFormatGroup _asImageFormatGroup(dynamic rawFormat) { if (defaultTargetPlatform == TargetPlatform.android) { - // android.graphics.ImageFormat.YUV_420_888 - if (rawFormat == 35) { - return ImageFormatGroup.yuv420; + switch (rawFormat) { + // android.graphics.ImageFormat.YUV_420_888 + case 35: + return ImageFormatGroup.yuv420; + // android.graphics.ImageFormat.JPEG + case 256: + return ImageFormatGroup.jpeg; } } diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 50f504a8d0e8..7c275c2268cd 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,13 +2,13 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.4+5 +version: 0.6.5 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: flutter: sdk: flutter - camera_platform_interface: ^1.2.0 + camera_platform_interface: ^1.3.0 pedantic: ^1.8.0 dev_dependencies: @@ -31,5 +31,5 @@ flutter: pluginClass: CameraPlugin environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.7.0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/camera/camera/test/camera_image_test.dart b/packages/camera/camera/test/camera_image_test.dart index c8f808f2c1a1..c7f8e4320434 100644 --- a/packages/camera/camera/test/camera_image_test.dart +++ b/packages/camera/camera/test/camera_image_test.dart @@ -5,6 +5,7 @@ import 'dart:typed_data'; import 'package:camera/camera.dart'; +import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 5a4a7fc8771b..4f2109371392 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -8,6 +8,7 @@ import 'dart:ui'; import 'package:camera/camera.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -164,6 +165,22 @@ void main() { mockPlatformException = false; }); + test('initialize() sets imageFormat', () async { + debugDefaultTargetPlatformOverride = TargetPlatform.android; + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max, + imageFormatGroup: ImageFormatGroup.yuv420, + ); + await cameraController.initialize(); + verify(CameraPlatform.instance + .initializeCamera(13, imageFormatGroup: ImageFormatGroup.yuv420)) + .called(1); + }); + test('prepareForVideoRecording() calls $CameraPlatform ', () async { CameraController cameraController = CameraController( CameraDescription( @@ -1004,6 +1021,10 @@ class MockCameraPlatform extends Mock with MockPlatformInterfaceMixin implements CameraPlatform { @override + Future initializeCamera(int cameraId, + {ImageFormatGroup imageFormatGroup}); + + @override Future> availableCameras() => Future.value(mockAvailableCameras); From 71a831790220f898bf8120c8a23840ac6e742db5 Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Mon, 11 Jan 2021 17:20:24 +0100 Subject: [PATCH 090/924] [camera] Add iOS and Android implementations for managing auto focus. (#3370) * Added platform interface methods for setting auto exposure. * Added platform interface methods for setting auto exposure. * Remove workspace files * Added auto exposure implementations for Android and iOS * Added platform interface methods for managing auto focus. * Formatted code * Export focus mode * Add Android and iOS implementations (WIP) * Update platform interface for changes to autofocus methods * WIP * Revert "Update platform interface for changes to autofocus methods" This reverts commit bdeed1d213a9f106d0bd80b8905c0ae3af29886e. * Finish android implementation * Fix iOS implementation * iOS fix for setting the exposure point * Removed unnecessary check * Updated changelog and pubspec.yaml * Updated changelog and pubspec.yaml * Update platform interface dependency * Implement PR feedback * Restore test * Revert test change * Update camera pubspec * Update platform interface to prevent breaking changes with current master * Update test to match platform interface updates * Code format * Fixed compilation error * Fix formatting * Add missing license headers to java source files. * Update platform interface dependency * Change fps range determination * Fix analysis warnings Co-authored-by: Maurits van Beusekom --- packages/camera/camera/CHANGELOG.md | 5 + .../io/flutter/plugins/camera/Camera.java | 115 ++++++++++++++--- .../plugins/camera/CameraPermissions.java | 4 + .../flutter/plugins/camera/CameraRegions.java | 17 +++ .../flutter/plugins/camera/CameraUtils.java | 4 + .../io/flutter/plugins/camera/CameraZoom.java | 4 + .../flutter/plugins/camera/DartMessenger.java | 13 +- .../plugins/camera/MethodCallHandlerImpl.java | 36 ++++++ .../plugins/camera/PictureCaptureRequest.java | 4 + .../camera/media/MediaRecorderBuilder.java | 1 + .../plugins/camera/types/ExposureMode.java | 4 + .../plugins/camera/types/FlashMode.java | 4 + .../plugins/camera/types/FocusMode.java | 29 +++++ .../camera/types/ResolutionPreset.java | 4 + .../plugins/camera/CameraPermissionsTest.java | 4 + .../plugins/camera/CameraRegionsTest.java | 21 ++++ .../plugins/camera/CameraZoomTest.java | 4 + .../plugins/camera/DartMessengerTest.java | 9 +- .../camera/PictureCaptureRequestTest.java | 4 + .../media/MediaRecorderBuilderTest.java | 4 + .../camera/types/ExposureModeTest.java | 4 + .../plugins/camera/types/FlashModeTest.java | 4 + .../plugins/camera/types/FocusModeTest.java | 34 +++++ packages/camera/camera/example/lib/main.dart | 104 ++++++++++++++- .../camera/camera/ios/Classes/CameraPlugin.m | 118 ++++++++++++++++-- packages/camera/camera/lib/camera.dart | 1 + .../camera/lib/src/camera_controller.dart | 53 +++++++- packages/camera/camera/pubspec.yaml | 4 +- packages/camera/camera/test/camera_test.dart | 11 +- .../camera/camera/test/camera_value_test.dart | 5 +- 30 files changed, 591 insertions(+), 37 deletions(-) create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 0ba77e5ee1d5..1a2b03d93a6a 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,6 +1,11 @@ +## 0.6.6 + +* Adds auto focus support for Android and iOS implementations. + ## 0.6.5 * Adds ImageFormat selection for ImageStream and Video(iOS only). + ## 0.6.4+5 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index fd7f4d67fa04..3fc702a2a879 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import static android.view.OrientationEventListener.ORIENTATION_UNKNOWN; @@ -47,6 +51,7 @@ import io.flutter.plugins.camera.media.MediaRecorderBuilder; import io.flutter.plugins.camera.types.ExposureMode; import io.flutter.plugins.camera.types.FlashMode; +import io.flutter.plugins.camera.types.FocusMode; import io.flutter.plugins.camera.types.ResolutionPreset; import io.flutter.view.TextureRegistry.SurfaceTextureEntry; import java.io.File; @@ -95,6 +100,7 @@ public class Camera { private int currentOrientation = ORIENTATION_UNKNOWN; private FlashMode flashMode; private ExposureMode exposureMode; + private FocusMode focusMode; private PictureCaptureRequest pictureCaptureRequest; private CameraRegions cameraRegions; private int exposureOffset; @@ -128,6 +134,7 @@ public Camera( this.applicationContext = activity.getApplicationContext(); this.flashMode = FlashMode.auto; this.exposureMode = ExposureMode.auto; + this.focusMode = FocusMode.auto; this.exposureOffset = 0; orientationEventListener = new OrientationEventListener(activity.getApplicationContext()) { @@ -168,7 +175,7 @@ private void initFps(CameraCharacteristics cameraCharacteristics) { int upper = range.getUpper(); Log.i("Camera", "[FPS Range Available] is:" + range); if (upper >= 10) { - if (fpsRange == null || upper < fpsRange.getUpper()) { + if (fpsRange == null || upper > fpsRange.getUpper()) { fpsRange = range; } } @@ -221,7 +228,9 @@ public void onOpened(@NonNull CameraDevice device) { previewSize.getWidth(), previewSize.getHeight(), exposureMode, - isExposurePointSupported()); + focusMode, + isExposurePointSupported(), + isFocusPointSupported()); } catch (CameraAccessException e) { dartMessenger.sendCameraErrorEvent(e.getMessage()); close(); @@ -309,7 +318,7 @@ public void onConfigured(@NonNull CameraCaptureSession session) { cameraCaptureSession = session; updateFpsRange(); - updateAutoFocus(); + updateFocus(focusMode); updateFlash(flashMode); updateExposure(exposureMode); @@ -510,7 +519,7 @@ private void runPictureAutoFocus() { assert (pictureCaptureRequest != null); pictureCaptureRequest.setState(PictureCaptureRequest.State.focusing); - lockAutoFocus(); + lockAutoFocus(pictureCaptureCallback); } private void runPicturePreCapture() { @@ -570,7 +579,7 @@ public void onCaptureCompleted( } } - private void lockAutoFocus() { + private void lockAutoFocus(CaptureCallback callback) { captureRequestBuilder.set( CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); @@ -581,7 +590,7 @@ private void lockAutoFocus() { private void unlockAutoFocus() { captureRequestBuilder.set( CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL); - updateAutoFocus(); + updateFocus(focusMode); try { cameraCaptureSession.capture(captureRequestBuilder.build(), null, null); } catch (CameraAccessException ignored) { @@ -764,25 +773,72 @@ public void setExposurePoint(@NonNull final Result result, Double x, Double y) "setExposurePointFailed", "Device does not have exposure point capabilities", null); return; } - // Check if we are doing a reset or not - if (x == null || y == null) { - x = 0.5; - y = 0.5; - } - // Get the current region boundaries. - Size maxBoundaries = getRegionBoundaries(); - if (maxBoundaries == null) { + // Check if the current region boundaries are known + if (cameraRegions.getMaxBoundaries() == null) { result.error("setExposurePointFailed", "Could not determine max region boundaries", null); return; } // Set the metering rectangle - cameraRegions.setAutoExposureMeteringRectangleFromPoint(x, y); + if (x == null || y == null) cameraRegions.resetAutoExposureMeteringRectangle(); + else cameraRegions.setAutoExposureMeteringRectangleFromPoint(x, y); // Apply it updateExposure(exposureMode); refreshPreviewCaptureSession( () -> result.success(null), (code, message) -> result.error("CameraAccess", message, null)); } + public void setFocusMode(@NonNull final Result result, FocusMode mode) + throws CameraAccessException { + this.focusMode = mode; + + updateFocus(mode); + + switch (mode) { + case auto: + refreshPreviewCaptureSession( + null, (code, message) -> result.error("setFocusMode", message, null)); + break; + case locked: + lockAutoFocus( + new CaptureCallback() { + @Override + public void onCaptureCompleted( + @NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, + @NonNull TotalCaptureResult result) { + unlockAutoFocus(); + } + }); + break; + } + result.success(null); + } + + public void setFocusPoint(@NonNull final Result result, Double x, Double y) + throws CameraAccessException { + // Check if focus point functionality is available. + if (!isFocusPointSupported()) { + result.error("setFocusPointFailed", "Device does not have focus point capabilities", null); + return; + } + + // Check if the current region boundaries are known + if (cameraRegions.getMaxBoundaries() == null) { + result.error("setFocusPointFailed", "Could not determine max region boundaries", null); + return; + } + + // Set the metering rectangle + if (x == null || y == null) { + cameraRegions.resetAutoFocusMeteringRectangle(); + } else { + cameraRegions.setAutoFocusMeteringRectangleFromPoint(x, y); + } + + // Apply the new metering rectangle + setFocusMode(result, focusMode); + } + @TargetApi(VERSION_CODES.P) private boolean supportsDistortionCorrection() throws CameraAccessException { int[] availableDistortionCorrectionModes = @@ -832,6 +888,14 @@ private boolean isExposurePointSupported() throws CameraAccessException { return supportedRegions != null && supportedRegions > 0; } + private boolean isFocusPointSupported() throws CameraAccessException { + Integer supportedRegions = + cameraManager + .getCameraCharacteristics(cameraDevice.getId()) + .get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF); + return supportedRegions != null && supportedRegions > 0; + } + public double getMinExposureOffset() throws CameraAccessException { Range range = cameraManager @@ -912,7 +976,7 @@ private void updateFpsRange() { captureRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange); } - private void updateAutoFocus() { + private void updateFocus(FocusMode mode) { if (useAutoFocus) { int[] modes = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); // Auto focus is not supported @@ -923,8 +987,25 @@ private void updateAutoFocus() { captureRequestBuilder.set( CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); } else { + // Applying auto focus + switch (mode) { + case locked: + captureRequestBuilder.set( + CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO); + break; + case auto: + captureRequestBuilder.set( + CaptureRequest.CONTROL_AF_MODE, + recordingVideo + ? CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO + : CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + default: + break; + } + MeteringRectangle afRect = cameraRegions.getAFMeteringRectangle(); captureRequestBuilder.set( - CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + CaptureRequest.CONTROL_AF_REGIONS, + afRect == null ? null : new MeteringRectangle[] {afRect}); } } else { captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java index b4569d2fec07..3529e69a2b0b 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import android.Manifest; diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java index 2285f67ad25c..04412a56631f 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import android.hardware.camera2.params.MeteringRectangle; @@ -5,6 +9,7 @@ public final class CameraRegions { private MeteringRectangle aeMeteringRectangle; + private MeteringRectangle afMeteringRectangle; private Size maxBoundaries; public CameraRegions(Size maxBoundaries) { @@ -17,6 +22,10 @@ public MeteringRectangle getAEMeteringRectangle() { return aeMeteringRectangle; } + public MeteringRectangle getAFMeteringRectangle() { + return afMeteringRectangle; + } + public Size getMaxBoundaries() { return this.maxBoundaries; } @@ -29,6 +38,14 @@ public void setAutoExposureMeteringRectangleFromPoint(double x, double y) { this.aeMeteringRectangle = getMeteringRectangleForPoint(maxBoundaries, x, y); } + public void resetAutoFocusMeteringRectangle() { + this.afMeteringRectangle = null; + } + + public void setAutoFocusMeteringRectangleFromPoint(double x, double y) { + this.afMeteringRectangle = getMeteringRectangleForPoint(maxBoundaries, x, y); + } + public MeteringRectangle getMeteringRectangleForPoint(Size maxBoundaries, double x, double y) { assert (x >= 0 && x <= 1); assert (y >= 0 && y <= 1); diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java index 3b665d6b24f2..6f04dc80e102 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import android.app.Activity; diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java index a179f12db224..5eed9f4734b7 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import android.graphics.Rect; diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java index 2fee13816b51..ec68ac0acda3 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import android.text.TextUtils; @@ -5,6 +9,7 @@ import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.camera.types.ExposureMode; +import io.flutter.plugins.camera.types.FocusMode; import java.util.HashMap; import java.util.Map; @@ -25,11 +30,15 @@ void sendCameraInitializedEvent( Integer previewWidth, Integer previewHeight, ExposureMode exposureMode, - Boolean exposurePointSupported) { + FocusMode focusMode, + Boolean exposurePointSupported, + Boolean focusPointSupported) { assert (previewWidth != null); assert (previewHeight != null); assert (exposureMode != null); + assert (focusMode != null); assert (exposurePointSupported != null); + assert (focusPointSupported != null); this.send( EventType.INITIALIZED, new HashMap() { @@ -37,7 +46,9 @@ void sendCameraInitializedEvent( put("previewWidth", previewWidth.doubleValue()); put("previewHeight", previewHeight.doubleValue()); put("exposureMode", exposureMode.toString()); + put("focusMode", focusMode.toString()); put("exposurePointSupported", exposurePointSupported); + put("focusPointSupported", focusPointSupported); } }); } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 95c0b198e43d..36048dbb5176 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import android.app.Activity; @@ -12,6 +16,7 @@ import io.flutter.plugins.camera.CameraPermissions.PermissionsRegistry; import io.flutter.plugins.camera.types.ExposureMode; import io.flutter.plugins.camera.types.FlashMode; +import io.flutter.plugins.camera.types.FocusMode; import io.flutter.view.TextureRegistry; import java.util.HashMap; import java.util.Map; @@ -206,6 +211,37 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) } break; } + case "setFocusMode": + { + String modeStr = call.argument("mode"); + FocusMode mode = FocusMode.getValueForString(modeStr); + if (mode == null) { + result.error("setFocusModeFailed", "Unknown focus mode " + modeStr, null); + return; + } + try { + camera.setFocusMode(result, mode); + } catch (Exception e) { + handleException(e, result); + } + break; + } + case "setFocusPoint": + { + Boolean reset = call.argument("reset"); + Double x = null; + Double y = null; + if (reset == null || !reset) { + x = call.argument("x"); + y = call.argument("y"); + } + try { + camera.setFocusPoint(result, x, y); + } catch (Exception e) { + handleException(e, result); + } + break; + } case "startImageStream": { try { diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java index 1103b8583ad6..189f2f1490dc 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import androidx.annotation.Nullable; diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java index b2309c83a4a5..4c3fb3add230 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java @@ -1,6 +1,7 @@ // Copyright 2019 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. + package io.flutter.plugins.camera.media; import android.media.CamcorderProfile; diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java index 8066f59d2b14..595206fa2216 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera.types; // Mirrors exposure_mode.dart diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java index ee6fe489511f..c4f0998c418a 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera.types; // Mirrors flash_mode.dart diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java new file mode 100644 index 000000000000..b0dba047f7eb --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java @@ -0,0 +1,29 @@ +// Copyright 2019 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. + +package io.flutter.plugins.camera.types; + +// Mirrors focus_mode.dart +public enum FocusMode { + auto("auto"), + locked("locked"); + + private final String strValue; + + FocusMode(String strValue) { + this.strValue = strValue; + } + + public static FocusMode getValueForString(String modeStr) { + for (FocusMode value : values()) { + if (value.strValue.equals(modeStr)) return value; + } + return null; + } + + @Override + public String toString() { + return strValue; + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java index ffbe2e62095d..1508dcefb293 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera.types; // Mirrors camera.dart diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java index b622c313258a..2b19b5dbb0d6 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import static junit.framework.TestCase.assertEquals; diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java index ca66918e2493..99745e56a857 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import static org.junit.Assert.assertEquals; @@ -85,6 +89,7 @@ public void constructor_should_initialize() { CameraRegions cr = new CameraRegions(new Size(100, 50)); assertEquals(new Size(100, 50), cr.getMaxBoundaries()); assertNull(cr.getAEMeteringRectangle()); + assertNull(cr.getAFMeteringRectangle()); } @Test @@ -102,4 +107,20 @@ public void resetAutoExposureMeteringRectangle_should_reset_aeMeteringRectangle( cr.resetAutoExposureMeteringRectangle(); assertNull(cr.getAEMeteringRectangle()); } + + @Test + public void setAutoFocusMeteringRectangleFromPoint_should_set_afMeteringRectangle_for_point() { + CameraRegions cr = new CameraRegions(new Size(100, 50)); + cr.setAutoFocusMeteringRectangleFromPoint(0, 0); + assertEquals(new MeteringRectangle(0, 0, 10, 5, 1), cr.getAFMeteringRectangle()); + } + + @Test + public void resetAutoFocusMeteringRectangle_should_reset_afMeteringRectangle() { + CameraRegions cr = new CameraRegions(new Size(100, 50)); + cr.setAutoFocusMeteringRectangleFromPoint(0, 0); + assertNotNull(cr.getAFMeteringRectangle()); + cr.resetAutoFocusMeteringRectangle(); + assertNull(cr.getAFMeteringRectangle()); + } } diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java index 93aaa5d926b4..8f05da71b5c5 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import static org.junit.Assert.assertEquals; diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java index f91bf82c7063..64425b7b8283 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import static junit.framework.TestCase.assertNull; @@ -8,6 +12,7 @@ import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.StandardMethodCodec; import io.flutter.plugins.camera.types.ExposureMode; +import io.flutter.plugins.camera.types.FocusMode; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -59,7 +64,7 @@ public void sendCameraErrorEvent_includesErrorDescriptions() { @Test public void sendCameraInitializedEvent_includesPreviewSize() { - dartMessenger.sendCameraInitializedEvent(0, 0, ExposureMode.auto, true); + dartMessenger.sendCameraInitializedEvent(0, 0, ExposureMode.auto, FocusMode.auto, true, true); List sentMessages = fakeBinaryMessenger.getMessages(); assertEquals(1, sentMessages.size()); @@ -68,7 +73,9 @@ public void sendCameraInitializedEvent_includesPreviewSize() { assertEquals(0, (double) call.argument("previewWidth"), 0); assertEquals(0, (double) call.argument("previewHeight"), 0); assertEquals("ExposureMode auto", call.argument("exposureMode"), "auto"); + assertEquals("FocusMode continuous", call.argument("focusMode"), "auto"); assertEquals("exposurePointSupported", call.argument("exposurePointSupported"), true); + assertEquals("focusPointSupported", call.argument("focusPointSupported"), true); } @Test diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java index 2356b306c6c4..3ede0b7abe3a 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera; import static org.junit.Assert.assertEquals; diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java index 622b49b660a2..823975803994 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera.media; import static org.junit.Assert.assertNotNull; diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java index 28d2343cedcd..63810f0b5684 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera.types; import static org.junit.Assert.assertEquals; diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java index bba01836545a..1f5f0c6272ed 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.plugins.camera.types; import static org.junit.Assert.assertEquals; diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java new file mode 100644 index 000000000000..4aa6fadf776b --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java @@ -0,0 +1,34 @@ +// Copyright 2019 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. + +package io.flutter.plugins.camera.types; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class FocusModeTest { + + @Test + public void getValueForString_returns_correct_values() { + assertEquals( + "Returns FocusMode.auto for 'auto'", FocusMode.getValueForString("auto"), FocusMode.auto); + assertEquals( + "Returns FocusMode.locked for 'locked'", + FocusMode.getValueForString("locked"), + FocusMode.locked); + } + + @Test + public void getValueForString_returns_null_for_nonexistant_value() { + assertEquals( + "Returns null for 'nonexistant'", FocusMode.getValueForString("nonexistant"), null); + } + + @Test + public void toString_returns_correct_value() { + assertEquals("Returns 'auto' for FocusMode.auto", FocusMode.auto.toString(), "auto"); + assertEquals("Returns 'locked' for FocusMode.locked", FocusMode.locked.toString(), "locked"); + } +} diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 6eaf66a256de..681a45172816 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -49,6 +49,8 @@ class _CameraExampleHomeState extends State Animation _flashModeControlRowAnimation; AnimationController _exposureModeControlRowAnimationController; Animation _exposureModeControlRowAnimation; + AnimationController _focusModeControlRowAnimationController; + Animation _focusModeControlRowAnimation; double _minAvailableZoom; double _maxAvailableZoom; double _currentScale = 1.0; @@ -77,6 +79,14 @@ class _CameraExampleHomeState extends State parent: _exposureModeControlRowAnimationController, curve: Curves.easeInCubic, ); + _focusModeControlRowAnimationController = AnimationController( + duration: const Duration(milliseconds: 300), + vsync: this, + ); + _focusModeControlRowAnimation = CurvedAnimation( + parent: _focusModeControlRowAnimationController, + curve: Curves.easeInCubic, + ); } @override @@ -249,6 +259,11 @@ class _CameraExampleHomeState extends State onPressed: controller != null ? onExposureModeButtonPressed : null, ), + IconButton( + icon: Icon(Icons.filter_center_focus), + color: Colors.blue, + onPressed: controller != null ? onFocusModeButtonPressed : null, + ), IconButton( icon: Icon(enableAudio ? Icons.volume_up : Icons.volume_mute), color: Colors.blue, @@ -258,6 +273,7 @@ class _CameraExampleHomeState extends State ), _flashModeControlRowWidget(), _exposureModeControlRowWidget(), + _focusModeControlRowWidget(), ], ); } @@ -323,6 +339,7 @@ class _CameraExampleHomeState extends State ? Colors.orange : Colors.blue, ); + return SizeTransition( sizeFactor: _exposureModeControlRowAnimation, child: ClipRect( @@ -387,6 +404,59 @@ class _CameraExampleHomeState extends State ); } + Widget _focusModeControlRowWidget() { + final ButtonStyle styleAuto = TextButton.styleFrom( + primary: controller?.value?.focusMode == FocusMode.auto + ? Colors.orange + : Colors.blue, + ); + final ButtonStyle styleLocked = TextButton.styleFrom( + primary: controller?.value?.focusMode == FocusMode.locked + ? Colors.orange + : Colors.blue, + ); + + return SizeTransition( + sizeFactor: _focusModeControlRowAnimation, + child: ClipRect( + child: Container( + color: Colors.grey.shade50, + child: Column( + children: [ + Center( + child: Text("Focus Mode"), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisSize: MainAxisSize.max, + children: [ + TextButton( + child: Text('AUTO'), + style: styleAuto, + onPressed: controller != null + ? () => onSetFocusModeButtonPressed(FocusMode.auto) + : null, + onLongPress: () { + if (controller != null) controller.setFocusPoint(null); + showInSnackBar('Resetting focus point'); + }, + ), + TextButton( + child: Text('LOCKED'), + style: styleLocked, + onPressed: controller != null + ? () => onSetFocusModeButtonPressed(FocusMode.locked) + : null, + ), + ], + ), + ], + ), + ), + ), + ); + } + /// Display the control bar with buttons to take pictures and record videos. Widget _captureControlRowWidget() { return Row( @@ -472,10 +542,12 @@ class _CameraExampleHomeState extends State } void onViewFinderTap(TapDownDetails details, BoxConstraints constraints) { - controller.setExposurePoint(Offset( + final offset = Offset( details.localPosition.dx / constraints.maxWidth, details.localPosition.dy / constraints.maxHeight, - )); + ); + controller.setExposurePoint(offset); + controller.setFocusPoint(offset); } void onNewCameraSelected(CameraDescription cameraDescription) async { @@ -531,6 +603,7 @@ class _CameraExampleHomeState extends State } else { _flashModeControlRowAnimationController.forward(); _exposureModeControlRowAnimationController.reverse(); + _focusModeControlRowAnimationController.reverse(); } } @@ -540,6 +613,17 @@ class _CameraExampleHomeState extends State } else { _exposureModeControlRowAnimationController.forward(); _flashModeControlRowAnimationController.reverse(); + _focusModeControlRowAnimationController.reverse(); + } + } + + void onFocusModeButtonPressed() { + if (_focusModeControlRowAnimationController.value == 1) { + _focusModeControlRowAnimationController.reverse(); + } else { + _focusModeControlRowAnimationController.forward(); + _flashModeControlRowAnimationController.reverse(); + _exposureModeControlRowAnimationController.reverse(); } } @@ -564,6 +648,13 @@ class _CameraExampleHomeState extends State }); } + void onSetFocusModeButtonPressed(FocusMode mode) { + setFocusMode(mode).then((_) { + if (mounted) setState(() {}); + showInSnackBar('Focus mode set to ${mode.toString().split('.').last}'); + }); + } + void onVideoRecordButtonPressed() { startVideoRecording().then((_) { if (mounted) setState(() {}); @@ -683,6 +774,15 @@ class _CameraExampleHomeState extends State } } + Future setFocusMode(FocusMode mode) async { + try { + await controller.setFocusMode(mode); + } on CameraException catch (e) { + _showCameraException(e); + rethrow; + } + } + Future _startVideoPlayer() async { final VideoPlayerController vController = VideoPlayerController.file(File(videoFile.path)); diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index d1ef0e5c923e..298b906ace7b 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -226,6 +226,44 @@ static ExposureMode getExposureModeForString(NSString *mode) { } } +// Mirrors FocusMode in camera.dart +typedef enum { + FocusModeAuto, + FocusModeLocked, +} FocusMode; + +static NSString *getStringForFocusMode(FocusMode mode) { + switch (mode) { + case FocusModeAuto: + return @"auto"; + case FocusModeLocked: + return @"locked"; + } + NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:NSURLErrorUnknown + userInfo:@{ + NSLocalizedDescriptionKey : [NSString + stringWithFormat:@"Unknown string for focus mode"] + }]; + @throw error; +} + +static FocusMode getFocusModeForString(NSString *mode) { + if ([mode isEqualToString:@"auto"]) { + return FocusModeAuto; + } else if ([mode isEqualToString:@"locked"]) { + return FocusModeLocked; + } else { + NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:NSURLErrorUnknown + userInfo:@{ + NSLocalizedDescriptionKey : [NSString + stringWithFormat:@"Unknown focus mode %@", mode] + }]; + @throw error; + } +} + // Mirrors ResolutionPreset in camera.dart typedef enum { veryLow, @@ -294,6 +332,7 @@ @interface FLTCam : NSObject { )), exposureMode: await _initializeCompleter.future .then((event) => event.exposureMode), + focusMode: + await _initializeCompleter.future.then((event) => event.focusMode), exposurePointSupported: await _initializeCompleter.future .then((event) => event.exposurePointSupported), + focusPointSupported: await _initializeCompleter.future + .then((event) => event.focusPointSupported), ); } on PlatformException catch (e) { throw CameraException(e.code, e.message); @@ -699,6 +718,38 @@ class CameraController extends ValueNotifier { } } + /// Sets the focus mode for taking pictures. + Future setFocusMode(FocusMode mode) async { + try { + await CameraPlatform.instance.setFocusMode(_cameraId, mode); + value = value.copyWith(focusMode: mode); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Sets the focus point for automatically determining the focus value. + Future setFocusPoint(Offset point) async { + if (point != null && + (point.dx < 0 || point.dx > 1 || point.dy < 0 || point.dy > 1)) { + throw ArgumentError( + 'The values of point should be anywhere between (0,0) and (1,1).'); + } + try { + await CameraPlatform.instance.setFocusPoint( + _cameraId, + point == null + ? null + : Point( + point.dx, + point.dy, + ), + ); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + /// Releases the resources of this camera. @override Future dispose() async { diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 7c275c2268cd..0b21497b5462 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,13 +2,13 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.5 +version: 0.6.6 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: flutter: sdk: flutter - camera_platform_interface: ^1.3.0 + camera_platform_interface: ^1.5.0 pedantic: ^1.8.0 dev_dependencies: diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 4f2109371392..1cea609d1741 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -28,8 +28,15 @@ get mockAvailableCameras => [ get mockInitializeCamera => 13; -get mockOnCameraInitializedEvent => - CameraInitializedEvent(13, 75, 75, ExposureMode.auto, true); +get mockOnCameraInitializedEvent => CameraInitializedEvent( + 13, + 75, + 75, + ExposureMode.auto, + true, + FocusMode.auto, + true, + ); get mockOnCameraClosingEvent => null; diff --git a/packages/camera/camera/test/camera_value_test.dart b/packages/camera/camera/test/camera_value_test.dart index d9193e212ea9..eb7927b9eb6c 100644 --- a/packages/camera/camera/test/camera_value_test.dart +++ b/packages/camera/camera/test/camera_value_test.dart @@ -106,11 +106,14 @@ void main() { isTakingPicture: false, isStreamingImages: false, flashMode: FlashMode.auto, + exposureMode: ExposureMode.auto, + focusMode: FocusMode.auto, exposurePointSupported: true, + focusPointSupported: true, ); expect(cameraValue.toString(), - 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false, flashMode: FlashMode.auto, exposureMode: null, exposurePointSupported: true)'); + 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false, flashMode: FlashMode.auto, exposureMode: ExposureMode.auto, focusMode: FocusMode.auto, exposurePointSupported: true, focusPointSupported: true)'); }); }); } From a0e793734eac4eeb566ce090c64ed928e72214b2 Mon Sep 17 00:00:00 2001 From: Aleksandr Yurkovskiy Date: Tue, 12 Jan 2021 21:39:02 +0300 Subject: [PATCH 091/924] [google_maps_flutter_platform_interface] Adds support for holes in polygon overlays to the Google Maps plugin (#3135) --- AUTHORS | 1 + .../CHANGELOG.md | 4 +++ .../lib/src/types/polygon.dart | 29 +++++++++++++++++++ .../pubspec.yaml | 3 +- 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 51345c9a3481..09bab9d34d02 100644 --- a/AUTHORS +++ b/AUTHORS @@ -59,3 +59,4 @@ Kazuki Yamaguchi Eitan Schwartz Chris Rutkowski Juan Alvarez +Aleksandr Yurkovskiy diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index b40fc9d40e5b..1e761681e543 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.0 + +* Add support for holes in Polygons. + ## 1.0.6 * Update Flutter SDK constraint. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart index 3b5e25060faf..96b39157418d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart' show listEquals, VoidCallback; import 'package:flutter/material.dart' show Color, Colors; import 'package:meta/meta.dart' show immutable, required; @@ -46,6 +47,7 @@ class Polygon { this.fillColor = Colors.black, this.geodesic = false, this.points = const [], + this.holes = const >[], this.strokeColor = Colors.black, this.strokeWidth = 10, this.visible = true, @@ -77,6 +79,14 @@ class Polygon { /// default; to form a closed polygon, the start and end points must be the same. final List points; + /// To create an empty area within a polygon, you need to use holes. + /// To create the hole, the coordinates defining the hole path must be inside the polygon. + /// + /// The vertices of the holes to be cut out of polygon. + /// + /// Line segments of each points of hole are drawn inside polygon between consecutive hole points. + final List> holes; + /// True if the marker is visible. final bool visible; @@ -106,6 +116,7 @@ class Polygon { Color fillColorParam, bool geodesicParam, List pointsParam, + List> holesParam, Color strokeColorParam, int strokeWidthParam, bool visibleParam, @@ -118,6 +129,7 @@ class Polygon { fillColor: fillColorParam ?? fillColor, geodesic: geodesicParam ?? geodesic, points: pointsParam ?? points, + holes: holesParam ?? holes, strokeColor: strokeColorParam ?? strokeColor, strokeWidth: strokeWidthParam ?? strokeWidth, visible: visibleParam ?? visible, @@ -154,6 +166,10 @@ class Polygon { json['points'] = _pointsToJson(); } + if (holes != null) { + json['holes'] = _holesToJson(); + } + return json; } @@ -167,6 +183,7 @@ class Polygon { fillColor == typedOther.fillColor && geodesic == typedOther.geodesic && listEquals(points, typedOther.points) && + DeepCollectionEquality().equals(holes, typedOther.holes) && visible == typedOther.visible && strokeColor == typedOther.strokeColor && strokeWidth == typedOther.strokeWidth && @@ -183,4 +200,16 @@ class Polygon { } return result; } + + List> _holesToJson() { + final List> result = >[]; + for (final List hole in holes) { + final List jsonHole = []; + for (final LatLng point in hole) { + jsonHole.add(point.toJson()); + } + result.add(jsonHole); + } + return result; + } } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index 633478c5d636..d8b260a7a3eb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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.0.6 +version: 1.1.0 dependencies: flutter: @@ -11,6 +11,7 @@ dependencies: meta: ^1.0.5 plugin_platform_interface: ^1.0.1 stream_transform: ^1.2.0 + collection: ^1.14.13 dev_dependencies: flutter_test: From 782a7a9c95c81724eaed543a4aa99947b8b83ea5 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 13 Jan 2021 11:50:34 -0600 Subject: [PATCH 092/924] [video_player] Migrate deprecated api (#3409) --- .../video_player/video_player/CHANGELOG.md | 4 + .../video_player/video_player/pubspec.yaml | 2 +- .../video_player/test/video_player_test.dart | 6 +- .../method_channel_video_player_test.dart | 123 ++++++++---------- 4 files changed, 58 insertions(+), 77 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index f9bae8dee6e1..3e8047ced6bc 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.8 + +* Migrated from deprecated `defaultBinaryMessenger`. + ## 2.0.0-nullsafety.7 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index e4694195ebde..72fb54b125ea 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for displaying inline video with other Flutter # 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 2.0.0-nullsafety.7 +version: 2.0.0-nullsafety.8 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart index f3f2b5e8faf1..eb276a8d72e7 100644 --- a/packages/video_player/video_player/test/video_player_test.dart +++ b/packages/video_player/video_player/test/video_player_test.dart @@ -795,11 +795,7 @@ class FakeEventsChannel { } void _sendMessage(ByteData data) { - // TODO(jackson): This has been deprecated and should be replaced - // with `ServicesBinding.instance.defaultBinaryMessenger` when it's - // available on all the versions of Flutter that we test. - // ignore: deprecated_member_use - defaultBinaryMessenger.handlePlatformMessage( + ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage( eventsMethodChannel.name, data, (ByteData? data) {}); } } diff --git a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart index 5c19ebca0d12..7f54c4f24f2c 100644 --- a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart +++ b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart @@ -234,82 +234,63 @@ void main() { }); test('videoEventsFor', () async { - // TODO(cbenhagen): This has been deprecated and should be replaced - // with `ServicesBinding.instance.defaultBinaryMessenger` when it's - // available on all the versions of Flutter that we test. - // ignore: deprecated_member_use - defaultBinaryMessenger.setMockMessageHandler( + ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler( "flutter.io/videoPlayer/videoEvents123", (ByteData message) async { final MethodCall methodCall = const StandardMethodCodec().decodeMethodCall(message); if (methodCall.method == 'listen') { - // TODO(cbenhagen): This has been deprecated and should be replaced - // with `ServicesBinding.instance.defaultBinaryMessenger` when it's - // available on all the versions of Flutter that we test. - // ignore: deprecated_member_use - await defaultBinaryMessenger.handlePlatformMessage( - "flutter.io/videoPlayer/videoEvents123", - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'initialized', - 'duration': 98765, - 'width': 1920, - 'height': 1080, - }), - (ByteData data) {}); - - // TODO(cbenhagen): This has been deprecated and should be replaced - // with `ServicesBinding.instance.defaultBinaryMessenger` when it's - // available on all the versions of Flutter that we test. - // ignore: deprecated_member_use - await defaultBinaryMessenger.handlePlatformMessage( - "flutter.io/videoPlayer/videoEvents123", - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'completed', - }), - (ByteData data) {}); - - // TODO(cbenhagen): This has been deprecated and should be replaced - // with `ServicesBinding.instance.defaultBinaryMessenger` when it's - // available on all the versions of Flutter that we test. - // ignore: deprecated_member_use - await defaultBinaryMessenger.handlePlatformMessage( - "flutter.io/videoPlayer/videoEvents123", - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'bufferingUpdate', - 'values': >[ - [0, 1234], - [1235, 4000], - ], - }), - (ByteData data) {}); - - // TODO(cbenhagen): This has been deprecated and should be replaced - // with `ServicesBinding.instance.defaultBinaryMessenger` when it's - // available on all the versions of Flutter that we test. - // ignore: deprecated_member_use - await defaultBinaryMessenger.handlePlatformMessage( - "flutter.io/videoPlayer/videoEvents123", - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'bufferingStart', - }), - (ByteData data) {}); - - // TODO(cbenhagen): This has been deprecated and should be replaced - // with `ServicesBinding.instance.defaultBinaryMessenger` when it's - // available on all the versions of Flutter that we test. - // ignore: deprecated_member_use - await defaultBinaryMessenger.handlePlatformMessage( - "flutter.io/videoPlayer/videoEvents123", - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'bufferingEnd', - }), - (ByteData data) {}); + await ServicesBinding.instance.defaultBinaryMessenger + .handlePlatformMessage( + "flutter.io/videoPlayer/videoEvents123", + const StandardMethodCodec() + .encodeSuccessEnvelope({ + 'event': 'initialized', + 'duration': 98765, + 'width': 1920, + 'height': 1080, + }), + (ByteData data) {}); + + await ServicesBinding.instance.defaultBinaryMessenger + .handlePlatformMessage( + "flutter.io/videoPlayer/videoEvents123", + const StandardMethodCodec() + .encodeSuccessEnvelope({ + 'event': 'completed', + }), + (ByteData data) {}); + + await ServicesBinding.instance.defaultBinaryMessenger + .handlePlatformMessage( + "flutter.io/videoPlayer/videoEvents123", + const StandardMethodCodec() + .encodeSuccessEnvelope({ + 'event': 'bufferingUpdate', + 'values': >[ + [0, 1234], + [1235, 4000], + ], + }), + (ByteData data) {}); + + await ServicesBinding.instance.defaultBinaryMessenger + .handlePlatformMessage( + "flutter.io/videoPlayer/videoEvents123", + const StandardMethodCodec() + .encodeSuccessEnvelope({ + 'event': 'bufferingStart', + }), + (ByteData data) {}); + + await ServicesBinding.instance.defaultBinaryMessenger + .handlePlatformMessage( + "flutter.io/videoPlayer/videoEvents123", + const StandardMethodCodec() + .encodeSuccessEnvelope({ + 'event': 'bufferingEnd', + }), + (ByteData data) {}); return const StandardMethodCodec().encodeSuccessEnvelope(null); } else if (methodCall.method == 'cancel') { From 4fec227387314d86fd1acbdb056802e57675a463 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 13 Jan 2021 13:03:38 -0500 Subject: [PATCH 093/924] [battery] Migrate battery to null safety (#3380) --- packages/battery/battery/CHANGELOG.md | 4 ++++ packages/battery/battery/example/lib/main.dart | 8 ++++---- packages/battery/battery/example/pubspec.yaml | 4 ++-- .../battery/integration_test/battery_test.dart | 2 ++ packages/battery/battery/pubspec.yaml | 16 +++++++--------- packages/battery/battery/test/battery_test.dart | 4 ++-- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/battery/battery/CHANGELOG.md b/packages/battery/battery/CHANGELOG.md index ca35c96fb569..d907ca33fe1e 100644 --- a/packages/battery/battery/CHANGELOG.md +++ b/packages/battery/battery/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.0.11 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/battery/battery/example/lib/main.dart b/packages/battery/battery/example/lib/main.dart index c84f5eec519b..8482655771f2 100644 --- a/packages/battery/battery/example/lib/main.dart +++ b/packages/battery/battery/example/lib/main.dart @@ -27,7 +27,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @@ -36,10 +36,10 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - Battery _battery = Battery(); + final Battery _battery = Battery(); - BatteryState _batteryState; - StreamSubscription _batteryStateSubscription; + BatteryState? _batteryState; + late StreamSubscription _batteryStateSubscription; @override void initState() { diff --git a/packages/battery/battery/example/pubspec.yaml b/packages/battery/battery/example/pubspec.yaml index 4e7b9ef035eb..748660adf284 100644 --- a/packages/battery/battery/example/pubspec.yaml +++ b/packages/battery/battery/example/pubspec.yaml @@ -12,11 +12,11 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/packages/battery/battery/integration_test/battery_test.dart b/packages/battery/battery/integration_test/battery_test.dart index ed7b6fe5a0e4..2b0e26967b6c 100644 --- a/packages/battery/battery/integration_test/battery_test.dart +++ b/packages/battery/battery/integration_test/battery_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'package:flutter_test/flutter_test.dart'; import 'package:battery/battery.dart'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/battery/battery/pubspec.yaml b/packages/battery/battery/pubspec.yaml index 9c2c2766c85f..455905d62a9a 100644 --- a/packages/battery/battery/pubspec.yaml +++ b/packages/battery/battery/pubspec.yaml @@ -2,7 +2,7 @@ name: battery description: Flutter plugin for accessing information about the battery state (full, charging, discharging) on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/battery/battery -version: 1.0.11 +version: 2.0.0-nullsafety flutter: plugin: @@ -16,20 +16,18 @@ flutter: dependencies: flutter: sdk: flutter - meta: ^1.0.5 - battery_platform_interface: ^1.0.0 + meta: ^1.3.0-nullsafety + battery_platform_interface: ^2.0.0-nullsafety dev_dependencies: - async: ^2.0.8 - test: ^1.3.0 - mockito: ^4.1.1 + mockito: ^5.0.0-nullsafety.0 flutter_test: sdk: flutter - plugin_platform_interface: ^1.0.0 + plugin_platform_interface: ^1.1.0-nullsafety integration_test: path: ../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/battery/battery/test/battery_test.dart b/packages/battery/battery/test/battery_test.dart index 5c789207d7eb..43155c59692c 100644 --- a/packages/battery/battery/test/battery_test.dart +++ b/packages/battery/battery/test/battery_test.dart @@ -5,14 +5,14 @@ import 'dart:async'; import 'package:battery_platform_interface/battery_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'package:test/test.dart'; import 'package:battery/battery.dart'; import 'package:mockito/mockito.dart'; void main() { group('battery', () { - Battery battery; + late Battery battery; MockBatteryPlatform fakePlatform; setUp(() async { fakePlatform = MockBatteryPlatform(); From 1eabad7de3ab62eb1d38bdc86e61cdaa4fe0dfa1 Mon Sep 17 00:00:00 2001 From: Juanjo Tugores Date: Wed, 13 Jan 2021 13:15:13 -0600 Subject: [PATCH 094/924] [file_selector_web] Add initial implementation (#3141) Add the file_selector web implementation --- .../file_selector_web/CHANGELOG.md | 3 + .../file_selector/file_selector_web/LICENSE | 25 ++++ .../file_selector/file_selector_web/README.md | 30 +++++ .../integration_test/dom_helper_test.dart | 116 ++++++++++++++++++ .../file_selector_web_test.dart | 89 ++++++++++++++ .../lib/file_selector_web.dart | 74 +++++++++++ .../file_selector_web/lib/src/dom_helper.dart | 63 ++++++++++ .../file_selector_web/lib/src/utils.dart | 38 ++++++ .../file_selector_web/pubspec.yaml | 32 +++++ .../file_selector_web/run_integration_test | 17 +++ .../file_selector_web/test/utils_test.dart | 59 +++++++++ .../test_driver/integration_test.dart | 7 ++ 12 files changed, 553 insertions(+) create mode 100644 packages/file_selector/file_selector_web/CHANGELOG.md create mode 100644 packages/file_selector/file_selector_web/LICENSE create mode 100644 packages/file_selector/file_selector_web/README.md create mode 100644 packages/file_selector/file_selector_web/integration_test/dom_helper_test.dart create mode 100644 packages/file_selector/file_selector_web/integration_test/file_selector_web_test.dart create mode 100644 packages/file_selector/file_selector_web/lib/file_selector_web.dart create mode 100644 packages/file_selector/file_selector_web/lib/src/dom_helper.dart create mode 100644 packages/file_selector/file_selector_web/lib/src/utils.dart create mode 100644 packages/file_selector/file_selector_web/pubspec.yaml create mode 100755 packages/file_selector/file_selector_web/run_integration_test create mode 100644 packages/file_selector/file_selector_web/test/utils_test.dart create mode 100644 packages/file_selector/file_selector_web/test_driver/integration_test.dart diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md new file mode 100644 index 000000000000..cf87cfec36fd --- /dev/null +++ b/packages/file_selector/file_selector_web/CHANGELOG.md @@ -0,0 +1,3 @@ +# 0.7.0 + +- Initial open-source release. diff --git a/packages/file_selector/file_selector_web/LICENSE b/packages/file_selector/file_selector_web/LICENSE new file mode 100644 index 000000000000..2c91f1438173 --- /dev/null +++ b/packages/file_selector/file_selector_web/LICENSE @@ -0,0 +1,25 @@ +Copyright 2020 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/packages/file_selector/file_selector_web/README.md b/packages/file_selector/file_selector_web/README.md new file mode 100644 index 000000000000..36e0b446ffe8 --- /dev/null +++ b/packages/file_selector/file_selector_web/README.md @@ -0,0 +1,30 @@ +# file_picker_web + +The web implementation of [`file_picker`][1]. + +## Usage + +### Import the package +To use this plugin in your Flutter Web app, simply add it as a dependency in +your pubspec alongside the base `file_picker` plugin. + +_(This is only temporary: in the future we hope to make this package an +"endorsed" implementation of `file_picker`, so that it is automatically +included in your Flutter Web app when you depend on `package:file_picker`.)_ + +This is what the above means to your `pubspec.yaml`: + +```yaml +... +dependencies: + ... + file_picker: ^0.7.0 + file_picker_web: ^0.7.0 + ... +``` + +### Use the plugin +Once you have the `file_picker_web` dependency in your pubspec, you should +be able to use `package:file_picker` as normal. + +[1]: ../file_picker/file_picker diff --git a/packages/file_selector/file_selector_web/integration_test/dom_helper_test.dart b/packages/file_selector/file_selector_web/integration_test/dom_helper_test.dart new file mode 100644 index 000000000000..a942c0db10bf --- /dev/null +++ b/packages/file_selector/file_selector_web/integration_test/dom_helper_test.dart @@ -0,0 +1,116 @@ +// Copyright 2020 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. + +// @dart = 2.9 + +import 'dart:html'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:file_selector_web/src/dom_helper.dart'; +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; + +void main() { + group('FileSelectorWeb', () { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + DomHelper domHelper; + FileUploadInputElement input; + + FileList FileListItems(List files) { + final dataTransfer = DataTransfer(); + files.forEach(dataTransfer.items.add); + return dataTransfer.files; + } + + void setFilesAndTriggerChange(List files) { + input.files = FileListItems(files); + input.dispatchEvent(Event('change')); + } + + setUp(() { + domHelper = DomHelper(); + input = FileUploadInputElement(); + }); + + group('getFiles', () { + final mockFile1 = File(['123456'], 'file1.txt'); + final mockFile2 = File([], 'file2.txt'); + + testWidgets('works', (_) async { + final Future> futureFiles = domHelper.getFiles( + input: input, + ); + + setFilesAndTriggerChange([mockFile1, mockFile2]); + + final List files = await futureFiles; + + expect(files.length, 2); + + expect(files[0].name, 'file1.txt'); + expect(await files[0].length(), 6); + expect(await files[0].readAsString(), '123456'); + expect(await files[0].lastModified(), isNotNull); + + expect(files[1].name, 'file2.txt'); + expect(await files[1].length(), 0); + expect(await files[1].readAsString(), ''); + expect(await files[1].lastModified(), isNotNull); + }); + + testWidgets('works multiple times', (_) async { + Future> futureFiles; + List files; + + // It should work the first time + futureFiles = domHelper.getFiles(input: input); + setFilesAndTriggerChange([mockFile1]); + + files = await futureFiles; + + expect(files.length, 1); + expect(files.first.name, mockFile1.name); + + // The same input should work more than once + futureFiles = domHelper.getFiles(input: input); + setFilesAndTriggerChange([mockFile2]); + + files = await futureFiles; + + expect(files.length, 1); + expect(files.first.name, mockFile2.name); + }); + + testWidgets('sets the attributes and clicks it', (_) async { + final accept = '.jpg,.png'; + final multiple = true; + bool wasClicked = false; + + //ignore: unawaited_futures + input.onClick.first.then((_) => wasClicked = true); + + final futureFile = domHelper.getFiles( + accept: accept, + multiple: multiple, + input: input, + ); + + expect(input.matchesWithAncestors('body'), true); + expect(input.accept, accept); + expect(input.multiple, multiple); + expect( + wasClicked, + true, + reason: + 'The should be clicked otherwise no dialog will be shown', + ); + + setFilesAndTriggerChange([]); + await futureFile; + + // It should be already removed from the DOM after the file is resolved. + expect(input.parent, isNull); + }); + }); + }); +} diff --git a/packages/file_selector/file_selector_web/integration_test/file_selector_web_test.dart b/packages/file_selector/file_selector_web/integration_test/file_selector_web_test.dart new file mode 100644 index 000000000000..abd31dd9fcc6 --- /dev/null +++ b/packages/file_selector/file_selector_web/integration_test/file_selector_web_test.dart @@ -0,0 +1,89 @@ +// Copyright 2020 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. + +// @dart = 2.9 + +import 'dart:typed_data'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:file_selector_web/file_selector_web.dart'; +import 'package:file_selector_web/src/dom_helper.dart'; + +void main() { + group('FileSelectorWeb', () { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + MockDomHelper mockDomHelper; + FileSelectorWeb plugin; + + setUp(() { + mockDomHelper = MockDomHelper(); + plugin = FileSelectorWeb(domHelper: mockDomHelper); + }); + + group('openFile', () { + final mockFile = createXFile('1001', 'identity.png'); + + testWidgets('works', (WidgetTester _) async { + final typeGroup = XTypeGroup( + label: 'images', + extensions: ['jpg', 'jpeg'], + mimeTypes: ['image/png'], + webWildCards: ['image/*'], + ); + + when(mockDomHelper.getFiles( + accept: '.jpg,.jpeg,image/png,image/*', + multiple: false, + )).thenAnswer((_) async => [mockFile]); + + final file = await plugin.openFile(acceptedTypeGroups: [typeGroup]); + + expect(file.name, mockFile.name); + expect(await file.length(), 4); + expect(await file.readAsString(), '1001'); + expect(await file.lastModified(), isNotNull); + }); + }); + + group('openFiles', () { + final mockFile1 = createXFile('123456', 'file1.txt'); + final mockFile2 = createXFile('', 'file2.txt'); + + testWidgets('works', (WidgetTester _) async { + final typeGroup = XTypeGroup( + label: 'files', + extensions: ['.txt'], + ); + + when(mockDomHelper.getFiles( + accept: '.txt', + multiple: true, + )).thenAnswer((_) async => [mockFile1, mockFile2]); + + final files = await plugin.openFiles(acceptedTypeGroups: [typeGroup]); + + expect(files.length, 2); + + expect(files[0].name, mockFile1.name); + expect(await files[0].length(), 6); + expect(await files[0].readAsString(), '123456'); + expect(await files[0].lastModified(), isNotNull); + + expect(files[1].name, mockFile2.name); + expect(await files[1].length(), 0); + expect(await files[1].readAsString(), ''); + expect(await files[1].lastModified(), isNotNull); + }); + }); + }); +} + +class MockDomHelper extends Mock implements DomHelper {} + +XFile createXFile(String content, String name) { + final data = Uint8List.fromList(content.codeUnits); + return XFile.fromData(data, name: name, lastModified: DateTime.now()); +} diff --git a/packages/file_selector/file_selector_web/lib/file_selector_web.dart b/packages/file_selector/file_selector_web/lib/file_selector_web.dart new file mode 100644 index 000000000000..48f57ee880c8 --- /dev/null +++ b/packages/file_selector/file_selector_web/lib/file_selector_web.dart @@ -0,0 +1,74 @@ +// Copyright 2020 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 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:file_selector_web/src/dom_helper.dart'; +import 'package:file_selector_web/src/utils.dart'; + +/// The web implementation of [FileSelectorPlatform]. +/// +/// This class implements the `package:file_selector` functionality for the web. +class FileSelectorWeb extends FileSelectorPlatform { + final _domHelper; + + /// Registers this class as the default instance of [FileSelectorPlatform]. + static void registerWith(Registrar registrar) { + FileSelectorPlatform.instance = FileSelectorWeb(); + } + + /// Default constructor, initializes _domHelper that we can use + /// to interact with the DOM. + /// overrides parameter allows for testing to override functions + FileSelectorWeb({@visibleForTesting DomHelper domHelper}) + : _domHelper = domHelper ?? DomHelper(); + + @override + Future openFile({ + List acceptedTypeGroups, + String initialDirectory, + String confirmButtonText, + }) async { + final files = await _openFiles(acceptedTypeGroups: acceptedTypeGroups); + return files.first; + } + + @override + Future> openFiles({ + List acceptedTypeGroups, + String initialDirectory, + String confirmButtonText, + }) async { + return _openFiles(acceptedTypeGroups: acceptedTypeGroups, multiple: true); + } + + @override + Future getSavePath({ + List acceptedTypeGroups, + String initialDirectory, + String suggestedName, + String confirmButtonText, + }) async => + null; + + @override + Future getDirectoryPath({ + String initialDirectory, + String confirmButtonText, + }) async => + null; + + Future> _openFiles({ + List acceptedTypeGroups, + bool multiple = false, + }) async { + final accept = acceptedTypesToString(acceptedTypeGroups); + return _domHelper.getFiles( + accept: accept, + multiple: multiple, + ); + } +} diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart new file mode 100644 index 000000000000..a965cebe97f9 --- /dev/null +++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart @@ -0,0 +1,63 @@ +// Copyright 2020 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 'dart:async'; +import 'dart:html'; +import 'package:meta/meta.dart'; +import 'package:flutter/services.dart'; +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; + +/// Class to manipulate the DOM with the intention of reading files from it. +class DomHelper { + final _container = Element.tag('file-selector'); + + /// Default constructor, initializes the container DOM element. + DomHelper() { + final body = querySelector('body'); + body.children.add(_container); + } + + /// Sets the attributes and waits for a file to be selected. + Future> getFiles({ + String accept = '', + bool multiple = false, + @visibleForTesting FileUploadInputElement input, + }) { + final Completer> _completer = Completer(); + input = input ?? FileUploadInputElement(); + + _container.children.add( + input + ..accept = accept + ..multiple = multiple, + ); + + input.onChange.first.then((_) { + final List files = input.files.map(_convertFileToXFile).toList(); + input.remove(); + _completer.complete(files); + }); + + input.onError.first.then((event) { + final ErrorEvent error = event; + final platformException = PlatformException( + code: error.type, + message: error.message, + ); + input.remove(); + _completer.completeError(platformException); + }); + + input.click(); + + return _completer.future; + } + + XFile _convertFileToXFile(File file) => XFile( + Url.createObjectUrl(file), + name: file.name, + length: file.size, + lastModified: DateTime.fromMillisecondsSinceEpoch(file.lastModified), + ); +} diff --git a/packages/file_selector/file_selector_web/lib/src/utils.dart b/packages/file_selector/file_selector_web/lib/src/utils.dart new file mode 100644 index 000000000000..4ddd7ddcbda5 --- /dev/null +++ b/packages/file_selector/file_selector_web/lib/src/utils.dart @@ -0,0 +1,38 @@ +// Copyright 2020 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:file_selector_platform_interface/file_selector_platform_interface.dart'; + +/// Convert list of XTypeGroups to a comma-separated string +String acceptedTypesToString(List acceptedTypes) { + if (acceptedTypes == null) return ''; + final List allTypes = []; + for (final group in acceptedTypes) { + _assertTypeGroupIsValid(group); + if (group.extensions != null) { + allTypes.addAll(group.extensions.map(_normalizeExtension)); + } + if (group.mimeTypes != null) { + allTypes.addAll(group.mimeTypes); + } + if (group.webWildCards != null) { + allTypes.addAll(group.webWildCards); + } + } + return allTypes.join(','); +} + +/// Make sure that at least one of its fields is populated. +void _assertTypeGroupIsValid(XTypeGroup group) { + assert( + !((group.extensions == null || group.extensions.isEmpty) && + (group.mimeTypes == null || group.mimeTypes.isEmpty) && + (group.webWildCards == null || group.webWildCards.isEmpty)), + 'At least one of extensions / mimeTypes / webWildCards is required for web.'); +} + +/// Append a dot at the beggining if it is not there png -> .png +String _normalizeExtension(String ext) { + return ext.isNotEmpty && ext[0] != '.' ? '.' + ext : ext; +} diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml new file mode 100644 index 000000000000..c8e0eef56276 --- /dev/null +++ b/packages/file_selector/file_selector_web/pubspec.yaml @@ -0,0 +1,32 @@ +name: file_selector_web +description: Web platform implementation of file_selector +homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_web +version: 0.7.0 + +flutter: + plugin: + platforms: + web: + pluginClass: FileSelectorWeb + fileName: file_selector_web.dart + +dependencies: + file_selector_platform_interface: ^1.0.2 + platform_detect: ^1.4.0 + flutter: + sdk: flutter + flutter_web_plugins: + sdk: flutter + meta: ^1.1.7 + +dev_dependencies: + flutter_test: + sdk: flutter + mockito: ^4.1.1 + pedantic: ^1.8.0 + integration_test: + path: ../../integration_test + +environment: + sdk: ">=2.2.0 <3.0.0" + flutter: ">=1.10.0" diff --git a/packages/file_selector/file_selector_web/run_integration_test b/packages/file_selector/file_selector_web/run_integration_test new file mode 100755 index 000000000000..c9f547a4f7d7 --- /dev/null +++ b/packages/file_selector/file_selector_web/run_integration_test @@ -0,0 +1,17 @@ +#!/usr/bin/bash + +if pgrep -lf chromedriver > /dev/null; then + echo "chromedriver is running." + + if [ $# -eq 0 ]; then + echo "No target specified, running all tests..." + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' + else + echo "Running test target: $1..." + set -x + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target=$1 + fi + + else + echo "chromedriver is not running." +fi diff --git a/packages/file_selector/file_selector_web/test/utils_test.dart b/packages/file_selector/file_selector_web/test/utils_test.dart new file mode 100644 index 000000000000..9fa187eede5b --- /dev/null +++ b/packages/file_selector/file_selector_web/test/utils_test.dart @@ -0,0 +1,59 @@ +// Copyright 2020 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. + +// @dart = 2.9 + +import 'package:flutter_test/flutter_test.dart'; +import 'package:file_selector_web/src/utils.dart'; +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; + +void main() { + group('FileSelectorWeb utils', () { + group('acceptedTypesToString', () { + test('works', () { + final List acceptedTypes = [ + XTypeGroup(label: 'images', webWildCards: ['images/*']), + XTypeGroup(label: 'jpgs', extensions: ['jpg', 'jpeg']), + XTypeGroup(label: 'pngs', mimeTypes: ['image/png']), + ]; + final accepts = acceptedTypesToString(acceptedTypes); + expect(accepts, 'images/*,.jpg,.jpeg,image/png'); + }); + + test('works with an empty list', () { + final List acceptedTypes = []; + final accepts = acceptedTypesToString(acceptedTypes); + expect(accepts, ''); + }); + + test('works with extensions', () { + final List acceptedTypes = [ + XTypeGroup(label: 'jpgs', extensions: ['jpeg', 'jpg']), + XTypeGroup(label: 'pngs', extensions: ['png']), + ]; + final accepts = acceptedTypesToString(acceptedTypes); + expect(accepts, '.jpeg,.jpg,.png'); + }); + + test('works with mime types', () { + final List acceptedTypes = [ + XTypeGroup(label: 'jpgs', mimeTypes: ['image/jpeg', 'image/jpg']), + XTypeGroup(label: 'pngs', mimeTypes: ['image/png']), + ]; + final accepts = acceptedTypesToString(acceptedTypes); + expect(accepts, 'image/jpeg,image/jpg,image/png'); + }); + + test('works with web wild cards', () { + final List acceptedTypes = [ + XTypeGroup(label: 'images', webWildCards: ['image/*']), + XTypeGroup(label: 'audios', webWildCards: ['audio/*']), + XTypeGroup(label: 'videos', webWildCards: ['video/*']), + ]; + final accepts = acceptedTypesToString(acceptedTypes); + expect(accepts, 'image/*,audio/*,video/*'); + }); + }); + }); +} diff --git a/packages/file_selector/file_selector_web/test_driver/integration_test.dart b/packages/file_selector/file_selector_web/test_driver/integration_test.dart new file mode 100644 index 000000000000..44d6ed9c64bc --- /dev/null +++ b/packages/file_selector/file_selector_web/test_driver/integration_test.dart @@ -0,0 +1,7 @@ +// Copyright 2020 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:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); From 100c7470d4066b1d0f8f7e4ec6d7c943e736f970 Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Wed, 13 Jan 2021 20:59:04 +0100 Subject: [PATCH 095/924] [camera] Implemented capture orientation locking. Fixed preview rotation issues. Fixed video and photo orientation upon save. (#3390) --- packages/camera/camera/CHANGELOG.md | 10 +- packages/camera/camera/android/build.gradle | 2 +- .../io/flutter/plugins/camera/Camera.java | 52 +++-- .../flutter/plugins/camera/CameraUtils.java | 54 +++++ .../flutter/plugins/camera/DartMessenger.java | 66 ++++-- .../camera/DeviceOrientationManager.java | 201 +++++++++++++++++ .../plugins/camera/MethodCallHandlerImpl.java | 26 ++- .../plugins/camera/CameraUtilsTest.java | 102 +++++++++ .../plugins/camera/DartMessengerTest.java | 12 + .../camera/example/android/app/build.gradle | 2 +- .../camera/example/ios/Runner/Info.plist | 1 + packages/camera/camera/example/lib/main.dart | 34 ++- .../camera/camera/ios/Classes/CameraPlugin.m | 209 +++++++++++++----- .../camera/lib/src/camera_controller.dart | 81 ++++++- .../camera/camera/lib/src/camera_preview.dart | 47 +++- packages/camera/camera/pubspec.yaml | 3 +- packages/camera/camera/test/camera_test.dart | 107 +++++++++ .../camera/camera/test/camera_value_test.dart | 42 +++- 18 files changed, 930 insertions(+), 121 deletions(-) create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 1a2b03d93a6a..8525ad1e21d8 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.7.0 + +* Added support for capture orientation locking on Android and iOS. +* Fixed camera preview not rotating correctly on Android and iOS. +* Fixed camera preview sometimes appearing stretched on Android and iOS. +* Fixed videos & photos saving with the incorrect rotation on iOS. +* BREAKING CHANGE: `CameraValue.aspectRatio` now returns `width / height` rather than `height / width`. + ## 0.6.6 * Adds auto focus support for Android and iOS implementations. @@ -20,7 +28,7 @@ ## 0.6.4+2 -* Set ImageStreamReader listener to null to prevent stale images when streaming images. +* Set ImageStreamReader listener to null to prevent stale images when streaming images. ## 0.6.4+1 diff --git a/packages/camera/camera/android/build.gradle b/packages/camera/camera/android/build.gradle index 0b88fd10fb71..0606738a0a69 100644 --- a/packages/camera/camera/android/build.gradle +++ b/packages/camera/camera/android/build.gradle @@ -27,7 +27,7 @@ project.getTasks().withType(JavaCompile){ apply plugin: 'com.android.library' android { - compileSdkVersion 29 + compileSdkVersion 30 defaultConfig { minSdkVersion 21 diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 3fc702a2a879..10d58f5e8792 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -4,7 +4,6 @@ package io.flutter.plugins.camera; -import static android.view.OrientationEventListener.ORIENTATION_UNKNOWN; import static io.flutter.plugins.camera.CameraUtils.computeBestPreviewSize; import android.annotation.SuppressLint; @@ -41,10 +40,10 @@ import android.util.Range; import android.util.Rational; import android.util.Size; -import android.view.OrientationEventListener; import android.view.Surface; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.camera.PictureCaptureRequest.State; @@ -76,7 +75,7 @@ public class Camera { private final SurfaceTextureEntry flutterTexture; private final CameraManager cameraManager; - private final OrientationEventListener orientationEventListener; + private final DeviceOrientationManager deviceOrientationListener; private final boolean isFrontFacing; private final int sensorOrientation; private final String cameraName; @@ -97,7 +96,6 @@ public class Camera { private MediaRecorder mediaRecorder; private boolean recordingVideo; private File videoRecordingFile; - private int currentOrientation = ORIENTATION_UNKNOWN; private FlashMode flashMode; private ExposureMode exposureMode; private FocusMode focusMode; @@ -106,6 +104,7 @@ public class Camera { private int exposureOffset; private boolean useAutoFocus = true; private Range fpsRange; + private PlatformChannel.DeviceOrientation lockedCaptureOrientation; private static final HashMap supportedImageFormats; // Current supported outputs @@ -136,18 +135,6 @@ public Camera( this.exposureMode = ExposureMode.auto; this.focusMode = FocusMode.auto; this.exposureOffset = 0; - orientationEventListener = - new OrientationEventListener(activity.getApplicationContext()) { - @Override - public void onOrientationChanged(int i) { - if (i == ORIENTATION_UNKNOWN) { - return; - } - // Convert the raw deg angle to the nearest multiple of 90. - currentOrientation = (int) Math.round(i / 90.0) * 90; - } - }; - orientationEventListener.enable(); cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraName); initFps(cameraCharacteristics); @@ -164,6 +151,10 @@ public void onOrientationChanged(int i) { new CameraZoom( cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE), cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)); + + deviceOrientationListener = + new DeviceOrientationManager(activity, dartMessenger, isFrontFacing, sensorOrientation); + deviceOrientationListener.start(); } private void initFps(CameraCharacteristics cameraCharacteristics) { @@ -195,7 +186,10 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException { mediaRecorder = new MediaRecorderBuilder(recordingProfile, outputFilePath) .setEnableAudio(enableAudio) - .setMediaOrientation(getMediaOrientation()) + .setMediaOrientation( + lockedCaptureOrientation == null + ? deviceOrientationListener.getMediaOrientation() + : deviceOrientationListener.getMediaOrientation(lockedCaptureOrientation)) .build(); } @@ -545,7 +539,11 @@ private void runPictureCapture() { final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(pictureImageReader.getSurface()); - captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getMediaOrientation()); + captureBuilder.set( + CaptureRequest.JPEG_ORIENTATION, + lockedCaptureOrientation == null + ? deviceOrientationListener.getMediaOrientation() + : deviceOrientationListener.getMediaOrientation(lockedCaptureOrientation)); switch (flashMode) { case off: captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); @@ -968,6 +966,14 @@ public void setZoomLevel(@NonNull final Result result, float zoom) throws Camera result.success(null); } + public void lockCaptureOrientation(PlatformChannel.DeviceOrientation orientation) { + this.lockedCaptureOrientation = orientation; + } + + public void unlockCaptureOrientation() { + this.lockedCaptureOrientation = null; + } + private void updateFpsRange() { if (fpsRange == null) { return; @@ -1160,14 +1166,6 @@ public void close() { public void dispose() { close(); flutterTexture.release(); - orientationEventListener.disable(); - } - - private int getMediaOrientation() { - final int sensorOrientationOffset = - (currentOrientation == ORIENTATION_UNKNOWN) - ? 0 - : (isFrontFacing) ? -currentOrientation : currentOrientation; - return (sensorOrientationOffset + sensorOrientation + 360) % 360; + deviceOrientationListener.stop(); } } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java index 6f04dc80e102..03993a3b51f9 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java @@ -14,6 +14,7 @@ import android.hardware.camera2.params.StreamConfigurationMap; import android.media.CamcorderProfile; import android.util.Size; +import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugins.camera.types.ResolutionPreset; import java.util.ArrayList; import java.util.Arrays; @@ -28,6 +29,59 @@ public final class CameraUtils { private CameraUtils() {} + static PlatformChannel.DeviceOrientation getDeviceOrientationFromDegrees(int degrees) { + // Round to the nearest 90 degrees. + degrees = (int) (Math.round(degrees / 90.0) * 90) % 360; + // Determine the corresponding device orientation. + switch (degrees) { + case 90: + return PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT; + case 180: + return PlatformChannel.DeviceOrientation.PORTRAIT_DOWN; + case 270: + return PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT; + case 0: + default: + return PlatformChannel.DeviceOrientation.PORTRAIT_UP; + } + } + + static String serializeDeviceOrientation(PlatformChannel.DeviceOrientation orientation) { + if (orientation == null) + throw new UnsupportedOperationException("Could not serialize null device orientation."); + switch (orientation) { + case PORTRAIT_UP: + return "portraitUp"; + case PORTRAIT_DOWN: + return "portraitDown"; + case LANDSCAPE_LEFT: + return "landscapeLeft"; + case LANDSCAPE_RIGHT: + return "landscapeRight"; + default: + throw new UnsupportedOperationException( + "Could not serialize device orientation: " + orientation.toString()); + } + } + + static PlatformChannel.DeviceOrientation deserializeDeviceOrientation(String orientation) { + if (orientation == null) + throw new UnsupportedOperationException("Could not deserialize null device orientation."); + switch (orientation) { + case "portraitUp": + return PlatformChannel.DeviceOrientation.PORTRAIT_UP; + case "portraitDown": + return PlatformChannel.DeviceOrientation.PORTRAIT_DOWN; + case "landscapeLeft": + return PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT; + case "landscapeRight": + return PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT; + default: + throw new UnsupportedOperationException( + "Could not deserialize device orientation: " + orientation); + } + } + static Size computeBestPreviewSize(String cameraName, ResolutionPreset preset) { if (preset.ordinal() > ResolutionPreset.high.ordinal()) { preset = ResolutionPreset.high; diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java index ec68ac0acda3..5681f723ed80 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java @@ -6,6 +6,7 @@ import android.text.TextUtils; import androidx.annotation.Nullable; +import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.camera.types.ExposureMode; @@ -14,16 +15,44 @@ import java.util.Map; class DartMessenger { - @Nullable private MethodChannel channel; + @Nullable private MethodChannel cameraChannel; + @Nullable private MethodChannel deviceChannel; - enum EventType { - ERROR, - CAMERA_CLOSING, - INITIALIZED, + enum DeviceEventType { + ORIENTATION_CHANGED("orientation_changed"); + private final String method; + + DeviceEventType(String method) { + this.method = method; + } + } + + enum CameraEventType { + ERROR("error"), + CLOSING("camera_closing"), + INITIALIZED("initialized"); + + private final String method; + + CameraEventType(String method) { + this.method = method; + } } DartMessenger(BinaryMessenger messenger, long cameraId) { - channel = new MethodChannel(messenger, "flutter.io/cameraPlugin/camera" + cameraId); + cameraChannel = new MethodChannel(messenger, "flutter.io/cameraPlugin/camera" + cameraId); + deviceChannel = new MethodChannel(messenger, "flutter.io/cameraPlugin/device"); + } + + void sendDeviceOrientationChangeEvent(PlatformChannel.DeviceOrientation orientation) { + assert (orientation != null); + this.send( + DeviceEventType.ORIENTATION_CHANGED, + new HashMap() { + { + put("orientation", CameraUtils.serializeDeviceOrientation(orientation)); + } + }); } void sendCameraInitializedEvent( @@ -40,7 +69,7 @@ void sendCameraInitializedEvent( assert (exposurePointSupported != null); assert (focusPointSupported != null); this.send( - EventType.INITIALIZED, + CameraEventType.INITIALIZED, new HashMap() { { put("previewWidth", previewWidth.doubleValue()); @@ -54,12 +83,12 @@ void sendCameraInitializedEvent( } void sendCameraClosingEvent() { - send(EventType.CAMERA_CLOSING); + send(CameraEventType.CLOSING); } void sendCameraErrorEvent(@Nullable String description) { this.send( - EventType.ERROR, + CameraEventType.ERROR, new HashMap() { { if (!TextUtils.isEmpty(description)) put("description", description); @@ -67,14 +96,25 @@ void sendCameraErrorEvent(@Nullable String description) { }); } - void send(EventType eventType) { + void send(CameraEventType eventType) { + send(eventType, new HashMap<>()); + } + + void send(CameraEventType eventType, Map args) { + if (cameraChannel == null) { + return; + } + cameraChannel.invokeMethod(eventType.method, args); + } + + void send(DeviceEventType eventType) { send(eventType, new HashMap<>()); } - void send(EventType eventType, Map args) { - if (channel == null) { + void send(DeviceEventType eventType, Map args) { + if (deviceChannel == null) { return; } - channel.invokeMethod(eventType.toString().toLowerCase(), args); + deviceChannel.invokeMethod(eventType.method, args); } } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java new file mode 100644 index 000000000000..d39a8da55cc8 --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java @@ -0,0 +1,201 @@ +// Copyright 2019 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. + +package io.flutter.plugins.camera; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Configuration; +import android.hardware.SensorManager; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; +import android.provider.Settings; +import android.view.Display; +import android.view.OrientationEventListener; +import android.view.Surface; +import android.view.WindowManager; +import io.flutter.embedding.engine.systemchannels.PlatformChannel; + +class DeviceOrientationManager { + + private static final IntentFilter orientationIntentFilter = + new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED); + + private final Activity activity; + private final DartMessenger messenger; + private final boolean isFrontFacing; + private final int sensorOrientation; + private PlatformChannel.DeviceOrientation lastOrientation; + private OrientationEventListener orientationEventListener; + private BroadcastReceiver broadcastReceiver; + + public DeviceOrientationManager( + Activity activity, DartMessenger messenger, boolean isFrontFacing, int sensorOrientation) { + this.activity = activity; + this.messenger = messenger; + this.isFrontFacing = isFrontFacing; + this.sensorOrientation = sensorOrientation; + } + + public void start() { + startSensorListener(); + startUIListener(); + } + + public void stop() { + stopSensorListener(); + stopUIListener(); + } + + public int getMediaOrientation() { + return this.getMediaOrientation(this.lastOrientation); + } + + public int getMediaOrientation(PlatformChannel.DeviceOrientation orientation) { + int angle = 0; + switch (orientation) { + case PORTRAIT_UP: + angle = 0; + break; + case PORTRAIT_DOWN: + angle = 180; + break; + case LANDSCAPE_LEFT: + angle = 90; + break; + case LANDSCAPE_RIGHT: + angle = 270; + break; + } + if (isFrontFacing) angle *= -1; + return (angle + sensorOrientation + 360) % 360; + } + + private void startSensorListener() { + if (orientationEventListener != null) return; + orientationEventListener = + new OrientationEventListener(activity, SensorManager.SENSOR_DELAY_NORMAL) { + @Override + public void onOrientationChanged(int angle) { + if (!isSystemAutoRotationLocked()) { + PlatformChannel.DeviceOrientation newOrientation = calculateSensorOrientation(angle); + if (!newOrientation.equals(lastOrientation)) { + lastOrientation = newOrientation; + messenger.sendDeviceOrientationChangeEvent(newOrientation); + } + } + } + }; + if (orientationEventListener.canDetectOrientation()) { + orientationEventListener.enable(); + } + } + + private void startUIListener() { + if (broadcastReceiver != null) return; + broadcastReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (isSystemAutoRotationLocked()) { + PlatformChannel.DeviceOrientation orientation = getUIOrientation(); + if (!orientation.equals(lastOrientation)) { + lastOrientation = orientation; + messenger.sendDeviceOrientationChangeEvent(orientation); + } + } + } + }; + activity.registerReceiver(broadcastReceiver, orientationIntentFilter); + broadcastReceiver.onReceive(activity, null); + } + + private void stopSensorListener() { + if (orientationEventListener == null) return; + orientationEventListener.disable(); + orientationEventListener = null; + } + + private void stopUIListener() { + if (broadcastReceiver == null) return; + activity.unregisterReceiver(broadcastReceiver); + broadcastReceiver = null; + } + + private boolean isSystemAutoRotationLocked() { + return android.provider.Settings.System.getInt( + activity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) + != 1; + } + + private PlatformChannel.DeviceOrientation getUIOrientation() { + final int rotation = getDisplay().getRotation(); + final int orientation = activity.getResources().getConfiguration().orientation; + + switch (orientation) { + case Configuration.ORIENTATION_PORTRAIT: + if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90) { + return PlatformChannel.DeviceOrientation.PORTRAIT_UP; + } else { + return PlatformChannel.DeviceOrientation.PORTRAIT_DOWN; + } + case Configuration.ORIENTATION_LANDSCAPE: + if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90) { + return PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT; + } else { + return PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT; + } + default: + return PlatformChannel.DeviceOrientation.PORTRAIT_UP; + } + } + + private PlatformChannel.DeviceOrientation calculateSensorOrientation(int angle) { + final int tolerance = 45; + angle += tolerance; + + // Orientation is 0 in the default orientation mode. This is portait-mode for phones + // and landscape for tablets. We have to compensate for this by calculating the default + // orientation, and apply an offset accordingly. + int defaultDeviceOrientation = getDeviceDefaultOrientation(); + if (defaultDeviceOrientation == Configuration.ORIENTATION_LANDSCAPE) { + angle += 90; + } + // Determine the orientation + angle = angle % 360; + return new PlatformChannel.DeviceOrientation[] { + PlatformChannel.DeviceOrientation.PORTRAIT_UP, + PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT, + PlatformChannel.DeviceOrientation.PORTRAIT_DOWN, + PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT, + } + [angle / 90]; + } + + private int getDeviceDefaultOrientation() { + Configuration config = activity.getResources().getConfiguration(); + int rotation = getDisplay().getRotation(); + if (((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) + && config.orientation == Configuration.ORIENTATION_LANDSCAPE) + || ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) + && config.orientation == Configuration.ORIENTATION_PORTRAIT)) { + return Configuration.ORIENTATION_LANDSCAPE; + } else { + return Configuration.ORIENTATION_PORTRAIT; + } + } + + @SuppressWarnings("deprecation") + private Display getDisplay() { + if (VERSION.SDK_INT >= VERSION_CODES.R) { + return activity.getDisplay(); + } else { + return ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay(); + } + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 36048dbb5176..aa7483f55679 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -8,6 +8,7 @@ import android.hardware.camera2.CameraAccessException; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodCall; @@ -255,7 +256,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) case "stopImageStream": { try { - camera.stopImageStream(); + camera.startPreview(); result.success(null); } catch (Exception e) { handleException(e, result); @@ -305,6 +306,29 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) } break; } + case "lockCaptureOrientation": + { + PlatformChannel.DeviceOrientation orientation = + CameraUtils.deserializeDeviceOrientation(call.argument("orientation")); + + try { + camera.lockCaptureOrientation(orientation); + result.success(null); + } catch (Exception e) { + handleException(e, result); + } + break; + } + case "unlockCaptureOrientation": + { + try { + camera.unlockCaptureOrientation(); + result.success(null); + } catch (Exception e) { + handleException(e, result); + } + break; + } case "dispose": { if (camera != null) { diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java new file mode 100644 index 000000000000..8026b6349aa1 --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java @@ -0,0 +1,102 @@ +// Copyright 2019 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. + +package io.flutter.plugins.camera; + +import static org.junit.Assert.assertEquals; + +import io.flutter.embedding.engine.systemchannels.PlatformChannel; +import org.junit.Test; + +public class CameraUtilsTest { + + @Test + public void serializeDeviceOrientation_serializes_correctly() { + assertEquals( + "portraitUp", + CameraUtils.serializeDeviceOrientation(PlatformChannel.DeviceOrientation.PORTRAIT_UP)); + assertEquals( + "portraitDown", + CameraUtils.serializeDeviceOrientation(PlatformChannel.DeviceOrientation.PORTRAIT_DOWN)); + assertEquals( + "landscapeLeft", + CameraUtils.serializeDeviceOrientation(PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT)); + assertEquals( + "landscapeRight", + CameraUtils.serializeDeviceOrientation(PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT)); + } + + @Test(expected = UnsupportedOperationException.class) + public void serializeDeviceOrientation_throws_for_null() { + CameraUtils.serializeDeviceOrientation(null); + } + + @Test + public void deserializeDeviceOrientation_deserializes_correctly() { + assertEquals( + PlatformChannel.DeviceOrientation.PORTRAIT_UP, + CameraUtils.deserializeDeviceOrientation("portraitUp")); + assertEquals( + PlatformChannel.DeviceOrientation.PORTRAIT_DOWN, + CameraUtils.deserializeDeviceOrientation("portraitDown")); + assertEquals( + PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT, + CameraUtils.deserializeDeviceOrientation("landscapeLeft")); + assertEquals( + PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT, + CameraUtils.deserializeDeviceOrientation("landscapeRight")); + } + + @Test(expected = UnsupportedOperationException.class) + public void deserializeDeviceOrientation_throws_for_null() { + CameraUtils.deserializeDeviceOrientation(null); + } + + @Test + public void getDeviceOrientationFromDegrees_converts_correctly() { + // Portrait UP + assertEquals( + PlatformChannel.DeviceOrientation.PORTRAIT_UP, + CameraUtils.getDeviceOrientationFromDegrees(0)); + assertEquals( + PlatformChannel.DeviceOrientation.PORTRAIT_UP, + CameraUtils.getDeviceOrientationFromDegrees(315)); + assertEquals( + PlatformChannel.DeviceOrientation.PORTRAIT_UP, + CameraUtils.getDeviceOrientationFromDegrees(44)); + assertEquals( + PlatformChannel.DeviceOrientation.PORTRAIT_UP, + CameraUtils.getDeviceOrientationFromDegrees(-45)); + // Portrait DOWN + assertEquals( + PlatformChannel.DeviceOrientation.PORTRAIT_DOWN, + CameraUtils.getDeviceOrientationFromDegrees(180)); + assertEquals( + PlatformChannel.DeviceOrientation.PORTRAIT_DOWN, + CameraUtils.getDeviceOrientationFromDegrees(135)); + assertEquals( + PlatformChannel.DeviceOrientation.PORTRAIT_DOWN, + CameraUtils.getDeviceOrientationFromDegrees(224)); + // Landscape LEFT + assertEquals( + PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT, + CameraUtils.getDeviceOrientationFromDegrees(90)); + assertEquals( + PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT, + CameraUtils.getDeviceOrientationFromDegrees(45)); + assertEquals( + PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT, + CameraUtils.getDeviceOrientationFromDegrees(134)); + // Landscape RIGHT + assertEquals( + PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT, + CameraUtils.getDeviceOrientationFromDegrees(270)); + assertEquals( + PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT, + CameraUtils.getDeviceOrientationFromDegrees(225)); + assertEquals( + PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT, + CameraUtils.getDeviceOrientationFromDegrees(314)); + } +} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java index 64425b7b8283..e835b08f441a 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java @@ -8,6 +8,7 @@ import static org.junit.Assert.assertEquals; import androidx.annotation.NonNull; +import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.StandardMethodCodec; @@ -89,6 +90,17 @@ public void sendCameraClosingEvent() { assertNull(call.argument("description")); } + @Test + public void sendDeviceOrientationChangedEvent() { + dartMessenger.sendDeviceOrientationChangeEvent(PlatformChannel.DeviceOrientation.PORTRAIT_UP); + + List sentMessages = fakeBinaryMessenger.getMessages(); + assertEquals(1, sentMessages.size()); + MethodCall call = decodeSentMessage(sentMessages.get(0)); + assertEquals("orientation_changed", call.method); + assertEquals(call.argument("orientation"), "portraitUp"); + } + private MethodCall decodeSentMessage(ByteBuffer sentMessage) { sentMessage.position(0); diff --git a/packages/camera/camera/example/android/app/build.gradle b/packages/camera/camera/example/android/app/build.gradle index 7d0e281b74e8..c5eeb246fe30 100644 --- a/packages/camera/camera/example/android/app/build.gradle +++ b/packages/camera/camera/example/android/app/build.gradle @@ -25,7 +25,7 @@ apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 29 + compileSdkVersion 30 lintOptions { disable 'InvalidPackage' diff --git a/packages/camera/camera/example/ios/Runner/Info.plist b/packages/camera/camera/example/ios/Runner/Info.plist index f389a129e028..ff2e341a1803 100644 --- a/packages/camera/camera/example/ios/Runner/Info.plist +++ b/packages/camera/camera/example/ios/Runner/Info.plist @@ -39,6 +39,7 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 681a45172816..490cae6676d3 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -171,18 +171,18 @@ class _CameraExampleHomeState extends State ), ); } else { - return AspectRatio( - aspectRatio: controller.value.aspectRatio, - child: Listener( - onPointerDown: (_) => _pointers++, - onPointerUp: (_) => _pointers--, + return Listener( + onPointerDown: (_) => _pointers++, + onPointerUp: (_) => _pointers--, + child: CameraPreview( + controller, child: LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { return GestureDetector( + behavior: HitTestBehavior.opaque, onScaleStart: _handleScaleStart, onScaleUpdate: _handleScaleUpdate, onTapDown: (details) => onViewFinderTap(details, constraints), - child: CameraPreview(controller), ); }), ), @@ -269,6 +269,15 @@ class _CameraExampleHomeState extends State color: Colors.blue, onPressed: controller != null ? onAudioModeButtonPressed : null, ), + IconButton( + icon: Icon(controller?.value?.isCaptureOrientationLocked ?? false + ? Icons.screen_lock_rotation + : Icons.screen_rotation), + color: Colors.blue, + onPressed: controller != null + ? onCaptureOrientationLockButtonPressed + : null, + ), ], ), _flashModeControlRowWidget(), @@ -634,6 +643,19 @@ class _CameraExampleHomeState extends State } } + void onCaptureOrientationLockButtonPressed() async { + if (controller != null) { + if (controller.value.isCaptureOrientationLocked) { + await controller.unlockCaptureOrientation(); + showInSnackBar('Capture orientation unlocked'); + } else { + await controller.lockCaptureOrientation(); + showInSnackBar( + 'Capture orientation locked to ${controller.value.lockedCaptureOrientation.toString().split('.').last}'); + } + } + } + void onSetFlashModeButtonPressed(FlashMode mode) { setFlashMode(mode).then((_) { if (mounted) setState(() {}); diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index 298b906ace7b..40d93fde7af6 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -18,8 +18,6 @@ @interface FLTSavePhotoDelegate : NSObject @property(readonly, nonatomic) NSString *path; @property(readonly, nonatomic) FlutterResult result; -@property(readonly, nonatomic) CMMotionManager *motionManager; -@property(readonly, nonatomic) AVCaptureDevicePosition cameraPosition; @end @interface FLTImageStreamHandler : NSObject @@ -45,15 +43,10 @@ @implementation FLTSavePhotoDelegate { FLTSavePhotoDelegate *selfReference; } -- initWithPath:(NSString *)path - result:(FlutterResult)result - motionManager:(CMMotionManager *)motionManager - cameraPosition:(AVCaptureDevicePosition)cameraPosition { +- initWithPath:(NSString *)path result:(FlutterResult)result { self = [super init]; NSAssert(self, @"super init cannot be nil"); _path = path; - _motionManager = motionManager; - _cameraPosition = cameraPosition; selfReference = self; _result = result; return self; @@ -70,15 +63,14 @@ - (void)captureOutput:(AVCapturePhotoOutput *)output _result(getFlutterError(error)); return; } + NSData *data = [AVCapturePhotoOutput JPEGPhotoDataRepresentationForJPEGSampleBuffer:photoSampleBuffer previewPhotoSampleBuffer:previewPhotoSampleBuffer]; - UIImage *image = [UIImage imageWithCGImage:[UIImage imageWithData:data].CGImage - scale:1.0 - orientation:[self getImageRotation]]; // TODO(sigurdm): Consider writing file asynchronously. - bool success = [UIImageJPEGRepresentation(image, 1.0) writeToFile:_path atomically:YES]; + bool success = [data writeToFile:_path atomically:YES]; + if (!success) { _result([FlutterError errorWithCode:@"IOError" message:@"Unable to write file" details:nil]); return; @@ -104,34 +96,6 @@ - (void)captureOutput:(AVCapturePhotoOutput *)output } _result(_path); } - -- (UIImageOrientation)getImageRotation { - float const threshold = 45.0; - BOOL (^isNearValue)(float value1, float value2) = ^BOOL(float value1, float value2) { - return fabsf(value1 - value2) < threshold; - }; - BOOL (^isNearValueABS)(float value1, float value2) = ^BOOL(float value1, float value2) { - return isNearValue(fabsf(value1), fabsf(value2)); - }; - float yxAtan = (atan2(_motionManager.accelerometerData.acceleration.y, - _motionManager.accelerometerData.acceleration.x)) * - 180 / M_PI; - if (isNearValue(-90.0, yxAtan)) { - return UIImageOrientationRight; - } else if (isNearValueABS(180.0, yxAtan)) { - return _cameraPosition == AVCaptureDevicePositionBack ? UIImageOrientationUp - : UIImageOrientationDown; - } else if (isNearValueABS(0.0, yxAtan)) { - return _cameraPosition == AVCaptureDevicePositionBack ? UIImageOrientationDown /*rotate 180* */ - : UIImageOrientationUp /*do not rotate*/; - } else if (isNearValue(90.0, yxAtan)) { - return UIImageOrientationLeft; - } - // If none of the above, then the device is likely facing straight down or straight up -- just - // pick something arbitrary - // TODO: Maybe use the UIInterfaceOrientation if in these scenarios - return UIImageOrientationUp; -} @end // Mirrors FlashMode in flash_mode.dart @@ -226,6 +190,42 @@ static ExposureMode getExposureModeForString(NSString *mode) { } } +static UIDeviceOrientation getUIDeviceOrientationForString(NSString *orientation) { + if ([orientation isEqualToString:@"portraitDown"]) { + return UIDeviceOrientationPortraitUpsideDown; + } else if ([orientation isEqualToString:@"landscapeLeft"]) { + return UIDeviceOrientationLandscapeRight; + } else if ([orientation isEqualToString:@"landscapeRight"]) { + return UIDeviceOrientationLandscapeLeft; + } else if ([orientation isEqualToString:@"portraitUp"]) { + return UIDeviceOrientationPortrait; + } else { + NSError *error = [NSError + errorWithDomain:NSCocoaErrorDomain + code:NSURLErrorUnknown + userInfo:@{ + NSLocalizedDescriptionKey : + [NSString stringWithFormat:@"Unknown device orientation %@", orientation] + }]; + @throw error; + } +} + +static NSString *getStringForUIDeviceOrientation(UIDeviceOrientation orientation) { + switch (orientation) { + case UIDeviceOrientationPortraitUpsideDown: + return @"portraitDown"; + case UIDeviceOrientationLandscapeRight: + return @"landscapeLeft"; + case UIDeviceOrientationLandscapeLeft: + return @"landscapeRight"; + case UIDeviceOrientationPortrait: + default: + return @"portraitUp"; + break; + }; +} + // Mirrors FocusMode in camera.dart typedef enum { FocusModeAuto, @@ -334,6 +334,7 @@ @interface FLTCam : NSObject *registry; @property(readonly, nonatomic) NSObject *messenger; @property(readonly, nonatomic) FLTCam *camera; +@property(readonly, nonatomic) FlutterMethodChannel *deviceEventMethodChannel; @end @implementation CameraPlugin { @@ -1161,9 +1236,36 @@ - (instancetype)initWithRegistry:(NSObject *)registry NSAssert(self, @"super init cannot be nil"); _registry = registry; _messenger = messenger; + [self initDeviceEventMethodChannel]; + [self startOrientationListener]; return self; } +- (void)initDeviceEventMethodChannel { + _deviceEventMethodChannel = + [FlutterMethodChannel methodChannelWithName:@"flutter.io/cameraPlugin/device" + binaryMessenger:_messenger]; +} + +- (void)startOrientationListener { + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(orientationChanged:) + name:UIDeviceOrientationDidChangeNotification + object:[UIDevice currentDevice]]; +} + +- (void)orientationChanged:(NSNotification *)note { + UIDevice *device = note.object; + [self sendDeviceOrientation:device.orientation]; +} + +- (void)sendDeviceOrientation:(UIDeviceOrientation)orientation { + [_deviceEventMethodChannel + invokeMethod:@"orientation_changed" + arguments:@{@"orientation" : getStringForUIDeviceOrientation(orientation)}]; +} + - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { if (_dispatchQueue == nil) { _dispatchQueue = dispatch_queue_create("io.flutter.camera.dispatchqueue", NULL); @@ -1265,6 +1367,7 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re @([_camera.captureDevice isExposurePointOfInterestSupported]), @"focusPointSupported" : @([_camera.captureDevice isFocusPointOfInterestSupported]), }]; + [self sendDeviceOrientation:[UIDevice currentDevice].orientation]; [_camera start]; result(nil); } else if ([@"takePicture" isEqualToString:call.method]) { @@ -1318,6 +1421,10 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re } else if ([@"setExposureOffset" isEqualToString:call.method]) { [_camera setExposureOffsetWithResult:result offset:((NSNumber *)call.arguments[@"offset"]).doubleValue]; + } else if ([@"lockCaptureOrientation" isEqualToString:call.method]) { + [_camera lockCaptureOrientationWithResult:result orientation:call.arguments[@"orientation"]]; + } else if ([@"unlockCaptureOrientation" isEqualToString:call.method]) { + [_camera unlockCaptureOrientationWithResult:result]; } else if ([@"setFocusMode" isEqualToString:call.method]) { [_camera setFocusModeWithResult:result mode:call.arguments[@"mode"]]; } else if ([@"setFocusPoint" isEqualToString:call.method]) { diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index ae79cc4ad367..807bec367256 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -11,6 +11,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:pedantic/pedantic.dart'; +import 'package:quiver/core.dart'; final MethodChannel _channel = const MethodChannel('plugins.flutter.io/camera'); @@ -43,6 +44,9 @@ class CameraValue { this.focusMode, this.exposurePointSupported, this.focusPointSupported, + this.deviceOrientation, + this.lockedCaptureOrientation, + this.recordingOrientation, }) : _isRecordingPaused = isRecordingPaused; /// Creates a new camera controller state for an uninitialized controller. @@ -56,6 +60,7 @@ class CameraValue { flashMode: FlashMode.auto, exposurePointSupported: false, focusPointSupported: false, + deviceOrientation: DeviceOrientation.portraitUp, ); /// True after [CameraController.initialize] has completed successfully. @@ -86,10 +91,10 @@ class CameraValue { /// Is `null` until [isInitialized] is `true`. final Size previewSize; - /// Convenience getter for `previewSize.height / previewSize.width`. + /// Convenience getter for `previewSize.width / previewSize.height`. /// /// Can only be called when [initialize] is done. - double get aspectRatio => previewSize.height / previewSize.width; + double get aspectRatio => previewSize.width / previewSize.height; /// Whether the controller is in an error state. /// @@ -111,6 +116,18 @@ class CameraValue { /// Whether setting the focus point is supported. final bool focusPointSupported; + /// The current device orientation. + final DeviceOrientation deviceOrientation; + + /// The currently locked capture orientation. + final DeviceOrientation lockedCaptureOrientation; + + /// Whether the capture orientation is currently locked. + bool get isCaptureOrientationLocked => lockedCaptureOrientation != null; + + /// The orientation of the currently running video recording. + final DeviceOrientation recordingOrientation; + /// Creates a modified copy of the object. /// /// Explicitly specified fields get the specified value, all other fields get @@ -128,6 +145,9 @@ class CameraValue { FocusMode focusMode, bool exposurePointSupported, bool focusPointSupported, + DeviceOrientation deviceOrientation, + Optional lockedCaptureOrientation, + Optional recordingOrientation, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -143,6 +163,13 @@ class CameraValue { exposurePointSupported: exposurePointSupported ?? this.exposurePointSupported, focusPointSupported: focusPointSupported ?? this.focusPointSupported, + deviceOrientation: deviceOrientation ?? this.deviceOrientation, + lockedCaptureOrientation: lockedCaptureOrientation == null + ? this.lockedCaptureOrientation + : lockedCaptureOrientation.orNull, + recordingOrientation: recordingOrientation == null + ? this.recordingOrientation + : recordingOrientation.orNull, ); } @@ -158,7 +185,10 @@ class CameraValue { 'exposureMode: $exposureMode, ' 'focusMode: $focusMode, ' 'exposurePointSupported: $exposurePointSupported, ' - 'focusPointSupported: $focusPointSupported)'; + 'focusPointSupported: $focusPointSupported, ' + 'deviceOrientation: $deviceOrientation, ' + 'lockedCaptureOrientation: $lockedCaptureOrientation, ' + 'recordingOrientation: $recordingOrientation)'; } } @@ -201,6 +231,7 @@ class CameraController extends ValueNotifier { bool _isDisposed = false; StreamSubscription _imageStreamSubscription; FutureOr _initCalled; + StreamSubscription _deviceOrientationSubscription; /// Checks whether [CameraController.dispose] has completed successfully. /// @@ -225,6 +256,13 @@ class CameraController extends ValueNotifier { try { Completer _initializeCompleter = Completer(); + _deviceOrientationSubscription = + CameraPlatform.instance.onDeviceOrientationChanged().listen((event) { + value = value.copyWith( + deviceOrientation: event.orientation, + ); + }); + _cameraId = await CameraPlatform.instance.createCamera( description, resolutionPreset, @@ -431,7 +469,11 @@ class CameraController extends ValueNotifier { try { await CameraPlatform.instance.startVideoRecording(_cameraId); - value = value.copyWith(isRecordingVideo: true, isRecordingPaused: false); + value = value.copyWith( + isRecordingVideo: true, + isRecordingPaused: false, + recordingOrientation: Optional.fromNullable( + value.lockedCaptureOrientation ?? value.deviceOrientation)); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } @@ -455,7 +497,10 @@ class CameraController extends ValueNotifier { } try { XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); - value = value.copyWith(isRecordingVideo: false); + value = value.copyWith( + isRecordingVideo: false, + recordingOrientation: Optional.absent(), + ); return file; } on PlatformException catch (e) { throw CameraException(e.code, e.message); @@ -718,6 +763,21 @@ class CameraController extends ValueNotifier { } } + /// Locks the capture orientation. + /// + /// If [orientation] is omitted, the current device orientation is used. + Future lockCaptureOrientation([DeviceOrientation orientation]) async { + try { + await CameraPlatform.instance.lockCaptureOrientation( + _cameraId, orientation ?? value.deviceOrientation); + value = value.copyWith( + lockedCaptureOrientation: + Optional.fromNullable(orientation ?? value.deviceOrientation)); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + /// Sets the focus mode for taking pictures. Future setFocusMode(FocusMode mode) async { try { @@ -728,6 +788,16 @@ class CameraController extends ValueNotifier { } } + /// Unlocks the capture orientation. + Future unlockCaptureOrientation() async { + try { + await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); + value = value.copyWith(lockedCaptureOrientation: Optional.absent()); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + /// Sets the focus point for automatically determining the focus value. Future setFocusPoint(Offset point) async { if (point != null && @@ -756,6 +826,7 @@ class CameraController extends ValueNotifier { if (_isDisposed) { return; } + unawaited(_deviceOrientationSubscription?.cancel()); _isDisposed = true; super.dispose(); if (_initCalled != null) { diff --git a/packages/camera/camera/lib/src/camera_preview.dart b/packages/camera/camera/lib/src/camera_preview.dart index bf7862eb9151..05e969004233 100644 --- a/packages/camera/camera/lib/src/camera_preview.dart +++ b/packages/camera/camera/lib/src/camera_preview.dart @@ -4,20 +4,63 @@ import 'package:camera/camera.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; /// A widget showing a live camera preview. class CameraPreview extends StatelessWidget { /// Creates a preview widget for the given camera controller. - const CameraPreview(this.controller); + const CameraPreview(this.controller, {this.child}); /// The controller for the camera that the preview is shown for. final CameraController controller; + /// A widget to overlay on top of the camera preview + final Widget child; + @override Widget build(BuildContext context) { return controller.value.isInitialized - ? CameraPlatform.instance.buildPreview(controller.cameraId) + ? AspectRatio( + aspectRatio: _isLandscape() + ? controller.value.aspectRatio + : (1 / controller.value.aspectRatio), + child: Stack( + fit: StackFit.expand, + children: [ + RotatedBox( + quarterTurns: _getQuarterTurns(), + child: + CameraPlatform.instance.buildPreview(controller.cameraId), + ), + child ?? Container(), + ], + ), + ) : Container(); } + + DeviceOrientation _getApplicableOrientation() { + return controller.value.isRecordingVideo + ? controller.value.recordingOrientation + : (controller.value.lockedCaptureOrientation ?? + controller.value.deviceOrientation); + } + + bool _isLandscape() { + return [DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight] + .contains(_getApplicableOrientation()); + } + + int _getQuarterTurns() { + int platformOffset = defaultTargetPlatform == TargetPlatform.iOS ? 1 : 0; + Map turns = { + DeviceOrientation.portraitUp: 0, + DeviceOrientation.landscapeLeft: 1, + DeviceOrientation.portraitDown: 2, + DeviceOrientation.landscapeRight: 3, + }; + return turns[_getApplicableOrientation()] + platformOffset; + } } diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 0b21497b5462..b0ebb9c16361 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.6 +version: 0.7.0 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: @@ -10,6 +10,7 @@ dependencies: sdk: flutter camera_platform_interface: ^1.5.0 pedantic: ^1.8.0 + quiver: ^2.1.5 dev_dependencies: path_provider: ^0.5.0 diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 1cea609d1741..2f53691217cb 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -38,6 +38,9 @@ get mockOnCameraInitializedEvent => CameraInitializedEvent( true, ); +get mockOnDeviceOrientationChangedEvent => + DeviceOrientationChangedEvent(DeviceOrientation.portraitUp); + get mockOnCameraClosingEvent => null; get mockOnCameraErrorEvent => CameraErrorEvent(13, 'closing'); @@ -1021,6 +1024,106 @@ void main() { .setExposureOffset(cameraController.cameraId, -0.4)) .called(4); }); + + test('lockCaptureOrientation() calls $CameraPlatform', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.lockCaptureOrientation(); + expect(cameraController.value.lockedCaptureOrientation, + equals(DeviceOrientation.portraitUp)); + await cameraController + .lockCaptureOrientation(DeviceOrientation.landscapeRight); + expect(cameraController.value.lockedCaptureOrientation, + equals(DeviceOrientation.landscapeRight)); + + verify(CameraPlatform.instance.lockCaptureOrientation( + cameraController.cameraId, DeviceOrientation.portraitUp)) + .called(1); + verify(CameraPlatform.instance.lockCaptureOrientation( + cameraController.cameraId, DeviceOrientation.landscapeRight)) + .called(1); + }); + + test( + 'lockCaptureOrientation() throws $CameraException on $PlatformException', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + when(CameraPlatform.instance.lockCaptureOrientation( + cameraController.cameraId, DeviceOrientation.portraitUp)) + .thenThrow( + PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error message', + details: null, + ), + ); + + expect( + cameraController.lockCaptureOrientation(DeviceOrientation.portraitUp), + throwsA(isA().having( + (error) => error.description, + 'TEST_ERROR', + 'This is a test error message', + ))); + }); + + test('unlockCaptureOrientation() calls $CameraPlatform', () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + await cameraController.unlockCaptureOrientation(); + expect(cameraController.value.lockedCaptureOrientation, equals(null)); + + verify(CameraPlatform.instance + .unlockCaptureOrientation(cameraController.cameraId)) + .called(1); + }); + + test( + 'unlockCaptureOrientation() throws $CameraException on $PlatformException', + () async { + CameraController cameraController = CameraController( + CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + when(CameraPlatform.instance + .unlockCaptureOrientation(cameraController.cameraId)) + .thenThrow( + PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error message', + details: null, + ), + ); + + expect( + cameraController.unlockCaptureOrientation(), + throwsA(isA().having( + (error) => error.description, + 'TEST_ERROR', + 'This is a test error message', + ))); + }); }); } @@ -1057,6 +1160,10 @@ class MockCameraPlatform extends Mock Stream onCameraError(int cameraId) => Stream.value(mockOnCameraErrorEvent); + @override + Stream onDeviceOrientationChanged() => + Stream.value(mockOnDeviceOrientationChangedEvent); + @override Future takePicture(int cameraId) => mockPlatformException ? throw PlatformException(code: 'foo', message: 'bar') diff --git a/packages/camera/camera/test/camera_value_test.dart b/packages/camera/camera/test/camera_value_test.dart index eb7927b9eb6c..c365f6ddb9de 100644 --- a/packages/camera/camera/test/camera_value_test.dart +++ b/packages/camera/camera/test/camera_value_test.dart @@ -7,22 +7,27 @@ import 'dart:ui'; import 'package:camera/camera.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { group('camera_value', () { test('Can be created', () { var cameraValue = const CameraValue( - isInitialized: false, - errorDescription: null, - previewSize: Size(10, 10), - isRecordingPaused: false, - isRecordingVideo: false, - isTakingPicture: false, - isStreamingImages: false, - flashMode: FlashMode.auto, - exposureMode: ExposureMode.auto, - exposurePointSupported: true); + isInitialized: false, + errorDescription: null, + previewSize: Size(10, 10), + isRecordingPaused: false, + isRecordingVideo: false, + isTakingPicture: false, + isStreamingImages: false, + flashMode: FlashMode.auto, + exposureMode: ExposureMode.auto, + exposurePointSupported: true, + deviceOrientation: DeviceOrientation.portraitUp, + lockedCaptureOrientation: DeviceOrientation.portraitUp, + recordingOrientation: DeviceOrientation.portraitUp, + ); expect(cameraValue, isA()); expect(cameraValue.isInitialized, isFalse); @@ -35,6 +40,10 @@ void main() { expect(cameraValue.flashMode, FlashMode.auto); expect(cameraValue.exposureMode, ExposureMode.auto); expect(cameraValue.exposurePointSupported, true); + expect(cameraValue.deviceOrientation, DeviceOrientation.portraitUp); + expect( + cameraValue.lockedCaptureOrientation, DeviceOrientation.portraitUp); + expect(cameraValue.recordingOrientation, DeviceOrientation.portraitUp); }); test('Can be created as uninitialized', () { @@ -51,6 +60,9 @@ void main() { expect(cameraValue.flashMode, FlashMode.auto); expect(cameraValue.exposureMode, null); expect(cameraValue.exposurePointSupported, false); + expect(cameraValue.deviceOrientation, DeviceOrientation.portraitUp); + expect(cameraValue.lockedCaptureOrientation, null); + expect(cameraValue.recordingOrientation, null); }); test('Can be copied with isInitialized', () { @@ -68,6 +80,9 @@ void main() { expect(cameraValue.flashMode, FlashMode.auto); expect(cameraValue.exposureMode, null); expect(cameraValue.exposurePointSupported, false); + expect(cameraValue.deviceOrientation, DeviceOrientation.portraitUp); + expect(cameraValue.lockedCaptureOrientation, null); + expect(cameraValue.recordingOrientation, null); }); test('Has aspectRatio after setting size', () { @@ -75,7 +90,7 @@ void main() { var cameraValue = cv.copyWith(isInitialized: true, previewSize: Size(20, 10)); - expect(cameraValue.aspectRatio, 0.5); + expect(cameraValue.aspectRatio, 2.0); }); test('hasError is true after setting errorDescription', () { @@ -110,10 +125,13 @@ void main() { focusMode: FocusMode.auto, exposurePointSupported: true, focusPointSupported: true, + deviceOrientation: DeviceOrientation.portraitUp, + lockedCaptureOrientation: DeviceOrientation.portraitUp, + recordingOrientation: DeviceOrientation.portraitUp, ); expect(cameraValue.toString(), - 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false, flashMode: FlashMode.auto, exposureMode: ExposureMode.auto, focusMode: FocusMode.auto, exposurePointSupported: true, focusPointSupported: true)'); + 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false, flashMode: FlashMode.auto, exposureMode: ExposureMode.auto, focusMode: FocusMode.auto, exposurePointSupported: true, focusPointSupported: true, deviceOrientation: DeviceOrientation.portraitUp, lockedCaptureOrientation: DeviceOrientation.portraitUp, recordingOrientation: DeviceOrientation.portraitUp)'); }); }); } From 0434f0640052927f12f08439fc78d5afcaeb56c1 Mon Sep 17 00:00:00 2001 From: Aleksandr Yurkovskiy Date: Wed, 13 Jan 2021 23:29:06 +0300 Subject: [PATCH 096/924] [google_maps_flutter] Adds support for holes in polygon overlays to the Google Maps plugin (#1721) --- .../google_maps_flutter/CHANGELOG.md | 4 + .../flutter/plugins/googlemaps/Convert.java | 18 +- .../plugins/googlemaps/PolygonBuilder.java | 7 + .../plugins/googlemaps/PolygonController.java | 4 + .../googlemaps/PolygonOptionsSink.java | 2 + .../example/lib/place_polygon.dart | 60 ++++- .../ios/Classes/GoogleMapPolygonController.h | 1 + .../ios/Classes/GoogleMapPolygonController.m | 22 ++ .../ios/Classes/JsonConversions.h | 1 + .../ios/Classes/JsonConversions.m | 10 + .../lib/google_maps_flutter.dart | 1 - .../google_maps_flutter/pubspec.yaml | 4 +- .../test/fake_maps_controllers.dart | 10 + .../test/polygon_updates_test.dart | 221 ++++++++++++++++-- 14 files changed, 341 insertions(+), 24 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index b23ef79651e7..6dcb967f9cb4 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.0 + +* Add support for holes in Polygons. + ## 1.0.10 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 7222511a2a3b..4108a1d23bb5 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -468,6 +468,10 @@ static String interpretPolygonOptions(Object o, PolygonOptionsSink sink) { if (points != null) { sink.setPoints(toPoints(points)); } + final Object holes = data.get("holes"); + if (holes != null) { + sink.setHoles(toHoles(holes)); + } final String polygonId = (String) data.get("polygonId"); if (polygonId == null) { throw new IllegalArgumentException("polygonId was null"); @@ -576,13 +580,23 @@ private static List toPoints(Object o) { final List data = toList(o); final List points = new ArrayList<>(data.size()); - for (Object ob : data) { - final List point = toList(ob); + for (Object rawPoint : data) { + final List point = toList(rawPoint); points.add(new LatLng(toFloat(point.get(0)), toFloat(point.get(1)))); } return points; } + private static List> toHoles(Object o) { + final List data = toList(o); + final List> holes = new ArrayList<>(data.size()); + + for (Object rawHole : data) { + holes.add(toPoints(rawHole)); + } + return holes; + } + private static List toPattern(Object o) { final List data = toList(o); diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java index 600762afe4ee..7691e58e4ae6 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java @@ -41,6 +41,13 @@ public void setPoints(List points) { polygonOptions.addAll(points); } + @Override + public void setHoles(List> holes) { + for (List hole : holes) { + polygonOptions.addHole(hole); + } + } + @Override public void setConsumeTapEvents(boolean consumeTapEvents) { this.consumeTapEvents = consumeTapEvents; diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java index adb01b8a490a..43f1bfd7ec4c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java @@ -52,6 +52,10 @@ public void setPoints(List points) { polygon.setPoints(points); } + public void setHoles(List> holes) { + polygon.setHoles(holes); + } + @Override public void setVisible(boolean visible) { polygon.setVisible(visible); diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java index df4dae0fda4e..2985a7b762e5 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java @@ -20,6 +20,8 @@ interface PolygonOptionsSink { void setPoints(List points); + void setHoles(List> holes); + void setVisible(boolean visible); void setStrokeWidth(float width); diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart index af5ca16bea17..5f2a0985b1b9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart @@ -30,7 +30,8 @@ class PlacePolygonBodyState extends State { GoogleMapController controller; Map polygons = {}; - int _polygonIdCounter = 1; + Map polygonOffsets = {}; + int _polygonIdCounter = 0; PolygonId selectedPolygon; // Values when toggling polygon color @@ -79,7 +80,6 @@ class PlacePolygonBodyState extends State { } final String polygonIdVal = 'polygon_id_$_polygonIdCounter'; - _polygonIdCounter++; final PolygonId polygonId = PolygonId(polygonIdVal); final Polygon polygon = Polygon( @@ -96,6 +96,9 @@ class PlacePolygonBodyState extends State { setState(() { polygons[polygonId] = polygon; + polygonOffsets[polygonId] = _polygonIdCounter.ceilToDouble(); + // increment _polygonIdCounter to have unique polygon id each time + _polygonIdCounter++; }); } @@ -144,6 +147,22 @@ class PlacePolygonBodyState extends State { }); } + void _addHoles() { + final Polygon polygon = polygons[selectedPolygon]; + setState(() { + polygons[selectedPolygon] = polygon.copyWith(holesParam: _createHoles()); + }); + } + + void _removeHoles() { + final Polygon polygon = polygons[selectedPolygon]; + setState(() { + polygons[selectedPolygon] = polygon.copyWith( + holesParam: >[], + ); + }); + } + @override Widget build(BuildContext context) { return Column( @@ -196,6 +215,22 @@ class PlacePolygonBodyState extends State { ), Column( children: [ + TextButton( + child: const Text('add holes'), + onPressed: (selectedPolygon == null) + ? null + : ((polygons[selectedPolygon].holes.isNotEmpty) + ? null + : _addHoles), + ), + TextButton( + child: const Text('remove holes'), + onPressed: (selectedPolygon == null) + ? null + : ((polygons[selectedPolygon].holes.isEmpty) + ? null + : _removeHoles), + ), TextButton( child: const Text('change stroke width'), onPressed: @@ -235,6 +270,27 @@ class PlacePolygonBodyState extends State { return points; } + List> _createHoles() { + final List> holes = >[]; + final double offset = polygonOffsets[selectedPolygon]; + + final List hole1 = []; + hole1.add(_createLatLng(51.8395 + offset, -3.8814)); + hole1.add(_createLatLng(52.0234 + offset, -3.9914)); + hole1.add(_createLatLng(52.1351 + offset, -4.4435)); + hole1.add(_createLatLng(52.0231 + offset, -4.5829)); + holes.add(hole1); + + final List hole2 = []; + hole2.add(_createLatLng(52.2395 + offset, -3.6814)); + hole2.add(_createLatLng(52.4234 + offset, -3.7914)); + hole2.add(_createLatLng(52.5351 + offset, -4.2435)); + hole2.add(_createLatLng(52.4231 + offset, -4.3829)); + holes.add(hole2); + + return holes; + } + LatLng _createLatLng(double lat, double lng) { return LatLng(lat, lng); } diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h index c7613fde5f93..eb1735d134b8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h @@ -13,6 +13,7 @@ - (void)setStrokeColor:(UIColor*)color; - (void)setStrokeWidth:(CGFloat)width; - (void)setPoints:(NSArray*)points; +- (void)setHoles:(NSArray*>*)holes; - (void)setZIndex:(int)zIndex; @end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m index 678d40e3efec..1063a8cda990 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m @@ -45,6 +45,19 @@ - (void)setPoints:(NSArray*)points { } _polygon.path = path; } +- (void)setHoles:(NSArray*>*)rawHoles { + NSMutableArray* holes = [[NSMutableArray alloc] init]; + + for (NSArray* points in rawHoles) { + GMSMutablePath* path = [GMSMutablePath path]; + for (CLLocation* location in points) { + [path addCoordinate:location.coordinate]; + } + [holes addObject:path]; + } + + _polygon.holes = holes; +} - (void)setFillColor:(UIColor*)color { _polygon.fillColor = color; @@ -65,6 +78,10 @@ - (void)setStrokeWidth:(CGFloat)width { return [FLTGoogleMapJsonConversions toPoints:data]; } +static NSArray*>* ToHoles(NSArray* data) { + return [FLTGoogleMapJsonConversions toHoles:data]; +} + static UIColor* ToColor(NSNumber* data) { return [FLTGoogleMapJsonConversions toColor:data]; } static void InterpretPolygonOptions(NSDictionary* data, id sink, @@ -89,6 +106,11 @@ static void InterpretPolygonOptions(NSDictionary* data, id*)toPoints:(NSArray*)data; ++ (NSArray*>*)toHoles:(NSArray*)data; @end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m index 6381beaee8d2..829f87791a07 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m @@ -58,4 +58,14 @@ + (UIColor*)toColor:(NSNumber*)numberColor { return points; } ++ (NSArray*>*)toHoles:(NSArray*)data { + NSMutableArray*>* holes = [[[NSMutableArray alloc] init] init]; + for (unsigned i = 0; i < [data count]; i++) { + NSArray* points = [FLTGoogleMapJsonConversions toPoints:data[i]]; + [holes addObject:points]; + } + + return holes; +} + @end diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart index b879f3d302cf..682c901f4d4a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart @@ -13,7 +13,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; - import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:google_maps_flutter_platform_interface/src/method_channel/method_channel_google_maps_flutter.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 4faadf4c2166..c07d1899eba8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,13 +1,13 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 1.0.10 +version: 1.1.0 dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: ^1.0.0 - google_maps_flutter_platform_interface: ^1.0.4 + google_maps_flutter_platform_interface: ^1.1.0 dev_dependencies: flutter_test: diff --git a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart index adca8b4c2a0e..9a849bd94e70 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart @@ -202,12 +202,14 @@ class FakePlatformGoogleMap { final bool visible = polygonData['visible']; final bool geodesic = polygonData['geodesic']; final List points = _deserializePoints(polygonData['points']); + final List> holes = _deserializeHoles(polygonData['holes']); result.add(Polygon( polygonId: PolygonId(polygonId), visible: visible, geodesic: geodesic, points: points, + holes: holes, )); } @@ -220,6 +222,14 @@ class FakePlatformGoogleMap { }).toList(); } + List> _deserializeHoles(List holes) { + return holes.map>((dynamic hole) { + return hole.map((dynamic list) { + return LatLng(list[0], list[1]); + }).toList(); + }).toList(); + } + void updatePolylines(Map polylineUpdates) { if (polylineUpdates == null) { return; diff --git a/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart index 185c996113af..667c7d83644e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart @@ -33,6 +33,29 @@ Widget _mapWithPolygons(Set polygons) { ); } +List _rectPoints({ + @required double size, + LatLng center = const LatLng(0, 0), +}) { + final halfSize = size / 2; + + return [ + LatLng(center.latitude + halfSize, center.longitude + halfSize), + LatLng(center.latitude - halfSize, center.longitude + halfSize), + LatLng(center.latitude - halfSize, center.longitude - halfSize), + LatLng(center.latitude + halfSize, center.longitude - halfSize), + ]; +} + +Polygon _polygonWithPointsAndHole(PolygonId polygonId) { + _rectPoints(size: 1); + return Polygon( + polygonId: polygonId, + points: _rectPoints(size: 1), + holes: [_rectPoints(size: 0.5)], + ); +} + void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -113,23 +136,6 @@ void main() { expect(platformGoogleMap.polygonsToAdd.isEmpty, true); }); - testWidgets("Updating a polygon", (WidgetTester tester) async { - final Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); - final Polygon p2 = - Polygon(polygonId: PolygonId("polygon_1"), geodesic: true); - - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p2))); - - final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; - expect(platformGoogleMap.polygonsToChange.length, 1); - - final Polygon update = platformGoogleMap.polygonsToChange.first; - expect(update, equals(p2)); - expect(update.geodesic, true); - }); - testWidgets("Mutate a polygon", (WidgetTester tester) async { final Polygon p1 = Polygon( polygonId: PolygonId("polygon_1"), @@ -228,4 +234,185 @@ void main() { expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); expect(platformGoogleMap.polygonsToAdd.isEmpty, true); }); + + testWidgets('Initializing a polygon with points and hole', + (WidgetTester tester) async { + final Polygon p1 = _polygonWithPointsAndHole(PolygonId("polygon_1")); + await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.polygonsToAdd.length, 1); + + final Polygon initializedPolygon = platformGoogleMap.polygonsToAdd.first; + expect(initializedPolygon, equals(p1)); + expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); + expect(platformGoogleMap.polygonsToChange.isEmpty, true); + }); + + testWidgets("Adding a polygon with points and hole", + (WidgetTester tester) async { + final Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); + final Polygon p2 = _polygonWithPointsAndHole(PolygonId("polygon_2")); + + await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1, p2: p2))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.polygonsToAdd.length, 1); + + final Polygon addedPolygon = platformGoogleMap.polygonsToAdd.first; + expect(addedPolygon, equals(p2)); + + expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); + + expect(platformGoogleMap.polygonsToChange.isEmpty, true); + }); + + testWidgets("Removing a polygon with points and hole", + (WidgetTester tester) async { + final Polygon p1 = _polygonWithPointsAndHole(PolygonId("polygon_1")); + + await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolygons(null)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.polygonIdsToRemove.length, 1); + expect(platformGoogleMap.polygonIdsToRemove.first, equals(p1.polygonId)); + + expect(platformGoogleMap.polygonsToChange.isEmpty, true); + expect(platformGoogleMap.polygonsToAdd.isEmpty, true); + }); + + testWidgets("Updating a polygon by adding points and hole", + (WidgetTester tester) async { + final Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); + final Polygon p2 = _polygonWithPointsAndHole(PolygonId("polygon_1")); + + await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p2))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.polygonsToChange.length, 1); + expect(platformGoogleMap.polygonsToChange.first, equals(p2)); + + expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); + expect(platformGoogleMap.polygonsToAdd.isEmpty, true); + }); + + testWidgets("Mutate a polygon with points and holes", + (WidgetTester tester) async { + final Polygon p1 = Polygon( + polygonId: PolygonId("polygon_1"), + points: _rectPoints(size: 1), + holes: [_rectPoints(size: 0.5)], + ); + await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + + p1.points + ..clear() + ..addAll(_rectPoints(size: 2)); + p1.holes + ..clear() + ..addAll([_rectPoints(size: 1)]); + await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.polygonsToChange.length, 1); + expect(platformGoogleMap.polygonsToChange.first, equals(p1)); + + expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); + expect(platformGoogleMap.polygonsToAdd.isEmpty, true); + }); + + testWidgets("Multi Update polygons with points and hole", + (WidgetTester tester) async { + Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); + Polygon p2 = Polygon( + polygonId: PolygonId("polygon_2"), + points: _rectPoints(size: 2), + holes: [_rectPoints(size: 1)], + ); + final Set prev = _toSet(p1: p1, p2: p2); + p1 = Polygon(polygonId: PolygonId("polygon_1"), visible: false); + p2 = p2.copyWith( + pointsParam: _rectPoints(size: 5), + holesParam: [_rectPoints(size: 2)], + ); + final Set cur = _toSet(p1: p1, p2: p2); + + await tester.pumpWidget(_mapWithPolygons(prev)); + await tester.pumpWidget(_mapWithPolygons(cur)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + + expect(platformGoogleMap.polygonsToChange, cur); + expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); + expect(platformGoogleMap.polygonsToAdd.isEmpty, true); + }); + + testWidgets("Multi Update polygons with points and hole", + (WidgetTester tester) async { + Polygon p2 = Polygon( + polygonId: PolygonId("polygon_2"), + points: _rectPoints(size: 2), + holes: [_rectPoints(size: 1)], + ); + final Polygon p3 = Polygon(polygonId: PolygonId("polygon_3")); + final Set prev = _toSet(p2: p2, p3: p3); + + // p1 is added, p2 is updated, p3 is removed. + final Polygon p1 = _polygonWithPointsAndHole(PolygonId("polygon_1")); + p2 = p2.copyWith( + pointsParam: _rectPoints(size: 5), + holesParam: [_rectPoints(size: 3)], + ); + final Set cur = _toSet(p1: p1, p2: p2); + + await tester.pumpWidget(_mapWithPolygons(prev)); + await tester.pumpWidget(_mapWithPolygons(cur)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + + expect(platformGoogleMap.polygonsToChange.length, 1); + expect(platformGoogleMap.polygonsToAdd.length, 1); + expect(platformGoogleMap.polygonIdsToRemove.length, 1); + + expect(platformGoogleMap.polygonsToChange.first, equals(p2)); + expect(platformGoogleMap.polygonsToAdd.first, equals(p1)); + expect(platformGoogleMap.polygonIdsToRemove.first, equals(p3.polygonId)); + }); + + testWidgets("Partial Update polygons with points and hole", + (WidgetTester tester) async { + final Polygon p1 = _polygonWithPointsAndHole(PolygonId("polygon_1")); + final Polygon p2 = Polygon(polygonId: PolygonId("polygon_2")); + Polygon p3 = Polygon( + polygonId: PolygonId("polygon_3"), + points: _rectPoints(size: 2), + holes: [_rectPoints(size: 1)], + ); + final Set prev = _toSet(p1: p1, p2: p2, p3: p3); + p3 = p3.copyWith( + pointsParam: _rectPoints(size: 5), + holesParam: [_rectPoints(size: 3)], + ); + final Set cur = _toSet(p1: p1, p2: p2, p3: p3); + + await tester.pumpWidget(_mapWithPolygons(prev)); + await tester.pumpWidget(_mapWithPolygons(cur)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + + expect(platformGoogleMap.polygonsToChange, _toSet(p3: p3)); + expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); + expect(platformGoogleMap.polygonsToAdd.isEmpty, true); + }); } From edda73d0b876afc21c8d2d902f11ddba51a8f95f Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Wed, 13 Jan 2021 16:06:08 -0800 Subject: [PATCH 097/924] [file_selector_web] Add dummy ios directory. (#3416) This is required so the plugin is publishable. --- .../file_selector_web/CHANGELOG.md | 4 ++++ .../ios/file_selector_web.podspec | 21 +++++++++++++++++++ .../file_selector_web/pubspec.yaml | 2 +- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 packages/file_selector/file_selector_web/ios/file_selector_web.podspec diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md index cf87cfec36fd..619aa769d5f6 100644 --- a/packages/file_selector/file_selector_web/CHANGELOG.md +++ b/packages/file_selector/file_selector_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.7.0+1 + +- Add dummy `ios` dir, so flutter sdk can be lower than 1.20 + # 0.7.0 - Initial open-source release. diff --git a/packages/file_selector/file_selector_web/ios/file_selector_web.podspec b/packages/file_selector/file_selector_web/ios/file_selector_web.podspec new file mode 100644 index 000000000000..20656121029d --- /dev/null +++ b/packages/file_selector/file_selector_web/ios/file_selector_web.podspec @@ -0,0 +1,21 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'file_selector_web' + s.version = '0.0.1' + s.summary = 'No-op implementation of file_selector_web web plugin to avoid build issues on iOS' + s.description = <<-DESC + temp fake file_selector_web plugin + DESC + s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_web' + s.license = { :file => '../LICENSE' } + s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.public_header_files = 'Classes/**/*.h' + s.dependency 'Flutter' + + s.ios.deployment_target = '8.0' + end + \ No newline at end of file diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml index c8e0eef56276..a170d5f39607 100644 --- a/packages/file_selector/file_selector_web/pubspec.yaml +++ b/packages/file_selector/file_selector_web/pubspec.yaml @@ -1,7 +1,7 @@ name: file_selector_web description: Web platform implementation of file_selector homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_web -version: 0.7.0 +version: 0.7.0+1 flutter: plugin: From 6d18db83f00f4861ffe485aba2d1f8aa08845ce6 Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Thu, 14 Jan 2021 06:45:47 +0100 Subject: [PATCH 098/924] [camera] Fix picture capture causing a crash on some Huawei devices. (#3414) --- packages/camera/camera/CHANGELOG.md | 4 ++ .../io/flutter/plugins/camera/Camera.java | 5 +- .../plugins/camera/PictureCaptureRequest.java | 43 +++++++++++++++- .../camera/PictureCaptureRequestTest.java | 51 +++++++++++++++++++ packages/camera/camera/pubspec.yaml | 2 +- 5 files changed, 102 insertions(+), 3 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 8525ad1e21d8..5fd62d2b716b 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+1 + +* Fixes picture captures causing a crash on some Huawei devices. + ## 0.7.0 * Added support for capture orientation locking on Android and iOS. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 10d58f5e8792..d5a5c5cfeb6b 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -458,17 +458,20 @@ public void onCaptureFailed( return; } String reason; + boolean fatalFailure = false; switch (failure.getReason()) { case CaptureFailure.REASON_ERROR: reason = "An error happened in the framework"; break; case CaptureFailure.REASON_FLUSHED: reason = "The capture has failed due to an abortCaptures() call"; + fatalFailure = true; break; default: reason = "Unknown reason"; } - pictureCaptureRequest.error("captureFailure", reason, null); + Log.w("Camera", "pictureCaptureCallback.onCaptureFailed(): " + reason); + if (fatalFailure) pictureCaptureRequest.error("captureFailure", reason, null); } private void processCapture(CaptureResult result) { diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java index 189f2f1490dc..396f782a2a08 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java @@ -4,6 +4,8 @@ package io.flutter.plugins.camera; +import android.os.Handler; +import android.os.Looper; import androidx.annotation.Nullable; import io.flutter.plugin.common.MethodChannel; @@ -19,17 +21,36 @@ enum State { error, } + private final Runnable timeoutCallback = + new Runnable() { + @Override + public void run() { + error("captureTimeout", "Picture capture request timed out", state.toString()); + } + }; + private final MethodChannel.Result result; + private final TimeoutHandler timeoutHandler; private State state; public PictureCaptureRequest(MethodChannel.Result result) { + this(result, new TimeoutHandler()); + } + + public PictureCaptureRequest(MethodChannel.Result result, TimeoutHandler timeoutHandler) { this.result = result; - state = State.idle; + this.state = State.idle; + this.timeoutHandler = timeoutHandler; } public void setState(State state) { if (isFinished()) throw new IllegalStateException("Request has already been finished"); this.state = state; + if (state != State.idle && state != State.finished && state != State.error) { + this.timeoutHandler.resetTimeout(timeoutCallback); + } else { + this.timeoutHandler.clearTimeout(timeoutCallback); + } } public State getState() { @@ -42,6 +63,7 @@ public boolean isFinished() { public void finish(String absolutePath) { if (isFinished()) throw new IllegalStateException("Request has already been finished"); + this.timeoutHandler.clearTimeout(timeoutCallback); result.success(absolutePath); state = State.finished; } @@ -49,7 +71,26 @@ public void finish(String absolutePath) { public void error( String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) { if (isFinished()) throw new IllegalStateException("Request has already been finished"); + this.timeoutHandler.clearTimeout(timeoutCallback); result.error(errorCode, errorMessage, errorDetails); state = State.error; } + + static class TimeoutHandler { + private static final int REQUEST_TIMEOUT = 5000; + private final Handler handler; + + TimeoutHandler() { + this.handler = new Handler(Looper.getMainLooper()); + } + + public void resetTimeout(Runnable runnable) { + clearTimeout(runnable); + handler.postDelayed(runnable, REQUEST_TIMEOUT); + } + + public void clearTimeout(Runnable runnable) { + handler.removeCallbacks(runnable); + } + } } diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java index 3ede0b7abe3a..3252b3e111c4 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java @@ -7,7 +7,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import io.flutter.plugin.common.MethodChannel; @@ -38,6 +41,32 @@ public void setState_sets_state() { "State is awaitingPreCapture", req.getState(), PictureCaptureRequest.State.capturing); } + @Test + public void setState_resets_timeout() { + PictureCaptureRequest.TimeoutHandler mockTimeoutHandler = + mock(PictureCaptureRequest.TimeoutHandler.class); + PictureCaptureRequest req = new PictureCaptureRequest(null, mockTimeoutHandler); + req.setState(PictureCaptureRequest.State.focusing); + req.setState(PictureCaptureRequest.State.preCapture); + req.setState(PictureCaptureRequest.State.waitingPreCaptureReady); + req.setState(PictureCaptureRequest.State.capturing); + verify(mockTimeoutHandler, times(4)).resetTimeout(any()); + verify(mockTimeoutHandler, never()).clearTimeout(any()); + } + + @Test + public void setState_clears_timeout() { + PictureCaptureRequest.TimeoutHandler mockTimeoutHandler = + mock(PictureCaptureRequest.TimeoutHandler.class); + PictureCaptureRequest req = new PictureCaptureRequest(null, mockTimeoutHandler); + req.setState(PictureCaptureRequest.State.idle); + req.setState(PictureCaptureRequest.State.finished); + req = new PictureCaptureRequest(null, mockTimeoutHandler); + req.setState(PictureCaptureRequest.State.error); + verify(mockTimeoutHandler, never()).resetTimeout(any()); + verify(mockTimeoutHandler, times(3)).clearTimeout(any()); + } + @Test public void finish_sets_result_and_state() { // Setup @@ -50,6 +79,17 @@ public void finish_sets_result_and_state() { assertEquals("State is finished", req.getState(), PictureCaptureRequest.State.finished); } + @Test + public void finish_clears_timeout() { + PictureCaptureRequest.TimeoutHandler mockTimeoutHandler = + mock(PictureCaptureRequest.TimeoutHandler.class); + MethodChannel.Result mockResult = mock(MethodChannel.Result.class); + PictureCaptureRequest req = new PictureCaptureRequest(mockResult, mockTimeoutHandler); + req.finish("/test/path"); + verify(mockTimeoutHandler, never()).resetTimeout(any()); + verify(mockTimeoutHandler).clearTimeout(any()); + } + @Test public void isFinished_is_true_When_state_is_finished_or_error() { // Setup @@ -90,6 +130,17 @@ public void error_sets_result_and_state() { assertEquals("State is error", req.getState(), PictureCaptureRequest.State.error); } + @Test + public void error_clears_timeout() { + PictureCaptureRequest.TimeoutHandler mockTimeoutHandler = + mock(PictureCaptureRequest.TimeoutHandler.class); + MethodChannel.Result mockResult = mock(MethodChannel.Result.class); + PictureCaptureRequest req = new PictureCaptureRequest(mockResult, mockTimeoutHandler); + req.error("ERROR_CODE", "Error Message", null); + verify(mockTimeoutHandler, never()).resetTimeout(any()); + verify(mockTimeoutHandler).clearTimeout(any()); + } + @Test(expected = IllegalStateException.class) public void error_throws_When_already_finished() { // Setup diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index b0ebb9c16361..b406ce5ba64f 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0 +version: 0.7.0+1 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From d0b7109f6b00a0eda03506fed2c74cc123ffc6f3 Mon Sep 17 00:00:00 2001 From: Bodhi Mulders Date: Thu, 14 Jan 2021 10:33:03 +0100 Subject: [PATCH 099/924] [camera] Fix initialization error in camera example on iOS (#3406) * Fix error on first camera initialize in example app * Improved error handling a bit & updated tests. * Updated pubspec and changelog Co-authored-by: Maurits van Beusekom --- packages/camera/camera/CHANGELOG.md | 4 + packages/camera/camera/example/lib/main.dart | 14 +- .../camera/lib/src/camera_controller.dart | 129 ++++---------- packages/camera/camera/pubspec.yaml | 2 +- .../camera/test/camera_image_stream_test.dart | 42 +++-- packages/camera/camera/test/camera_test.dart | 168 +++++++++++++----- 6 files changed, 195 insertions(+), 164 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 5fd62d2b716b..8d2c20108ed0 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+2 + +* Improved error feedback by differentiating between uninitialized and disposed camera controllers. + ## 0.7.0+1 * Fixes picture captures causing a crash on some Huawei devices. diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 490cae6676d3..6244aa5a8e37 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -580,10 +580,16 @@ class _CameraExampleHomeState extends State try { await controller.initialize(); - _minAvailableExposureOffset = await controller.getMinExposureOffset(); - _maxAvailableExposureOffset = await controller.getMaxExposureOffset(); - _maxAvailableZoom = await controller.getMaxZoomLevel(); - _minAvailableZoom = await controller.getMinZoomLevel(); + await Future.wait([ + controller + .getMinExposureOffset() + .then((value) => _minAvailableExposureOffset = value), + controller + .getMaxExposureOffset() + .then((value) => _maxAvailableExposureOffset = value), + controller.getMaxZoomLevel().then((value) => _maxAvailableZoom = value), + controller.getMinZoomLevel().then((value) => _minAvailableZoom = value), + ]); } on CameraException catch (e) { _showCameraException(e); } diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index 807bec367256..80e83c867954 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -323,12 +323,7 @@ class CameraController extends ValueNotifier { /// /// Throws a [CameraException] if the capture fails. Future takePicture() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController.', - 'takePicture was called on uninitialized CameraController', - ); - } + _throwIfNotInitialized("takePicture"); if (value.isTakingPicture) { throw CameraException( 'Previous capture has not returned yet.', @@ -366,13 +361,7 @@ class CameraController extends ValueNotifier { Future startImageStream(onLatestImageAvailable onAvailable) async { assert(defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.iOS); - - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'startImageStream was called on uninitialized CameraController.', - ); - } + _throwIfNotInitialized("startImageStream"); if (value.isRecordingVideo) { throw CameraException( 'A video recording is already started.', @@ -412,13 +401,7 @@ class CameraController extends ValueNotifier { Future stopImageStream() async { assert(defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.iOS); - - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'stopImageStream was called on uninitialized CameraController.', - ); - } + _throwIfNotInitialized("stopImageStream"); if (value.isRecordingVideo) { throw CameraException( 'A video recording is already started.', @@ -448,12 +431,7 @@ class CameraController extends ValueNotifier { /// The video is returned as a [XFile] after calling [stopVideoRecording]. /// Throws a [CameraException] if the capture fails. Future startVideoRecording() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'startVideoRecording was called on uninitialized CameraController', - ); - } + _throwIfNotInitialized("startVideoRecording"); if (value.isRecordingVideo) { throw CameraException( 'A video recording is already started.', @@ -483,12 +461,7 @@ class CameraController extends ValueNotifier { /// /// Throws a [CameraException] if the capture failed. Future stopVideoRecording() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'stopVideoRecording was called on uninitialized CameraController', - ); - } + _throwIfNotInitialized("stopVideoRecording"); if (!value.isRecordingVideo) { throw CameraException( 'No video is recording', @@ -511,12 +484,7 @@ class CameraController extends ValueNotifier { /// /// This feature is only available on iOS and Android sdk 24+. Future pauseVideoRecording() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'pauseVideoRecording was called on uninitialized CameraController', - ); - } + _throwIfNotInitialized("pauseVideoRecording"); if (!value.isRecordingVideo) { throw CameraException( 'No video is recording', @@ -535,12 +503,7 @@ class CameraController extends ValueNotifier { /// /// This feature is only available on iOS and Android sdk 24+. Future resumeVideoRecording() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'resumeVideoRecording was called on uninitialized CameraController', - ); - } + _throwIfNotInitialized("resumeVideoRecording"); if (!value.isRecordingVideo) { throw CameraException( 'No video is recording', @@ -557,12 +520,7 @@ class CameraController extends ValueNotifier { /// Returns a widget showing a live camera preview. Widget buildPreview() { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'buildView() was called on uninitialized CameraController.', - ); - } + _throwIfNotInitialized("buildPreview"); try { return CameraPlatform.instance.buildPreview(_cameraId); } on PlatformException catch (e) { @@ -572,13 +530,7 @@ class CameraController extends ValueNotifier { /// Gets the maximum supported zoom level for the selected camera. Future getMaxZoomLevel() { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'getMaxZoomLevel was called on uninitialized CameraController', - ); - } - + _throwIfNotInitialized("getMaxZoomLevel"); try { return CameraPlatform.instance.getMaxZoomLevel(_cameraId); } on PlatformException catch (e) { @@ -588,13 +540,7 @@ class CameraController extends ValueNotifier { /// Gets the minimum supported zoom level for the selected camera. Future getMinZoomLevel() { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'getMinZoomLevel was called on uninitialized CameraController', - ); - } - + _throwIfNotInitialized("getMinZoomLevel"); try { return CameraPlatform.instance.getMinZoomLevel(_cameraId); } on PlatformException catch (e) { @@ -608,13 +554,7 @@ class CameraController extends ValueNotifier { /// zoom level returned by the `getMaxZoomLevel`. Throws an `CameraException` /// when an illegal zoom level is suplied. Future setZoomLevel(double zoom) { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'setZoomLevel was called on uninitialized CameraController', - ); - } - + _throwIfNotInitialized("setZoomLevel"); try { return CameraPlatform.instance.setZoomLevel(_cameraId, zoom); } on PlatformException catch (e) { @@ -666,13 +606,7 @@ class CameraController extends ValueNotifier { /// Gets the minimum supported exposure offset for the selected camera in EV units. Future getMinExposureOffset() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'getMinExposureOffset was called on uninitialized CameraController', - ); - } - + _throwIfNotInitialized("getMinExposureOffset"); try { return CameraPlatform.instance.getMinExposureOffset(_cameraId); } on PlatformException catch (e) { @@ -682,13 +616,7 @@ class CameraController extends ValueNotifier { /// Gets the maximum supported exposure offset for the selected camera in EV units. Future getMaxExposureOffset() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'getMaxExposureOffset was called on uninitialized CameraController', - ); - } - + _throwIfNotInitialized("getMaxExposureOffset"); try { return CameraPlatform.instance.getMaxExposureOffset(_cameraId); } on PlatformException catch (e) { @@ -700,13 +628,7 @@ class CameraController extends ValueNotifier { /// /// Returns 0 when the camera supports using a free value without stepping. Future getExposureOffsetStepSize() async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'getExposureOffsetStepSize was called on uninitialized CameraController', - ); - } - + _throwIfNotInitialized("getExposureOffsetStepSize"); try { return CameraPlatform.instance.getExposureOffsetStepSize(_cameraId); } on PlatformException catch (e) { @@ -726,13 +648,7 @@ class CameraController extends ValueNotifier { /// /// Returns the (rounded) offset value that was set. Future setExposureOffset(double offset) async { - if (!value.isInitialized || _isDisposed) { - throw CameraException( - 'Uninitialized CameraController', - 'setExposureOffset was called on uninitialized CameraController', - ); - } - + _throwIfNotInitialized("setExposureOffset"); // Check if offset is in range List range = await Future.wait([getMinExposureOffset(), getMaxExposureOffset()]); @@ -834,4 +750,19 @@ class CameraController extends ValueNotifier { await CameraPlatform.instance.dispose(_cameraId); } } + + void _throwIfNotInitialized(String functionName) { + if (!value.isInitialized) { + throw CameraException( + 'Uninitialized CameraController', + '$functionName() was called on an uninitialized CameraController.', + ); + } + if (_isDisposed) { + throw CameraException( + 'Disposed CameraController', + '$functionName() was called on a disposed CameraController.', + ); + } + } } diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index b406ce5ba64f..2b6d163dfbeb 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+1 +version: 0.7.0+2 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: diff --git a/packages/camera/camera/test/camera_image_stream_test.dart b/packages/camera/camera/test/camera_image_stream_test.dart index be7047f2220f..57e3aeb36f3f 100644 --- a/packages/camera/camera/test/camera_image_stream_test.dart +++ b/packages/camera/camera/test/camera_image_stream_test.dart @@ -22,12 +22,21 @@ void main() { ResolutionPreset.max); expect( - () => cameraController.startImageStream((image) => null), - throwsA(isA().having( - (error) => error.description, - 'Uninitialized CameraController.', - 'startImageStream was called on uninitialized CameraController.', - ))); + () => cameraController.startImageStream((image) => null), + throwsA( + isA() + .having( + (error) => error.code, + 'code', + 'Uninitialized CameraController', + ) + .having( + (error) => error.description, + 'description', + 'startImageStream() was called on an uninitialized CameraController.', + ), + ), + ); }); test('startImageStream() throws $CameraException when recording videos', @@ -107,12 +116,21 @@ void main() { ResolutionPreset.max); expect( - cameraController.stopImageStream, - throwsA(isA().having( - (error) => error.description, - 'Uninitialized CameraController.', - 'stopImageStream was called on uninitialized CameraController.', - ))); + cameraController.stopImageStream, + throwsA( + isA() + .having( + (error) => error.code, + 'code', + 'Uninitialized CameraController', + ) + .having( + (error) => error.description, + 'description', + 'stopImageStream() was called on an uninitialized CameraController.', + ), + ), + ); }); test('stopImageStream() throws $CameraException when recording videos', diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 2f53691217cb..d0b09fae1304 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -213,12 +213,21 @@ void main() { sensorOrientation: 90), ResolutionPreset.max); expect( - cameraController.takePicture(), - throwsA(isA().having( - (error) => error.description, - 'Uninitialized CameraController.', - 'takePicture was called on uninitialized CameraController', - ))); + cameraController.takePicture(), + throwsA( + isA() + .having( + (error) => error.code, + 'code', + 'Uninitialized CameraController', + ) + .having( + (error) => error.description, + 'description', + 'takePicture() was called on an uninitialized CameraController.', + ), + ), + ); }); test('takePicture() throws $CameraException when takePicture is true', @@ -286,12 +295,21 @@ void main() { ResolutionPreset.max); expect( - cameraController.startVideoRecording(), - throwsA(isA().having( - (error) => error.description, - 'Uninitialized CameraController', - 'startVideoRecording was called on uninitialized CameraController', - ))); + cameraController.startVideoRecording(), + throwsA( + isA() + .having( + (error) => error.code, + 'code', + 'Uninitialized CameraController', + ) + .having( + (error) => error.description, + 'description', + 'startVideoRecording() was called on an uninitialized CameraController.', + ), + ), + ); }); test('startVideoRecording() throws $CameraException when recording videos', () async { @@ -350,12 +368,21 @@ void main() { ResolutionPreset.max); expect( - cameraController.getMaxZoomLevel, - throwsA(isA().having( - (error) => error.description, - 'Uninitialized CameraController', - 'getMaxZoomLevel was called on uninitialized CameraController', - ))); + cameraController.getMaxZoomLevel, + throwsA( + isA() + .having( + (error) => error.code, + 'code', + 'Uninitialized CameraController', + ) + .having( + (error) => error.description, + 'description', + 'getMaxZoomLevel() was called on an uninitialized CameraController.', + ), + ), + ); }); test('getMaxZoomLevel() throws $CameraException when disposed', () async { @@ -370,12 +397,21 @@ void main() { await cameraController.dispose(); expect( - cameraController.getMaxZoomLevel, - throwsA(isA().having( - (error) => error.description, - 'Uninitialized CameraController', - 'getMaxZoomLevel was called on uninitialized CameraController', - ))); + cameraController.getMaxZoomLevel, + throwsA( + isA() + .having( + (error) => error.code, + 'code', + 'Disposed CameraController', + ) + .having( + (error) => error.description, + 'description', + 'getMaxZoomLevel() was called on a disposed CameraController.', + ), + ), + ); }); test( @@ -432,12 +468,21 @@ void main() { ResolutionPreset.max); expect( - cameraController.getMinZoomLevel, - throwsA(isA().having( - (error) => error.description, - 'Uninitialized CameraController', - 'getMinZoomLevel was called on uninitialized CameraController', - ))); + cameraController.getMinZoomLevel, + throwsA( + isA() + .having( + (error) => error.code, + 'code', + 'Uninitialized CameraController', + ) + .having( + (error) => error.description, + 'description', + 'getMinZoomLevel() was called on an uninitialized CameraController.', + ), + ), + ); }); test('getMinZoomLevel() throws $CameraException when disposed', () async { @@ -452,12 +497,21 @@ void main() { await cameraController.dispose(); expect( - cameraController.getMinZoomLevel, - throwsA(isA().having( - (error) => error.description, - 'Uninitialized CameraController', - 'getMinZoomLevel was called on uninitialized CameraController', - ))); + cameraController.getMinZoomLevel, + throwsA( + isA() + .having( + (error) => error.code, + 'code', + 'Disposed CameraController', + ) + .having( + (error) => error.description, + 'description', + 'getMinZoomLevel() was called on a disposed CameraController.', + ), + ), + ); }); test( @@ -513,12 +567,21 @@ void main() { ResolutionPreset.max); expect( - () => cameraController.setZoomLevel(42.0), - throwsA(isA().having( - (error) => error.description, - 'Uninitialized CameraController', - 'setZoomLevel was called on uninitialized CameraController', - ))); + () => cameraController.setZoomLevel(42.0), + throwsA( + isA() + .having( + (error) => error.code, + 'code', + 'Uninitialized CameraController', + ) + .having( + (error) => error.description, + 'description', + 'setZoomLevel() was called on an uninitialized CameraController.', + ), + ), + ); }); test('setZoomLevel() throws $CameraException when disposed', () async { @@ -533,12 +596,21 @@ void main() { await cameraController.dispose(); expect( - () => cameraController.setZoomLevel(42.0), - throwsA(isA().having( - (error) => error.description, - 'Uninitialized CameraController', - 'setZoomLevel was called on uninitialized CameraController', - ))); + () => cameraController.setZoomLevel(42.0), + throwsA( + isA() + .having( + (error) => error.code, + 'code', + 'Disposed CameraController', + ) + .having( + (error) => error.description, + 'description', + 'setZoomLevel() was called on a disposed CameraController.', + ), + ), + ); }); test( From 980b674cb4020c1927917426211a87e275346d5e Mon Sep 17 00:00:00 2001 From: najeira Date: Thu, 14 Jan 2021 20:29:03 +0900 Subject: [PATCH 100/924] [camera] Fixes crash with using inner camera on some Android devices. (#3419) --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../src/main/java/io/flutter/plugins/camera/Camera.java | 3 ++- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 8d2c20108ed0..6ce8737862f4 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+3 + +* Fixes crash with using inner camera on some Android devices. + ## 0.7.0+2 * Improved error feedback by differentiating between uninitialized and disposed camera controllers. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index d5a5c5cfeb6b..5dba68eed723 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -216,7 +216,6 @@ public void open(String imageFormatGroup) throws CameraAccessException { public void onOpened(@NonNull CameraDevice device) { cameraDevice = device; try { - cameraRegions = new CameraRegions(getRegionBoundaries()); startPreview(); dartMessenger.sendCameraInitializedEvent( previewSize.getWidth(), @@ -300,6 +299,8 @@ private void createCaptureSession( } } + cameraRegions = new CameraRegions(getRegionBoundaries()); + // Prepare the callback CameraCaptureSession.StateCallback callback = new CameraCaptureSession.StateCallback() { diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 2b6d163dfbeb..cebbb334c8f2 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+2 +version: 0.7.0+3 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 5916f55664e1772a4c3f0c02c5c71fc11e491b76 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 14 Jan 2021 18:57:35 +0100 Subject: [PATCH 101/924] [camera] Copy zoom settings from preview to final capture builder on Android (#3413) * Copy SCALER_CROP_REGION from preview to final capture builder * Update version number * Fix formatting --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../src/main/java/io/flutter/plugins/camera/Camera.java | 4 ++++ packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 6ce8737862f4..972ca5a31503 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+4 + +* Make sure the configured zoom scale is copied over to the final capture builder on Android. Fixes the issue where the preview is zoomed but the final picture is not. + ## 0.7.0+3 * Fixes crash with using inner camera on some Android devices. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 5dba68eed723..1b6cce95d08c 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -543,11 +543,15 @@ private void runPictureCapture() { final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(pictureImageReader.getSurface()); + captureBuilder.set( + CaptureRequest.SCALER_CROP_REGION, + captureRequestBuilder.get(CaptureRequest.SCALER_CROP_REGION)); captureBuilder.set( CaptureRequest.JPEG_ORIENTATION, lockedCaptureOrientation == null ? deviceOrientationListener.getMediaOrientation() : deviceOrientationListener.getMediaOrientation(lockedCaptureOrientation)); + switch (flashMode) { case off: captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index cebbb334c8f2..5ac4b57a15ef 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+3 +version: 0.7.0+4 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 1e90b58847c12252f6144160f975445804f1d05c Mon Sep 17 00:00:00 2001 From: klaes-ashford <36758008+klaes-ashford@users.noreply.github.com> Date: Fri, 15 Jan 2021 01:39:09 +0530 Subject: [PATCH 102/924] fix to properly place polyline at initial camera position in example app (#2941) --- packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md | 4 ++++ .../google_maps_flutter/example/lib/place_polyline.dart | 4 ++-- packages/google_maps_flutter/google_maps_flutter/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index 6dcb967f9cb4..3b6db09ea10b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.1 + +* Fix in example app to properly place polyline at initial camera position. + ## 1.1.0 * Add support for holes in Polygons. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart index 65201d5d1839..fe22603853bc 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart @@ -31,7 +31,7 @@ class PlacePolylineBodyState extends State { GoogleMapController controller; Map polylines = {}; - int _polylineIdCounter = 1; + int _polylineIdCounter = 0; PolylineId selectedPolyline; // Values when toggling polyline color @@ -215,7 +215,7 @@ class PlacePolylineBodyState extends State { height: 300.0, child: GoogleMap( initialCameraPosition: const CameraPosition( - target: LatLng(52.4478, -3.5402), + target: LatLng(53.1721, -3.5402), zoom: 7.0, ), polylines: Set.of(polylines.values), diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index c07d1899eba8..ef3a06f5862c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 1.1.0 +version: 1.1.1 dependencies: flutter: From 831344490984b1feec007afc9c8595d80b6c13f4 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Fri, 15 Jan 2021 00:00:49 +0100 Subject: [PATCH 103/924] [camera] Fixes crash when taking a picture on iOS devices without flash (#3411) --- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/ios/Classes/CameraPlugin.m | 4 ++-- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 972ca5a31503..66398996e053 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+5 + +* Fixes crash when taking a picture on iOS devices without flash. + ## 0.7.0+4 * Make sure the configured zoom scale is copied over to the final capture builder on Android. Fixes the issue where the preview is zoomed but the final picture is not. diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index 40d93fde7af6..d97ce88a58d8 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -365,12 +365,12 @@ - (instancetype)initWithCameraName:(NSString *)cameraName _enableAudio = enableAudio; _dispatchQueue = dispatchQueue; _captureSession = [[AVCaptureSession alloc] init]; - _flashMode = FlashModeAuto; + _captureDevice = [AVCaptureDevice deviceWithUniqueID:cameraName]; + _flashMode = _captureDevice.hasFlash ? FlashModeAuto : FlashModeOff; _exposureMode = ExposureModeAuto; _focusMode = FocusModeAuto; _lockedCaptureOrientation = UIDeviceOrientationUnknown; - _captureDevice = [AVCaptureDevice deviceWithUniqueID:cameraName]; NSError *localError = nil; _captureVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:_captureDevice error:&localError]; diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 5ac4b57a15ef..406ff94ab1b9 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+4 +version: 0.7.0+5 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From cc234f6fddcef124f49a26c05351b1de333329f5 Mon Sep 17 00:00:00 2001 From: Juanjo Tugores Date: Thu, 14 Jan 2021 19:59:58 -0600 Subject: [PATCH 104/924] [file_selector_platform_interface] Bump the cross_file version (#3422) --- .../file_selector_platform_interface/CHANGELOG.md | 4 ++++ .../file_selector_platform_interface/pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md index 0d6d6d08c298..aafe4db278d8 100644 --- a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md +++ b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.3+1 + +* Bump the [cross_file](https://pub.dev/packages/cross_file) package version. + ## 1.0.3 * Update Flutter SDK constraint. diff --git a/packages/file_selector/file_selector_platform_interface/pubspec.yaml b/packages/file_selector/file_selector_platform_interface/pubspec.yaml index 2d0b7c954ece..f1d0038a5062 100644 --- a/packages/file_selector/file_selector_platform_interface/pubspec.yaml +++ b/packages/file_selector/file_selector_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the file_selector plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_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.0.3 +version: 1.0.3+1 dependencies: flutter: @@ -11,7 +11,7 @@ dependencies: meta: ^1.0.5 http: ^0.12.0+1 plugin_platform_interface: ^1.0.1 - cross_file: ^0.1.0 + cross_file: ^0.2.0 dev_dependencies: test: ^1.15.0 From eccc3cd6440210c2fdec03b06d57f94ae454d479 Mon Sep 17 00:00:00 2001 From: Kenneth Jones Date: Thu, 14 Jan 2021 23:29:02 -0600 Subject: [PATCH 105/924] [local_auth] Allow device authentication (pin/pattern/passcode) (#2489) --- .../android/gradle.properties | 1 - packages/local_auth/CHANGELOG.md | 9 + packages/local_auth/README.md | 36 +- packages/local_auth/android/build.gradle | 2 +- .../android/src/main/AndroidManifest.xml | 2 + .../localauth/AuthenticationHelper.java | 54 +-- .../plugins/localauth/LocalAuthPlugin.java | 343 +++++++++++++----- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../local_auth/example/android/build.gradle | 2 +- .../example/android/gradle.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +- .../example/android/settings_aar.gradle | 1 + packages/local_auth/example/lib/main.dart | 144 ++++++-- .../integration_test/local_auth_test.dart | 5 +- .../ios/Classes/FLTLocalAuthPlugin.m | 54 ++- packages/local_auth/lib/auth_strings.dart | 84 +++-- packages/local_auth/lib/error_codes.dart | 2 +- packages/local_auth/lib/local_auth.dart | 63 +++- packages/local_auth/pubspec.yaml | 4 +- packages/local_auth/test/local_auth_test.dart | 178 ++++++--- 20 files changed, 727 insertions(+), 265 deletions(-) create mode 100644 packages/local_auth/example/android/settings_aar.gradle diff --git a/packages/integration_test/android/gradle.properties b/packages/integration_test/android/gradle.properties index 2bd6f4fda009..8bd86f680510 100644 --- a/packages/integration_test/android/gradle.properties +++ b/packages/integration_test/android/gradle.properties @@ -1,2 +1 @@ org.gradle.jvmargs=-Xmx1536M - diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index b27ec83d41a7..8bb043f52d8f 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,12 @@ +## 1.1.0-nullsafety + +* Allow pin, passcode, and pattern authentication with `authenticate` method +* **Breaking change**. Parameter names refactored to use the generic `biometric` prefix in place of `fingerprint` in the `AndroidAuthMessages` class + * `fingerprintHint` is now `biometricHint` + * `fingerprintNotRecognized`is now `biometricNotRecognized` + * `fingerprintSuccess`is now `biometricSuccess` + * `fingerprintRequiredTitle` is now `biometricRequiredTitle` + ## 1.0.0-nullsafety.3 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/local_auth/README.md b/packages/local_auth/README.md index 516561be4230..80820d759fec 100644 --- a/packages/local_auth/README.md +++ b/packages/local_auth/README.md @@ -23,8 +23,8 @@ bool canCheckBiometrics = Currently the following biometric types are implemented: -* BiometricType.face -* BiometricType.fingerprint +- BiometricType.face +- BiometricType.fingerprint To get a list of enrolled biometrics, call getAvailableBiometrics: @@ -44,10 +44,10 @@ if (Platform.isIOS) { We have default dialogs with an 'OK' button to show authentication error messages for the following 2 cases: -1. Passcode/PIN/Pattern Not Set. The user has not yet configured a passcode on - iOS or PIN/pattern on Android. -2. Touch ID/Fingerprint Not Enrolled. The user has not enrolled any - fingerprints on the device. +1. Passcode/PIN/Pattern Not Set. The user has not yet configured a passcode on + iOS or PIN/pattern on Android. +2. Touch ID/Fingerprint Not Enrolled. The user has not enrolled any + fingerprints on the device. Which means, if there's no fingerprint on the user's device, a dialog with instructions will pop up to let the user set up fingerprint. If the user clicks @@ -55,20 +55,33 @@ instructions will pop up to let the user set up fingerprint. If the user clicks Use the exported APIs to trigger local authentication with default dialogs: +The `authenticate()` method uses biometric authentication, but also allows +users to use pin, pattern, or passcode. + ```dart var localAuth = LocalAuthentication(); bool didAuthenticate = - await localAuth.authenticateWithBiometrics( + await localAuth.authenticate( localizedReason: 'Please authenticate to show account balance'); ``` +To authenticate using biometric authentication only, set `biometricOnly` to `true`. + +```dart +var localAuth = LocalAuthentication(); +bool didAuthenticate = + await localAuth.authenticate( + localizedReason: 'Please authenticate to show account balance', + biometricOnly: true); +``` + If you don't want to use the default dialogs, call this API with 'useErrorDialogs = false'. In this case, it will throw the error message back and you need to handle them in your dart code: ```dart bool didAuthenticate = - await localAuth.authenticateWithBiometrics( + await localAuth.authenticate( localizedReason: 'Please authenticate to show account balance', useErrorDialogs: false); ``` @@ -84,7 +97,7 @@ const iosStrings = const IOSAuthMessages( goToSettingsButton: 'settings', goToSettingsDescription: 'Please set up your Touch ID.', lockOut: 'Please reenable your Touch ID'); -await localAuth.authenticateWithBiometrics( +await localAuth.authenticate( localizedReason: 'Please authenticate to show account balance', useErrorDialogs: false, iOSAuthStrings: iosStrings); @@ -112,7 +125,7 @@ import 'package:flutter/services.dart'; import 'package:local_auth/error_codes.dart' as auth_error; try { - bool didAuthenticate = await local_auth.authenticateWithBiometrics( + bool didAuthenticate = await local_auth.authenticate( localizedReason: 'Please authenticate to show account balance'); } on PlatformException catch (e) { if (e.code == auth_error.notAvailable) { @@ -134,7 +147,6 @@ you need to also add: to your Info.plist file. Failure to do so results in a dialog that tells the user your app has not been updated to use TouchID. - ## Android Integration Note that local_auth plugin requires the use of a FragmentActivity as @@ -191,7 +203,7 @@ Update your project's `AndroidManifest.xml` file to include the On Android, you can check only for existence of fingerprint hardware prior to API 29 (Android Q). Therefore, if you would like to support other biometrics types (such as face scanning) and you want to support SDKs lower than Q, -*do not* call `getAvailableBiometrics`. Simply call `authenticateWithBiometrics`. +_do not_ call `getAvailableBiometrics`. Simply call `authenticate` with `biometricOnly: true`. This will return an error if there was no hardware available. ## Sticky Auth diff --git a/packages/local_auth/android/build.gradle b/packages/local_auth/android/build.gradle index 0fc603c36867..ae8e6f2828a2 100644 --- a/packages/local_auth/android/build.gradle +++ b/packages/local_auth/android/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:4.1.1' } } diff --git a/packages/local_auth/android/src/main/AndroidManifest.xml b/packages/local_auth/android/src/main/AndroidManifest.xml index b7da0caab6da..cb6cb985a986 100644 --- a/packages/local_auth/android/src/main/AndroidManifest.xml +++ b/packages/local_auth/android/src/main/AndroidManifest.xml @@ -1,3 +1,5 @@ + + diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java index e907cc43f2b4..096c7efd6d3d 100644 --- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java +++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java @@ -29,7 +29,7 @@ import java.util.concurrent.Executor; /** - * Authenticates the user with fingerprint and sends corresponding response back to Flutter. + * Authenticates the user with biometrics and sends corresponding response back to Flutter. * *

One instance per call is generated to ensure readable separation of executable paths across * method calls. @@ -37,10 +37,8 @@ @SuppressWarnings("deprecation") class AuthenticationHelper extends BiometricPrompt.AuthenticationCallback implements Application.ActivityLifecycleCallbacks, DefaultLifecycleObserver { - /** The callback that handles the result of this authentication process. */ interface AuthCompletionHandler { - /** Called when authentication was successful. */ void onSuccess(); @@ -75,24 +73,32 @@ interface AuthCompletionHandler { Lifecycle lifecycle, FragmentActivity activity, MethodCall call, - AuthCompletionHandler completionHandler) { + AuthCompletionHandler completionHandler, + boolean allowCredentials) { this.lifecycle = lifecycle; this.activity = activity; this.completionHandler = completionHandler; this.call = call; this.isAuthSticky = call.argument("stickyAuth"); this.uiThreadExecutor = new UiThreadExecutor(); - this.promptInfo = + + BiometricPrompt.PromptInfo.Builder promptBuilder = new BiometricPrompt.PromptInfo.Builder() .setDescription((String) call.argument("localizedReason")) .setTitle((String) call.argument("signInTitle")) - .setSubtitle((String) call.argument("fingerprintHint")) - .setNegativeButtonText((String) call.argument("cancelButton")) + .setSubtitle((String) call.argument("biometricHint")) .setConfirmationRequired((Boolean) call.argument("sensitiveTransaction")) - .build(); + .setConfirmationRequired((Boolean) call.argument("sensitiveTransaction")); + + if (allowCredentials) { + promptBuilder.setDeviceCredentialAllowed(true); + } else { + promptBuilder.setNegativeButtonText((String) call.argument("cancelButton")); + } + this.promptInfo = promptBuilder.build(); } - /** Start the fingerprint listener. */ + /** Start the biometric listener. */ void authenticate() { if (lifecycle != null) { lifecycle.addObserver(this); @@ -103,7 +109,7 @@ void authenticate() { biometricPrompt.authenticate(promptInfo); } - /** Cancels the fingerprint authentication. */ + /** Cancels the biometric authentication. */ void stopAuthentication() { if (biometricPrompt != null) { biometricPrompt.cancelAuthentication(); @@ -111,7 +117,7 @@ void stopAuthentication() { } } - /** Stops the fingerprint listener. */ + /** Stops the biometric listener. */ private void stop() { if (lifecycle != null) { lifecycle.removeObserver(this); @@ -125,21 +131,27 @@ private void stop() { public void onAuthenticationError(int errorCode, CharSequence errString) { switch (errorCode) { case BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL: - completionHandler.onError( - "PasscodeNotSet", - "Phone not secured by PIN, pattern or password, or SIM is currently locked."); - break; + if (call.argument("useErrorDialogs")) { + showGoToSettingsDialog( + (String) call.argument("deviceCredentialsRequired"), + (String) call.argument("deviceCredentialsSetupDescription")); + return; + } + completionHandler.onError("NotAvailable", "Security credentials not available."); case BiometricPrompt.ERROR_NO_SPACE: case BiometricPrompt.ERROR_NO_BIOMETRICS: + if (promptInfo.isDeviceCredentialAllowed()) return; if (call.argument("useErrorDialogs")) { - showGoToSettingsDialog(); + showGoToSettingsDialog( + (String) call.argument("biometricRequired"), + (String) call.argument("goToSettingDescription")); return; } completionHandler.onError("NotEnrolled", "No Biometrics enrolled on this device."); break; case BiometricPrompt.ERROR_HW_UNAVAILABLE: case BiometricPrompt.ERROR_HW_NOT_PRESENT: - completionHandler.onError("NotAvailable", "Biometrics is not available on this device."); + completionHandler.onError("NotAvailable", "Security credentials not available."); break; case BiometricPrompt.ERROR_LOCKOUT: completionHandler.onError( @@ -176,7 +188,7 @@ public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult resul public void onAuthenticationFailed() {} /** - * If the activity is paused, we keep track because fingerprint dialog simply returns "User + * If the activity is paused, we keep track because biometric dialog simply returns "User * cancelled" when the activity is paused. */ @Override @@ -215,12 +227,12 @@ public void onResume(@NonNull LifecycleOwner owner) { // Suppress inflateParams lint because dialogs do not need to attach to a parent view. @SuppressLint("InflateParams") - private void showGoToSettingsDialog() { + private void showGoToSettingsDialog(String title, String descriptionText) { View view = LayoutInflater.from(activity).inflate(R.layout.go_to_setting, null, false); TextView message = (TextView) view.findViewById(R.id.fingerprint_required); TextView description = (TextView) view.findViewById(R.id.go_to_setting_description); - message.setText((String) call.argument("fingerprintRequired")); - description.setText((String) call.argument("goToSettingDescription")); + message.setText(title); + description.setText(descriptionText); Context context = new ContextThemeWrapper(activity, R.style.AlertDialogCustom); OnClickListener goToSettingHandler = new OnClickListener() { diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java index 0f93f40e947a..f4c6c168f54d 100644 --- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java +++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java @@ -4,9 +4,18 @@ package io.flutter.plugins.localauth; +import static android.app.Activity.RESULT_OK; +import static android.content.Context.KEYGUARD_SERVICE; + import android.app.Activity; +import android.app.KeyguardManager; +import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; +import android.hardware.fingerprint.FingerprintManager; import android.os.Build; +import androidx.annotation.NonNull; +import androidx.biometric.BiometricManager; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.Lifecycle; import io.flutter.embedding.engine.plugins.FlutterPlugin; @@ -17,6 +26,8 @@ import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.PluginRegistry; +import io.flutter.plugin.common.PluginRegistry.Registrar; import io.flutter.plugins.localauth.AuthenticationHelper.AuthCompletionHandler; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; @@ -29,14 +40,33 @@ @SuppressWarnings("deprecation") public class LocalAuthPlugin implements MethodCallHandler, FlutterPlugin, ActivityAware { private static final String CHANNEL_NAME = "plugins.flutter.io/local_auth"; - + private static final int LOCK_REQUEST_CODE = 221; private Activity activity; private final AtomicBoolean authInProgress = new AtomicBoolean(false); - private AuthenticationHelper authenticationHelper; + private AuthenticationHelper authHelper; // These are null when not using v2 embedding. private MethodChannel channel; private Lifecycle lifecycle; + private BiometricManager biometricManager; + private FingerprintManager fingerprintManager; + private KeyguardManager keyguardManager; + private Result lockRequestResult; + private final PluginRegistry.ActivityResultListener resultListener = + new PluginRegistry.ActivityResultListener() { + @Override + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == LOCK_REQUEST_CODE) { + if (resultCode == RESULT_OK && lockRequestResult != null) { + authenticateSuccess(lockRequestResult); + } else { + authenticateFail(lockRequestResult); + } + lockRequestResult = null; + } + return false; + } + }; /** * Registers a plugin with the v1 embedding api {@code io.flutter.plugin.common}. @@ -49,13 +79,12 @@ public class LocalAuthPlugin implements MethodCallHandler, FlutterPlugin, Activi * io.flutter.plugin.common.BinaryMessenger}. */ @SuppressWarnings("deprecation") - public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) { + public static void registerWith(Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME); - channel.setMethodCallHandler(new LocalAuthPlugin(registrar.activity())); - } - - private LocalAuthPlugin(Activity activity) { - this.activity = activity; + final LocalAuthPlugin plugin = new LocalAuthPlugin(); + plugin.activity = registrar.activity(); + channel.setMethodCallHandler(plugin); + registrar.addActivityResultListener(plugin.resultListener); } /** @@ -66,118 +95,241 @@ private LocalAuthPlugin(Activity activity) { public LocalAuthPlugin() {} @Override - public void onMethodCall(MethodCall call, final Result result) { - if (call.method.equals("authenticateWithBiometrics")) { - if (authInProgress.get()) { - // Apps should not invoke another authentication request while one is in progress, - // so we classify this as an error condition. If we ever find a legitimate use case for - // this, we can try to cancel the ongoing auth and start a new one but for now, not worth - // the complexity. - result.error("auth_in_progress", "Authentication in progress", null); - return; - } + public void onMethodCall(MethodCall call, @NonNull final Result result) { + switch (call.method) { + case "authenticate": + authenticate(call, result); + break; + case "getAvailableBiometrics": + getAvailableBiometrics(result); + break; + case "isDeviceSupported": + isDeviceSupported(result); + break; + case "stopAuthentication": + stopAuthentication(result); + break; + default: + result.notImplemented(); + break; + } + } - if (activity == null || activity.isFinishing()) { - result.error("no_activity", "local_auth plugin requires a foreground activity", null); - return; - } + /* + * Starts authentication process + */ + private void authenticate(MethodCall call, final Result result) { + if (authInProgress.get()) { + result.error("auth_in_progress", "Authentication in progress", null); + return; + } - if (!(activity instanceof FragmentActivity)) { - result.error( - "no_fragment_activity", - "local_auth plugin requires activity to be a FragmentActivity.", - null); - return; - } - authInProgress.set(true); - authenticationHelper = - new AuthenticationHelper( - lifecycle, - (FragmentActivity) activity, - call, - new AuthCompletionHandler() { - @Override - public void onSuccess() { - if (authInProgress.compareAndSet(true, false)) { - result.success(true); - } - } - - @Override - public void onFailure() { - if (authInProgress.compareAndSet(true, false)) { - result.success(false); - } - } - - @Override - public void onError(String code, String error) { - if (authInProgress.compareAndSet(true, false)) { - result.error(code, error, null); - } - } - }); - authenticationHelper.authenticate(); - } else if (call.method.equals("getAvailableBiometrics")) { - try { - if (activity == null || activity.isFinishing()) { - result.error("no_activity", "local_auth plugin requires a foreground activity", null); - return; - } - ArrayList biometrics = new ArrayList(); - PackageManager packageManager = activity.getPackageManager(); - if (Build.VERSION.SDK_INT >= 23) { - if (packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { - biometrics.add("fingerprint"); + if (activity == null || activity.isFinishing()) { + result.error("no_activity", "local_auth plugin requires a foreground activity", null); + return; + } + + if (!(activity instanceof FragmentActivity)) { + result.error( + "no_fragment_activity", + "local_auth plugin requires activity to be a FragmentActivity.", + null); + return; + } + + if (!isDeviceSupported()) { + authInProgress.set(false); + result.error("NotAvailable", "Required security features not enabled", null); + return; + } + + authInProgress.set(true); + AuthCompletionHandler completionHandler = + new AuthCompletionHandler() { + @Override + public void onSuccess() { + authenticateSuccess(result); } - } - if (Build.VERSION.SDK_INT >= 29) { - if (packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) { - biometrics.add("face"); + + @Override + public void onFailure() { + authenticateFail(result); } - if (packageManager.hasSystemFeature(PackageManager.FEATURE_IRIS)) { - biometrics.add("iris"); + + @Override + public void onError(String code, String error) { + if (authInProgress.compareAndSet(true, false)) { + result.error(code, error, null); + } } + }; + + // if is biometricOnly try biometric prompt - might not work + boolean isBiometricOnly = call.argument("biometricOnly"); + if (isBiometricOnly) { + if (!canAuthenticateWithBiometrics()) { + if (!hasBiometricHardware()) { + completionHandler.onError("NoHardware", "No biometric hardware found"); } - result.success(biometrics); - } catch (Exception e) { - result.error("no_biometrics_available", e.getMessage(), null); + completionHandler.onError("NotEnrolled", "No biometrics enrolled on this device."); + return; } - } else if (call.method.equals(("stopAuthentication"))) { - stopAuthentication(result); - } else { - result.notImplemented(); + authHelper = + new AuthenticationHelper( + lifecycle, (FragmentActivity) activity, call, completionHandler, false); + authHelper.authenticate(); + return; + } + + // API 29 and above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + authHelper = + new AuthenticationHelper( + lifecycle, (FragmentActivity) activity, call, completionHandler, true); + authHelper.authenticate(); + return; + } + + // API 23 - 28 with fingerprint + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && fingerprintManager != null) { + if (fingerprintManager.hasEnrolledFingerprints()) { + authHelper = + new AuthenticationHelper( + lifecycle, (FragmentActivity) activity, call, completionHandler, false); + authHelper.authenticate(); + return; + } + } + + // API 23 or higher with device credentials + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && keyguardManager != null + && keyguardManager.isDeviceSecure()) { + String title = call.argument("signInTitle"); + String reason = call.argument("localizedReason"); + Intent authIntent = keyguardManager.createConfirmDeviceCredentialIntent(title, reason); + + // save result for async response + lockRequestResult = result; + activity.startActivityForResult(authIntent, LOCK_REQUEST_CODE); + return; + } + + // Unable to authenticate + result.error("NotSupported", "This device does not support required security features", null); + } + + private void authenticateSuccess(Result result) { + if (authInProgress.compareAndSet(true, false)) { + result.success(true); + } + } + + private void authenticateFail(Result result) { + if (authInProgress.compareAndSet(true, false)) { + result.success(false); } } /* - Stops the authentication if in progress. - */ + * Stops the authentication if in progress. + */ private void stopAuthentication(Result result) { try { - if (authenticationHelper != null && authInProgress.get()) { - authenticationHelper.stopAuthentication(); - authenticationHelper = null; - result.success(true); - return; + if (authHelper != null && authInProgress.get()) { + authHelper.stopAuthentication(); + authHelper = null; } - result.success(false); + authInProgress.set(false); + result.success(true); } catch (Exception e) { result.success(false); } } + /* + * Returns biometric types available on device + */ + private void getAvailableBiometrics(final Result result) { + try { + if (activity == null || activity.isFinishing()) { + result.error("no_activity", "local_auth plugin requires a foreground activity", null); + return; + } + ArrayList biometrics = getAvailableBiometrics(); + result.success(biometrics); + } catch (Exception e) { + result.error("no_biometrics_available", e.getMessage(), null); + } + } + + private ArrayList getAvailableBiometrics() { + ArrayList biometrics = new ArrayList<>(); + if (activity == null || activity.isFinishing()) { + return biometrics; + } + PackageManager packageManager = activity.getPackageManager(); + if (Build.VERSION.SDK_INT >= 23) { + if (packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { + biometrics.add("fingerprint"); + } + } + if (Build.VERSION.SDK_INT >= 29) { + if (packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) { + biometrics.add("face"); + } + if (packageManager.hasSystemFeature(PackageManager.FEATURE_IRIS)) { + biometrics.add("iris"); + } + } + + return biometrics; + } + + private boolean isDeviceSupported() { + if (keyguardManager == null) return false; + return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && keyguardManager.isDeviceSecure()); + } + + private boolean canAuthenticateWithBiometrics() { + if (biometricManager == null) return false; + return biometricManager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS; + } + + private boolean hasBiometricHardware() { + if (biometricManager == null) return false; + return biometricManager.canAuthenticate() != BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE; + } + + private void isDeviceSupported(Result result) { + result.success(isDeviceSupported()); + } + @Override public void onAttachedToEngine(FlutterPluginBinding binding) { - channel = new MethodChannel(binding.getBinaryMessenger(), CHANNEL_NAME); + channel = new MethodChannel(binding.getFlutterEngine().getDartExecutor(), CHANNEL_NAME); + channel.setMethodCallHandler(this); } @Override - public void onDetachedFromEngine(FlutterPluginBinding binding) {} + public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {} + + private void setServicesFromActivity(Activity activity) { + if (activity == null) return; + this.activity = activity; + Context context = activity.getBaseContext(); + biometricManager = BiometricManager.from(activity); + keyguardManager = (KeyguardManager) context.getSystemService(KEYGUARD_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + fingerprintManager = + (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE); + } + } @Override public void onAttachedToActivity(ActivityPluginBinding binding) { - activity = binding.getActivity(); + binding.addActivityResultListener(resultListener); + setServicesFromActivity(binding.getActivity()); lifecycle = FlutterLifecycleAdapter.getActivityLifecycle(binding); channel.setMethodCallHandler(this); } @@ -185,18 +337,17 @@ public void onAttachedToActivity(ActivityPluginBinding binding) { @Override public void onDetachedFromActivityForConfigChanges() { lifecycle = null; - activity = null; } @Override public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) { - activity = binding.getActivity(); + binding.addActivityResultListener(resultListener); + setServicesFromActivity(binding.getActivity()); lifecycle = FlutterLifecycleAdapter.getActivityLifecycle(binding); } @Override public void onDetachedFromActivity() { - activity = null; lifecycle = null; channel.setMethodCallHandler(null); } diff --git a/packages/local_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties b/packages/local_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties index 9a4163a4f5ee..186b71557c50 100644 --- a/packages/local_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties +++ b/packages/local_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/packages/local_auth/example/android/build.gradle b/packages/local_auth/example/android/build.gradle index 541636cc492a..ea78cdf2c29c 100644 --- a/packages/local_auth/example/android/build.gradle +++ b/packages/local_auth/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:4.1.1' } } diff --git a/packages/local_auth/example/android/gradle.properties b/packages/local_auth/example/android/gradle.properties index a6738207fd15..7fe61a74cee0 100644 --- a/packages/local_auth/example/android/gradle.properties +++ b/packages/local_auth/example/android/gradle.properties @@ -1,4 +1,4 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx1024m android.useAndroidX=true android.enableJetifier=true android.enableR8=true diff --git a/packages/local_auth/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/local_auth/example/android/gradle/wrapper/gradle-wrapper.properties index 562393332f6c..cd9fe1c68282 100644 --- a/packages/local_auth/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/local_auth/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu May 30 07:21:52 NPT 2019 +#Sun Jan 03 14:07:08 CST 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip diff --git a/packages/local_auth/example/android/settings_aar.gradle b/packages/local_auth/example/android/settings_aar.gradle new file mode 100644 index 000000000000..e7b4def49cb5 --- /dev/null +++ b/packages/local_auth/example/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/packages/local_auth/example/lib/main.dart b/packages/local_auth/example/lib/main.dart index 0a07e2c4437d..8cdad5b7eed3 100644 --- a/packages/local_auth/example/lib/main.dart +++ b/packages/local_auth/example/lib/main.dart @@ -21,11 +21,22 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { final LocalAuthentication auth = LocalAuthentication(); - late bool _canCheckBiometrics; - late List _availableBiometrics; + _SupportState _supportState = _SupportState.unknown; + bool? _canCheckBiometrics; + List? _availableBiometrics; String _authorized = 'Not Authorized'; bool _isAuthenticating = false; + @override + void initState() { + super.initState(); + auth.isDeviceSupported().then( + (isSupported) => setState(() => _supportState = isSupported + ? _SupportState.supported + : _SupportState.unsupported), + ); + } + Future _checkBiometrics() async { late bool canCheckBiometrics; try { @@ -63,8 +74,8 @@ class _MyAppState extends State { _isAuthenticating = true; _authorized = 'Authenticating'; }); - authenticated = await auth.authenticateWithBiometrics( - localizedReason: 'Scan your fingerprint to authenticate', + authenticated = await auth.authenticate( + localizedReason: 'Let OS determine authentication method', useErrorDialogs: true, stickyAuth: true); setState(() { @@ -73,6 +84,42 @@ class _MyAppState extends State { }); } on PlatformException catch (e) { print(e); + setState(() { + _isAuthenticating = false; + _authorized = "Error - ${e.message}"; + }); + return; + } + if (!mounted) return; + + setState( + () => _authorized = authenticated ? 'Authorized' : 'Not Authorized'); + } + + Future _authenticateWithBiometrics() async { + bool authenticated = false; + try { + setState(() { + _isAuthenticating = true; + _authorized = 'Authenticating'; + }); + authenticated = await auth.authenticate( + localizedReason: + 'Scan your fingerprint (or face or whatever) to authenticate', + useErrorDialogs: true, + stickyAuth: true, + biometricOnly: true); + setState(() { + _isAuthenticating = false; + _authorized = 'Authenticating'; + }); + } on PlatformException catch (e) { + print(e); + setState(() { + _isAuthenticating = false; + _authorized = "Error - ${e.message}"; + }); + return; } if (!mounted) return; @@ -82,39 +129,92 @@ class _MyAppState extends State { }); } - void _cancelAuthentication() { - auth.stopAuthentication(); + void _cancelAuthentication() async { + await auth.stopAuthentication(); + setState(() => _isAuthenticating = false); } @override Widget build(BuildContext context) { return MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('Plugin example app'), - ), - body: ConstrainedBox( - constraints: const BoxConstraints.expand(), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ + home: Scaffold( + appBar: AppBar( + title: const Text('Plugin example app'), + ), + body: ListView( + padding: const EdgeInsets.only(top: 30), + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (_supportState == _SupportState.unknown) + CircularProgressIndicator() + else if (_supportState == _SupportState.supported) + Text("This device is supported") + else + Text("This device is not supported"), + Divider(height: 100), Text('Can check biometrics: $_canCheckBiometrics\n'), ElevatedButton( child: const Text('Check biometrics'), onPressed: _checkBiometrics, ), + Divider(height: 100), Text('Available biometrics: $_availableBiometrics\n'), ElevatedButton( child: const Text('Get available biometrics'), onPressed: _getAvailableBiometrics, ), + Divider(height: 100), Text('Current State: $_authorized\n'), - ElevatedButton( - child: Text(_isAuthenticating ? 'Cancel' : 'Authenticate'), - onPressed: - _isAuthenticating ? _cancelAuthentication : _authenticate, - ) - ])), - )); + (_isAuthenticating) + ? ElevatedButton( + onPressed: _cancelAuthentication, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text("Cancel Authentication"), + Icon(Icons.cancel), + ], + ), + ) + : Column( + children: [ + ElevatedButton( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text('Authenticate'), + Icon(Icons.perm_device_information), + ], + ), + onPressed: _authenticate, + ), + ElevatedButton( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text(_isAuthenticating + ? 'Cancel' + : 'Authenticate: biometrics only'), + Icon(Icons.fingerprint), + ], + ), + onPressed: _authenticateWithBiometrics, + ), + ], + ), + ], + ), + ], + ), + ), + ); } } + +enum _SupportState { + unknown, + supported, + unsupported, +} diff --git a/packages/local_auth/integration_test/local_auth_test.dart b/packages/local_auth/integration_test/local_auth_test.dart index c09810032461..d6527c7601e4 100644 --- a/packages/local_auth/integration_test/local_auth_test.dart +++ b/packages/local_auth/integration_test/local_auth_test.dart @@ -13,6 +13,9 @@ void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('canCheckBiometrics', (WidgetTester tester) async { - expect(LocalAuthentication().getAvailableBiometrics(), completion(isList)); + expect( + LocalAuthentication().getAvailableBiometrics(), + completion(isList), + ); }); } diff --git a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m index aa0c217ef543..cda49a7d68c3 100644 --- a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m +++ b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m @@ -22,10 +22,17 @@ + (void)registerWithRegistrar:(NSObject *)registrar { } - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { - if ([@"authenticateWithBiometrics" isEqualToString:call.method]) { - [self authenticateWithBiometrics:call.arguments withFlutterResult:result]; + if ([@"authenticate" isEqualToString:call.method]) { + bool isBiometricOnly = [call.arguments[@"biometricOnly"] boolValue]; + if (isBiometricOnly) { + [self authenticateWithBiometrics:call.arguments withFlutterResult:result]; + } else { + [self authenticate:call.arguments withFlutterResult:result]; + } } else if ([@"getAvailableBiometrics" isEqualToString:call.method]) { [self getAvailableBiometrics:result]; + } else if ([@"isDeviceSupported" isEqualToString:call.method]) { + result(@YES); } else { result(FlutterMethodNotImplemented); } @@ -89,7 +96,6 @@ - (void)getAvailableBiometrics:(FlutterResult)result { } result(biometrics); } - - (void)authenticateWithBiometrics:(NSDictionary *)arguments withFlutterResult:(FlutterResult)result { LAContext *context = [[LAContext alloc] init]; @@ -130,6 +136,48 @@ - (void)authenticateWithBiometrics:(NSDictionary *)arguments } } +- (void)authenticate:(NSDictionary *)arguments withFlutterResult:(FlutterResult)result { + LAContext *context = [[LAContext alloc] init]; + NSError *authError = nil; + _lastCallArgs = nil; + _lastResult = nil; + context.localizedFallbackTitle = @""; + + if (@available(iOS 9.0, *)) { + if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&authError]) { + [context evaluatePolicy:kLAPolicyDeviceOwnerAuthentication + localizedReason:arguments[@"localizedReason"] + reply:^(BOOL success, NSError *error) { + if (success) { + result(@YES); + } else { + switch (error.code) { + case LAErrorPasscodeNotSet: + case LAErrorTouchIDNotAvailable: + case LAErrorTouchIDNotEnrolled: + case LAErrorTouchIDLockout: + [self handleErrors:error + flutterArguments:arguments + withFlutterResult:result]; + return; + case LAErrorSystemCancel: + if ([arguments[@"stickyAuth"] boolValue]) { + self->_lastCallArgs = arguments; + self->_lastResult = result; + return; + } + } + result(@NO); + } + }]; + } else { + [self handleErrors:authError flutterArguments:arguments withFlutterResult:result]; + } + } else { + // Fallback on earlier versions + } +} + - (void)handleErrors:(NSError *)authError flutterArguments:(NSDictionary *)arguments withFlutterResult:(FlutterResult)result { diff --git a/packages/local_auth/lib/auth_strings.dart b/packages/local_auth/lib/auth_strings.dart index 3afc23827d98..855098b6aba4 100644 --- a/packages/local_auth/lib/auth_strings.dart +++ b/packages/local_auth/lib/auth_strings.dart @@ -15,38 +15,46 @@ import 'package:intl/intl.dart'; /// Provides default values for all messages. class AndroidAuthMessages { const AndroidAuthMessages({ - this.fingerprintHint, - this.fingerprintNotRecognized, - this.fingerprintSuccess, + this.biometricHint, + this.biometricNotRecognized, + this.biometricRequiredTitle, + this.biometricSuccess, this.cancelButton, - this.signInTitle, - this.fingerprintRequiredTitle, + this.deviceCredentialsRequiredTitle, + this.deviceCredentialsSetupDescription, this.goToSettingsButton, this.goToSettingsDescription, + this.signInTitle, }); - final String? fingerprintHint; - final String? fingerprintNotRecognized; - final String? fingerprintSuccess; + final String? biometricHint; + final String? biometricNotRecognized; + final String? biometricRequiredTitle; + final String? biometricSuccess; final String? cancelButton; - final String? signInTitle; - final String? fingerprintRequiredTitle; + final String? deviceCredentialsRequiredTitle; + final String? deviceCredentialsSetupDescription; final String? goToSettingsButton; final String? goToSettingsDescription; + final String? signInTitle; Map get args { return { - 'fingerprintHint': fingerprintHint ?? androidFingerprintHint, - 'fingerprintNotRecognized': - fingerprintNotRecognized ?? androidFingerprintNotRecognized, - 'fingerprintSuccess': fingerprintSuccess ?? androidFingerprintSuccess, + 'biometricHint': biometricHint ?? androidBiometricHint, + 'biometricNotRecognized': + biometricNotRecognized ?? androidBiometricNotRecognized, + 'biometricSuccess': biometricSuccess ?? androidBiometricSuccess, + 'biometricRequired': + biometricRequiredTitle ?? androidBiometricRequiredTitle, 'cancelButton': cancelButton ?? androidCancelButton, - 'signInTitle': signInTitle ?? androidSignInTitle, - 'fingerprintRequired': - fingerprintRequiredTitle ?? androidFingerprintRequiredTitle, + 'deviceCredentialsRequired': deviceCredentialsRequiredTitle ?? + androidDeviceCredentialsRequiredTitle, + 'deviceCredentialsSetupDescription': deviceCredentialsSetupDescription ?? + androidDeviceCredentialsSetupDescription, 'goToSetting': goToSettingsButton ?? goToSettings, 'goToSettingDescription': goToSettingsDescription ?? androidGoToSettingsDescription, + 'signInTitle': signInTitle ?? androidSignInTitle, }; } } @@ -80,16 +88,17 @@ class IOSAuthMessages { // Strings for local_authentication plugin. Currently supports English. // Intl.message must be string literals. -String get androidFingerprintHint => Intl.message('Touch sensor', - desc: 'Hint message advising the user how to scan their fingerprint. It is ' +String get androidBiometricHint => Intl.message('Verify identity', + desc: + 'Hint message advising the user how to authenticate with biometrics. It is ' 'used on Android side. Maximum 60 characters.'); -String get androidFingerprintNotRecognized => - Intl.message('Fingerprint not recognized. Try again.', +String get androidBiometricNotRecognized => + Intl.message('Not recognized. Try again.', desc: 'Message to let the user know that authentication was failed. It ' 'is used on Android side. Maximum 60 characters.'); -String get androidFingerprintSuccess => Intl.message('Fingerprint recognized.', +String get androidBiometricSuccess => Intl.message('Success', desc: 'Message to let the user know that authentication was successful. It ' 'is used on Android side. Maximum 60 characters.'); @@ -97,17 +106,26 @@ String get androidCancelButton => Intl.message('Cancel', desc: 'Message showed on a button that the user can click to leave the ' 'current dialog. It is used on Android side. Maximum 30 characters.'); -String get androidSignInTitle => Intl.message('Fingerprint Authentication', +String get androidSignInTitle => Intl.message('Authentication required', desc: 'Message showed as a title in a dialog which indicates the user ' - 'that they need to scan fingerprint to continue. It is used on ' + 'that they need to scan biometric to continue. It is used on ' 'Android side. Maximum 60 characters.'); -String get androidFingerprintRequiredTitle { - return Intl.message('Fingerprint required', - desc: 'Message showed as a title in a dialog which indicates the user ' - 'fingerprint is not set up yet on their device. It is used on Android' - ' side. Maximum 60 characters.'); -} +String get androidBiometricRequiredTitle => Intl.message('Biometric required', + desc: 'Message showed as a title in a dialog which indicates the user ' + 'has not set up biometric authentication on their device. It is used on Android' + ' side. Maximum 60 characters.'); + +String get androidDeviceCredentialsRequiredTitle => Intl.message( + 'Device credentials required', + desc: 'Message showed as a title in a dialog which indicates the user ' + 'has not set up credentials authentication on their device. It is used on Android' + ' side. Maximum 60 characters.'); + +String get androidDeviceCredentialsSetupDescription => Intl.message( + 'Device credentials required', + desc: 'Message advising the user to go to the settings and configure ' + 'device credentials on their device. It shows in a dialog on Android side.'); String get goToSettings => Intl.message('Go to settings', desc: 'Message showed on a button that the user can click to go to ' @@ -115,10 +133,10 @@ String get goToSettings => Intl.message('Go to settings', 'and iOS side. Maximum 30 characters.'); String get androidGoToSettingsDescription => Intl.message( - 'Fingerprint is not set up on your device. Go to ' - '\'Settings > Security\' to add your fingerprint.', + 'Biometric authentication is not set up on your device. Go to ' + '\'Settings > Security\' to add biometric authentication.', desc: 'Message advising the user to go to the settings and configure ' - 'fingerprint on their device. It shows in a dialog on Android side.'); + 'biometric on their device. It shows in a dialog on Android side.'); String get iOSLockOut => Intl.message( 'Biometric authentication is disabled. Please lock and unlock your screen to ' diff --git a/packages/local_auth/lib/error_codes.dart b/packages/local_auth/lib/error_codes.dart index 3f6f298ba4f3..3b080c13baf7 100644 --- a/packages/local_auth/lib/error_codes.dart +++ b/packages/local_auth/lib/error_codes.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. // Exception codes for `PlatformException` returned by -// `authenticateWithBiometrics`. +// `authenticate`. /// Indicates that the user has not yet configured a passcode (iOS) or /// PIN/pattern/password (Android) on the device. diff --git a/packages/local_auth/lib/local_auth.dart b/packages/local_auth/lib/local_auth.dart index f1dbdd4840a8..f8a7228bcd8d 100644 --- a/packages/local_auth/lib/local_auth.dart +++ b/packages/local_auth/lib/local_auth.dart @@ -30,7 +30,29 @@ void setMockPathProviderPlatform(Platform platform) { /// A Flutter plugin for authenticating the user identity locally. class LocalAuthentication { - /// Authenticates the user with biometrics available on the device. + /// The `authenticateWithBiometrics` method has been deprecated. + /// Use `authenticate` with `biometricOnly: true` instead + @Deprecated("Use `authenticate` with `biometricOnly: true` instead") + Future authenticateWithBiometrics({ + required String localizedReason, + bool useErrorDialogs = true, + bool stickyAuth = false, + AndroidAuthMessages androidAuthStrings = const AndroidAuthMessages(), + IOSAuthMessages iOSAuthStrings = const IOSAuthMessages(), + bool sensitiveTransaction = true, + }) => + authenticate( + localizedReason: localizedReason, + useErrorDialogs: useErrorDialogs, + stickyAuth: stickyAuth, + androidAuthStrings: androidAuthStrings, + iOSAuthStrings: iOSAuthStrings, + sensitiveTransaction: sensitiveTransaction, + biometricOnly: true, + ); + + /// Authenticates the user with biometrics available on the device while also + /// allowing the user to use device authentication - pin, pattern, passcode. /// /// Returns a [Future] holding true, if the user successfully authenticated, /// false otherwise. @@ -62,17 +84,21 @@ class LocalAuthentication { /// dialog after the face is recognized to make sure the user meant to unlock /// their phone. /// + /// Setting [biometricOnly] to true prevents authenticates from using non-biometric + /// local authentication such as pin, passcode, and passcode. + /// /// Throws an [PlatformException] if there were technical problems with local /// authentication (e.g. lack of relevant hardware). This might throw /// [PlatformException] with error code [otherOperatingSystem] on the iOS /// simulator. - Future authenticateWithBiometrics({ + Future authenticate({ required String localizedReason, bool useErrorDialogs = true, bool stickyAuth = false, AndroidAuthMessages androidAuthStrings = const AndroidAuthMessages(), IOSAuthMessages iOSAuthStrings = const IOSAuthMessages(), bool sensitiveTransaction = true, + bool biometricOnly = false, }) async { assert(localizedReason != null); final Map args = { @@ -80,6 +106,7 @@ class LocalAuthentication { 'useErrorDialogs': useErrorDialogs, 'stickyAuth': stickyAuth, 'sensitiveTransaction': sensitiveTransaction, + 'biometricOnly': biometricOnly, }; if (_platform.isIOS) { args.addAll(iOSAuthStrings.args); @@ -87,14 +114,13 @@ class LocalAuthentication { args.addAll(androidAuthStrings.args); } else { throw PlatformException( - code: otherOperatingSystem, - message: 'Local authentication does not support non-Android/iOS ' - 'operating systems.', - details: 'Your operating system is ${_platform.operatingSystem}'); + code: otherOperatingSystem, + message: 'Local authentication does not support non-Android/iOS ' + 'operating systems.', + details: 'Your operating system is ${_platform.operatingSystem}', + ); } - final bool? result = - await _channel.invokeMethod('authenticateWithBiometrics', args); - return result!; + return (await _channel.invokeMethod('authenticate', args)) ?? false; } /// Returns true if auth was cancelled successfully. @@ -104,9 +130,7 @@ class LocalAuthentication { /// Returns [Future] bool true or false: Future stopAuthentication() async { if (_platform.isAndroid) { - final bool? result = - await _channel.invokeMethod('stopAuthentication'); - return result!; + return await _channel.invokeMethod('stopAuthentication') ?? false; } return true; } @@ -118,6 +142,13 @@ class LocalAuthentication { (await _channel.invokeListMethod('getAvailableBiometrics'))! .isNotEmpty; + /// Returns true if device is capable of checking biometrics or is able to + /// fail over to device credentials. + /// + /// Returns a [Future] bool true or false: + Future isDeviceSupported() async => + (await _channel.invokeMethod('isDeviceSupported')) ?? false; + /// Returns a list of enrolled biometrics /// /// Returns a [Future] List with the following possibilities: @@ -125,10 +156,12 @@ class LocalAuthentication { /// - BiometricType.fingerprint /// - BiometricType.iris (not yet implemented) Future> getAvailableBiometrics() async { - final List? result = - await _channel.invokeListMethod('getAvailableBiometrics'); + final List result = (await _channel.invokeListMethod( + 'getAvailableBiometrics', + )) ?? + []; final List biometrics = []; - result!.forEach((String value) { + result.forEach((String value) { switch (value) { case 'face': biometrics.add(BiometricType.face); diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 050cedb5d7d0..0f5a58835c3c 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -1,6 +1,6 @@ name: local_auth -description: Flutter plugin for Android and iOS device authentication sensors - such as Fingerprint Reader and Touch ID. +description: Flutter plugin for Android and iOS devices to allow local + authentication via fingerprint, touch ID, face ID, passcode, pin, or pattern. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth version: 1.0.0-nullsafety.3 diff --git a/packages/local_auth/test/local_auth_test.dart b/packages/local_auth/test/local_auth_test.dart index 52b8dbf21f72..f4bf9fe0314d 100644 --- a/packages/local_auth/test/local_auth_test.dart +++ b/packages/local_auth/test/local_auth_test.dart @@ -30,61 +30,135 @@ void main() { log.clear(); }); - test('authenticate with no args on Android.', () async { - setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android')); - await localAuthentication.authenticateWithBiometrics( - localizedReason: 'Needs secure'); - expect( - log, - [ - isMethodCall('authenticateWithBiometrics', - arguments: { - 'localizedReason': 'Needs secure', - 'useErrorDialogs': true, - 'stickyAuth': false, - 'sensitiveTransaction': true, - }..addAll(const AndroidAuthMessages().args)), - ], - ); - }); + group("With device auth fail over", () { + test('authenticate with no args on Android.', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android')); + await localAuthentication.authenticate( + localizedReason: 'Needs secure', + biometricOnly: true, + ); + expect( + log, + [ + isMethodCall('authenticate', + arguments: { + 'localizedReason': 'Needs secure', + 'useErrorDialogs': true, + 'stickyAuth': false, + 'sensitiveTransaction': true, + 'biometricOnly': true, + }..addAll(const AndroidAuthMessages().args)), + ], + ); + }); - test('authenticate with no args on iOS.', () async { - setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); - await localAuthentication.authenticateWithBiometrics( - localizedReason: 'Needs secure'); - expect( - log, - [ - isMethodCall('authenticateWithBiometrics', - arguments: { - 'localizedReason': 'Needs secure', - 'useErrorDialogs': true, - 'stickyAuth': false, - 'sensitiveTransaction': true, - }..addAll(const IOSAuthMessages().args)), - ], - ); + test('authenticate with no args on iOS.', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); + await localAuthentication.authenticate( + localizedReason: 'Needs secure', + biometricOnly: true, + ); + expect( + log, + [ + isMethodCall('authenticate', + arguments: { + 'localizedReason': 'Needs secure', + 'useErrorDialogs': true, + 'stickyAuth': false, + 'sensitiveTransaction': true, + 'biometricOnly': true, + }..addAll(const IOSAuthMessages().args)), + ], + ); + }); + + test('authenticate with no sensitive transaction.', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android')); + await localAuthentication.authenticate( + localizedReason: 'Insecure', + sensitiveTransaction: false, + useErrorDialogs: false, + biometricOnly: true, + ); + expect( + log, + [ + isMethodCall('authenticate', + arguments: { + 'localizedReason': 'Insecure', + 'useErrorDialogs': false, + 'stickyAuth': false, + 'sensitiveTransaction': false, + 'biometricOnly': true, + }..addAll(const AndroidAuthMessages().args)), + ], + ); + }); }); - test('authenticate with no sensitive transaction.', () async { - setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android')); - await localAuthentication.authenticateWithBiometrics( - localizedReason: 'Insecure', - sensitiveTransaction: false, - useErrorDialogs: false, - ); - expect( - log, - [ - isMethodCall('authenticateWithBiometrics', - arguments: { - 'localizedReason': 'Insecure', - 'useErrorDialogs': false, - 'stickyAuth': false, - 'sensitiveTransaction': false, - }..addAll(const AndroidAuthMessages().args)), - ], - ); + group("With biometrics only", () { + test('authenticate with no args on Android.', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android')); + await localAuthentication.authenticate( + localizedReason: 'Needs secure', + ); + expect( + log, + [ + isMethodCall('authenticate', + arguments: { + 'localizedReason': 'Needs secure', + 'useErrorDialogs': true, + 'stickyAuth': false, + 'sensitiveTransaction': true, + 'biometricOnly': false, + }..addAll(const AndroidAuthMessages().args)), + ], + ); + }); + + test('authenticate with no args on iOS.', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); + await localAuthentication.authenticate( + localizedReason: 'Needs secure', + ); + expect( + log, + [ + isMethodCall('authenticate', + arguments: { + 'localizedReason': 'Needs secure', + 'useErrorDialogs': true, + 'stickyAuth': false, + 'sensitiveTransaction': true, + 'biometricOnly': false, + }..addAll(const IOSAuthMessages().args)), + ], + ); + }); + + test('authenticate with no sensitive transaction.', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android')); + await localAuthentication.authenticate( + localizedReason: 'Insecure', + sensitiveTransaction: false, + useErrorDialogs: false, + ); + expect( + log, + [ + isMethodCall('authenticate', + arguments: { + 'localizedReason': 'Insecure', + 'useErrorDialogs': false, + 'stickyAuth': false, + 'sensitiveTransaction': false, + 'biometricOnly': false, + }..addAll(const AndroidAuthMessages().args)), + ], + ); + }); }); }); } From e113013247215446dd5c3a13cb7d69c852f1d330 Mon Sep 17 00:00:00 2001 From: Mehmet Fidanboylu Date: Fri, 15 Jan 2021 07:46:59 -0800 Subject: [PATCH 106/924] [google_sign_in] Migrate to nnbd (#3329) --- .../google_sign_in/CHANGELOG.md | 4 ++ .../integration_test/google_sign_in_test.dart | 2 + .../google_sign_in/lib/google_sign_in.dart | 56 +++++++++---------- .../google_sign_in/lib/src/common.dart | 4 +- .../google_sign_in/lib/testing.dart | 18 +++--- .../google_sign_in/lib/widgets.dart | 29 +++------- .../google_sign_in/pubspec.yaml | 18 ++---- .../test/google_sign_in_test.dart | 36 ++++++------ .../test_driver/integration_test.dart | 2 + .../CHANGELOG.md | 4 ++ .../google_sign_in_platform_interface.dart | 21 +++---- .../src/method_channel_google_sign_in.dart | 35 ++++++------ .../lib/src/types.dart | 28 ++++++---- .../lib/src/utils.dart | 9 +-- .../pubspec.yaml | 14 ++--- ...oogle_sign_in_platform_interface_test.dart | 12 ++-- .../method_channel_google_sign_in_test.dart | 9 ++- 17 files changed, 150 insertions(+), 151 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md index 7f5b4f2bdd17..d87df7466312 100644 --- a/packages/google_sign_in/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.0.0-nullsafety + +* Migrate to nnbd. + ## 4.5.9 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart index 7b2b8d800778..a900bfbfdc2e 100644 --- a/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart @@ -1,3 +1,5 @@ +// @dart = 2.9 + import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:google_sign_in/google_sign_in.dart'; diff --git a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart index 0f1f15bbb8c4..1317eb91ecfb 100644 --- a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart @@ -22,13 +22,13 @@ class GoogleSignInAuthentication { final GoogleSignInTokenData _data; /// An OpenID Connect ID token that identifies the user. - String get idToken => _data.idToken; + String? get idToken => _data.idToken; /// The OAuth2 access token to access Google services. - String get accessToken => _data.accessToken; + String? get accessToken => _data.accessToken; /// Server auth code used to access Google Login - String get serverAuthCode => _data.serverAuthCode; + String? get serverAuthCode => _data.serverAuthCode; @override String toString() => 'GoogleSignInAuthentication:$_data'; @@ -57,7 +57,7 @@ class GoogleSignInAccount implements GoogleIdentity { static const String kUserRecoverableAuthError = 'user_recoverable_auth'; @override - final String displayName; + final String? displayName; @override final String email; @@ -66,9 +66,9 @@ class GoogleSignInAccount implements GoogleIdentity { final String id; @override - final String photoUrl; + final String? photoUrl; - final String _idToken; + final String? _idToken; final GoogleSignIn _googleSignIn; /// Retrieve [GoogleSignInAuthentication] for this account. @@ -105,7 +105,7 @@ class GoogleSignInAccount implements GoogleIdentity { /// /// See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization. Future> get authHeaders async { - final String token = (await authentication).accessToken; + final String? token = (await authentication).accessToken; return { "Authorization": "Bearer $token", "X-Goog-AuthUser": "0", @@ -117,7 +117,7 @@ class GoogleSignInAccount implements GoogleIdentity { /// If client runs into 401 errors using a token, it is expected to call /// this method and grab `authHeaders` once again. Future clearAuthCache() async { - final String token = (await authentication).accessToken; + final String token = (await authentication).accessToken!; await GoogleSignInPlatform.instance.clearAuthCache(token: token); } @@ -174,7 +174,7 @@ class GoogleSignIn { /// Factory for creating default sign in user experience. factory GoogleSignIn.standard({ List scopes = const [], - String hostedDomain, + String? hostedDomain, }) { return GoogleSignIn( signInOption: SignInOption.standard, @@ -212,22 +212,22 @@ class GoogleSignIn { final List scopes; /// Domain to restrict sign-in to. - final String hostedDomain; + final String? hostedDomain; /// Client ID being used to connect to google sign-in. Only supported on web. - final String clientId; + final String? clientId; - StreamController _currentUserController = - StreamController.broadcast(); + StreamController _currentUserController = + StreamController.broadcast(); /// Subscribe to this stream to be notified when the current user changes. - Stream get onCurrentUserChanged => + Stream get onCurrentUserChanged => _currentUserController.stream; // Future that completes when we've finished calling `init` on the native side - Future _initialization; + Future? _initialization; - Future _callMethod(Function method) async { + Future _callMethod(Function method) async { await _ensureInitialized(); final dynamic response = await method(); @@ -237,7 +237,7 @@ class GoogleSignIn { : null); } - GoogleSignInAccount _setCurrentUser(GoogleSignInAccount currentUser) { + GoogleSignInAccount? _setCurrentUser(GoogleSignInAccount? currentUser) { if (currentUser != _currentUser) { _currentUser = currentUser; _currentUserController.add(_currentUser); @@ -258,7 +258,7 @@ class GoogleSignIn { } /// The most recently scheduled method call. - Future _lastMethodCall; + Future? _lastMethodCall; /// Returns a [Future] that completes with a success after [future], whether /// it completed with a value or an error. @@ -279,15 +279,15 @@ class GoogleSignIn { /// The optional, named parameter [canSkipCall] lets the plugin know that the /// method call may be skipped, if there's already [_currentUser] information. /// This is used from the [signIn] and [signInSilently] methods. - Future _addMethodCall( + Future _addMethodCall( Function method, { bool canSkipCall = false, }) async { - Future response; + Future response; if (_lastMethodCall == null) { response = _callMethod(method); } else { - response = _lastMethodCall.then((_) { + response = _lastMethodCall!.then((_) { // If after the last completed call `currentUser` is not `null` and requested // method can be skipped (`canSkipCall`), re-use the same authenticated user // instead of making extra call to the native side. @@ -303,8 +303,8 @@ class GoogleSignIn { } /// The currently signed in account, or null if the user is signed out. - GoogleSignInAccount get currentUser => _currentUser; - GoogleSignInAccount _currentUser; + GoogleSignInAccount? get currentUser => _currentUser; + GoogleSignInAccount? _currentUser; /// Attempts to sign in a previously authenticated user without interaction. /// @@ -323,7 +323,7 @@ class GoogleSignIn { /// one of [kSignInRequiredError] (when there is no authenticated user) , /// [kNetworkError] (when a network error occurred) or [kSignInFailedError] /// (when an unknown error occurred). - Future signInSilently({ + Future signInSilently({ bool suppressErrors = true, }) async { try { @@ -354,8 +354,8 @@ class GoogleSignIn { /// a Future which resolves to the same user instance. /// /// Re-authentication can be triggered only after [signOut] or [disconnect]. - Future signIn() { - final Future result = + Future signIn() { + final Future result = _addMethodCall(GoogleSignInPlatform.instance.signIn, canSkipCall: true); bool isCanceled(dynamic error) => error is PlatformException && error.code == kSignInCanceledError; @@ -363,12 +363,12 @@ class GoogleSignIn { } /// Marks current user as being in the signed out state. - Future signOut() => + Future signOut() => _addMethodCall(GoogleSignInPlatform.instance.signOut); /// Disconnects the current user from the app and revokes previous /// authentication. - Future disconnect() => + Future disconnect() => _addMethodCall(GoogleSignInPlatform.instance.disconnect); /// Requests the user grants additional Oauth [scopes]. diff --git a/packages/google_sign_in/google_sign_in/lib/src/common.dart b/packages/google_sign_in/google_sign_in/lib/src/common.dart index 14bed4fe114a..60c74ab4c6d5 100644 --- a/packages/google_sign_in/google_sign_in/lib/src/common.dart +++ b/packages/google_sign_in/google_sign_in/lib/src/common.dart @@ -28,10 +28,10 @@ abstract class GoogleIdentity { /// The display name of the signed in user. /// /// Not guaranteed to be present for all users, even when configured. - String get displayName; + String? get displayName; /// The photo url of the signed in user if the user has a profile picture. /// /// Not guaranteed to be present for all users, even when configured. - String get photoUrl; + String? get photoUrl; } diff --git a/packages/google_sign_in/google_sign_in/lib/testing.dart b/packages/google_sign_in/google_sign_in/lib/testing.dart index 8d62ff463ca6..ed0ca4f2de7c 100644 --- a/packages/google_sign_in/google_sign_in/lib/testing.dart +++ b/packages/google_sign_in/google_sign_in/lib/testing.dart @@ -32,7 +32,7 @@ class FakeSignInBackend { /// This does not represent the signed-in user, but rather an object that will /// be returned when [GoogleSignIn.signIn] or [GoogleSignIn.signInSilently] is /// called. - FakeUser user; + late FakeUser user; /// Handles method calls that would normally be sent to the native backend. /// Returns with the expected values based on the current [user]. @@ -42,7 +42,7 @@ class FakeSignInBackend { // do nothing return null; case 'getTokens': - return { + return { 'idToken': user.idToken, 'accessToken': user.accessToken, }; @@ -72,24 +72,24 @@ class FakeUser { }); /// Will be converted into [GoogleSignInUserData.id]. - final String id; + final String? id; /// Will be converted into [GoogleSignInUserData.email]. - final String email; + final String? email; /// Will be converted into [GoogleSignInUserData.displayName]. - final String displayName; + final String? displayName; /// Will be converted into [GoogleSignInUserData.photoUrl]. - final String photoUrl; + final String? photoUrl; /// Will be converted into [GoogleSignInTokenData.idToken]. - final String idToken; + final String? idToken; /// Will be converted into [GoogleSignInTokenData.accessToken]. - final String accessToken; + final String? accessToken; - Map get _asMap => { + Map get _asMap => { 'id': id, 'email': email, 'displayName': displayName, diff --git a/packages/google_sign_in/google_sign_in/lib/widgets.dart b/packages/google_sign_in/google_sign_in/lib/widgets.dart index 3375628f47b5..c9682930b089 100644 --- a/packages/google_sign_in/google_sign_in/lib/widgets.dart +++ b/packages/google_sign_in/google_sign_in/lib/widgets.dart @@ -4,7 +4,6 @@ import 'dart:typed_data'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'src/common.dart'; @@ -23,7 +22,7 @@ class GoogleUserCircleAvatar extends StatelessWidget { /// in place of a profile photo, or a default profile photo if the user's /// identity does not specify a `displayName`. const GoogleUserCircleAvatar({ - @required this.identity, + required this.identity, this.placeholderPhotoUrl, this.foregroundColor, this.backgroundColor, @@ -42,13 +41,13 @@ class GoogleUserCircleAvatar extends StatelessWidget { /// The color of the text to be displayed if photo is not available. /// /// If a foreground color is not specified, the theme's text color is used. - final Color foregroundColor; + final Color? foregroundColor; /// The color with which to fill the circle. Changing the background color /// will cause the avatar to animate to the new color. /// /// If a background color is not specified, the theme's primary color is used. - final Color backgroundColor; + final Color? backgroundColor; /// The URL of a photo to use if the user's [identity] does not specify a /// `photoUrl`. @@ -57,7 +56,7 @@ class GoogleUserCircleAvatar extends StatelessWidget { /// then this widget will attempt to display the user's first initial as /// determined from the identity's [displayName] field. If that is `null` a /// default (generic) Google profile photo will be displayed. - final String placeholderPhotoUrl; + final String? placeholderPhotoUrl; @override Widget build(BuildContext context) { @@ -68,38 +67,26 @@ class GoogleUserCircleAvatar extends StatelessWidget { ); } - /// Adds correct sizing information to [photoUrl]. - /// - /// Falls back to the default profile photo if [photoUrl] is [null]. - static String _sizedProfileImageUrl(String photoUrl, double size) { - if (photoUrl == null) { - // If the user has no profile photo and no display name, fall back to - // the default profile photo as a last resort. - return 'https://lh3.googleusercontent.com/a/default-user=s${size.round()}-c'; - } - return fife.addSizeDirectiveToUrl(photoUrl, size); - } - Widget _buildClippedImage(BuildContext context, BoxConstraints constraints) { assert(constraints.maxWidth == constraints.maxHeight); // Placeholder to use when there is no photo URL, and while the photo is // loading. Uses the first character of the display name (if it has one), // or the first letter of the email address if it does not. - final List placeholderCharSources = [ + final List placeholderCharSources = [ identity.displayName, identity.email, '-', ]; final String placeholderChar = placeholderCharSources - .firstWhere((String str) => str != null && str.trimLeft().isNotEmpty) + .firstWhere((String? str) => str != null && str.trimLeft().isNotEmpty)! .trimLeft()[0] .toUpperCase(); final Widget placeholder = Center( child: Text(placeholderChar, textAlign: TextAlign.center), ); - final String photoUrl = identity.photoUrl ?? placeholderPhotoUrl; + final String? photoUrl = identity.photoUrl ?? placeholderPhotoUrl; if (photoUrl == null) { return placeholder; } @@ -107,7 +94,7 @@ class GoogleUserCircleAvatar extends StatelessWidget { // Add a sizing directive to the profile photo URL. final double size = MediaQuery.of(context).devicePixelRatio * constraints.maxWidth; - final String sizedPhotoUrl = _sizedProfileImageUrl(photoUrl, size); + final String sizedPhotoUrl = fife.addSizeDirectiveToUrl(photoUrl, size); // Fade the photo in over the top of the placeholder. return SizedBox( diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index 6e0366c790bf..2a2506a38357 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in -version: 4.5.9 +version: 5.0.0-nullsafety flutter: plugin: @@ -16,16 +16,10 @@ flutter: default_package: google_sign_in_web dependencies: - google_sign_in_platform_interface: ^1.1.1 + google_sign_in_platform_interface: ^2.0.0-nullsafety flutter: sdk: flutter - meta: ^1.0.4 - # The design on https://flutter.dev/go/federated-plugins was to leave - # this constraint as "any". We cannot do it right now as it fails pub publish - # validation, so we set a ^ constraint. - # TODO(amirh): Revisit this (either update this part in the design or the pub tool). - # https://github.com/flutter/flutter/issues/46264 - google_sign_in_web: ^0.9.1 + meta: ^1.3.0-nullsafety.6 dev_dependencies: http: ^0.12.0 @@ -33,10 +27,10 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.1 integration_test: path: ../../integration_test environment: - sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4" + sdk: ">=2.12.0-0 <3.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart index 7305800296f9..2a8d65e32ffd 100755 --- a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; import 'package:flutter/services.dart'; @@ -43,8 +41,8 @@ void main() { }; final List log = []; - Map responses; - GoogleSignIn googleSignIn; + late Map responses; + late GoogleSignIn googleSignIn; setUp(() { responses = Map.from(kDefaultResponses); @@ -173,16 +171,16 @@ void main() { }); test('concurrent calls of the same method trigger sign in once', () async { - final List> futures = - >[ + final List> futures = + >[ googleSignIn.signInSilently(), googleSignIn.signInSilently(), ]; expect(futures.first, isNot(futures.last), reason: 'Must return new Future'); - final List users = await Future.wait(futures); + final List users = await Future.wait(futures); expect(googleSignIn.currentUser, isNotNull); - expect(users, [ + expect(users, [ googleSignIn.currentUser, googleSignIn.currentUser ]); @@ -218,13 +216,13 @@ void main() { }); test('concurrent calls of different signIn methods', () async { - final List> futures = - >[ + final List> futures = + >[ googleSignIn.signInSilently(), googleSignIn.signIn(), ]; expect(futures.first, isNot(futures.last)); - final List users = await Future.wait(futures); + final List users = await Future.wait(futures); expect( log, [ @@ -248,8 +246,8 @@ void main() { }); test('signOut/disconnect methods always trigger native calls', () async { - final List> futures = - >[ + final List> futures = + >[ googleSignIn.signOut(), googleSignIn.signOut(), googleSignIn.disconnect(), @@ -273,8 +271,8 @@ void main() { }); test('queue of many concurrent calls', () async { - final List> futures = - >[ + final List> futures = + >[ googleSignIn.signInSilently(), googleSignIn.signOut(), googleSignIn.signIn(), @@ -368,7 +366,7 @@ void main() { await googleSignIn.signIn(); log.clear(); - final GoogleSignInAccount user = googleSignIn.currentUser; + final GoogleSignInAccount user = googleSignIn.currentUser!; final GoogleSignInAuthentication auth = await user.authentication; expect(auth.accessToken, '456'); @@ -415,11 +413,11 @@ void main() { photoUrl: "https://lh5.googleusercontent.com/photo.jpg", ); - GoogleSignIn googleSignIn; + late GoogleSignIn googleSignIn; setUp(() { final MethodChannelGoogleSignIn platformInstance = - GoogleSignInPlatform.instance; + GoogleSignInPlatform.instance as MethodChannelGoogleSignIn; platformInstance.channel.setMockMethodCallHandler( (FakeSignInBackend()..user = kUserData).handleMethodCall); googleSignIn = GoogleSignIn(); @@ -432,7 +430,7 @@ void main() { test('can sign in and sign out', () async { await googleSignIn.signIn(); - final GoogleSignInAccount user = googleSignIn.currentUser; + final GoogleSignInAccount user = googleSignIn.currentUser!; expect(user.displayName, equals(kUserData.displayName)); expect(user.email, equals(kUserData.email)); diff --git a/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart b/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart index f07dba382187..4a27ac2f986b 100644 --- a/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart +++ b/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md b/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md index e69e912195bf..f01d03080af7 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migration to nnbd. + ## 1.1.3 * Update Flutter SDK constraint. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart index 966e93551086..3499558f9114 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import 'dart:async'; -import 'package:meta/meta.dart' show required, visibleForTesting; +import 'package:meta/meta.dart' show visibleForTesting; import 'src/method_channel_google_sign_in.dart'; import 'src/types.dart'; @@ -78,27 +78,28 @@ abstract class GoogleSignInPlatform { /// /// See: /// https://developers.google.com/identity/sign-in/web/reference#gapiauth2initparams - Future init( - {@required String hostedDomain, - List scopes, - SignInOption signInOption, - String clientId}) async { + Future init({ + List scopes = const [], + SignInOption signInOption = SignInOption.standard, + String? hostedDomain, + String? clientId, + }) async { throw UnimplementedError('init() has not been implemented.'); } /// Attempts to reuse pre-existing credentials to sign in again, without user interaction. - Future signInSilently() async { + Future signInSilently() async { throw UnimplementedError('signInSilently() has not been implemented.'); } /// Signs in the user with the options specified to [init]. - Future signIn() async { + Future signIn() async { throw UnimplementedError('signIn() has not been implemented.'); } /// Returns the Tokens used to authenticate other API calls. Future getTokens( - {@required String email, bool shouldRecoverAuth}) async { + {required String email, bool? shouldRecoverAuth}) async { throw UnimplementedError('getTokens() has not been implemented.'); } @@ -118,7 +119,7 @@ abstract class GoogleSignInPlatform { } /// Clears any cached information that the plugin may be holding on to. - Future clearAuthCache({@required String token}) async { + Future clearAuthCache({required String token}) async { throw UnimplementedError('clearAuthCache() has not been implemented.'); } diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart index 4d2a34fe0fe7..b36676e2376d 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart @@ -5,7 +5,7 @@ import 'dart:async'; import 'package:flutter/services.dart'; -import 'package:meta/meta.dart' show required, visibleForTesting; +import 'package:meta/meta.dart' show visibleForTesting; import '../google_sign_in_platform_interface.dart'; import 'types.dart'; @@ -20,11 +20,12 @@ class MethodChannelGoogleSignIn extends GoogleSignInPlatform { const MethodChannel('plugins.flutter.io/google_sign_in'); @override - Future init( - {@required String hostedDomain, - List scopes = const [], - SignInOption signInOption = SignInOption.standard, - String clientId}) { + Future init({ + List scopes = const [], + SignInOption signInOption = SignInOption.standard, + String? hostedDomain, + String? clientId, + }) { return channel.invokeMethod('init', { 'signInOption': signInOption.toString(), 'scopes': scopes, @@ -33,14 +34,14 @@ class MethodChannelGoogleSignIn extends GoogleSignInPlatform { } @override - Future signInSilently() { + Future signInSilently() { return channel .invokeMapMethod('signInSilently') .then(getUserDataFromMap); } @override - Future signIn() { + Future signIn() { return channel .invokeMapMethod('signIn') .then(getUserDataFromMap); @@ -48,12 +49,12 @@ class MethodChannelGoogleSignIn extends GoogleSignInPlatform { @override Future getTokens( - {String email, bool shouldRecoverAuth = true}) { + {required String email, bool? shouldRecoverAuth = true}) { return channel .invokeMapMethod('getTokens', { 'email': email, 'shouldRecoverAuth': shouldRecoverAuth, - }).then(getTokenDataFromMap); + }).then((result) => getTokenDataFromMap(result!)); } @override @@ -67,23 +68,23 @@ class MethodChannelGoogleSignIn extends GoogleSignInPlatform { } @override - Future isSignedIn() { - return channel.invokeMethod('isSignedIn'); + Future isSignedIn() async { + return (await channel.invokeMethod('isSignedIn'))!; } @override - Future clearAuthCache({String token}) { + Future clearAuthCache({String? token}) { return channel.invokeMethod( 'clearAuthCache', - {'token': token}, + {'token': token}, ); } @override - Future requestScopes(List scopes) { - return channel.invokeMethod( + Future requestScopes(List scopes) async { + return (await channel.invokeMethod( 'requestScopes', >{'scopes': scopes}, - ); + ))!; } } diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart index c60402200bdd..a4c5906723dd 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart @@ -24,15 +24,19 @@ enum SignInOption { /// Holds information about the signed in user. class GoogleSignInUserData { - /// Uses the given data to construct an instance. Any of these parameters - /// could be null. - GoogleSignInUserData( - {this.displayName, this.email, this.id, this.photoUrl, this.idToken}); + /// Uses the given data to construct an instance. + GoogleSignInUserData({ + required this.email, + required this.id, + this.displayName, + this.photoUrl, + this.idToken, + }); /// The display name of the signed in user. /// /// Not guaranteed to be present for all users, even when configured. - String displayName; + String? displayName; /// The email address of the signed in user. /// @@ -56,15 +60,15 @@ class GoogleSignInUserData { /// The photo url of the signed in user if the user has a profile picture. /// /// Not guaranteed to be present for all users, even when configured. - String photoUrl; + String? photoUrl; /// A token that can be sent to your own server to verify the authentication /// data. - String idToken; + String? idToken; @override int get hashCode => - hashObjects([displayName, email, id, photoUrl, idToken]); + hashObjects([displayName, email, id, photoUrl, idToken]); @override bool operator ==(dynamic other) { @@ -81,7 +85,7 @@ class GoogleSignInUserData { /// Holds authentication data after sign in. class GoogleSignInTokenData { - /// Either or both parameters may be null. + /// Build `GoogleSignInTokenData`. GoogleSignInTokenData({ this.idToken, this.accessToken, @@ -89,13 +93,13 @@ class GoogleSignInTokenData { }); /// An OpenID Connect ID token for the authenticated user. - String idToken; + String? idToken; /// The OAuth2 access token used to access Google services. - String accessToken; + String? accessToken; /// Server auth code used to access Google Login - String serverAuthCode; + String? serverAuthCode; @override int get hashCode => hash3(idToken, accessToken, serverAuthCode); diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart index 1ae828604af6..f6236d4ca12e 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart @@ -5,23 +5,20 @@ import '../google_sign_in_platform_interface.dart'; /// Converts user data coming from native code into the proper platform interface type. -GoogleSignInUserData getUserDataFromMap(Map data) { +GoogleSignInUserData? getUserDataFromMap(Map? data) { if (data == null) { return null; } return GoogleSignInUserData( + email: data['email']!, + id: data['id']!, displayName: data['displayName'], - email: data['email'], - id: data['id'], photoUrl: data['photoUrl'], idToken: data['idToken']); } /// Converts token data coming from native code into the proper platform interface type. GoogleSignInTokenData getTokenDataFromMap(Map data) { - if (data == null) { - return null; - } return GoogleSignInTokenData( idToken: data['idToken'], accessToken: data['accessToken'], diff --git a/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml b/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml index 8edeba0072a8..4480debc9ba3 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml @@ -3,20 +3,20 @@ description: A common platform interface for the google_sign_in plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in_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.3 +version: 2.0.0-nullsafety dependencies: flutter: sdk: flutter - meta: ^1.0.5 - quiver: ">=2.0.0 <3.0.0" + meta: ^1.3.0-nullsafety.6 + quiver: ^3.0.0-nullsafety.2 dev_dependencies: flutter_test: sdk: flutter - mockito: ^4.1.1 - pedantic: ^1.8.0 + mockito: ^5.0.0-nullsafety.1 + pedantic: ^1.10.0-nullsafety.1 environment: - sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0" + sdk: ">=2.12.0-0 <3.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart b/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart index f411b8992821..e2565d799e1f 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart @@ -15,7 +15,7 @@ void main() { test('Cannot be implemented with `implements`', () { expect(() { GoogleSignInPlatform.instance = ImplementsGoogleSignInPlatform(); - }, throwsAssertionError); + }, throwsA(isA())); }); test('Can be extended', () { @@ -23,14 +23,16 @@ void main() { }); test('Can be mocked with `implements`', () { - final ImplementsGoogleSignInPlatform mock = - ImplementsGoogleSignInPlatform(); - when(mock.isMock).thenReturn(true); - GoogleSignInPlatform.instance = mock; + GoogleSignInPlatform.instance = ImplementsWithIsMock(); }); }); } +class ImplementsWithIsMock extends Mock implements GoogleSignInPlatform { + @override + bool get isMock => true; +} + class ImplementsGoogleSignInPlatform extends Mock implements GoogleSignInPlatform {} diff --git a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart index 5ac34ade1b8d..325f0c10a6ab 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart @@ -29,10 +29,12 @@ const Map kDefaultResponses = { 'disconnect': null, 'isSignedIn': true, 'getTokens': kTokenData, + 'requestScopes': true, }; -final GoogleSignInUserData kUser = getUserDataFromMap(kUserData); -final GoogleSignInTokenData kToken = getTokenDataFromMap(kTokenData); +final GoogleSignInUserData? kUser = getUserDataFromMap(kUserData); +final GoogleSignInTokenData? kToken = + getTokenDataFromMap(kTokenData as Map); void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -42,7 +44,8 @@ void main() { final MethodChannel channel = googleSignIn.channel; final List log = []; - Map responses; // Some tests mutate some kDefaultResponses + late Map + responses; // Some tests mutate some kDefaultResponses setUp(() { responses = Map.from(kDefaultResponses); From d950dda867539370af8b79d9b921f569cb074390 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Fri, 15 Jan 2021 15:49:23 -0800 Subject: [PATCH 107/924] [script] Update build_all_plugins_app to exclude some plugins in `master`. (#3432) --- script/build_all_plugins_app.sh | 4 ++++ script/nnbd_plugins.sh | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index ca97c05f8ee4..72390c213da9 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -56,6 +56,10 @@ ALL_EXCLUDED=($EXCLUDED) if [ "$CHANNEL" == "stable" ]; then ALL_EXCLUDED=("$EXCLUDED,$EXCLUDED_PLUGINS_FROM_STABLE") fi +# Exclude non-nnbd plugins from master. +if [ "$CHANNEL" != "stable" ]; then + ALL_EXCLUDED=("$EXCLUDED,$EXCLUDED_PLUGINS_FROM_MASTER") +fi echo "Excluding the following plugins: $ALL_EXCLUDED" diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 7bc5ac35a3a5..b2ca25bf6836 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -21,4 +21,22 @@ readonly NNBD_PLUGINS_LIST=( "webview_flutter" ) +# This list contains the list of plugins that have *not* been +# migrated to nnbd, and conflict with those that have when +# building the all plugins app. This list should be kept empty. + +readonly NON_NNBD_PLUGINS_LIST=( + # "android_alarm_manager" + "camera" + # "file_selector" + # "google_maps_flutter" + # "image_picker" + # "in_app_purchase" + # "quick_actions" + # "sensors" + # "shared_preferences" + # "wifi_info_flutter" +) + export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}") +export EXCLUDED_PLUGINS_FROM_MASTER=$(IFS=, ; echo "${NON_NNBD_PLUGINS_LIST[*]}") From 6ee63e8802d28ac1967b07332d413657529e974e Mon Sep 17 00:00:00 2001 From: Anton Borries Date: Sat, 16 Jan 2021 01:59:57 +0100 Subject: [PATCH 108/924] [google_maps_flutter_web] Support for Holes in Polygons (#3412) --- AUTHORS | 1 + .../google_maps_flutter_web/CHANGELOG.md | 5 ++ .../lib/src/convert.dart | 13 ++++- .../google_maps_flutter_web/pubspec.yaml | 4 +- .../google_maps_controller_integration.dart | 19 +++++++ .../test/test_driver/shapes_integration.dart | 55 +++++++++++++++++++ .../test/web/index.html | 2 +- 7 files changed, 94 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 09bab9d34d02..dabc20108f28 100644 --- a/AUTHORS +++ b/AUTHORS @@ -60,3 +60,4 @@ Eitan Schwartz Chris Rutkowski Juan Alvarez Aleksandr Yurkovskiy +Anton Borries \ No newline at end of file diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 2d03ab254bc0..940419a215fc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.1.0+10 + +* Update `package:google_maps_flutter_platform_interface` to `^1.1.0`. +* Add support for Polygon Holes. + ## 0.1.0+9 * Update Flutter SDK constraint. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index 551c1572b1bb..c9fd1cd55d3b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -366,6 +366,11 @@ Set _rawOptionsToInitialPolygons(Map rawOptions) { points: rawPolygon['points'] ?.map((rawPoint) => LatLng.fromJson(rawPoint)) ?.toList(), + holes: rawPolygon['holes'] + ?.map>((List hole) => hole + ?.map((rawPoint) => LatLng.fromJson(rawPoint)) + ?.toList()) + ?.toList(), ); }) ?? []); @@ -473,9 +478,13 @@ gmaps.CircleOptions _circleOptionsFromCircle(Circle circle) { gmaps.PolygonOptions _polygonOptionsFromPolygon( gmaps.GMap googleMap, Polygon polygon) { - List paths = []; + List path = []; polygon.points.forEach((point) { - paths.add(_latLngToGmLatLng(point)); + path.add(_latLngToGmLatLng(point)); + }); + List> paths = [path]; + polygon.holes?.forEach((hole) { + paths.add(hole.map((point) => _latLngToGmLatLng(point)).toList()); }); return gmaps.PolygonOptions() ..paths = paths diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index b41e24c25357..bd879553a06d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.1.0+9 +version: 0.1.0+10 flutter: plugin: @@ -16,7 +16,7 @@ dependencies: flutter_web_plugins: sdk: flutter meta: ^1.1.7 - google_maps_flutter_platform_interface: ^1.0.5 + google_maps_flutter_platform_interface: ^1.1.0 google_maps: ^3.4.5 stream_transform: ^1.2.0 sanitize_html: ^1.4.1 diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart index 70d4452e411f..302057f0ea57 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart @@ -166,6 +166,22 @@ void main() { [43.354762, -5.850824], ], }, + { + 'polygonId': 'polygon-2-with-holes', + 'points': [ + [43.355114, -5.851333], + [43.354797, -5.851860], + [43.354469, -5.851318], + [43.354762, -5.850824], + ], + 'holes': [ + [ + [41.354797, -6.851860], + [41.354469, -6.851318], + [41.354762, -6.850824], + ] + ] + }, ], 'polylinesToAdd': [ { @@ -202,6 +218,9 @@ void main() { expect(capturedMarkers.first.infoWindow.snippet, 'snippet for test'); expect(capturedMarkers.first.infoWindow.title, 'title for test'); expect(capturedPolygons.first.polygonId.value, 'polygon-1'); + expect(capturedPolygons.elementAt(1).polygonId.value, + 'polygon-2-with-holes'); + expect(capturedPolygons.elementAt(1).holes, isNot(null)); expect(capturedPolylines.first.polylineId.value, 'polyline-1'); }); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart index 0c92c6a924e7..4d5c2b17cc56 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart @@ -10,6 +10,8 @@ import 'dart:ui'; import 'package:integration_test/integration_test.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; +import 'package:google_maps/google_maps.dart' as gmaps; +import 'package:google_maps/google_maps_geometry.dart' as geometry; import 'package:flutter_test/flutter_test.dart'; // This value is used when comparing the results of @@ -190,6 +192,59 @@ void main() { expect(polygon.get('strokeColor'), '#c0ffee'); expect(polygon.get('strokeOpacity'), closeTo(1, _acceptableDelta)); }); + + testWidgets('Handle Polygons with holes', (WidgetTester tester) async { + final polygons = { + Polygon( + polygonId: PolygonId('BermudaTriangle'), + points: [ + LatLng(25.774, -80.19), + LatLng(18.466, -66.118), + LatLng(32.321, -64.757), + ], + holes: [ + [ + LatLng(28.745, -70.579), + LatLng(29.57, -67.514), + LatLng(27.339, -66.668), + ], + ], + ), + }; + + controller.addPolygons(polygons); + + expect(controller.polygons.length, 1); + expect(controller.polygons, contains(PolygonId('BermudaTriangle'))); + expect(controller.polygons, isNot(contains(PolygonId('66')))); + }); + + testWidgets('Polygon with hole has a hole', (WidgetTester tester) async { + final polygons = { + Polygon( + polygonId: PolygonId('BermudaTriangle'), + points: [ + LatLng(25.774, -80.19), + LatLng(18.466, -66.118), + LatLng(32.321, -64.757), + ], + holes: [ + [ + LatLng(28.745, -70.579), + LatLng(29.57, -67.514), + LatLng(27.339, -66.668), + ], + ], + ), + }; + + controller.addPolygons(polygons); + + final polygon = controller.polygons.values.first.polygon; + final pointInHole = gmaps.LatLng(28.632, -68.401); + + expect(geometry.poly.containsLocation(pointInHole, polygon), false); + }); }); group('PolylinesController', () { diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/web/index.html b/packages/google_maps_flutter/google_maps_flutter_web/test/web/index.html index 3b7e4edc3df1..03feba172d74 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/web/index.html +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/web/index.html @@ -5,7 +5,7 @@ Browser Tests - + From 5cff819332b13947c405cd6b8df306465df49829 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Fri, 15 Jan 2021 18:39:53 -0800 Subject: [PATCH 109/924] [google_sign_in, url_launcher] Document unendorsement of web. (#3436) Add some documentation to the CHANGELOGs to mention that null-safety is still not supported by web plugins, so they're being un-endorsed. --- packages/google_sign_in/google_sign_in/CHANGELOG.md | 5 +++++ packages/google_sign_in/google_sign_in/pubspec.yaml | 6 +++--- packages/url_launcher/url_launcher/CHANGELOG.md | 5 +++++ packages/url_launcher/url_launcher/pubspec.yaml | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md index d87df7466312..85c8cc491105 100644 --- a/packages/google_sign_in/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,6 +1,11 @@ +## 5.0.0-nullsafety.1 + +* Document that the web plugin is not endorsed in the `nullsafety` prerelease for now. + ## 5.0.0-nullsafety * Migrate to nnbd. +* **Breaking change**: web plugins aren't endorsed in null-safe plugins yet. ## 4.5.9 diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index 2a2506a38357..ca1fe8d829b8 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in -version: 5.0.0-nullsafety +version: 5.0.0-nullsafety.1 flutter: plugin: @@ -12,8 +12,8 @@ flutter: pluginClass: GoogleSignInPlugin ios: pluginClass: FLTGoogleSignInPlugin - web: - default_package: google_sign_in_web + #web: + # default_package: google_sign_in_web dependencies: google_sign_in_platform_interface: ^2.0.0-nullsafety diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 73852cdfea12..fb66bcd99c1f 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.0.0-nullsafety.5 + +* Document that the web plugin is not endorsed in the `nullsafety` prerelease for now. + ## 6.0.0-nullsafety.4 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. @@ -17,6 +21,7 @@ ## 6.0.0-nullsafety * Migrate to null safety. +* **Breaking change**: web plugins aren't endorsed in null-safe plugins yet. ## 5.7.13 diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 871c43ced733..2f9c38a22f36 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL on Android and iOS. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 6.0.0-nullsafety.4 +version: 6.0.0-nullsafety.5 flutter: plugin: From faa26ec364cd6d3c738d73526ea55a95b7f4ab1a Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Fri, 15 Jan 2021 19:14:03 -0800 Subject: [PATCH 110/924] [plugin_platform_interface] Use Mockito nnbd (#3437) --- packages/plugin_platform_interface/CHANGELOG.md | 4 ++++ .../lib/plugin_platform_interface.dart | 2 +- packages/plugin_platform_interface/pubspec.yaml | 4 ++-- .../test/plugin_platform_interface_test.dart | 2 -- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/plugin_platform_interface/CHANGELOG.md b/packages/plugin_platform_interface/CHANGELOG.md index 7df1834966dd..96533f01c10f 100644 --- a/packages/plugin_platform_interface/CHANGELOG.md +++ b/packages/plugin_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.0-nullsafety.2 + +* Use Mockito null safe. + ## 1.1.0-nullsafety.1 * Bump Dart SDK to support null safety. diff --git a/packages/plugin_platform_interface/lib/plugin_platform_interface.dart b/packages/plugin_platform_interface/lib/plugin_platform_interface.dart index cd87b04dc739..6e425a19a048 100644 --- a/packages/plugin_platform_interface/lib/plugin_platform_interface.dart +++ b/packages/plugin_platform_interface/lib/plugin_platform_interface.dart @@ -43,7 +43,7 @@ abstract class PlatformInterface { /// Pass a private, class-specific `const Object()` as the `token`. PlatformInterface({required Object token}) : _instanceToken = token; - final Object _instanceToken; + final Object? _instanceToken; /// Ensures that the platform instance has a token that matches the /// provided token and throws [AssertionError] if not. diff --git a/packages/plugin_platform_interface/pubspec.yaml b/packages/plugin_platform_interface/pubspec.yaml index 05fc918bf9b5..084e577dbf99 100644 --- a/packages/plugin_platform_interface/pubspec.yaml +++ b/packages/plugin_platform_interface/pubspec.yaml @@ -12,7 +12,7 @@ description: Reusable base class for Flutter plugin platform interfaces. # be done when absolutely necessary and after the ecosystem has already migrated to 1.X.Y version # that is forward compatible with 2.0.0 (ideally the ecosystem have migrated to depend on: # `plugin_platform_interface: >=1.X.Y <3.0.0`). -version: 1.1.0-nullsafety.1 +version: 1.1.0-nullsafety.2 repository: https://github.com/flutter/plugins/tree/master/packages/plugin_platform_interface @@ -23,6 +23,6 @@ dependencies: meta: ^1.3.0-nullsafety.3 dev_dependencies: - mockito: ^4.1.1 + mockito: ^5.0.0-nullsafety.2 test: ^1.10.0-nullsafety.1 pedantic: ^1.10.0-nullsafety.1 diff --git a/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart b/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart index b07dd4dcede1..0488c20f3efb 100644 --- a/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart +++ b/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(egarciad): Remove once Mockito is migrated to null safety. -// @dart = 2.9 import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; From 172338d02b177353bf517e5826cf6a25b5f0d887 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 19 Jan 2021 10:59:04 -0800 Subject: [PATCH 111/924] combine release messages and versions (#3435) --- packages/camera/camera/CHANGELOG.md | 47 +++++++++-------------------- packages/camera/camera/pubspec.yaml | 2 +- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 66398996e053..55145ffc82e7 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,38 +1,19 @@ -## 0.7.0+5 - -* Fixes crash when taking a picture on iOS devices without flash. - -## 0.7.0+4 - -* Make sure the configured zoom scale is copied over to the final capture builder on Android. Fixes the issue where the preview is zoomed but the final picture is not. - -## 0.7.0+3 - -* Fixes crash with using inner camera on some Android devices. - -## 0.7.0+2 - -* Improved error feedback by differentiating between uninitialized and disposed camera controllers. - -## 0.7.0+1 - -* Fixes picture captures causing a crash on some Huawei devices. - ## 0.7.0 -* Added support for capture orientation locking on Android and iOS. -* Fixed camera preview not rotating correctly on Android and iOS. -* Fixed camera preview sometimes appearing stretched on Android and iOS. -* Fixed videos & photos saving with the incorrect rotation on iOS. -* BREAKING CHANGE: `CameraValue.aspectRatio` now returns `width / height` rather than `height / width`. - -## 0.6.6 - -* Adds auto focus support for Android and iOS implementations. - -## 0.6.5 - -* Adds ImageFormat selection for ImageStream and Video(iOS only). +* BREAKING CHANGE: `CameraValue.aspectRatio` now returns `width / height` rather than `height / width`. [(commit)](https://github.com/flutter/plugins/commit/100c7470d4066b1d0f8f7e4ec6d7c943e736f970) + * Added support for capture orientation locking on Android and iOS. + * Fixed camera preview not rotating correctly on Android and iOS. + * Fixed camera preview sometimes appearing stretched on Android and iOS. + * Fixed videos & photos saving with the incorrect rotation on iOS. +* New Features: + * Adds auto focus support for Android and iOS implementations. [(commmit)](https://github.com/flutter/plugins/commit/71a831790220f898bf8120c8a23840ac6e742db5) + * Adds ImageFormat selection for ImageStream and Video(iOS only). [(commit)](https://github.com/flutter/plugins/commit/da1b4638b750a5ff832d7be86a42831c42c6d6c0) +* Bug Fixes: + * Fixes crash when taking a picture on iOS devices without flash. [(commit)](https://github.com/flutter/plugins/commit/831344490984b1feec007afc9c8595d80b6c13f4) + * Make sure the configured zoom scale is copied over to the final capture builder on Android. Fixes the issue where the preview is zoomed but the final picture is not. [(commit)](https://github.com/flutter/plugins/commit/5916f55664e1772a4c3f0c02c5c71fc11e491b76) + * Fixes crash with using inner camera on some Android devices. [(commit)](https://github.com/flutter/plugins/commit/980b674cb4020c1927917426211a87e275346d5e) + * Improved error feedback by differentiating between uninitialized and disposed camera controllers. [(commit)](https://github.com/flutter/plugins/commit/d0b7109f6b00a0eda03506fed2c74cc123ffc6f3) + * Fixes picture captures causing a crash on some Huawei devices. [(commit)](https://github.com/flutter/plugins/commit/6d18db83f00f4861ffe485aba2d1f8aa08845ce6) ## 0.6.4+5 diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 406ff94ab1b9..b0ebb9c16361 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+5 +version: 0.7.0 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From bea4b14a6a6f41f503a0887b8e0504fa63778381 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 20 Jan 2021 07:16:20 -0800 Subject: [PATCH 112/924] Add Labeler Github Action (#3433) --- .github/labeler.yml | 86 ++++++++++++++++++++++++ .github/workflows/pull_request_label.yml | 20 ++++++ 2 files changed, 106 insertions(+) create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/pull_request_label.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000000..66dc68f1fbbe --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,86 @@ +'p: android_alarm_manager': + - packages/android_alarm_manager/**/* + +'p: android_intent': + - packages/android_intent/**/* + +'p: battery': + - packages/battery/**/* + +'p: camera': + - packages/camera/**/* + +'p: connectivity': + - packages/connectivity/**/* + +'p: cross_file': + - packages/cross_file/**/* + +'p: device_info': + - packages/device_info/**/* + +'p: e2e': + - packages/e2e/**/* + +'p: espresso': + - packages/espresso/**/* + +'p: file_selector': + - packages/file_selector/**/* + +'p: flutter_plugin_android_lifecycle': + - packages/flutter_plugin_android_lifecycle/**/* + +'p: google_maps_flutter': + - packages/google_maps_flutter/**/* + +'p: google_sign_in': + - packages/google_sign_in/**/* + +'p: image_picker': + - packages/image_picker/**/* + +'p: in_app_purchase': + - packages/in_app_purchase/**/* + +'p: integration_test': + - packages/integration_test/**/* + +'p: ios_platform_images': + - packages/ios_platform_images/**/* + +'p: local_auth': + - packages/local_auth/**/* + +'p: package_info': + - packages/package_info/**/* + +'p: path_provider': + - packages/path_provider/**/* + +'p: plugin_platform_interface': + - packages/plugin_platform_interface/**/* + +'p: quick_actions': + - packages/quick_actions/**/* + +'p: sensors': + - packages/sensors/**/* + +'p: share': + - packages/share/**/* + +'p: shared_preferences': + - packages/shared_preferences/**/* + +'p: url_launcher': + - packages/url_launcher/**/* + +'p: video_player': + - packages/video_player/**/* + +'p: webview_flutter': + - packages/webview_flutter/**/* + +'p: wifi_info_flutter': + - packages/wifi_info_flutter/**/* diff --git a/.github/workflows/pull_request_label.yml b/.github/workflows/pull_request_label.yml new file mode 100644 index 000000000000..5016184d6d11 --- /dev/null +++ b/.github/workflows/pull_request_label.yml @@ -0,0 +1,20 @@ +# This workflow applies labels to pull requests based on the +# paths that are modified in the pull request. +# +# Edit `.github/labeler.yml` to configure labels. +# +# For more information, see: https://github.com/actions/labeler + +name: Pull Request Labeler + +on: + - pull_request_target + +jobs: + label: + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@main + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + sync-labels: true From f3024731b090659edaa92d01416549c690f65678 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Wed, 20 Jan 2021 14:07:43 -0800 Subject: [PATCH 113/924] Windows nullsafety prep (#3442) shared_preferences_windows depends on path_provider_windows, and both use 'ffi'. This relaxes the 'ffi' version constraint on shared_preferences_windows to allow path_provider_windows to be migrated to null-safety (which requires updating to the nullsafe version of ffi). Part of https://github.com/flutter/flutter/issues/70229 --- .../shared_preferences_windows/CHANGELOG.md | 4 ++++ .../shared_preferences_windows/pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md index ecc790ef9bab..f6a199d52cb0 100644 --- a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2+2 + +* Relax 'ffi' version constraint. + ## 0.0.2+1 * Update Flutter SDK constraint. diff --git a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml index ce559d5ea3fb..2970b3ff053e 100644 --- a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: shared_preferences_windows description: Windows implementation of shared_preferences homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_windows -version: 0.0.2+1 +version: 0.0.2+2 flutter: plugin: @@ -18,7 +18,7 @@ dependencies: shared_preferences_platform_interface: ^1.0.0 flutter: sdk: flutter - ffi: ^0.1.3 + ffi: ">=0.1.3 < 0.3.0" file: ">=5.1.0 <7.0.0" meta: ^1.1.7 path: ^1.6.4 From 31923c805dbb03201fc9b3a97ca99c4c09838b1a Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 21 Jan 2021 08:54:52 -0800 Subject: [PATCH 114/924] [path_provider] Migrate path_provider_windows to nullsafety (#3410) Migrates path_provider_windows to null-safety. Part of flutter/flutter#70229 --- .../path_provider_windows/CHANGELOG.md | 4 ++ .../lib/src/path_provider_windows_real.dart | 36 ++++++++---------- .../lib/src/path_provider_windows_stub.dart | 2 +- .../path_provider_windows/pubspec.yaml | 16 ++++---- .../test/path_provider_windows_test.dart | 38 ++++++++++++------- 5 files changed, 54 insertions(+), 42 deletions(-) diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index ef1f5043a2b7..ea271681e63c 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0-nullsafety + +* Migrate to null safety + ## 0.0.4+4 * Update Flutter SDK constraint. diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart index e1063957879e..856249036b62 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart @@ -22,20 +22,19 @@ import 'folders.dart'; class VersionInfoQuerier { /// Returns the value for [key] in [versionInfo]s English strings section, or /// null if there is no such entry, or if versionInfo is null. - getStringValue(Pointer versionInfo, key) { + getStringValue(Pointer? versionInfo, key) { if (versionInfo == null) { return null; } const kEnUsLanguageCode = '040904e4'; final keyPath = TEXT('\\StringFileInfo\\$kEnUsLanguageCode\\$key'); final length = allocate(); - final valueAddress = allocate(); + final valueAddress = allocate>(); try { if (VerQueryValue(versionInfo, keyPath, valueAddress, length) == 0) { return null; } - return Pointer.fromAddress(valueAddress.value) - .unpackString(length.value); + return valueAddress.value.unpackString(length.value); } finally { free(keyPath); free(length); @@ -54,7 +53,7 @@ class PathProviderWindows extends PathProviderPlatform { /// This is typically the same as the TMP environment variable. @override - Future getTemporaryPath() async { + Future getTemporaryPath() async { final buffer = allocate(count: MAX_PATH + 1).cast(); String path; @@ -88,7 +87,7 @@ class PathProviderWindows extends PathProviderPlatform { } @override - Future getApplicationSupportPath() async { + Future getApplicationSupportPath() async { final appDataRoot = await getPath(WindowsKnownFolder.RoamingAppData); final directory = Directory( path.join(appDataRoot, _getApplicationSpecificSubdirectory())); @@ -105,25 +104,23 @@ class PathProviderWindows extends PathProviderPlatform { } @override - Future getApplicationDocumentsPath() => + Future getApplicationDocumentsPath() => getPath(WindowsKnownFolder.Documents); @override - Future getDownloadsPath() => getPath(WindowsKnownFolder.Downloads); + Future getDownloadsPath() => getPath(WindowsKnownFolder.Downloads); /// Retrieve any known folder from Windows. /// /// folderID is a GUID that represents a specific known folder ID, drawn from /// [WindowsKnownFolder]. Future getPath(String folderID) { - final pathPtrPtr = allocate(); - Pointer pathPtr; + final pathPtrPtr = allocate>(); + final Pointer knownFolderID = calloc()..setGUID(folderID); try { - GUID knownFolderID = GUID.fromString(folderID); - final hr = SHGetKnownFolderPath( - knownFolderID.addressOf, // ignore: deprecated_member_use + knownFolderID, KF_FLAG_DEFAULT, NULL, pathPtrPtr, @@ -135,12 +132,11 @@ class PathProviderWindows extends PathProviderPlatform { } } - pathPtr = Pointer.fromAddress(pathPtrPtr.value); - final path = pathPtr.unpackString(MAX_PATH); + final path = pathPtrPtr.value.unpackString(MAX_PATH); return Future.value(path); } finally { - CoTaskMemFree(pathPtr.cast()); free(pathPtrPtr); + free(knownFolderID); } } @@ -155,13 +151,13 @@ class PathProviderWindows extends PathProviderPlatform { /// - If the product name isn't there, it will use the exe's filename (without /// extension). String _getApplicationSpecificSubdirectory() { - String companyName; - String productName; + String? companyName; + String? productName; final Pointer moduleNameBuffer = allocate(count: MAX_PATH + 1).cast(); final Pointer unused = allocate(); - Pointer infoBuffer; + Pointer? infoBuffer; try { // Get the module name. final moduleNameLength = GetModuleFileName(0, moduleNameBuffer, MAX_PATH); @@ -207,7 +203,7 @@ class PathProviderWindows extends PathProviderPlatform { /// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions /// /// If after sanitizing the string is empty, returns null. - String _sanitizedDirectoryName(String rawString) { + String? _sanitizedDirectoryName(String? rawString) { if (rawString == null) { return null; } diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart index 11a946542f26..1a0e84e8f0da 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart @@ -19,7 +19,7 @@ class PathProviderWindows extends PathProviderPlatform { } /// Stub; see comment on VersionInfoQuerier. - VersionInfoQuerier versionInfoQuerier; + VersionInfoQuerier versionInfoQuerier = VersionInfoQuerier(); /// Match PathProviderWindows so that the analyzer won't report invalid /// overrides if tests provide fake PathProviderWindows implementations. diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index 62185f42e765..55c73c87ad19 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_windows -version: 0.0.4+4 +version: 0.1.0-nullsafety flutter: plugin: @@ -11,19 +11,19 @@ flutter: pluginClass: none dependencies: - path_provider_platform_interface: ^1.0.3 - meta: ^1.0.5 - path: ^1.6.4 + path_provider_platform_interface: ^2.0.0-nullsafety + meta: ^1.3.0-nullsafety.6 + path: ^1.8.0-nullsafety.3 flutter: sdk: flutter - ffi: ^0.1.3 - win32: ^1.7.1 + ffi: ^0.2.0-nullsafety.1 + win32: ^2.0.0-nullsafety.8 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.3 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.12.13+hotfix.4" diff --git a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart index 83ceea9cdf0c..989f3673ac63 100644 --- a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart +++ b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart @@ -13,7 +13,7 @@ class FakeVersionInfoQuerier implements VersionInfoQuerier { final Map responses; - getStringValue(Pointer versionInfo, key) => responses[key]; + getStringValue(Pointer? versionInfo, key) => responses[key]; } void main() { @@ -40,8 +40,11 @@ void main() { 'ProductName': 'Amazing App', }); final path = await pathProvider.getApplicationSupportPath(); - expect(path, endsWith(r'AppData\Roaming\A Company\Amazing App')); - expect(Directory(path).existsSync(), isTrue); + expect(path, isNotNull); + if (path != null) { + expect(path, endsWith(r'AppData\Roaming\A Company\Amazing App')); + expect(Directory(path).existsSync(), isTrue); + } }, skip: !Platform.isWindows); test('getApplicationSupportPath with missing company', () async { @@ -50,8 +53,11 @@ void main() { 'ProductName': 'Amazing App', }); final path = await pathProvider.getApplicationSupportPath(); - expect(path, endsWith(r'AppData\Roaming\Amazing App')); - expect(Directory(path).existsSync(), isTrue); + expect(path, isNotNull); + if (path != null) { + expect(path, endsWith(r'AppData\Roaming\Amazing App')); + expect(Directory(path).existsSync(), isTrue); + } }, skip: !Platform.isWindows); test('getApplicationSupportPath with problematic values', () async { @@ -61,12 +67,15 @@ void main() { 'ProductName': r'A"/Terrible\|App?*Name', }); final path = await pathProvider.getApplicationSupportPath(); - expect( - path, - endsWith(r'AppData\Roaming\' - r'A _Bad_ Company_ Name\' - r'A__Terrible__App__Name')); - expect(Directory(path).existsSync(), isTrue); + expect(path, isNotNull); + if (path != null) { + expect( + path, + endsWith(r'AppData\Roaming\' + r'A _Bad_ Company_ Name\' + r'A__Terrible__App__Name')); + expect(Directory(path).existsSync(), isTrue); + } }, skip: !Platform.isWindows); test('getApplicationSupportPath with a completely invalid company', () async { @@ -76,8 +85,11 @@ void main() { 'ProductName': r'Amazing App', }); final path = await pathProvider.getApplicationSupportPath(); - expect(path, endsWith(r'AppData\Roaming\Amazing App')); - expect(Directory(path).existsSync(), isTrue); + expect(path, isNotNull); + if (path != null) { + expect(path, endsWith(r'AppData\Roaming\Amazing App')); + expect(Directory(path).existsSync(), isTrue); + } }, skip: !Platform.isWindows); test('getApplicationSupportPath with very long app name', () async { From 07cf89a08b8800f3337049654bc5c1c19edd50d0 Mon Sep 17 00:00:00 2001 From: Sander Roest Date: Thu, 21 Jan 2021 19:09:06 +0100 Subject: [PATCH 115/924] [camera] Ensure that channel.invokeMethod runs on the main thread (#3444) --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../flutter/plugins/camera/DartMessenger.java | 20 +++++++++++++++++-- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 55145ffc82e7..cc734737182f 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+1 + +* Ensure communication from JAVA to Dart is done on the main UI thread. + ## 0.7.0 * BREAKING CHANGE: `CameraValue.aspectRatio` now returns `width / height` rather than `height / width`. [(commit)](https://github.com/flutter/plugins/commit/100c7470d4066b1d0f8f7e4ec6d7c943e736f970) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java index 5681f723ed80..3892452892d9 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java @@ -4,6 +4,8 @@ package io.flutter.plugins.camera; +import android.os.Handler; +import android.os.Looper; import android.text.TextUtils; import androidx.annotation.Nullable; import io.flutter.embedding.engine.systemchannels.PlatformChannel; @@ -104,7 +106,14 @@ void send(CameraEventType eventType, Map args) { if (cameraChannel == null) { return; } - cameraChannel.invokeMethod(eventType.method, args); + new Handler(Looper.getMainLooper()) + .post( + new Runnable() { + @Override + public void run() { + cameraChannel.invokeMethod(eventType.method, args); + } + }); } void send(DeviceEventType eventType) { @@ -115,6 +124,13 @@ void send(DeviceEventType eventType, Map args) { if (deviceChannel == null) { return; } - deviceChannel.invokeMethod(eventType.method, args); + new Handler(Looper.getMainLooper()) + .post( + new Runnable() { + @Override + public void run() { + deviceChannel.invokeMethod(eventType.method, args); + } + }); } } diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index b0ebb9c16361..b406ce5ba64f 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0 +version: 0.7.0+1 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From c923ef857c5fd13b1543ffa40013b1ca70d81dde Mon Sep 17 00:00:00 2001 From: Anton Borries Date: Thu, 21 Jan 2021 23:51:09 +0100 Subject: [PATCH 116/924] [google_maps_flutter_web] Reverse Hole winding when needed (#3440) The Web Version needs the holes in a polygon to be defined in the opposite direction to their parent polygon. This change automatically reverses the definition of a hole, when needed. In debug mode, it'll let the user know that the holes need to be wound differently. Co-authored-by: Anton Borries --- .../google_maps_flutter_web/CHANGELOG.md | 4 +++ .../lib/src/convert.dart | 30 ++++++++++++++++- .../google_maps_flutter_web/pubspec.yaml | 2 +- .../test/test_driver/shapes_integration.dart | 33 +++++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 940419a215fc..caa64ec73088 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.1 + +* Auto-reverse holes if they're the same direction as the polygon. [Issue](https://github.com/flutter/flutter/issues/74096). + ## 0.1.0+10 * Update `package:google_maps_flutter_platform_interface` to `^1.1.0`. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index c9fd1cd55d3b..95f481a9bdc5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -482,9 +482,23 @@ gmaps.PolygonOptions _polygonOptionsFromPolygon( polygon.points.forEach((point) { path.add(_latLngToGmLatLng(point)); }); + final polygonDirection = _isPolygonClockwise(path); List> paths = [path]; + int holeIndex = 0; polygon.holes?.forEach((hole) { - paths.add(hole.map((point) => _latLngToGmLatLng(point)).toList()); + List holePath = + hole.map((point) => _latLngToGmLatLng(point)).toList(); + if (_isPolygonClockwise(holePath) == polygonDirection) { + holePath = holePath.reversed.toList(); + if (kDebugMode) { + print( + 'Hole [$holeIndex] in Polygon [${polygon.polygonId.value}] has been reversed.' + ' Ensure holes in polygons are "wound in the opposite direction to the outer path."' + ' More info: https://github.com/flutter/flutter/issues/74096'); + } + } + paths.add(holePath); + holeIndex++; }); return gmaps.PolygonOptions() ..paths = paths @@ -498,6 +512,20 @@ gmaps.PolygonOptions _polygonOptionsFromPolygon( ..geodesic = polygon.geodesic; } +/// Calculates the direction of a given Polygon +/// based on: https://stackoverflow.com/a/1165943 +/// +/// returns [true] if clockwise [false] if counterclockwise +bool _isPolygonClockwise(List path) { + var direction = 0.0; + for (var i = 0; i < path.length; i++) { + direction = direction + + ((path[(i + 1) % path.length].lat - path[i].lat) * + (path[(i + 1) % path.length].lng + path[i].lng)); + } + return direction >= 0; +} + gmaps.PolylineOptions _polylineOptionsFromPolyline( gmaps.GMap googleMap, Polyline polyline) { List paths = []; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index bd879553a06d..099a1238be1c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.1.0+10 +version: 0.1.1 flutter: plugin: diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart index 4d5c2b17cc56..26db542c60fe 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart @@ -245,6 +245,39 @@ void main() { expect(geometry.poly.containsLocation(pointInHole, polygon), false); }); + + testWidgets('Hole Path gets reversed to display correctly', + (WidgetTester tester) async { + final polygons = { + Polygon( + polygonId: PolygonId('BermudaTriangle'), + points: [ + LatLng(25.774, -80.19), + LatLng(18.466, -66.118), + LatLng(32.321, -64.757), + ], + holes: [ + [ + LatLng(27.339, -66.668), + LatLng(29.57, -67.514), + LatLng(28.745, -70.579), + ], + ], + ), + }; + + controller.addPolygons(polygons); + + expect( + controller.polygons.values.first.polygon.paths.getAt(1).getAt(0).lat, + 28.745); + expect( + controller.polygons.values.first.polygon.paths.getAt(1).getAt(1).lat, + 29.57); + expect( + controller.polygons.values.first.polygon.paths.getAt(1).getAt(2).lat, + 27.339); + }); }); group('PolylinesController', () { From 6fa2ead23e8d58de047f38c0f90ce5e218ef8ea5 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 21 Jan 2021 16:19:05 -0800 Subject: [PATCH 117/924] [google_maps_flutter_platform_interface] add custom tile support (#3418) --- .../CHANGELOG.md | 4 + .../method_channel_google_maps_flutter.dart | 61 +++++++ .../google_maps_flutter_platform.dart | 27 +++ .../lib/src/types/tile.dart | 42 +++++ .../lib/src/types/tile_overlay.dart | 161 ++++++++++++++++++ .../lib/src/types/tile_overlay_updates.dart | 122 +++++++++++++ .../lib/src/types/tile_provider.dart | 16 ++ .../lib/src/types/types.dart | 3 + .../lib/src/types/utils/tile_overlay.dart | 23 +++ .../google_maps_flutter_platform_test.dart | 3 - .../test/types/tile_overlay_test.dart | 107 ++++++++++++ .../test/types/tile_overlay_updates_test.dart | 125 ++++++++++++++ .../test/types/tile_test.dart | 28 +++ .../google_maps_flutter_web/CHANGELOG.md | 4 + .../google_maps_flutter_web/pubspec.yaml | 2 +- 15 files changed, 724 insertions(+), 4 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index 1e761681e543..4273f596cf39 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.2.0 + +* Add TileOverlay support. + ## 1.1.0 * Add support for holes in Polygons. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index 31392354d946..0ebfad5b5137 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -12,6 +12,8 @@ import 'package:flutter/gestures.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:stream_transform/stream_transform.dart'; +import '../types/tile_overlay_updates.dart'; +import '../types/utils/tile_overlay.dart'; /// An implementation of [GoogleMapsFlutterPlatform] that uses [MethodChannel] to communicate with the native code. /// @@ -33,6 +35,9 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { return _channels[mapId]; } + // Keep a collection of mapId to a map of TileOverlays. + final Map> _tileOverlays = {}; + /// Initializes the platform interface with [id]. /// /// This method is called when the plugin is first initialized. @@ -184,6 +189,18 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { LatLng.fromJson(call.arguments['position']), )); break; + case 'tileOverlay#getTile': + final Map tileOverlaysForThisMap = + _tileOverlays[mapId]; + final String tileOverlayId = call.arguments['tileOverlayId']; + final TileOverlay tileOverlay = tileOverlaysForThisMap[tileOverlayId]; + assert(tileOverlay.tileProvider.getTile != null); + final Tile tile = await tileOverlay.tileProvider.getTile( + call.arguments['x'], + call.arguments['y'], + call.arguments['zoom'], + ); + return tile.toJson(); default: throw MissingPluginException(); } @@ -281,6 +298,50 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { ); } + /// Updates tile overlay configuration. + /// + /// Change listeners are notified once the update has been made on the + /// platform side. + /// + /// The returned [Future] completes after listeners have been notified. + /// + /// If `newTileOverlays` is null, all the [TileOverlays] are removed for the Map with `mapId`. + @override + Future updateTileOverlays({ + Set newTileOverlays, + @required int mapId, + }) { + final Map currentTileOverlays = + _tileOverlays[mapId]; + Set previousSet = + currentTileOverlays != null ? currentTileOverlays.values.toSet() : null; + final TileOverlayUpdates updates = + TileOverlayUpdates.from(previousSet, newTileOverlays); + _tileOverlays[mapId] = keyTileOverlayId(newTileOverlays); + return channel(mapId).invokeMethod( + 'tileOverlays#update', + updates.toJson(), + ); + } + + /// Clears the tile cache so that all tiles will be requested again from the + /// [TileProvider]. + /// + /// The current tiles from this tile overlay will also be + /// cleared from the map after calling this method. The Google Map SDK maintains a small + /// in-memory cache of tiles. If you want to cache tiles for longer, you + /// should implement an on-disk cache. + @override + Future clearTileCache( + TileOverlayId tileOverlayId, { + @required int mapId, + }) { + return channel(mapId) + .invokeMethod('tileOverlays#clearTileCache', { + 'tileOverlayId': tileOverlayId.value, + }); + } + /// Starts an animated change of the map camera position. /// /// The returned [Future] completes after the change has been started on the diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart index a4f487740811..b9d3fecc0d0a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart @@ -115,6 +115,33 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { throw UnimplementedError('updateCircles() has not been implemented.'); } + /// Updates tile overlay configuration. + /// + /// Change listeners are notified once the update has been made on the + /// platform side. + /// + /// The returned [Future] completes after listeners have been notified. + Future updateTileOverlays({ + Set newTileOverlays, + @required int mapId, + }) { + throw UnimplementedError('updateTileOverlays() has not been implemented.'); + } + + /// Clears the tile cache so that all tiles will be requested again from the + /// [TileProvider]. + /// + /// The current tiles from this tile overlay will also be + /// cleared from the map after calling this method. The Google Maps SDK maintains a small + /// in-memory cache of tiles. If you want to cache tiles for longer, you + /// should implement an on-disk cache. + Future clearTileCache( + TileOverlayId tileOverlayId, { + @required int mapId, + }) { + throw UnimplementedError('clearTileCache() has not been implemented.'); + } + /// Starts an animated change of the map camera position. /// /// The returned [Future] completes after the change has been started on the diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart new file mode 100644 index 000000000000..a992b41fb6c0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart @@ -0,0 +1,42 @@ +// Copyright 2018 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:typed_data'; +import 'package:meta/meta.dart' show immutable; + +/// Contains information about a Tile that is returned by a [TileProvider]. +@immutable +class Tile { + /// Creates an immutable representation of a [Tile] to draw by [TileProvider]. + const Tile(this.width, this.height, this.data); + + /// The width of the image encoded by data in logical pixels. + final int width; + + /// The height of the image encoded by data in logical pixels. + final int height; + + /// A byte array containing the image data. + /// + /// The image data format must be natively supported for decoding by the platform. + /// e.g on Android it can only be one of the [supported image formats for decoding](https://developer.android.com/guide/topics/media/media-formats#image-formats). + final Uint8List data; + + /// Converts this object to JSON. + Map toJson() { + final Map json = {}; + + void addIfPresent(String fieldName, dynamic value) { + if (value != null) { + json[fieldName] = value; + } + } + + addIfPresent('width', width); + addIfPresent('height', height); + addIfPresent('data', data); + + return json; + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart new file mode 100644 index 000000000000..3978f23f05f8 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart @@ -0,0 +1,161 @@ +// Copyright 2018 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:ui' show hashValues; +import 'package:flutter/foundation.dart'; + +import 'types.dart'; +import 'package:meta/meta.dart' show immutable, required; + +/// Uniquely identifies a [TileOverlay] among [GoogleMap] tile overlays. +@immutable +class TileOverlayId { + /// Creates an immutable identifier for a [TileOverlay]. + TileOverlayId(this.value) : assert(value != null); + + /// The value of the [TileOverlayId]. + final String value; + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) { + return false; + } + return other is TileOverlayId && other.value == value; + } + + @override + int get hashCode => value.hashCode; + + @override + String toString() => '${objectRuntimeType(this, 'TileOverlayId')}($value)'; +} + +/// A set of images which are displayed on top of the base map tiles. +/// +/// These tiles may be transparent, allowing you to add features to existing maps. +/// +/// ## Tile Coordinates +/// +/// Note that the world is projected using the Mercator projection +/// (see [Wikipedia](https://en.wikipedia.org/wiki/Mercator_projection)) with the left (west) side +/// of the map corresponding to -180 degrees of longitude and the right (east) side of the map +/// corresponding to 180 degrees of longitude. To make the map square, the top (north) side of the +/// map corresponds to 85.0511 degrees of latitude and the bottom (south) side of the map +/// corresponds to -85.0511 degrees of latitude. Areas outside this latitude range are not rendered. +/// +/// At each zoom level, the map is divided into tiles and only the tiles that overlap the screen are +/// downloaded and rendered. Each tile is square and the map is divided into tiles as follows: +/// +/// * At zoom level 0, one tile represents the entire world. The coordinates of that tile are +/// (x, y) = (0, 0). +/// * At zoom level 1, the world is divided into 4 tiles arranged in a 2 x 2 grid. +/// * ... +/// * At zoom level N, the world is divided into 4N tiles arranged in a 2N x 2N grid. +/// +/// Note that the minimum zoom level that the camera supports (which can depend on various factors) +/// is GoogleMap.getMinZoomLevel and the maximum zoom level is GoogleMap.getMaxZoomLevel. +/// +/// The coordinates of the tiles are measured from the top left (northwest) corner of the map. +/// At zoom level N, the x values of the tile coordinates range from 0 to 2N - 1 and increase from +/// west to east and the y values range from 0 to 2N - 1 and increase from north to south. +/// +class TileOverlay { + /// Creates an immutable representation of a [TileOverlay] to draw on [GoogleMap]. + const TileOverlay({ + @required this.tileOverlayId, + this.fadeIn = true, + this.tileProvider, + this.transparency = 0.0, + this.zIndex, + this.visible = true, + this.tileSize = 256, + }) : assert(transparency >= 0.0 && transparency <= 1.0); + + /// Uniquely identifies a [TileOverlay]. + final TileOverlayId tileOverlayId; + + /// Whether the tiles should fade in. The default is true. + final bool fadeIn; + + /// The tile provider to use for this tile overlay. + final TileProvider tileProvider; + + /// The transparency of the tile overlay. The default transparency is 0 (opaque). + final double transparency; + + /// The tile overlay's zIndex, i.e., the order in which it will be drawn where + /// overlays with larger values are drawn above those with lower values + final int zIndex; + + /// The visibility for the tile overlay. The default visibility is true. + final bool visible; + + /// Specifies the number of logical pixels (not points) that the returned tile images will prefer + /// to display as. iOS only. + /// + /// Defaults to 256, which is the traditional size of Google Maps tiles. + /// As an example, an application developer may wish to provide retina tiles (512 pixel edge length) + /// on retina devices, to keep the same number of tiles per view as the default value of 256 + /// would give on a non-retina device. + final int tileSize; + + /// Creates a new [TileOverlay] object whose values are the same as this instance, + /// unless overwritten by the specified parameters. + TileOverlay copyWith({ + TileOverlayId tileOverlayId, + bool fadeInParam, + double transparencyParam, + int zIndexParam, + bool visibleParam, + int tileSizeParam, + }) { + return TileOverlay( + tileOverlayId: tileOverlayId, + fadeIn: fadeInParam ?? fadeIn, + transparency: transparencyParam ?? transparency, + zIndex: zIndexParam ?? zIndex, + visible: visibleParam ?? visible, + tileSize: tileSizeParam ?? tileSize, + ); + } + + /// Converts this object to JSON. + Map toJson() { + final Map json = {}; + + void addIfPresent(String fieldName, dynamic value) { + if (value != null) { + json[fieldName] = value; + } + } + + addIfPresent('tileOverlayId', tileOverlayId.value); + addIfPresent('fadeIn', fadeIn); + addIfPresent('transparency', transparency); + addIfPresent('zIndex', zIndex); + addIfPresent('visible', visible); + addIfPresent('tileSize', tileSize); + + return json; + } + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) { + return false; + } + return other is TileOverlay && + tileOverlayId == other.tileOverlayId && + fadeIn == other.fadeIn && + transparency == other.transparency && + zIndex == other.zIndex && + visible == other.visible && + tileSize == other.tileSize; + } + + @override + int get hashCode => hashValues( + tileOverlayId, fadeIn, transparency, zIndex, visible, tileSize); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart new file mode 100644 index 000000000000..2910fc37d495 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart @@ -0,0 +1,122 @@ +// Copyright 2018 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 'package:flutter/foundation.dart' show objectRuntimeType, setEquals; +import 'dart:ui' show hashValues, hashList; + +import 'utils/tile_overlay.dart'; +import 'types.dart'; + +/// Update specification for a set of [TileOverlay]s. +class TileOverlayUpdates { + /// Computes [TileOverlayUpdates] given previous and current [TileOverlay]s. + TileOverlayUpdates.from(Set previous, Set current) { + if (previous == null) { + previous = Set.identity(); + } + + if (current == null) { + current = Set.identity(); + } + + final Map previousTileOverlays = + keyTileOverlayId(previous); + final Map currentTileOverlays = + keyTileOverlayId(current); + + final Set prevTileOverlayIds = + previousTileOverlays.keys.toSet(); + final Set currentTileOverlayIds = + currentTileOverlays.keys.toSet(); + + TileOverlay idToCurrentTileOverlay(TileOverlayId id) { + return currentTileOverlays[id]; + } + + _tileOverlayIdsToRemove = + prevTileOverlayIds.difference(currentTileOverlayIds); + + _tileOverlaysToAdd = currentTileOverlayIds + .difference(prevTileOverlayIds) + .map(idToCurrentTileOverlay) + .toSet(); + + // Returns `true` if [current] is not equals to previous one with the + // same id. + bool hasChanged(TileOverlay current) { + final TileOverlay previous = previousTileOverlays[current.tileOverlayId]; + return current != previous; + } + + _tileOverlaysToChange = currentTileOverlayIds + .intersection(prevTileOverlayIds) + .map(idToCurrentTileOverlay) + .where(hasChanged) + .toSet(); + } + + /// Set of TileOverlays to be added in this update. + Set get tileOverlaysToAdd { + return _tileOverlaysToAdd; + } + + Set _tileOverlaysToAdd; + + /// Set of TileOverlayIds to be removed in this update. + Set get tileOverlayIdsToRemove { + return _tileOverlayIdsToRemove; + } + + Set _tileOverlayIdsToRemove; + + /// Set of TileOverlays to be changed in this update. + Set get tileOverlaysToChange { + return _tileOverlaysToChange; + } + + Set _tileOverlaysToChange; + + /// Converts this object to JSON. + Map toJson() { + final Map updateMap = {}; + + void addIfNonNull(String fieldName, dynamic value) { + if (value != null) { + updateMap[fieldName] = value; + } + } + + addIfNonNull( + 'tileOverlaysToAdd', serializeTileOverlaySet(_tileOverlaysToAdd)); + addIfNonNull( + 'tileOverlaysToChange', serializeTileOverlaySet(_tileOverlaysToChange)); + addIfNonNull( + 'tileOverlayIdsToRemove', + _tileOverlayIdsToRemove + .map((TileOverlayId m) => m.value) + .toList()); + + return updateMap; + } + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) { + return false; + } + return other is TileOverlayUpdates && + setEquals(_tileOverlaysToAdd, other._tileOverlaysToAdd) && + setEquals(_tileOverlayIdsToRemove, other._tileOverlayIdsToRemove) && + setEquals(_tileOverlaysToChange, other._tileOverlaysToChange); + } + + @override + int get hashCode => hashValues(hashList(_tileOverlaysToAdd), + hashList(_tileOverlayIdsToRemove), hashList(_tileOverlaysToChange)); + + @override + String toString() { + return '${objectRuntimeType(this, 'TileOverlayUpdates')}($_tileOverlaysToAdd, $_tileOverlayIdsToRemove, $_tileOverlaysToChange)'; + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart new file mode 100644 index 000000000000..c3c4f807e283 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart @@ -0,0 +1,16 @@ +// Copyright 2018 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 'types.dart'; + +/// An interface for a class that provides the tile images for a TileOverlay. +abstract class TileProvider { + /// Stub tile that is used to indicate that no tile exists for a specific tile coordinate. + static const Tile noTile = Tile(-1, -1, null); + + /// Returns the tile to be used for this tile coordinate. + /// + /// See [TileOverlay] for the specification of tile coordinates. + Future getTile(int x, int y, int zoom); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart index e56c3a5dd646..e4b5c0bc3ab2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart @@ -19,6 +19,9 @@ export 'polygon.dart'; export 'polyline_updates.dart'; export 'polyline.dart'; export 'screen_coordinate.dart'; +export 'tile.dart'; +export 'tile_overlay.dart'; +export 'tile_provider.dart'; export 'ui.dart'; // Export the utils, they're used by the Widget diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart new file mode 100644 index 000000000000..0736c836481f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart @@ -0,0 +1,23 @@ +import '../types.dart'; + +/// Converts an [Iterable] of TileOverlay in a Map of TileOverlayId -> TileOverlay. +Map keyTileOverlayId( + Iterable tileOverlays) { + if (tileOverlays == null) { + return {}; + } + return Map.fromEntries(tileOverlays.map( + (TileOverlay tileOverlay) => MapEntry( + tileOverlay.tileOverlayId, tileOverlay))); +} + +/// Converts a Set of TileOverlays into something serializable in JSON. +List> serializeTileOverlaySet( + Set tileOverlays) { + if (tileOverlays == null) { + return null; + } + return tileOverlays + .map>((TileOverlay p) => p.toJson()) + .toList(); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart index a003b94d544c..582acea54dd1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart @@ -45,14 +45,11 @@ void main() { log.add(methodCall); }); -// final MethodChannelGoogleMapsFlutter map = MethodChannelGoogleMapsFlutter(0); - tearDown(() { log.clear(); }); test('foo', () async { -// await map.foo(); expect( log, [], diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart new file mode 100644 index 000000000000..bb0621d23ae3 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart @@ -0,0 +1,107 @@ +// 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:ui' show hashValues; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('tile overlay id tests', () { + test('equality', () async { + final TileOverlayId id1 = TileOverlayId('1'); + final TileOverlayId id2 = TileOverlayId('1'); + final TileOverlayId id3 = TileOverlayId('2'); + expect(id1, id2); + expect(id1, isNot(id3)); + }); + + test('toString', () async { + final TileOverlayId id1 = TileOverlayId('1'); + expect(id1.toString(), 'TileOverlayId(1)'); + }); + }); + + group('tile overlay tests', () { + test('toJson returns correct format', () async { + final TileOverlay tileOverlay = TileOverlay( + tileOverlayId: TileOverlayId('id'), + fadeIn: false, + tileProvider: null, + transparency: 0.1, + zIndex: 1, + visible: false, + tileSize: 128); + final Map json = tileOverlay.toJson(); + expect(json['tileOverlayId'], 'id'); + expect(json['fadeIn'], false); + expect(json['transparency'], moreOrLessEquals(0.1)); + expect(json['zIndex'], 1); + expect(json['visible'], false); + expect(json['tileSize'], 128); + }); + + test('invalid transparency throws', () async { + expect( + () => TileOverlay( + tileOverlayId: TileOverlayId('id1'), transparency: -0.1), + throwsAssertionError); + expect( + () => TileOverlay( + tileOverlayId: TileOverlayId('id2'), transparency: 1.2), + throwsAssertionError); + }); + + test('equality', () async { + final TileOverlay tileOverlay1 = TileOverlay( + tileOverlayId: TileOverlayId('id1'), + fadeIn: false, + tileProvider: null, + transparency: 0.1, + zIndex: 1, + visible: false, + tileSize: 128); + final TileOverlay tileOverlay2 = TileOverlay( + tileOverlayId: TileOverlayId('id1'), + fadeIn: false, + tileProvider: null, + transparency: 0.1, + zIndex: 1, + visible: false, + tileSize: 128); + final TileOverlay tileOverlay3 = TileOverlay( + tileOverlayId: TileOverlayId('id2'), + fadeIn: false, + tileProvider: null, + transparency: 0.1, + zIndex: 1, + visible: false, + tileSize: 128); + expect(tileOverlay1, tileOverlay2); + expect(tileOverlay1, isNot(tileOverlay3)); + }); + + test('hashCode', () async { + TileOverlayId id = TileOverlayId('id1'); + final TileOverlay tileOverlay = TileOverlay( + tileOverlayId: id, + fadeIn: false, + tileProvider: null, + transparency: 0.1, + zIndex: 1, + visible: false, + tileSize: 128); + expect( + tileOverlay.hashCode, + hashValues( + tileOverlay.tileOverlayId, + tileOverlay.fadeIn, + tileOverlay.transparency, + tileOverlay.zIndex, + tileOverlay.visible, + tileOverlay.tileSize)); + }); + }); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart new file mode 100644 index 000000000000..980a203f709e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart @@ -0,0 +1,125 @@ +// 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:ui' show hashValues, hashList; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/utils/tile_overlay.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/tile_overlay_updates.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/tile_overlay.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('tile overlay updates tests', () { + test('Correctly set toRemove, toAdd and toChange', () async { + final TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); + final TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); + final TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); + final TileOverlay to3Changed = + TileOverlay(tileOverlayId: TileOverlayId('id3'), transparency: 0.5); + final TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); + final Set previous = Set.from([to1, to2, to3]); + final Set current = + Set.from([to2, to3Changed, to4]); + final TileOverlayUpdates updates = + TileOverlayUpdates.from(previous, current); + + final Set toRemove = + Set.from([TileOverlayId('id1')]); + expect(updates.tileOverlayIdsToRemove, toRemove); + + final Set toAdd = Set.from([to4]); + expect(updates.tileOverlaysToAdd, toAdd); + + final Set toChange = Set.from([to3Changed]); + expect(updates.tileOverlaysToChange, toChange); + }); + + test('toJson', () async { + final TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); + final TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); + final TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); + final TileOverlay to3Changed = + TileOverlay(tileOverlayId: TileOverlayId('id3'), transparency: 0.5); + final TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); + final Set previous = Set.from([to1, to2, to3]); + final Set current = + Set.from([to2, to3Changed, to4]); + final TileOverlayUpdates updates = + TileOverlayUpdates.from(previous, current); + + final Map json = updates.toJson(); + expect(json, { + 'tileOverlaysToAdd': serializeTileOverlaySet(updates.tileOverlaysToAdd), + 'tileOverlaysToChange': + serializeTileOverlaySet(updates.tileOverlaysToChange), + 'tileOverlayIdsToRemove': updates.tileOverlayIdsToRemove + .map((TileOverlayId m) => m.value) + .toList() + }); + }); + + test('equality', () async { + final TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); + final TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); + final TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); + final TileOverlay to3Changed = + TileOverlay(tileOverlayId: TileOverlayId('id3'), transparency: 0.5); + final TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); + final Set previous = Set.from([to1, to2, to3]); + final Set current1 = + Set.from([to2, to3Changed, to4]); + final Set current2 = + Set.from([to2, to3Changed, to4]); + final Set current3 = Set.from([to2, to4]); + final TileOverlayUpdates updates1 = + TileOverlayUpdates.from(previous, current1); + final TileOverlayUpdates updates2 = + TileOverlayUpdates.from(previous, current2); + final TileOverlayUpdates updates3 = + TileOverlayUpdates.from(previous, current3); + expect(updates1, updates2); + expect(updates1, isNot(updates3)); + }); + + test('hashCode', () async { + final TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); + final TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); + final TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); + final TileOverlay to3Changed = + TileOverlay(tileOverlayId: TileOverlayId('id3'), transparency: 0.5); + final TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); + final Set previous = Set.from([to1, to2, to3]); + final Set current = + Set.from([to2, to3Changed, to4]); + final TileOverlayUpdates updates = + TileOverlayUpdates.from(previous, current); + expect( + updates.hashCode, + hashValues( + hashList(updates.tileOverlaysToAdd), + hashList(updates.tileOverlayIdsToRemove), + hashList(updates.tileOverlaysToChange))); + }); + + test('toString', () async { + final TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); + final TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); + final TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); + final TileOverlay to3Changed = + TileOverlay(tileOverlayId: TileOverlayId('id3'), transparency: 0.5); + final TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); + final Set previous = Set.from([to1, to2, to3]); + final Set current = + Set.from([to2, to3Changed, to4]); + final TileOverlayUpdates updates = + TileOverlayUpdates.from(previous, current); + expect( + updates.toString(), + 'TileOverlayUpdates(${updates.tileOverlaysToAdd}, ' + '${updates.tileOverlayIdsToRemove}, ' + '${updates.tileOverlaysToChange})'); + }); + }); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart new file mode 100644 index 000000000000..0be9a7cea8f0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart @@ -0,0 +1,28 @@ +// 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:typed_data'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('tile tests', () { + test('toJson returns correct format', () async { + final Uint8List data = Uint8List.fromList([0, 1]); + final Tile tile = Tile(100, 200, data); + final Map json = tile.toJson(); + expect(json['width'], 100); + expect(json['height'], 200); + expect(json['data'], data); + }); + + test('toJson returns empty if nothing presents', () async { + final Tile tile = Tile(null, null, null); + final Map json = tile.toJson(); + expect(json.isEmpty, true); + }); + }); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index caa64ec73088..f5e289cb19ae 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.2 + +* Add support for Custom Tiles. + ## 0.1.1 * Auto-reverse holes if they're the same direction as the polygon. [Issue](https://github.com/flutter/flutter/issues/74096). diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index 099a1238be1c..83ac0fbdde5f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.1.1 +version: 0.1.2 flutter: plugin: From 6783cd5ebd54e034a77e2404f5565b48bd19e121 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 22 Jan 2021 11:04:03 -0800 Subject: [PATCH 118/924] [google_maps_flutter_platform_interface] Fixes for custom tiles (#3449) --- .../method_channel_google_maps_flutter.dart | 10 +++++++--- .../lib/src/types/types.dart | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index 0ebfad5b5137..8b7af2cc3515 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -193,9 +193,13 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { final Map tileOverlaysForThisMap = _tileOverlays[mapId]; final String tileOverlayId = call.arguments['tileOverlayId']; - final TileOverlay tileOverlay = tileOverlaysForThisMap[tileOverlayId]; - assert(tileOverlay.tileProvider.getTile != null); - final Tile tile = await tileOverlay.tileProvider.getTile( + final TileOverlay tileOverlay = + tileOverlaysForThisMap[TileOverlayId(tileOverlayId)]; + Tile tile; + if (tileOverlay == null || tileOverlay.tileProvider == null) { + return TileProvider.noTile.toJson(); + } + tile = await tileOverlay.tileProvider.getTile( call.arguments['x'], call.arguments['y'], call.arguments['zoom'], diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart index e4b5c0bc3ab2..3e2002f80ae3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart @@ -29,3 +29,4 @@ export 'utils/circle.dart'; export 'utils/marker.dart'; export 'utils/polygon.dart'; export 'utils/polyline.dart'; +export 'utils/tile_overlay.dart'; From 712dcc184380188522ca80b56e9b5b11651541ce Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Sat, 23 Jan 2021 10:54:06 -0800 Subject: [PATCH 119/924] [ci][image_picker]enable xcode 12/iOS 14 for all tasks except lint (#3304) --- .cirrus.yml | 50 +++++++++++++------ .../image_picker/image_picker/CHANGELOG.md | 4 ++ .../ImagePickerFromGalleryUITests.m | 20 ++++++-- .../image_picker/image_picker/pubspec.yaml | 2 +- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 4ec73ea3f24c..aa56ca26d82b 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -117,6 +117,7 @@ task: env: INTEGRATION_TEST_PATH: "./packages/integration_test" upgrade_script: + - sudo gem install cocoapods - flutter channel stable - flutter upgrade - flutter channel master @@ -134,13 +135,14 @@ task: - xvfb-run ./script/incremental_build.sh drive-examples --linux task: + # Xcode 11 task + # TODO(cyanglaz): merge Xcode 11 task to Xcode 12 task when all the matrix can be run in Xcode 12. # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins only_if: $CIRRUS_TAG == '' use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' osx_instance: image: catalina-xcode-11.3.1-flutter upgrade_script: - - sudo gem install cocoapods - flutter channel stable - flutter upgrade - flutter channel master @@ -151,17 +153,6 @@ task: - xcrun simctl list - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot matrix: - - name: build_all_plugins_ipa - env: - matrix: - CHANNEL: "master" - CHANNEL: "stable" - script: - # TODO(jackson): Allow web plugins once supported on stable - # https://github.com/flutter/flutter/issues/42864 - - if [[ "$CHANNEL" -eq "stable" ]]; then find . | grep _web$ | xargs rm -rf; fi - - flutter channel $CHANNEL - - ./script/build_all_plugins_app.sh ios --no-codesign - name: lint_darwin_plugins env: matrix: @@ -173,6 +164,37 @@ task: # Skip the dummy podspecs used to placate the tool. - find . -name "*_web*.podspec" -o -name "*_mac*.podspec" | xargs rm - ./script/incremental_build.sh podspecs + +task: + # Xcode 12 task + # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins + only_if: $CIRRUS_TAG == '' + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' + osx_instance: + image: big-sur-xcode-12.3 + upgrade_script: + - sudo gem install cocoapods + - flutter channel stable + - flutter upgrade + - flutter channel master + - flutter upgrade + - git fetch origin master + activate_script: pub global activate flutter_plugin_tools + create_simulator_script: + - xcrun simctl list + - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-3 | xargs xcrun simctl boot + matrix: + - name: build_all_plugins_ipa + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" + script: + # TODO(jackson): Allow web plugins once supported on stable + # https://github.com/flutter/flutter/issues/42864 + - if [[ "$CHANNEL" -eq "stable" ]]; then find . | grep _web$ | xargs rm -rf; fi + - flutter channel $CHANNEL + - ./script/build_all_plugins_app.sh ios --no-codesign - name: build-ipas+drive-examples env: PATH: $PATH:/usr/local/bin @@ -193,13 +215,13 @@ task: - flutter channel $CHANNEL - ./script/incremental_build.sh build-examples --ipa - ./script/incremental_build.sh drive-examples - - ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS + - ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=14.3" task: # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins only_if: $CIRRUS_TAG == '' use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' osx_instance: - image: catalina-xcode-11.3.1-flutter + image: big-sur-xcode-12.3 setup_script: - flutter config --enable-macos-desktop upgrade_script: diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 1b3146d532fa..1a09758d13ef 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+22 + +* iOS: update XCUITests to separate each test session. + ## 0.6.7+21 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m index 74df795a3df3..e30fabd2d071 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m @@ -16,6 +16,7 @@ @interface ImagePickerFromGalleryUITests : XCTestCase @implementation ImagePickerFromGalleryUITests - (void)setUp { + [super setUp]; // Delete the app if already exists, to test permission popups self.continueAfterFailure = NO; @@ -31,7 +32,7 @@ - (void)setUp { if (![allPhotoPermission waitForExistenceWithTimeout: kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", - self.app.debugDescription); + weakSelf.app.debugDescription); XCTFail(@"Failed due to not able to find " @"allPhotoPermission button with %@ seconds", @(kElementWaitingTime)); @@ -42,7 +43,7 @@ - (void)setUp { if (![ok waitForExistenceWithTimeout: kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", - self.app.debugDescription); + weakSelf.app.debugDescription); XCTFail(@"Failed due to not able to find ok button " @"with %@ seconds", @(kElementWaitingTime)); @@ -53,11 +54,19 @@ - (void)setUp { }]; } +- (void)tearDown { + [super tearDown]; + [self.app terminate]; +} + - (void)testPickingFromGallery { - [self launchPickerAndCancel]; [self launchPickerAndPick]; } +- (void)testCancel { + [self launchPickerAndCancel]; +} + - (void)launchPickerAndCancel { // Find and tap on the pick from gallery button. NSPredicate* predicateToFindImageFromGalleryButton = @@ -160,6 +169,10 @@ - (void)launchPickerAndPick { XCTAssertTrue(pickButton.exists); [pickButton tap]; + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + [self.app tap]; + // Find an image and tap on it. (IOS 14 UI, images are showing directly) XCUIElement* aImage; if (@available(iOS 14, *)) { @@ -177,6 +190,7 @@ - (void)launchPickerAndPick { identifier:@"PhotosGridView"] .cells.firstMatch; } + os_log_error(OS_LOG_DEFAULT, "description before picking image %@", self.app.debugDescription); if (![aImage waitForExistenceWithTimeout:kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); XCTFail(@"Failed due to not able to find an image with %@ seconds", @(kElementWaitingTime)); diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 789ca13d5bcb..075c90627bf4 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+21 +version: 0.6.7+22 flutter: plugin: From 18124285feeba5f62e2e0deafab3ef93e5895426 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 25 Jan 2021 10:21:11 -0800 Subject: [PATCH 120/924] Revert "[ci][image_picker]enable xcode 12/iOS 14 for all tasks except lint (#3304)" (#3459) This reverts commit 712dcc184380188522ca80b56e9b5b11651541ce. --- .cirrus.yml | 50 ++++++------------- .../image_picker/image_picker/CHANGELOG.md | 4 -- .../ImagePickerFromGalleryUITests.m | 20 ++------ .../image_picker/image_picker/pubspec.yaml | 2 +- 4 files changed, 18 insertions(+), 58 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index aa56ca26d82b..4ec73ea3f24c 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -117,7 +117,6 @@ task: env: INTEGRATION_TEST_PATH: "./packages/integration_test" upgrade_script: - - sudo gem install cocoapods - flutter channel stable - flutter upgrade - flutter channel master @@ -135,43 +134,11 @@ task: - xvfb-run ./script/incremental_build.sh drive-examples --linux task: - # Xcode 11 task - # TODO(cyanglaz): merge Xcode 11 task to Xcode 12 task when all the matrix can be run in Xcode 12. # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins only_if: $CIRRUS_TAG == '' use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' osx_instance: image: catalina-xcode-11.3.1-flutter - upgrade_script: - - flutter channel stable - - flutter upgrade - - flutter channel master - - flutter upgrade - - git fetch origin master - activate_script: pub global activate flutter_plugin_tools - create_simulator_script: - - xcrun simctl list - - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot - matrix: - - name: lint_darwin_plugins - env: - matrix: - PLUGIN_SHARDING: "--shardIndex 0 --shardCount 2" - PLUGIN_SHARDING: "--shardIndex 1 --shardCount 2" - script: - # TODO(jmagman): Lint macOS podspecs but skip any that fail library validation. - - find . -name "*.podspec" | xargs grep -l "osx" | xargs rm - # Skip the dummy podspecs used to placate the tool. - - find . -name "*_web*.podspec" -o -name "*_mac*.podspec" | xargs rm - - ./script/incremental_build.sh podspecs - -task: - # Xcode 12 task - # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins - only_if: $CIRRUS_TAG == '' - use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' - osx_instance: - image: big-sur-xcode-12.3 upgrade_script: - sudo gem install cocoapods - flutter channel stable @@ -182,7 +149,7 @@ task: activate_script: pub global activate flutter_plugin_tools create_simulator_script: - xcrun simctl list - - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-3 | xargs xcrun simctl boot + - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot matrix: - name: build_all_plugins_ipa env: @@ -195,6 +162,17 @@ task: - if [[ "$CHANNEL" -eq "stable" ]]; then find . | grep _web$ | xargs rm -rf; fi - flutter channel $CHANNEL - ./script/build_all_plugins_app.sh ios --no-codesign + - name: lint_darwin_plugins + env: + matrix: + PLUGIN_SHARDING: "--shardIndex 0 --shardCount 2" + PLUGIN_SHARDING: "--shardIndex 1 --shardCount 2" + script: + # TODO(jmagman): Lint macOS podspecs but skip any that fail library validation. + - find . -name "*.podspec" | xargs grep -l "osx" | xargs rm + # Skip the dummy podspecs used to placate the tool. + - find . -name "*_web*.podspec" -o -name "*_mac*.podspec" | xargs rm + - ./script/incremental_build.sh podspecs - name: build-ipas+drive-examples env: PATH: $PATH:/usr/local/bin @@ -215,13 +193,13 @@ task: - flutter channel $CHANNEL - ./script/incremental_build.sh build-examples --ipa - ./script/incremental_build.sh drive-examples - - ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=14.3" + - ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS task: # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins only_if: $CIRRUS_TAG == '' use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' osx_instance: - image: big-sur-xcode-12.3 + image: catalina-xcode-11.3.1-flutter setup_script: - flutter config --enable-macos-desktop upgrade_script: diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 1a09758d13ef..1b3146d532fa 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,7 +1,3 @@ -## 0.6.7+22 - -* iOS: update XCUITests to separate each test session. - ## 0.6.7+21 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m index e30fabd2d071..74df795a3df3 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m @@ -16,7 +16,6 @@ @interface ImagePickerFromGalleryUITests : XCTestCase @implementation ImagePickerFromGalleryUITests - (void)setUp { - [super setUp]; // Delete the app if already exists, to test permission popups self.continueAfterFailure = NO; @@ -32,7 +31,7 @@ - (void)setUp { if (![allPhotoPermission waitForExistenceWithTimeout: kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", - weakSelf.app.debugDescription); + self.app.debugDescription); XCTFail(@"Failed due to not able to find " @"allPhotoPermission button with %@ seconds", @(kElementWaitingTime)); @@ -43,7 +42,7 @@ - (void)setUp { if (![ok waitForExistenceWithTimeout: kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", - weakSelf.app.debugDescription); + self.app.debugDescription); XCTFail(@"Failed due to not able to find ok button " @"with %@ seconds", @(kElementWaitingTime)); @@ -54,17 +53,9 @@ - (void)setUp { }]; } -- (void)tearDown { - [super tearDown]; - [self.app terminate]; -} - - (void)testPickingFromGallery { - [self launchPickerAndPick]; -} - -- (void)testCancel { [self launchPickerAndCancel]; + [self launchPickerAndPick]; } - (void)launchPickerAndCancel { @@ -169,10 +160,6 @@ - (void)launchPickerAndPick { XCTAssertTrue(pickButton.exists); [pickButton tap]; - // There is a known bug where the permission popups interruption won't get fired until a tap - // happened in the app. We expect a permission popup so we do a tap here. - [self.app tap]; - // Find an image and tap on it. (IOS 14 UI, images are showing directly) XCUIElement* aImage; if (@available(iOS 14, *)) { @@ -190,7 +177,6 @@ - (void)launchPickerAndPick { identifier:@"PhotosGridView"] .cells.firstMatch; } - os_log_error(OS_LOG_DEFAULT, "description before picking image %@", self.app.debugDescription); if (![aImage waitForExistenceWithTimeout:kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); XCTFail(@"Failed due to not able to find an image with %@ seconds", @(kElementWaitingTime)); diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 075c90627bf4..789ca13d5bcb 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+22 +version: 0.6.7+21 flutter: plugin: From 207d129aefb53890223912974db1efcbcae4ca48 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Mon, 25 Jan 2021 16:04:57 -0800 Subject: [PATCH 121/924] bump vmservice (#3463) --- packages/integration_test/CHANGELOG.md | 4 ++++ packages/integration_test/pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/integration_test/CHANGELOG.md b/packages/integration_test/CHANGELOG.md index 4bbfe591d6cc..5ae0883ed081 100644 --- a/packages/integration_test/CHANGELOG.md +++ b/packages/integration_test/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2+1 + +* Update vm_service constraint + ## 1.0.2 * Update Flutter SDK constraint. diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index 997faa79e1ca..a233f066ea37 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -1,6 +1,6 @@ name: integration_test description: Runs tests that use the flutter_test API as integration tests. -version: 1.0.2 +version: 1.0.2+1 homepage: https://github.com/flutter/plugins/tree/master/packages/integration_test environment: @@ -18,7 +18,7 @@ dependencies: # TODO(dnfield): This is a problem - flutter_driver and flutter_tools depend # on this packkage, and so does integration_test. When this gets rev'd in the # SDK, it has to be rev'd here too so integration tests in the SDK can use it. - vm_service: ">= 4.2.0 <6.0.0" + vm_service: ">= 4.2.0 <7.0.0" dev_dependencies: pedantic: ^1.8.0 From 919eaef4dcc7b3e272850b74e9995a87d7b5ab39 Mon Sep 17 00:00:00 2001 From: Gary Roumanis Date: Mon, 25 Jan 2021 17:33:19 -0800 Subject: [PATCH 122/924] [cross_file] Use Uri when calling package:http methods (#3462) The next version of package:http expects URIs. See dart-lang/http#507 --- packages/cross_file/CHANGELOG.md | 6 +++++- packages/cross_file/lib/src/types/html.dart | 6 +++--- packages/cross_file/pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md index 5ad91979dc89..45f516ad334d 100644 --- a/packages/cross_file/CHANGELOG.md +++ b/packages/cross_file/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.1 + +* Prepare for breaking `package:http` change. + ## 0.2.0 * **breaking change** Make sure the `saveTo` method returns a `Future` so it can be awaited and users are sure the file has been written to disk. @@ -12,4 +16,4 @@ ## 0.1.0 -- Initial open-source release \ No newline at end of file +- Initial open-source release diff --git a/packages/cross_file/lib/src/types/html.dart b/packages/cross_file/lib/src/types/html.dart index 646939612d75..527d5e6911f6 100644 --- a/packages/cross_file/lib/src/types/html.dart +++ b/packages/cross_file/lib/src/types/html.dart @@ -3,14 +3,14 @@ // found in the LICENSE file. import 'dart:convert'; +import 'dart:html'; import 'dart:typed_data'; import 'package:http/http.dart' as http show readBytes; import 'package:meta/meta.dart'; -import 'dart:html'; -import '../web_helpers/web_helpers.dart'; import './base.dart'; +import '../web_helpers/web_helpers.dart'; /// A CrossFile that works on web. /// @@ -82,7 +82,7 @@ class XFile extends XFileBase { if (_data != null) { return Future.value(UnmodifiableUint8ListView(_data)); } - return http.readBytes(path); + return http.readBytes(Uri.parse(path)); } @override diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml index 4c9acf9b008a..2228674baf40 100644 --- a/packages/cross_file/pubspec.yaml +++ b/packages/cross_file/pubspec.yaml @@ -1,7 +1,7 @@ name: cross_file description: An abstraction to allow working with files across multiple platforms. homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file -version: 0.2.0 +version: 0.2.1 dependencies: flutter: From ced7fd696bba11cd0aabeb14a47b68b1fa5ed0c4 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Mon, 25 Jan 2021 20:59:24 -0800 Subject: [PATCH 123/924] [path_provider] drop uuid (#3465) --- packages/path_provider/path_provider/CHANGELOG.md | 4 ++++ packages/path_provider/path_provider/pubspec.yaml | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index bd6c0bc651f5..43e765aaf0b4 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.28 + +* Drop unused UUID dependency for tests. + ## 1.6.27 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index 649b3420d72f..065c53fec9fd 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 1.6.27 +version: 1.6.28 flutter: plugin: @@ -33,7 +33,6 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - uuid: "^1.0.0" pedantic: ^1.8.0 mockito: ^4.1.1 plugin_platform_interface: ^1.0.0 From ca9921196a7ae96edad91a9cd7b7d8fe9f5689ff Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 26 Jan 2021 11:16:40 -0800 Subject: [PATCH 124/924] [cross_file] Migrate to null-safety. (#3452) Also: skip some packages from the all_plugins app so CI passes. --- packages/cross_file/CHANGELOG.md | 12 ++- packages/cross_file/lib/src/types/base.dart | 10 +-- packages/cross_file/lib/src/types/html.dart | 79 +++++++++---------- .../cross_file/lib/src/types/interface.dart | 26 +++--- packages/cross_file/lib/src/types/io.dart | 32 ++++---- .../lib/src/web_helpers/web_helpers.dart | 2 +- packages/cross_file/pubspec.yaml | 9 +-- .../cross_file/test/x_file_html_test.dart | 18 ++--- packages/cross_file/test/x_file_io_test.dart | 2 +- script/build_all_plugins_app.sh | 3 +- script/nnbd_plugins.sh | 1 + 11 files changed, 99 insertions(+), 95 deletions(-) diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md index 45f516ad334d..c9b3d1ab2522 100644 --- a/packages/cross_file/CHANGELOG.md +++ b/packages/cross_file/CHANGELOG.md @@ -1,6 +1,12 @@ +## 0.3.0-nullsafety + +* Migrated package to null-safety. +* **breaking change** According to our unit tests, the API should be backwards-compatible. Some relevant changes were made, however: + * Web: `lastModified` returns the epoch time as a default value, to maintain the `Future` return type (and not `null`) + ## 0.2.1 -* Prepare for breaking `package:http` change. +* Prepare for breaking `package:http` change. ## 0.2.0 @@ -12,8 +18,8 @@ ## 0.1.0+1 -- Update Flutter SDK constraint. +* Update Flutter SDK constraint. ## 0.1.0 -- Initial open-source release +* Initial open-source release. diff --git a/packages/cross_file/lib/src/types/base.dart b/packages/cross_file/lib/src/types/base.dart index 1a1b5694d58f..2a59c1c2b246 100644 --- a/packages/cross_file/lib/src/types/base.dart +++ b/packages/cross_file/lib/src/types/base.dart @@ -15,7 +15,7 @@ import 'dart:typed_data'; /// the methods should seem familiar. abstract class XFileBase { /// Construct a CrossFile - XFileBase(String path); + XFileBase(String? path); /// Save the CrossFile at the indicated file path. Future saveTo(String path) { @@ -31,19 +31,19 @@ abstract class XFileBase { /// Accessing the data contained in the picked file by its path /// is platform-dependant (and won't work on web), so use the /// byte getters in the CrossFile instance instead. - String get path { + String? get path { throw UnimplementedError('.path has not been implemented.'); } /// The name of the file as it was selected by the user in their device. /// /// Use only for cosmetic reasons, do not try to use this as a path. - String get name { + String? get name { throw UnimplementedError('.name has not been implemented.'); } /// For web, it may be necessary for a file to know its MIME type. - String get mimeType { + String? get mimeType { throw UnimplementedError('.mimeType has not been implemented.'); } @@ -75,7 +75,7 @@ abstract class XFileBase { /// 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 openRead([int start, int end]) { + Stream openRead([int? start, int? end]) { throw UnimplementedError('openRead() has not been implemented.'); } diff --git a/packages/cross_file/lib/src/types/html.dart b/packages/cross_file/lib/src/types/html.dart index 527d5e6911f6..203ab5d82e12 100644 --- a/packages/cross_file/lib/src/types/html.dart +++ b/packages/cross_file/lib/src/types/html.dart @@ -6,7 +6,6 @@ import 'dart:convert'; import 'dart:html'; import 'dart:typed_data'; -import 'package:http/http.dart' as http show readBytes; import 'package:meta/meta.dart'; import './base.dart'; @@ -16,16 +15,17 @@ import '../web_helpers/web_helpers.dart'; /// /// It wraps the bytes of a selected file. class XFile extends XFileBase { - String path; + late String path; - final String mimeType; - final Uint8List _data; - final int _length; + final String? mimeType; + final Uint8List? _data; + final int? _length; final String name; - final DateTime _lastModified; - Element _target; + final DateTime? _lastModified; - final CrossFileTestOverrides _overrides; + late Element _target; + + final CrossFileTestOverrides? _overrides; bool get _hasTestOverrides => _overrides != null; @@ -39,56 +39,58 @@ class XFile extends XFileBase { XFile( this.path, { this.mimeType, - this.name, - int length, - Uint8List bytes, - DateTime lastModified, - @visibleForTesting CrossFileTestOverrides overrides, + String? name, + int? length, + Uint8List? bytes, + DateTime? lastModified, + @visibleForTesting CrossFileTestOverrides? overrides, }) : _data = bytes, _length = length, _overrides = overrides, - _lastModified = lastModified, + _lastModified = lastModified ?? DateTime.fromMillisecondsSinceEpoch(0), + name = name ?? '', super(path); /// Construct an CrossFile from its data XFile.fromData( Uint8List bytes, { this.mimeType, - this.name, - int length, - DateTime lastModified, - this.path, - @visibleForTesting CrossFileTestOverrides overrides, + String? name, + int? length, + DateTime? lastModified, + String? path, + @visibleForTesting CrossFileTestOverrides? overrides, }) : _data = bytes, _length = length, _overrides = overrides, - _lastModified = lastModified, + _lastModified = lastModified ?? DateTime.fromMillisecondsSinceEpoch(0), + name = name ?? '', super(path) { if (path == null) { final blob = (mimeType == null) ? Blob([bytes]) : Blob([bytes], mimeType); this.path = Url.createObjectUrl(blob); + } else { + this.path = path; } } @override - Future lastModified() async { - if (_lastModified != null) { - return Future.value(_lastModified); - } - return null; - } + Future lastModified() async => Future.value(_lastModified); Future get _bytes async { if (_data != null) { - return Future.value(UnmodifiableUint8ListView(_data)); + return Future.value(UnmodifiableUint8ListView(_data!)); } - return http.readBytes(Uri.parse(path)); + + // We can force 'response' to be a byte buffer by passing responseType: + ByteBuffer? response = + (await HttpRequest.request(path, responseType: 'arraybuffer')).response; + + return response?.asUint8List() ?? Uint8List(0); } @override - Future length() async { - return _length ?? (await _bytes).length; - } + Future length() async => _length ?? (await _bytes).length; @override Future readAsString({Encoding encoding = utf8}) async { @@ -96,12 +98,10 @@ class XFile extends XFileBase { } @override - Future readAsBytes() async { - return Future.value(await _bytes); - } + Future readAsBytes() async => Future.value(await _bytes); @override - Stream openRead([int start, int end]) async* { + Stream openRead([int? start, int? end]) async* { final bytes = await _bytes; yield bytes.sublist(start ?? 0, end ?? bytes.length); } @@ -114,10 +114,9 @@ class XFile extends XFileBase { // Create an tag with the appropriate download attributes and click it // May be overridden with CrossFileTestOverrides - final AnchorElement element = - (_hasTestOverrides && _overrides.createAnchorElement != null) - ? _overrides.createAnchorElement(this.path, this.name) - : createAnchorElement(this.path, this.name); + final AnchorElement element = _hasTestOverrides + ? _overrides!.createAnchorElement(this.path, this.name) as AnchorElement + : createAnchorElement(this.path, this.name); // Clear the children in our container so we can add an element to click _target.children.clear(); @@ -132,5 +131,5 @@ class CrossFileTestOverrides { Element Function(String href, String suggestedName) createAnchorElement; /// Default constructor for overrides - CrossFileTestOverrides({this.createAnchorElement}); + CrossFileTestOverrides({required this.createAnchorElement}); } diff --git a/packages/cross_file/lib/src/types/interface.dart b/packages/cross_file/lib/src/types/interface.dart index e30bc63b4c92..122f3d1d9364 100644 --- a/packages/cross_file/lib/src/types/interface.dart +++ b/packages/cross_file/lib/src/types/interface.dart @@ -21,12 +21,12 @@ class XFile extends XFileBase { /// (like in web) XFile( String path, { - String mimeType, - String name, - int length, - Uint8List bytes, - DateTime lastModified, - @visibleForTesting CrossFileTestOverrides overrides, + String? mimeType, + String? name, + int? length, + Uint8List? bytes, + DateTime? lastModified, + @visibleForTesting CrossFileTestOverrides? overrides, }) : super(path) { throw UnimplementedError( 'CrossFile is not available in your current platform.'); @@ -35,12 +35,12 @@ class XFile extends XFileBase { /// Construct a CrossFile object from its data XFile.fromData( Uint8List bytes, { - String mimeType, - String name, - int length, - DateTime lastModified, - String path, - @visibleForTesting CrossFileTestOverrides overrides, + String? mimeType, + String? name, + int? length, + DateTime? lastModified, + String? path, + @visibleForTesting CrossFileTestOverrides? overrides, }) : super(path) { throw UnimplementedError( 'CrossFile is not available in your current platform.'); @@ -54,5 +54,5 @@ class CrossFileTestOverrides { dynamic Function(String href, String suggestedName) createAnchorElement; /// Default constructor for overrides - CrossFileTestOverrides({this.createAnchorElement}); + CrossFileTestOverrides({required this.createAnchorElement}); } diff --git a/packages/cross_file/lib/src/types/io.dart b/packages/cross_file/lib/src/types/io.dart index d9a93559b507..6eafaf0ce0cc 100644 --- a/packages/cross_file/lib/src/types/io.dart +++ b/packages/cross_file/lib/src/types/io.dart @@ -11,20 +11,20 @@ import './base.dart'; /// A CrossFile backed by a dart:io File. class XFile extends XFileBase { final File _file; - final String mimeType; - final DateTime _lastModified; - int _length; + final String? mimeType; + final DateTime? _lastModified; + int? _length; - final Uint8List _bytes; + final Uint8List? _bytes; /// Construct a CrossFile object backed by a dart:io File. XFile( String path, { this.mimeType, - String name, - int length, - Uint8List bytes, - DateTime lastModified, + String? name, + int? length, + Uint8List? bytes, + DateTime? lastModified, }) : _file = File(path), _bytes = null, _lastModified = lastModified, @@ -34,10 +34,10 @@ class XFile extends XFileBase { XFile.fromData( Uint8List bytes, { this.mimeType, - String path, - String name, - int length, - DateTime lastModified, + String? path, + String? name, + int? length, + DateTime? lastModified, }) : _bytes = bytes, _file = File(path ?? ''), _length = length, @@ -84,7 +84,7 @@ class XFile extends XFileBase { @override Future readAsString({Encoding encoding = utf8}) { if (_bytes != null) { - return Future.value(String.fromCharCodes(_bytes)); + return Future.value(String.fromCharCodes(_bytes!)); } return _file.readAsString(encoding: encoding); } @@ -97,13 +97,13 @@ class XFile extends XFileBase { return _file.readAsBytes(); } - Stream _getBytes(int start, int end) async* { - final bytes = _bytes; + Stream _getBytes(int? start, int? end) async* { + final bytes = _bytes!; yield bytes.sublist(start ?? 0, end ?? bytes.length); } @override - Stream openRead([int start, int end]) { + Stream openRead([int? start, int? end]) { if (_bytes != null) { return _getBytes(start, end); } else { diff --git a/packages/cross_file/lib/src/web_helpers/web_helpers.dart b/packages/cross_file/lib/src/web_helpers/web_helpers.dart index 813f5f975561..a963e9933f99 100644 --- a/packages/cross_file/lib/src/web_helpers/web_helpers.dart +++ b/packages/cross_file/lib/src/web_helpers/web_helpers.dart @@ -31,7 +31,7 @@ Element ensureInitialized(String id) { if (target == null) { final Element targetElement = Element.tag('flt-x-file')..id = id; - querySelector('body').children.add(targetElement); + querySelector('body')!.children.add(targetElement); target = targetElement; } return target; diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml index 2228674baf40..af1b7e7d4c0f 100644 --- a/packages/cross_file/pubspec.yaml +++ b/packages/cross_file/pubspec.yaml @@ -1,19 +1,18 @@ name: cross_file description: An abstraction to allow working with files across multiple platforms. homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file -version: 0.2.1 +version: 0.3.0-nullsafety dependencies: flutter: sdk: flutter - http: ^0.12.0+1 - meta: ^1.0.5 + meta: ^1.3.0-nullsafety.3 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.3 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.22.0" diff --git a/packages/cross_file/test/x_file_html_test.dart b/packages/cross_file/test/x_file_html_test.dart index fadba96b3c6c..a271aa1f1525 100644 --- a/packages/cross_file/test/x_file_html_test.dart +++ b/packages/cross_file/test/x_file_html_test.dart @@ -11,10 +11,8 @@ import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:cross_file/cross_file.dart'; -import 'dart:html'; - final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = utf8.encode(expectedStringContents); +final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); final html.File textFile = html.File([bytes], 'hello.txt'); final String textFileUrl = html.Url.createObjectUrl(textFile); @@ -66,7 +64,7 @@ void main() { await file.saveTo(''); - final container = querySelector('#${CrossFileDomElementId}'); + final container = html.querySelector('#${CrossFileDomElementId}'); expect(container, isNotNull); }); @@ -76,18 +74,18 @@ void main() { await file.saveTo('path'); - final container = querySelector('#${CrossFileDomElementId}'); - final AnchorElement element = container?.children?.firstWhere( - (element) => element.tagName == 'A', - orElse: () => null); + final container = html.querySelector('#${CrossFileDomElementId}'); + final html.AnchorElement element = + container?.children.firstWhere((element) => element.tagName == 'A') + as html.AnchorElement; - expect(element, isNotNull); + // if element is not found, the `firstWhere` call will throw StateError. expect(element.href, file.path); expect(element.download, file.name); }); test('anchor element is clicked', () async { - final mockAnchor = AnchorElement(); + final mockAnchor = html.AnchorElement(); CrossFileTestOverrides overrides = CrossFileTestOverrides( createAnchorElement: (_, __) => mockAnchor, diff --git a/packages/cross_file/test/x_file_io_test.dart b/packages/cross_file/test/x_file_io_test.dart index 65edea1ea45d..25f46a4edad9 100644 --- a/packages/cross_file/test/x_file_io_test.dart +++ b/packages/cross_file/test/x_file_io_test.dart @@ -24,7 +24,7 @@ import 'package:cross_file/cross_file.dart'; final pathPrefix = './assets/'; final path = pathPrefix + 'hello.txt'; final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = utf8.encode(expectedStringContents); +final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); final File textFile = File(path); final String textFilePath = textFile.path; diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 72390c213da9..3e08b914ff86 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -23,14 +23,15 @@ readonly EXCLUDED_PLUGINS_LIST=( "connectivity_platform_interface" "connectivity_web" "extension_google_sign_in_as_googleapis_auth" + "file_selector" # currently out of sync with camera "flutter_plugin_android_lifecycle" "google_maps_flutter_platform_interface" "google_maps_flutter_web" "google_sign_in_platform_interface" "google_sign_in_web" "image_picker_platform_interface" - "local_auth" # flutter_plugin_android_lifecycle conflict "instrumentation_adapter" + "local_auth" # flutter_plugin_android_lifecycle conflict "path_provider_linux" "path_provider_macos" "path_provider_platform_interface" diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index b2ca25bf6836..44e5df9e95ef 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -8,6 +8,7 @@ readonly NNBD_PLUGINS_LIST=( "android_intent" "battery" "connectivity" + "cross_file" "device_info" "flutter_plugin_android_lifecycle" "flutter_webview" From 98d87d0589b2895d0e027cedc98fd88baf6ab2ed Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 26 Jan 2021 14:17:07 -0800 Subject: [PATCH 125/924] [image_picker_platform_interface] fix test asset file location (#3467) --- packages/cross_file/test/x_file_io_test.dart | 15 +++------------ .../image_picker_platform_interface/CHANGELOG.md | 4 ++++ .../image_picker_platform_interface/pubspec.yaml | 2 +- .../test/picked_file_io_test.dart | 9 ++++++--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/cross_file/test/x_file_io_test.dart b/packages/cross_file/test/x_file_io_test.dart index 25f46a4edad9..94ac81c4cac4 100644 --- a/packages/cross_file/test/x_file_io_test.dart +++ b/packages/cross_file/test/x_file_io_test.dart @@ -11,17 +11,8 @@ import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:cross_file/cross_file.dart'; -// Please note that executing this test with command -// `flutter test test/x_file_io_test.dart` will set the directory -// to ./file_selector_platform_interface. -// -// This will cause our hello.txt file to be not be found. Please -// execute this test with `flutter test` or change the path prefix -// to ./test/assets/ -// -// https://github.com/flutter/flutter/issues/20907 - -final pathPrefix = './assets/'; +final pathPrefix = + Directory.current.path.endsWith('test') ? './assets/' : './test/assets/'; final path = pathPrefix + 'hello.txt'; final String expectedStringContents = 'Hello, world!'; final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); @@ -30,7 +21,7 @@ final String textFilePath = textFile.path; void main() { group('Create with a path', () { - final file = XFile(textFilePath); + final XFile file = XFile(textFilePath); test('Can be read as a string', () async { expect(await file.readAsString(), equals(expectedStringContents)); diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index efcef0146cdc..581cf1830610 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.6 + +* Fix test asset file location. + ## 1.1.5 * Update Flutter SDK constraint. diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 7943a2a3eccd..b9ad12a50eb6 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the image_picker plugin. 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.5 +version: 1.1.6 dependencies: flutter: diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart index 94ff759a2fb2..28c0886b864e 100644 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart @@ -11,14 +11,17 @@ import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; +final pathPrefix = + Directory.current.path.endsWith('test') ? './assets/' : './test/assets/'; +final path = pathPrefix + 'hello.txt'; final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = utf8.encode(expectedStringContents); -final File textFile = File('./assets/hello.txt'); +final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); +final File textFile = File(path); final String textFilePath = textFile.path; void main() { group('Create with an objectUrl', () { - final pickedFile = PickedFile(textFilePath); + final PickedFile pickedFile = PickedFile(textFilePath); test('Can be read as a string', () async { expect(await pickedFile.readAsString(), equals(expectedStringContents)); From 4aacf970f3891c9cf23c768ca1c8bec04c42b35a Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 26 Jan 2021 17:33:26 -0800 Subject: [PATCH 126/924] Revert "[cross_file] Migrate to null-safety. (#3452)" (#3468) This reverts commit ca9921196a7ae96edad91a9cd7b7d8fe9f5689ff. --- packages/cross_file/CHANGELOG.md | 12 +-- packages/cross_file/lib/src/types/base.dart | 10 +-- packages/cross_file/lib/src/types/html.dart | 79 ++++++++++--------- .../cross_file/lib/src/types/interface.dart | 26 +++--- packages/cross_file/lib/src/types/io.dart | 32 ++++---- .../lib/src/web_helpers/web_helpers.dart | 2 +- packages/cross_file/pubspec.yaml | 9 ++- .../cross_file/test/x_file_html_test.dart | 18 +++-- packages/cross_file/test/x_file_io_test.dart | 2 +- script/build_all_plugins_app.sh | 3 +- script/nnbd_plugins.sh | 1 - 11 files changed, 95 insertions(+), 99 deletions(-) diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md index c9b3d1ab2522..45f516ad334d 100644 --- a/packages/cross_file/CHANGELOG.md +++ b/packages/cross_file/CHANGELOG.md @@ -1,12 +1,6 @@ -## 0.3.0-nullsafety - -* Migrated package to null-safety. -* **breaking change** According to our unit tests, the API should be backwards-compatible. Some relevant changes were made, however: - * Web: `lastModified` returns the epoch time as a default value, to maintain the `Future` return type (and not `null`) - ## 0.2.1 -* Prepare for breaking `package:http` change. +* Prepare for breaking `package:http` change. ## 0.2.0 @@ -18,8 +12,8 @@ ## 0.1.0+1 -* Update Flutter SDK constraint. +- Update Flutter SDK constraint. ## 0.1.0 -* Initial open-source release. +- Initial open-source release diff --git a/packages/cross_file/lib/src/types/base.dart b/packages/cross_file/lib/src/types/base.dart index 2a59c1c2b246..1a1b5694d58f 100644 --- a/packages/cross_file/lib/src/types/base.dart +++ b/packages/cross_file/lib/src/types/base.dart @@ -15,7 +15,7 @@ import 'dart:typed_data'; /// the methods should seem familiar. abstract class XFileBase { /// Construct a CrossFile - XFileBase(String? path); + XFileBase(String path); /// Save the CrossFile at the indicated file path. Future saveTo(String path) { @@ -31,19 +31,19 @@ abstract class XFileBase { /// Accessing the data contained in the picked file by its path /// is platform-dependant (and won't work on web), so use the /// byte getters in the CrossFile instance instead. - String? get path { + String get path { throw UnimplementedError('.path has not been implemented.'); } /// The name of the file as it was selected by the user in their device. /// /// Use only for cosmetic reasons, do not try to use this as a path. - String? get name { + String get name { throw UnimplementedError('.name has not been implemented.'); } /// For web, it may be necessary for a file to know its MIME type. - String? get mimeType { + String get mimeType { throw UnimplementedError('.mimeType has not been implemented.'); } @@ -75,7 +75,7 @@ abstract class XFileBase { /// 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 openRead([int? start, int? end]) { + Stream openRead([int start, int end]) { throw UnimplementedError('openRead() has not been implemented.'); } diff --git a/packages/cross_file/lib/src/types/html.dart b/packages/cross_file/lib/src/types/html.dart index 203ab5d82e12..527d5e6911f6 100644 --- a/packages/cross_file/lib/src/types/html.dart +++ b/packages/cross_file/lib/src/types/html.dart @@ -6,6 +6,7 @@ import 'dart:convert'; import 'dart:html'; import 'dart:typed_data'; +import 'package:http/http.dart' as http show readBytes; import 'package:meta/meta.dart'; import './base.dart'; @@ -15,17 +16,16 @@ import '../web_helpers/web_helpers.dart'; /// /// It wraps the bytes of a selected file. class XFile extends XFileBase { - late String path; + String path; - final String? mimeType; - final Uint8List? _data; - final int? _length; + final String mimeType; + final Uint8List _data; + final int _length; final String name; - final DateTime? _lastModified; + final DateTime _lastModified; + Element _target; - late Element _target; - - final CrossFileTestOverrides? _overrides; + final CrossFileTestOverrides _overrides; bool get _hasTestOverrides => _overrides != null; @@ -39,58 +39,56 @@ class XFile extends XFileBase { XFile( this.path, { this.mimeType, - String? name, - int? length, - Uint8List? bytes, - DateTime? lastModified, - @visibleForTesting CrossFileTestOverrides? overrides, + this.name, + int length, + Uint8List bytes, + DateTime lastModified, + @visibleForTesting CrossFileTestOverrides overrides, }) : _data = bytes, _length = length, _overrides = overrides, - _lastModified = lastModified ?? DateTime.fromMillisecondsSinceEpoch(0), - name = name ?? '', + _lastModified = lastModified, super(path); /// Construct an CrossFile from its data XFile.fromData( Uint8List bytes, { this.mimeType, - String? name, - int? length, - DateTime? lastModified, - String? path, - @visibleForTesting CrossFileTestOverrides? overrides, + this.name, + int length, + DateTime lastModified, + this.path, + @visibleForTesting CrossFileTestOverrides overrides, }) : _data = bytes, _length = length, _overrides = overrides, - _lastModified = lastModified ?? DateTime.fromMillisecondsSinceEpoch(0), - name = name ?? '', + _lastModified = lastModified, super(path) { if (path == null) { final blob = (mimeType == null) ? Blob([bytes]) : Blob([bytes], mimeType); this.path = Url.createObjectUrl(blob); - } else { - this.path = path; } } @override - Future lastModified() async => Future.value(_lastModified); + Future lastModified() async { + if (_lastModified != null) { + return Future.value(_lastModified); + } + return null; + } Future get _bytes async { if (_data != null) { - return Future.value(UnmodifiableUint8ListView(_data!)); + return Future.value(UnmodifiableUint8ListView(_data)); } - - // We can force 'response' to be a byte buffer by passing responseType: - ByteBuffer? response = - (await HttpRequest.request(path, responseType: 'arraybuffer')).response; - - return response?.asUint8List() ?? Uint8List(0); + return http.readBytes(Uri.parse(path)); } @override - Future length() async => _length ?? (await _bytes).length; + Future length() async { + return _length ?? (await _bytes).length; + } @override Future readAsString({Encoding encoding = utf8}) async { @@ -98,10 +96,12 @@ class XFile extends XFileBase { } @override - Future readAsBytes() async => Future.value(await _bytes); + Future readAsBytes() async { + return Future.value(await _bytes); + } @override - Stream openRead([int? start, int? end]) async* { + Stream openRead([int start, int end]) async* { final bytes = await _bytes; yield bytes.sublist(start ?? 0, end ?? bytes.length); } @@ -114,9 +114,10 @@ class XFile extends XFileBase { // Create an tag with the appropriate download attributes and click it // May be overridden with CrossFileTestOverrides - final AnchorElement element = _hasTestOverrides - ? _overrides!.createAnchorElement(this.path, this.name) as AnchorElement - : createAnchorElement(this.path, this.name); + final AnchorElement element = + (_hasTestOverrides && _overrides.createAnchorElement != null) + ? _overrides.createAnchorElement(this.path, this.name) + : createAnchorElement(this.path, this.name); // Clear the children in our container so we can add an element to click _target.children.clear(); @@ -131,5 +132,5 @@ class CrossFileTestOverrides { Element Function(String href, String suggestedName) createAnchorElement; /// Default constructor for overrides - CrossFileTestOverrides({required this.createAnchorElement}); + CrossFileTestOverrides({this.createAnchorElement}); } diff --git a/packages/cross_file/lib/src/types/interface.dart b/packages/cross_file/lib/src/types/interface.dart index 122f3d1d9364..e30bc63b4c92 100644 --- a/packages/cross_file/lib/src/types/interface.dart +++ b/packages/cross_file/lib/src/types/interface.dart @@ -21,12 +21,12 @@ class XFile extends XFileBase { /// (like in web) XFile( String path, { - String? mimeType, - String? name, - int? length, - Uint8List? bytes, - DateTime? lastModified, - @visibleForTesting CrossFileTestOverrides? overrides, + String mimeType, + String name, + int length, + Uint8List bytes, + DateTime lastModified, + @visibleForTesting CrossFileTestOverrides overrides, }) : super(path) { throw UnimplementedError( 'CrossFile is not available in your current platform.'); @@ -35,12 +35,12 @@ class XFile extends XFileBase { /// Construct a CrossFile object from its data XFile.fromData( Uint8List bytes, { - String? mimeType, - String? name, - int? length, - DateTime? lastModified, - String? path, - @visibleForTesting CrossFileTestOverrides? overrides, + String mimeType, + String name, + int length, + DateTime lastModified, + String path, + @visibleForTesting CrossFileTestOverrides overrides, }) : super(path) { throw UnimplementedError( 'CrossFile is not available in your current platform.'); @@ -54,5 +54,5 @@ class CrossFileTestOverrides { dynamic Function(String href, String suggestedName) createAnchorElement; /// Default constructor for overrides - CrossFileTestOverrides({required this.createAnchorElement}); + CrossFileTestOverrides({this.createAnchorElement}); } diff --git a/packages/cross_file/lib/src/types/io.dart b/packages/cross_file/lib/src/types/io.dart index 6eafaf0ce0cc..d9a93559b507 100644 --- a/packages/cross_file/lib/src/types/io.dart +++ b/packages/cross_file/lib/src/types/io.dart @@ -11,20 +11,20 @@ import './base.dart'; /// A CrossFile backed by a dart:io File. class XFile extends XFileBase { final File _file; - final String? mimeType; - final DateTime? _lastModified; - int? _length; + final String mimeType; + final DateTime _lastModified; + int _length; - final Uint8List? _bytes; + final Uint8List _bytes; /// Construct a CrossFile object backed by a dart:io File. XFile( String path, { this.mimeType, - String? name, - int? length, - Uint8List? bytes, - DateTime? lastModified, + String name, + int length, + Uint8List bytes, + DateTime lastModified, }) : _file = File(path), _bytes = null, _lastModified = lastModified, @@ -34,10 +34,10 @@ class XFile extends XFileBase { XFile.fromData( Uint8List bytes, { this.mimeType, - String? path, - String? name, - int? length, - DateTime? lastModified, + String path, + String name, + int length, + DateTime lastModified, }) : _bytes = bytes, _file = File(path ?? ''), _length = length, @@ -84,7 +84,7 @@ class XFile extends XFileBase { @override Future readAsString({Encoding encoding = utf8}) { if (_bytes != null) { - return Future.value(String.fromCharCodes(_bytes!)); + return Future.value(String.fromCharCodes(_bytes)); } return _file.readAsString(encoding: encoding); } @@ -97,13 +97,13 @@ class XFile extends XFileBase { return _file.readAsBytes(); } - Stream _getBytes(int? start, int? end) async* { - final bytes = _bytes!; + Stream _getBytes(int start, int end) async* { + final bytes = _bytes; yield bytes.sublist(start ?? 0, end ?? bytes.length); } @override - Stream openRead([int? start, int? end]) { + Stream openRead([int start, int end]) { if (_bytes != null) { return _getBytes(start, end); } else { diff --git a/packages/cross_file/lib/src/web_helpers/web_helpers.dart b/packages/cross_file/lib/src/web_helpers/web_helpers.dart index a963e9933f99..813f5f975561 100644 --- a/packages/cross_file/lib/src/web_helpers/web_helpers.dart +++ b/packages/cross_file/lib/src/web_helpers/web_helpers.dart @@ -31,7 +31,7 @@ Element ensureInitialized(String id) { if (target == null) { final Element targetElement = Element.tag('flt-x-file')..id = id; - querySelector('body')!.children.add(targetElement); + querySelector('body').children.add(targetElement); target = targetElement; } return target; diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml index af1b7e7d4c0f..2228674baf40 100644 --- a/packages/cross_file/pubspec.yaml +++ b/packages/cross_file/pubspec.yaml @@ -1,18 +1,19 @@ name: cross_file description: An abstraction to allow working with files across multiple platforms. homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file -version: 0.3.0-nullsafety +version: 0.2.1 dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety.3 + http: ^0.12.0+1 + meta: ^1.0.5 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.3 + pedantic: ^1.8.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.1.0 <3.0.0" flutter: ">=1.22.0" diff --git a/packages/cross_file/test/x_file_html_test.dart b/packages/cross_file/test/x_file_html_test.dart index a271aa1f1525..fadba96b3c6c 100644 --- a/packages/cross_file/test/x_file_html_test.dart +++ b/packages/cross_file/test/x_file_html_test.dart @@ -11,8 +11,10 @@ import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:cross_file/cross_file.dart'; +import 'dart:html'; + final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); +final Uint8List bytes = utf8.encode(expectedStringContents); final html.File textFile = html.File([bytes], 'hello.txt'); final String textFileUrl = html.Url.createObjectUrl(textFile); @@ -64,7 +66,7 @@ void main() { await file.saveTo(''); - final container = html.querySelector('#${CrossFileDomElementId}'); + final container = querySelector('#${CrossFileDomElementId}'); expect(container, isNotNull); }); @@ -74,18 +76,18 @@ void main() { await file.saveTo('path'); - final container = html.querySelector('#${CrossFileDomElementId}'); - final html.AnchorElement element = - container?.children.firstWhere((element) => element.tagName == 'A') - as html.AnchorElement; + final container = querySelector('#${CrossFileDomElementId}'); + final AnchorElement element = container?.children?.firstWhere( + (element) => element.tagName == 'A', + orElse: () => null); - // if element is not found, the `firstWhere` call will throw StateError. + expect(element, isNotNull); expect(element.href, file.path); expect(element.download, file.name); }); test('anchor element is clicked', () async { - final mockAnchor = html.AnchorElement(); + final mockAnchor = AnchorElement(); CrossFileTestOverrides overrides = CrossFileTestOverrides( createAnchorElement: (_, __) => mockAnchor, diff --git a/packages/cross_file/test/x_file_io_test.dart b/packages/cross_file/test/x_file_io_test.dart index 94ac81c4cac4..d45ff599fec1 100644 --- a/packages/cross_file/test/x_file_io_test.dart +++ b/packages/cross_file/test/x_file_io_test.dart @@ -15,7 +15,7 @@ final pathPrefix = Directory.current.path.endsWith('test') ? './assets/' : './test/assets/'; final path = pathPrefix + 'hello.txt'; final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); +final Uint8List bytes = utf8.encode(expectedStringContents); final File textFile = File(path); final String textFilePath = textFile.path; diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 3e08b914ff86..72390c213da9 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -23,15 +23,14 @@ readonly EXCLUDED_PLUGINS_LIST=( "connectivity_platform_interface" "connectivity_web" "extension_google_sign_in_as_googleapis_auth" - "file_selector" # currently out of sync with camera "flutter_plugin_android_lifecycle" "google_maps_flutter_platform_interface" "google_maps_flutter_web" "google_sign_in_platform_interface" "google_sign_in_web" "image_picker_platform_interface" - "instrumentation_adapter" "local_auth" # flutter_plugin_android_lifecycle conflict + "instrumentation_adapter" "path_provider_linux" "path_provider_macos" "path_provider_platform_interface" diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 44e5df9e95ef..b2ca25bf6836 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -8,7 +8,6 @@ readonly NNBD_PLUGINS_LIST=( "android_intent" "battery" "connectivity" - "cross_file" "device_info" "flutter_plugin_android_lifecycle" "flutter_webview" From 16f3281b04b0db12e609352b1c9544901392e428 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 26 Jan 2021 18:14:52 -0800 Subject: [PATCH 127/924] Reland "[cross_file] Migrate to null-safety. (#3452)" (#3469) This reverts commit 4aacf970f3891c9cf23c768ca1c8bec04c42b35a. --- packages/cross_file/CHANGELOG.md | 12 ++- packages/cross_file/lib/src/types/base.dart | 10 +-- packages/cross_file/lib/src/types/html.dart | 79 +++++++++---------- .../cross_file/lib/src/types/interface.dart | 26 +++--- packages/cross_file/lib/src/types/io.dart | 32 ++++---- .../lib/src/web_helpers/web_helpers.dart | 2 +- packages/cross_file/pubspec.yaml | 9 +-- .../cross_file/test/x_file_html_test.dart | 18 ++--- packages/cross_file/test/x_file_io_test.dart | 2 +- script/build_all_plugins_app.sh | 3 +- script/nnbd_plugins.sh | 1 + 11 files changed, 99 insertions(+), 95 deletions(-) diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md index 45f516ad334d..c9b3d1ab2522 100644 --- a/packages/cross_file/CHANGELOG.md +++ b/packages/cross_file/CHANGELOG.md @@ -1,6 +1,12 @@ +## 0.3.0-nullsafety + +* Migrated package to null-safety. +* **breaking change** According to our unit tests, the API should be backwards-compatible. Some relevant changes were made, however: + * Web: `lastModified` returns the epoch time as a default value, to maintain the `Future` return type (and not `null`) + ## 0.2.1 -* Prepare for breaking `package:http` change. +* Prepare for breaking `package:http` change. ## 0.2.0 @@ -12,8 +18,8 @@ ## 0.1.0+1 -- Update Flutter SDK constraint. +* Update Flutter SDK constraint. ## 0.1.0 -- Initial open-source release +* Initial open-source release. diff --git a/packages/cross_file/lib/src/types/base.dart b/packages/cross_file/lib/src/types/base.dart index 1a1b5694d58f..2a59c1c2b246 100644 --- a/packages/cross_file/lib/src/types/base.dart +++ b/packages/cross_file/lib/src/types/base.dart @@ -15,7 +15,7 @@ import 'dart:typed_data'; /// the methods should seem familiar. abstract class XFileBase { /// Construct a CrossFile - XFileBase(String path); + XFileBase(String? path); /// Save the CrossFile at the indicated file path. Future saveTo(String path) { @@ -31,19 +31,19 @@ abstract class XFileBase { /// Accessing the data contained in the picked file by its path /// is platform-dependant (and won't work on web), so use the /// byte getters in the CrossFile instance instead. - String get path { + String? get path { throw UnimplementedError('.path has not been implemented.'); } /// The name of the file as it was selected by the user in their device. /// /// Use only for cosmetic reasons, do not try to use this as a path. - String get name { + String? get name { throw UnimplementedError('.name has not been implemented.'); } /// For web, it may be necessary for a file to know its MIME type. - String get mimeType { + String? get mimeType { throw UnimplementedError('.mimeType has not been implemented.'); } @@ -75,7 +75,7 @@ abstract class XFileBase { /// 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 openRead([int start, int end]) { + Stream openRead([int? start, int? end]) { throw UnimplementedError('openRead() has not been implemented.'); } diff --git a/packages/cross_file/lib/src/types/html.dart b/packages/cross_file/lib/src/types/html.dart index 527d5e6911f6..203ab5d82e12 100644 --- a/packages/cross_file/lib/src/types/html.dart +++ b/packages/cross_file/lib/src/types/html.dart @@ -6,7 +6,6 @@ import 'dart:convert'; import 'dart:html'; import 'dart:typed_data'; -import 'package:http/http.dart' as http show readBytes; import 'package:meta/meta.dart'; import './base.dart'; @@ -16,16 +15,17 @@ import '../web_helpers/web_helpers.dart'; /// /// It wraps the bytes of a selected file. class XFile extends XFileBase { - String path; + late String path; - final String mimeType; - final Uint8List _data; - final int _length; + final String? mimeType; + final Uint8List? _data; + final int? _length; final String name; - final DateTime _lastModified; - Element _target; + final DateTime? _lastModified; - final CrossFileTestOverrides _overrides; + late Element _target; + + final CrossFileTestOverrides? _overrides; bool get _hasTestOverrides => _overrides != null; @@ -39,56 +39,58 @@ class XFile extends XFileBase { XFile( this.path, { this.mimeType, - this.name, - int length, - Uint8List bytes, - DateTime lastModified, - @visibleForTesting CrossFileTestOverrides overrides, + String? name, + int? length, + Uint8List? bytes, + DateTime? lastModified, + @visibleForTesting CrossFileTestOverrides? overrides, }) : _data = bytes, _length = length, _overrides = overrides, - _lastModified = lastModified, + _lastModified = lastModified ?? DateTime.fromMillisecondsSinceEpoch(0), + name = name ?? '', super(path); /// Construct an CrossFile from its data XFile.fromData( Uint8List bytes, { this.mimeType, - this.name, - int length, - DateTime lastModified, - this.path, - @visibleForTesting CrossFileTestOverrides overrides, + String? name, + int? length, + DateTime? lastModified, + String? path, + @visibleForTesting CrossFileTestOverrides? overrides, }) : _data = bytes, _length = length, _overrides = overrides, - _lastModified = lastModified, + _lastModified = lastModified ?? DateTime.fromMillisecondsSinceEpoch(0), + name = name ?? '', super(path) { if (path == null) { final blob = (mimeType == null) ? Blob([bytes]) : Blob([bytes], mimeType); this.path = Url.createObjectUrl(blob); + } else { + this.path = path; } } @override - Future lastModified() async { - if (_lastModified != null) { - return Future.value(_lastModified); - } - return null; - } + Future lastModified() async => Future.value(_lastModified); Future get _bytes async { if (_data != null) { - return Future.value(UnmodifiableUint8ListView(_data)); + return Future.value(UnmodifiableUint8ListView(_data!)); } - return http.readBytes(Uri.parse(path)); + + // We can force 'response' to be a byte buffer by passing responseType: + ByteBuffer? response = + (await HttpRequest.request(path, responseType: 'arraybuffer')).response; + + return response?.asUint8List() ?? Uint8List(0); } @override - Future length() async { - return _length ?? (await _bytes).length; - } + Future length() async => _length ?? (await _bytes).length; @override Future readAsString({Encoding encoding = utf8}) async { @@ -96,12 +98,10 @@ class XFile extends XFileBase { } @override - Future readAsBytes() async { - return Future.value(await _bytes); - } + Future readAsBytes() async => Future.value(await _bytes); @override - Stream openRead([int start, int end]) async* { + Stream openRead([int? start, int? end]) async* { final bytes = await _bytes; yield bytes.sublist(start ?? 0, end ?? bytes.length); } @@ -114,10 +114,9 @@ class XFile extends XFileBase { // Create an tag with the appropriate download attributes and click it // May be overridden with CrossFileTestOverrides - final AnchorElement element = - (_hasTestOverrides && _overrides.createAnchorElement != null) - ? _overrides.createAnchorElement(this.path, this.name) - : createAnchorElement(this.path, this.name); + final AnchorElement element = _hasTestOverrides + ? _overrides!.createAnchorElement(this.path, this.name) as AnchorElement + : createAnchorElement(this.path, this.name); // Clear the children in our container so we can add an element to click _target.children.clear(); @@ -132,5 +131,5 @@ class CrossFileTestOverrides { Element Function(String href, String suggestedName) createAnchorElement; /// Default constructor for overrides - CrossFileTestOverrides({this.createAnchorElement}); + CrossFileTestOverrides({required this.createAnchorElement}); } diff --git a/packages/cross_file/lib/src/types/interface.dart b/packages/cross_file/lib/src/types/interface.dart index e30bc63b4c92..122f3d1d9364 100644 --- a/packages/cross_file/lib/src/types/interface.dart +++ b/packages/cross_file/lib/src/types/interface.dart @@ -21,12 +21,12 @@ class XFile extends XFileBase { /// (like in web) XFile( String path, { - String mimeType, - String name, - int length, - Uint8List bytes, - DateTime lastModified, - @visibleForTesting CrossFileTestOverrides overrides, + String? mimeType, + String? name, + int? length, + Uint8List? bytes, + DateTime? lastModified, + @visibleForTesting CrossFileTestOverrides? overrides, }) : super(path) { throw UnimplementedError( 'CrossFile is not available in your current platform.'); @@ -35,12 +35,12 @@ class XFile extends XFileBase { /// Construct a CrossFile object from its data XFile.fromData( Uint8List bytes, { - String mimeType, - String name, - int length, - DateTime lastModified, - String path, - @visibleForTesting CrossFileTestOverrides overrides, + String? mimeType, + String? name, + int? length, + DateTime? lastModified, + String? path, + @visibleForTesting CrossFileTestOverrides? overrides, }) : super(path) { throw UnimplementedError( 'CrossFile is not available in your current platform.'); @@ -54,5 +54,5 @@ class CrossFileTestOverrides { dynamic Function(String href, String suggestedName) createAnchorElement; /// Default constructor for overrides - CrossFileTestOverrides({this.createAnchorElement}); + CrossFileTestOverrides({required this.createAnchorElement}); } diff --git a/packages/cross_file/lib/src/types/io.dart b/packages/cross_file/lib/src/types/io.dart index d9a93559b507..6eafaf0ce0cc 100644 --- a/packages/cross_file/lib/src/types/io.dart +++ b/packages/cross_file/lib/src/types/io.dart @@ -11,20 +11,20 @@ import './base.dart'; /// A CrossFile backed by a dart:io File. class XFile extends XFileBase { final File _file; - final String mimeType; - final DateTime _lastModified; - int _length; + final String? mimeType; + final DateTime? _lastModified; + int? _length; - final Uint8List _bytes; + final Uint8List? _bytes; /// Construct a CrossFile object backed by a dart:io File. XFile( String path, { this.mimeType, - String name, - int length, - Uint8List bytes, - DateTime lastModified, + String? name, + int? length, + Uint8List? bytes, + DateTime? lastModified, }) : _file = File(path), _bytes = null, _lastModified = lastModified, @@ -34,10 +34,10 @@ class XFile extends XFileBase { XFile.fromData( Uint8List bytes, { this.mimeType, - String path, - String name, - int length, - DateTime lastModified, + String? path, + String? name, + int? length, + DateTime? lastModified, }) : _bytes = bytes, _file = File(path ?? ''), _length = length, @@ -84,7 +84,7 @@ class XFile extends XFileBase { @override Future readAsString({Encoding encoding = utf8}) { if (_bytes != null) { - return Future.value(String.fromCharCodes(_bytes)); + return Future.value(String.fromCharCodes(_bytes!)); } return _file.readAsString(encoding: encoding); } @@ -97,13 +97,13 @@ class XFile extends XFileBase { return _file.readAsBytes(); } - Stream _getBytes(int start, int end) async* { - final bytes = _bytes; + Stream _getBytes(int? start, int? end) async* { + final bytes = _bytes!; yield bytes.sublist(start ?? 0, end ?? bytes.length); } @override - Stream openRead([int start, int end]) { + Stream openRead([int? start, int? end]) { if (_bytes != null) { return _getBytes(start, end); } else { diff --git a/packages/cross_file/lib/src/web_helpers/web_helpers.dart b/packages/cross_file/lib/src/web_helpers/web_helpers.dart index 813f5f975561..a963e9933f99 100644 --- a/packages/cross_file/lib/src/web_helpers/web_helpers.dart +++ b/packages/cross_file/lib/src/web_helpers/web_helpers.dart @@ -31,7 +31,7 @@ Element ensureInitialized(String id) { if (target == null) { final Element targetElement = Element.tag('flt-x-file')..id = id; - querySelector('body').children.add(targetElement); + querySelector('body')!.children.add(targetElement); target = targetElement; } return target; diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml index 2228674baf40..af1b7e7d4c0f 100644 --- a/packages/cross_file/pubspec.yaml +++ b/packages/cross_file/pubspec.yaml @@ -1,19 +1,18 @@ name: cross_file description: An abstraction to allow working with files across multiple platforms. homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file -version: 0.2.1 +version: 0.3.0-nullsafety dependencies: flutter: sdk: flutter - http: ^0.12.0+1 - meta: ^1.0.5 + meta: ^1.3.0-nullsafety.3 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.3 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.22.0" diff --git a/packages/cross_file/test/x_file_html_test.dart b/packages/cross_file/test/x_file_html_test.dart index fadba96b3c6c..a271aa1f1525 100644 --- a/packages/cross_file/test/x_file_html_test.dart +++ b/packages/cross_file/test/x_file_html_test.dart @@ -11,10 +11,8 @@ import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:cross_file/cross_file.dart'; -import 'dart:html'; - final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = utf8.encode(expectedStringContents); +final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); final html.File textFile = html.File([bytes], 'hello.txt'); final String textFileUrl = html.Url.createObjectUrl(textFile); @@ -66,7 +64,7 @@ void main() { await file.saveTo(''); - final container = querySelector('#${CrossFileDomElementId}'); + final container = html.querySelector('#${CrossFileDomElementId}'); expect(container, isNotNull); }); @@ -76,18 +74,18 @@ void main() { await file.saveTo('path'); - final container = querySelector('#${CrossFileDomElementId}'); - final AnchorElement element = container?.children?.firstWhere( - (element) => element.tagName == 'A', - orElse: () => null); + final container = html.querySelector('#${CrossFileDomElementId}'); + final html.AnchorElement element = + container?.children.firstWhere((element) => element.tagName == 'A') + as html.AnchorElement; - expect(element, isNotNull); + // if element is not found, the `firstWhere` call will throw StateError. expect(element.href, file.path); expect(element.download, file.name); }); test('anchor element is clicked', () async { - final mockAnchor = AnchorElement(); + final mockAnchor = html.AnchorElement(); CrossFileTestOverrides overrides = CrossFileTestOverrides( createAnchorElement: (_, __) => mockAnchor, diff --git a/packages/cross_file/test/x_file_io_test.dart b/packages/cross_file/test/x_file_io_test.dart index d45ff599fec1..94ac81c4cac4 100644 --- a/packages/cross_file/test/x_file_io_test.dart +++ b/packages/cross_file/test/x_file_io_test.dart @@ -15,7 +15,7 @@ final pathPrefix = Directory.current.path.endsWith('test') ? './assets/' : './test/assets/'; final path = pathPrefix + 'hello.txt'; final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = utf8.encode(expectedStringContents); +final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); final File textFile = File(path); final String textFilePath = textFile.path; diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 72390c213da9..3e08b914ff86 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -23,14 +23,15 @@ readonly EXCLUDED_PLUGINS_LIST=( "connectivity_platform_interface" "connectivity_web" "extension_google_sign_in_as_googleapis_auth" + "file_selector" # currently out of sync with camera "flutter_plugin_android_lifecycle" "google_maps_flutter_platform_interface" "google_maps_flutter_web" "google_sign_in_platform_interface" "google_sign_in_web" "image_picker_platform_interface" - "local_auth" # flutter_plugin_android_lifecycle conflict "instrumentation_adapter" + "local_auth" # flutter_plugin_android_lifecycle conflict "path_provider_linux" "path_provider_macos" "path_provider_platform_interface" diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index b2ca25bf6836..44e5df9e95ef 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -8,6 +8,7 @@ readonly NNBD_PLUGINS_LIST=( "android_intent" "battery" "connectivity" + "cross_file" "device_info" "flutter_plugin_android_lifecycle" "flutter_webview" From 8f66b2ded6de6fae80f1141d251d9f6342e38db2 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 28 Jan 2021 12:22:33 -0800 Subject: [PATCH 128/924] [ci] fix ci failure on ios builds (#3470) --- .cirrus.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.cirrus.yml b/.cirrus.yml index 4ec73ea3f24c..1f82270163fb 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -191,6 +191,7 @@ task: # https://github.com/flutter/flutter/issues/42864 - if [[ "$CHANNEL" -eq "stable" ]]; then find . | grep _web$ | xargs rm -rf; fi - flutter channel $CHANNEL + - flutter upgrade - ./script/incremental_build.sh build-examples --ipa - ./script/incremental_build.sh drive-examples - ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS From cd358b07e7bca7fc56e4add8870f69c86852b83a Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Thu, 28 Jan 2021 17:06:03 -0800 Subject: [PATCH 129/924] [package_info] Register IntegrationTestPlugin in the example app. (#3478) This change registers the IntegrationTestPlugin in the example app, so test results are correctly reported back to FTL. The end-to-end firebase tests for package_info haven't passed in a while (nor have been reported as broken before), but after this change, they start passing again. --- packages/package_info/CHANGELOG.md | 4 ++++ .../plugins/packageinfoexample/EmbedderV1Activity.java | 3 +++ packages/package_info/pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/package_info/CHANGELOG.md b/packages/package_info/CHANGELOG.md index ebb95c1da17e..f3f7734a4082 100644 --- a/packages/package_info/CHANGELOG.md +++ b/packages/package_info/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.3+4 + +* Ensure `IntegrationTestPlugin` is registered in `example` app, so Firebase Test Lab tests report test results correctly. [Issue](https://github.com/flutter/flutter/issues/74944). + ## 0.4.3+3 * Update Flutter SDK constraint. diff --git a/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java b/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java index a32c50484838..eb669bf16109 100644 --- a/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java +++ b/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java @@ -5,6 +5,7 @@ package io.flutter.plugins.packageinfoexample; import android.os.Bundle; +import dev.flutter.plugins.integration_test.IntegrationTestPlugin; import io.flutter.app.FlutterActivity; import io.flutter.plugins.packageinfo.PackageInfoPlugin; @@ -14,5 +15,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); PackageInfoPlugin.registerWith( registrarFor("io.flutter.plugins.packageinfo.PackageInfoPlugin")); + IntegrationTestPlugin.registerWith( + registrarFor("dev.flutter.plugins.integration_test.IntegrationTestPlugin")); } } diff --git a/packages/package_info/pubspec.yaml b/packages/package_info/pubspec.yaml index 884a71659a48..25e45a6be7bc 100644 --- a/packages/package_info/pubspec.yaml +++ b/packages/package_info/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/package_info # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.3+3 +version: 0.4.3+4 flutter: plugin: From 07dade429d22ca7d8659db2d2fde2fde3acfaae6 Mon Sep 17 00:00:00 2001 From: Jia Hao Date: Fri, 29 Jan 2021 10:34:57 +0800 Subject: [PATCH 130/924] [integration_test] Fix tests from changes to `flutter test` machine output (#3480) --- packages/integration_test/CHANGELOG.md | 4 ++++ packages/integration_test/pubspec.yaml | 2 +- packages/integration_test/test/binding_fail_test.dart | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/integration_test/CHANGELOG.md b/packages/integration_test/CHANGELOG.md index 5ae0883ed081..71ab0e86266b 100644 --- a/packages/integration_test/CHANGELOG.md +++ b/packages/integration_test/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2+2 + +* Fix tests from changes to `flutter test` machine output. + ## 1.0.2+1 * Update vm_service constraint diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index a233f066ea37..33c174a9724a 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -1,6 +1,6 @@ name: integration_test description: Runs tests that use the flutter_test API as integration tests. -version: 1.0.2+1 +version: 1.0.2+2 homepage: https://github.com/flutter/plugins/tree/master/packages/integration_test environment: diff --git a/packages/integration_test/test/binding_fail_test.dart b/packages/integration_test/test/binding_fail_test.dart index bb5961b18fc7..7ec176897c0c 100644 --- a/packages/integration_test/test/binding_fail_test.dart +++ b/packages/integration_test/test/binding_fail_test.dart @@ -61,13 +61,18 @@ Future> _runTest(String scriptPath) async { final String testResults = (await process.stdout .transform(utf8.decoder) .expand((String text) => text.split('\n')) - .map((String line) { + .map((String line) { try { return jsonDecode(line); } on FormatException { // Only interested in test events which are JSON. } }) + .expand>((dynamic json) { + return json is List + ? json.cast() + : >[json as Map]; + }) .where((dynamic testEvent) => testEvent != null && testEvent['type'] == 'print') .map((dynamic printEvent) => printEvent['message'] as String) From 647f69875803314f044730847a2263cd71c714e6 Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Fri, 29 Jan 2021 19:17:25 +0100 Subject: [PATCH 131/924] [url_launcher] Update description in pubspec.yaml (#2858) --- packages/url_launcher/url_launcher/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher/README.md | 2 +- packages/url_launcher/url_launcher/pubspec.yaml | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index fb66bcd99c1f..9f2719fd6662 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.0.0-nullsafety.6 + +* Correct statement in description about which platforms url_launcher supports. + ## 6.0.0-nullsafety.5 * Document that the web plugin is not endorsed in the `nullsafety` prerelease for now. diff --git a/packages/url_launcher/url_launcher/README.md b/packages/url_launcher/url_launcher/README.md index 573624fa18eb..bc399c73df7d 100644 --- a/packages/url_launcher/url_launcher/README.md +++ b/packages/url_launcher/url_launcher/README.md @@ -2,7 +2,7 @@ [![pub package](https://img.shields.io/pub/v/url_launcher.svg)](https://pub.dev/packages/url_launcher) -A Flutter plugin for launching a URL in the mobile platform. Supports +A Flutter plugin for launching a URL. Supports iOS, Android, web, Windows, macOS, and Linux. ## Usage diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 2f9c38a22f36..2fdfd8caf217 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -1,8 +1,8 @@ name: url_launcher -description: Flutter plugin for launching a URL on Android and iOS. Supports +description: Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 6.0.0-nullsafety.5 +version: 6.0.0-nullsafety.6 flutter: plugin: From 8c9ad1198a1e2b3d03fcd5c5244b4ac105973f21 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 29 Jan 2021 11:14:06 -0800 Subject: [PATCH 132/924] [ci][image_picker][webviews_flutter] enable Xcode 12 (#3461) --- .cirrus.yml | 51 ++++++++++++++----- .../image_picker/image_picker/CHANGELOG.md | 4 ++ .../ImagePickerFromGalleryUITests.m | 20 ++++++-- .../image_picker/image_picker/pubspec.yaml | 2 +- packages/webview_flutter/CHANGELOG.md | 4 ++ .../webview_flutter_test.dart | 6 ++- packages/webview_flutter/pubspec.yaml | 2 +- 7 files changed, 69 insertions(+), 20 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 1f82270163fb..b6a9c4884a22 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -134,11 +134,12 @@ task: - xvfb-run ./script/incremental_build.sh drive-examples --linux task: + # Xcode 12 task # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins only_if: $CIRRUS_TAG == '' use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' osx_instance: - image: catalina-xcode-11.3.1-flutter + image: big-sur-xcode-12.3 upgrade_script: - sudo gem install cocoapods - flutter channel stable @@ -149,7 +150,7 @@ task: activate_script: pub global activate flutter_plugin_tools create_simulator_script: - xcrun simctl list - - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot + - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-3 | xargs xcrun simctl boot matrix: - name: build_all_plugins_ipa env: @@ -162,17 +163,6 @@ task: - if [[ "$CHANNEL" -eq "stable" ]]; then find . | grep _web$ | xargs rm -rf; fi - flutter channel $CHANNEL - ./script/build_all_plugins_app.sh ios --no-codesign - - name: lint_darwin_plugins - env: - matrix: - PLUGIN_SHARDING: "--shardIndex 0 --shardCount 2" - PLUGIN_SHARDING: "--shardIndex 1 --shardCount 2" - script: - # TODO(jmagman): Lint macOS podspecs but skip any that fail library validation. - - find . -name "*.podspec" | xargs grep -l "osx" | xargs rm - # Skip the dummy podspecs used to placate the tool. - - find . -name "*_web*.podspec" -o -name "*_mac*.podspec" | xargs rm - - ./script/incremental_build.sh podspecs - name: build-ipas+drive-examples env: PATH: $PATH:/usr/local/bin @@ -194,13 +184,46 @@ task: - flutter upgrade - ./script/incremental_build.sh build-examples --ipa - ./script/incremental_build.sh drive-examples - - ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS + - ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=14.3" + task: + # Xcode 11 task + # TODO(cyanglaz): merge Xcode 11 task to Xcode 12 task when all the matrix can be run in Xcode 12. # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins only_if: $CIRRUS_TAG == '' use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' osx_instance: image: catalina-xcode-11.3.1-flutter + upgrade_script: + - sudo gem install cocoapods + - flutter channel stable + - flutter upgrade + - flutter channel master + - flutter upgrade + - git fetch origin master + activate_script: pub global activate flutter_plugin_tools + create_simulator_script: + - xcrun simctl list + - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot + matrix: + - name: lint_darwin_plugins + env: + matrix: + PLUGIN_SHARDING: "--shardIndex 0 --shardCount 2" + PLUGIN_SHARDING: "--shardIndex 1 --shardCount 2" + script: + # TODO(jmagman): Lint macOS podspecs but skip any that fail library validation. + - find . -name "*.podspec" | xargs grep -l "osx" | xargs rm + # Skip the dummy podspecs used to placate the tool. + - find . -name "*_web*.podspec" -o -name "*_mac*.podspec" | xargs rm + - ./script/incremental_build.sh podspecs + +task: + # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins + only_if: $CIRRUS_TAG == '' + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' + osx_instance: + image: big-sur-xcode-12.3 setup_script: - flutter config --enable-macos-desktop upgrade_script: diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 1b3146d532fa..1a09758d13ef 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+22 + +* iOS: update XCUITests to separate each test session. + ## 0.6.7+21 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m index 74df795a3df3..e30fabd2d071 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m @@ -16,6 +16,7 @@ @interface ImagePickerFromGalleryUITests : XCTestCase @implementation ImagePickerFromGalleryUITests - (void)setUp { + [super setUp]; // Delete the app if already exists, to test permission popups self.continueAfterFailure = NO; @@ -31,7 +32,7 @@ - (void)setUp { if (![allPhotoPermission waitForExistenceWithTimeout: kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", - self.app.debugDescription); + weakSelf.app.debugDescription); XCTFail(@"Failed due to not able to find " @"allPhotoPermission button with %@ seconds", @(kElementWaitingTime)); @@ -42,7 +43,7 @@ - (void)setUp { if (![ok waitForExistenceWithTimeout: kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", - self.app.debugDescription); + weakSelf.app.debugDescription); XCTFail(@"Failed due to not able to find ok button " @"with %@ seconds", @(kElementWaitingTime)); @@ -53,11 +54,19 @@ - (void)setUp { }]; } +- (void)tearDown { + [super tearDown]; + [self.app terminate]; +} + - (void)testPickingFromGallery { - [self launchPickerAndCancel]; [self launchPickerAndPick]; } +- (void)testCancel { + [self launchPickerAndCancel]; +} + - (void)launchPickerAndCancel { // Find and tap on the pick from gallery button. NSPredicate* predicateToFindImageFromGalleryButton = @@ -160,6 +169,10 @@ - (void)launchPickerAndPick { XCTAssertTrue(pickButton.exists); [pickButton tap]; + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + [self.app tap]; + // Find an image and tap on it. (IOS 14 UI, images are showing directly) XCUIElement* aImage; if (@available(iOS 14, *)) { @@ -177,6 +190,7 @@ - (void)launchPickerAndPick { identifier:@"PhotosGridView"] .cells.firstMatch; } + os_log_error(OS_LOG_DEFAULT, "description before picking image %@", self.app.debugDescription); if (![aImage waitForExistenceWithTimeout:kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); XCTFail(@"Failed due to not able to find an image with %@ seconds", @(kElementWaitingTime)); diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 789ca13d5bcb..075c90627bf4 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+21 +version: 0.6.7+22 flutter: plugin: diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 867ea1757985..9c54b4cc207d 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.4 + +* Update integration test to workaround an iOS 14 issue with `evaluateJavascript`. + ## 2.0.0-nullsafety.3 * Fix `onWebResourceError` on iOS. diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index 5f39cc3d86d2..50af77fe6c6e 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -144,7 +144,11 @@ void main() { await pageLoaded.future; expect(messagesReceived, isEmpty); - await controller.evaluateJavascript('Echo.postMessage("hello");'); + // Append a return value "1" in the end will prevent an iOS platform exception. + // See: https://github.com/flutter/flutter/issues/66318#issuecomment-701105380 + // TODO(cyanglaz): remove the workaround "1" in the end when the below issue is fixed. + // https://github.com/flutter/flutter/issues/66318 + await controller.evaluateJavascript('Echo.postMessage("hello");1;'); expect(messagesReceived, equals(['hello'])); }); diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 8bdd790e5e36..11769acce2ba 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 2.0.0-nullsafety.3 +version: 2.0.0-nullsafety.4 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: From 815beaff69c68584ba76393d6c858735ef34d995 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Fri, 29 Jan 2021 11:55:06 -0800 Subject: [PATCH 133/924] [url_launcher_web] Fix Link misalignment issue (#3476) The Link widget builds a Stack on the web. The Stack by default loosens the constraints passed by the parent. This is what was causing the misalignment. In order to fix it, we just need to pass fit: StackFit.passthrough to the Stack. --- .../url_launcher_web/CHANGELOG.md | 4 +++ .../url_launcher_web/lib/src/link.dart | 1 + .../url_launcher_web/pubspec.yaml | 2 +- .../url_launcher_web/test/lib/main.dart | 5 ++- .../url_launcher_web_integration.dart | 33 +++++++++++++++++++ .../url_launcher_web_integration_test.dart | 1 + 6 files changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/url_launcher/url_launcher_web/CHANGELOG.md b/packages/url_launcher/url_launcher_web/CHANGELOG.md index c8d52f5df13f..0416c033bf2b 100644 --- a/packages/url_launcher/url_launcher_web/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.1.5+3 + +- Fix Link misalignment [issue](https://github.com/flutter/flutter/issues/70053). + # 0.1.5+2 - Update Flutter SDK constraint. diff --git a/packages/url_launcher/url_launcher_web/lib/src/link.dart b/packages/url_launcher/url_launcher_web/lib/src/link.dart index e8a6d68348bb..8169a9c11b94 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/link.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/link.dart @@ -66,6 +66,7 @@ class WebLinkDelegateState extends State { @override Widget build(BuildContext context) { return Stack( + fit: StackFit.passthrough, children: [ widget.link.builder( context, diff --git a/packages/url_launcher/url_launcher_web/pubspec.yaml b/packages/url_launcher/url_launcher_web/pubspec.yaml index 2d1b8af8e49f..77a958677015 100644 --- a/packages/url_launcher/url_launcher_web/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/u # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.5+2 +version: 0.1.5+3 flutter: plugin: diff --git a/packages/url_launcher/url_launcher_web/test/lib/main.dart b/packages/url_launcher/url_launcher_web/test/lib/main.dart index 10415204570c..e1a38dcdcd46 100644 --- a/packages/url_launcher/url_launcher_web/test/lib/main.dart +++ b/packages/url_launcher/url_launcher_web/test/lib/main.dart @@ -17,6 +17,9 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { @override Widget build(BuildContext context) { - return Text('Testing... Look at the console output for results!'); + return Directionality( + textDirection: TextDirection.ltr, + child: Text('Testing... Look at the console output for results!'), + ); } } diff --git a/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration.dart b/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration.dart index 4d103443deb9..bfa94821e41a 100644 --- a/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration.dart +++ b/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 import 'dart:html' as html; import 'dart:js_util'; import 'package:flutter/widgets.dart'; @@ -271,6 +272,38 @@ void main() { expect(anchor.getAttribute('href'), uri2.toString()); expect(anchor.getAttribute('target'), '_self'); }); + + testWidgets('sizes itself correctly', (WidgetTester tester) async { + final Key containerKey = GlobalKey(); + final Uri uri = Uri.parse('http://foobar'); + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: ConstrainedBox( + constraints: BoxConstraints.tight(Size(100.0, 100.0)), + child: WebLinkDelegate(TestLinkInfo( + uri: uri, + target: LinkTarget.blank, + builder: (BuildContext context, FollowLink followLink) { + return Container( + key: containerKey, + child: SizedBox(width: 50.0, height: 50.0), + ); + }, + )), + ), + ), + )); + await tester.pumpAndSettle(); + + final Size containerSize = tester.getSize(find.byKey(containerKey)); + // The Stack widget inserted by the `WebLinkDelegate` shouldn't loosen the + // constraints before passing them to the inner container. So the inner + // container should respect the tight constraints given by the ancestor + // `ConstrainedBox` widget. + expect(containerSize.width, 100.0); + expect(containerSize.height, 100.0); + }); }); } diff --git a/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration_test.dart b/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration_test.dart index 64e2248a4f9b..2d68bb93e9a7 100644 --- a/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration_test.dart +++ b/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 import 'package:integration_test/integration_test_driver.dart'; Future main() async => integrationDriver(); From 97646369b0a88e70624c4dc22fc1931e35060f94 Mon Sep 17 00:00:00 2001 From: Amir Hardon Date: Fri, 29 Jan 2021 15:09:34 -0800 Subject: [PATCH 134/924] Remove amirh from CODEOWNERS (#3484) --- CODEOWNERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 5f6d83c209ac..656bd2604c75 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,7 +6,7 @@ packages/android_alarm_manager/** @bkonyi packages/android_intent/** @mklim @matthew-carroll -packages/battery/** @amirh @matthew-carroll +packages/battery/** @matthew-carroll packages/camera/** @bparrishMines packages/connectivity/** @cyanglaz @matthew-carroll packages/cross_file/** @ditman @mvanbeusekom @@ -24,4 +24,3 @@ packages/path_provider/** @matthew-carroll packages/shared_preferences/** @matthew-carroll packages/url_launcher/** @mklim packages/video_player/** @iskakaushik @cyanglaz -packages/webview_flutter/** @amirh From 35847e4734d4bd22f8b08394897ffa5997972ba2 Mon Sep 17 00:00:00 2001 From: Jia Hao Date: Sat, 30 Jan 2021 08:33:00 +0800 Subject: [PATCH 135/924] [local_auth] Fix incorrect switch fallthrough (#3473) --- packages/local_auth/CHANGELOG.md | 14 +++++++++----- .../plugins/localauth/AuthenticationHelper.java | 1 + packages/local_auth/pubspec.yaml | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index 8bb043f52d8f..152ffb603e10 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -2,10 +2,14 @@ * Allow pin, passcode, and pattern authentication with `authenticate` method * **Breaking change**. Parameter names refactored to use the generic `biometric` prefix in place of `fingerprint` in the `AndroidAuthMessages` class - * `fingerprintHint` is now `biometricHint` - * `fingerprintNotRecognized`is now `biometricNotRecognized` - * `fingerprintSuccess`is now `biometricSuccess` - * `fingerprintRequiredTitle` is now `biometricRequiredTitle` + * `fingerprintHint` is now `biometricHint` + * `fingerprintNotRecognized`is now `biometricNotRecognized` + * `fingerprintSuccess`is now `biometricSuccess` + * `fingerprintRequiredTitle` is now `biometricRequiredTitle` + +## 1.0.0-nullsafety.4 + +* Fix incorrect error handling switch case fallthrough. ## 1.0.0-nullsafety.3 @@ -203,4 +207,4 @@ ## 0.0.1 -* Initial release of local authentication plugin. \ No newline at end of file +* Initial release of local authentication plugin. diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java index 096c7efd6d3d..3a7e2d76ca08 100644 --- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java +++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java @@ -138,6 +138,7 @@ public void onAuthenticationError(int errorCode, CharSequence errString) { return; } completionHandler.onError("NotAvailable", "Security credentials not available."); + break; case BiometricPrompt.ERROR_NO_SPACE: case BiometricPrompt.ERROR_NO_BIOMETRICS: if (promptInfo.isDeviceCredentialAllowed()) return; diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 0f5a58835c3c..79870cc57da2 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -1,8 +1,8 @@ name: local_auth -description: Flutter plugin for Android and iOS devices to allow local +description: Flutter plugin for Android and iOS devices to allow local authentication via fingerprint, touch ID, face ID, passcode, pin, or pattern. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 1.0.0-nullsafety.3 +version: 1.0.0-nullsafety.4 flutter: plugin: From 04b0b4b13f59bea7b3375dbe2c5a013e6f0ed5a4 Mon Sep 17 00:00:00 2001 From: Tim Sneath Date: Sat, 30 Jan 2021 12:11:08 -0800 Subject: [PATCH 136/924] [path_provider_windows] Resolve FFI stabilization changes (#3485) Ensures that path_provider_windows works on current null safety builds. --- packages/path_provider/path_provider_windows/CHANGELOG.md | 4 ++++ .../lib/src/path_provider_windows_real.dart | 2 +- packages/path_provider/path_provider_windows/pubspec.yaml | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index ea271681e63c..24304e36dc0c 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0-nullsafety.1 + +* Bump win32 dependency to latest version. + ## 0.1.0-nullsafety * Migrate to null safety diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart index 856249036b62..c104343f2502 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart @@ -116,7 +116,7 @@ class PathProviderWindows extends PathProviderPlatform { /// [WindowsKnownFolder]. Future getPath(String folderID) { final pathPtrPtr = allocate>(); - final Pointer knownFolderID = calloc()..setGUID(folderID); + final Pointer knownFolderID = calloc()..ref.setGUID(folderID); try { final hr = SHGetKnownFolderPath( diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index 55c73c87ad19..578000682e63 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_windows -version: 0.1.0-nullsafety +version: 0.1.0-nullsafety.1 flutter: plugin: @@ -17,7 +17,7 @@ dependencies: flutter: sdk: flutter ffi: ^0.2.0-nullsafety.1 - win32: ^2.0.0-nullsafety.8 + win32: ^2.0.0-nullsafety.9 dev_dependencies: flutter_test: From a16411b50970d988ae6510f399114520149053dc Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 1 Feb 2021 14:22:59 -0800 Subject: [PATCH 137/924] Remove Dart stubs from macOS plugins (#3491) When these federated plugins were created, plugins had to have at least one Dart file to avoid issues with the analyzer, so were created with a stub file since all the code is native. The analyzer no longer has this limitation, so the stub is no longer necesssary. --- packages/connectivity/connectivity_macos/CHANGELOG.md | 4 ++++ .../connectivity_macos/lib/connectivity_macos.dart | 3 --- packages/connectivity/connectivity_macos/pubspec.yaml | 2 +- packages/path_provider/path_provider_macos/CHANGELOG.md | 4 ++++ .../path_provider_macos/lib/path_provider_macos.dart | 3 --- packages/path_provider/path_provider_macos/pubspec.yaml | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) delete mode 100644 packages/connectivity/connectivity_macos/lib/connectivity_macos.dart delete mode 100644 packages/path_provider/path_provider_macos/lib/path_provider_macos.dart diff --git a/packages/connectivity/connectivity_macos/CHANGELOG.md b/packages/connectivity/connectivity_macos/CHANGELOG.md index 9261b0e789fe..890c8938482f 100644 --- a/packages/connectivity/connectivity_macos/CHANGELOG.md +++ b/packages/connectivity/connectivity_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.0-nullsafety.1 + +* Remove placeholder Dart file. + ## 0.2.0-nullsafety * Update Dart SDK constraint. diff --git a/packages/connectivity/connectivity_macos/lib/connectivity_macos.dart b/packages/connectivity/connectivity_macos/lib/connectivity_macos.dart deleted file mode 100644 index 7be7b143ca79..000000000000 --- a/packages/connectivity/connectivity_macos/lib/connectivity_macos.dart +++ /dev/null @@ -1,3 +0,0 @@ -// Analyze will fail if there is no main.dart file. This file should -// be removed once an example app has been added to connectivity_macos. -// https://github.com/flutter/flutter/issues/51007 diff --git a/packages/connectivity/connectivity_macos/pubspec.yaml b/packages/connectivity/connectivity_macos/pubspec.yaml index dd193f715c2a..49c28f081ad7 100644 --- a/packages/connectivity/connectivity_macos/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the connectivity plugin. # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.2.0-nullsafety +version: 0.2.0-nullsafety.1 homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_macos flutter: diff --git a/packages/path_provider/path_provider_macos/CHANGELOG.md b/packages/path_provider/path_provider_macos/CHANGELOG.md index b082aefd9da6..1380d76a8f3c 100644 --- a/packages/path_provider/path_provider_macos/CHANGELOG.md +++ b/packages/path_provider/path_provider_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.4+9 + +* Remove placeholder Dart file. + ## 0.0.4+8 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart b/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart deleted file mode 100644 index cf440b2858af..000000000000 --- a/packages/path_provider/path_provider_macos/lib/path_provider_macos.dart +++ /dev/null @@ -1,3 +0,0 @@ -// Analyze will fail if there is no main.dart file. This file should -// be removed once an example app has been added to path_provider_macos. -// https://github.com/flutter/flutter/issues/51007 diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index 0af1cfbf0aaa..9d3a3896903e 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the path_provider plugin # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.4+8 +version: 0.0.4+9 homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_macos flutter: From 31a8b5c3d5be8bf8db0def800496a6c7076bb59c Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 1 Feb 2021 16:04:43 -0800 Subject: [PATCH 138/924] Migrate shared_preferences_platform_interfaces to null safety (#3466) --- .../CHANGELOG.md | 4 ++ .../method_channel_shared_preferences.dart | 43 ++++++++----------- ...shared_preferences_platform_interface.dart | 2 +- .../pubspec.yaml | 7 ++- ...ethod_channel_shared_preferences_test.dart | 14 +++--- script/nnbd_plugins.sh | 2 +- 6 files changed, 33 insertions(+), 39 deletions(-) diff --git a/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md b/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md index 88d3a9ac5f00..6661e2757326 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.0.5 * Update Flutter SDK constraint. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart b/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart index 66009a5caf14..c02c537adcbd 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart @@ -18,39 +18,32 @@ const MethodChannel _kChannel = class MethodChannelSharedPreferencesStore extends SharedPreferencesStorePlatform { @override - Future remove(String key) { - return _invokeBoolMethod('remove', { - 'key': key, - }); + Future remove(String key) async { + return (await _kChannel.invokeMethod( + 'remove', + {'key': key}, + ))!; } @override - Future setValue(String valueType, String key, Object value) { - return _invokeBoolMethod('set$valueType', { - 'key': key, - 'value': value, - }); - } - - Future _invokeBoolMethod(String method, Map params) { - return _kChannel - .invokeMethod(method, params) - // TODO(yjbanov): I copied this from the original - // shared_preferences.dart implementation, but I - // actually do not know why it's necessary to pipe the - // result through an identity function. - // - // Source: https://github.com/flutter/plugins/blob/3a87296a40a2624d200917d58f036baa9fb18df8/packages/shared_preferences/lib/shared_preferences.dart#L134 - .then((dynamic result) => result); + Future setValue(String valueType, String key, Object value) async { + return (await _kChannel.invokeMethod( + 'set$valueType', + {'key': key, 'value': value}, + ))!; } @override - Future clear() { - return _kChannel.invokeMethod('clear'); + Future clear() async { + return (await _kChannel.invokeMethod('clear'))!; } @override - Future> getAll() { - return _kChannel.invokeMapMethod('getAll'); + Future> getAll() async { + final Map? preferences = + await _kChannel.invokeMapMethod('getAll'); + + if (preferences == null) return {}; + return preferences; } } diff --git a/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart b/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart index 5a2b99ca69b1..cf194f82c267 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart @@ -4,7 +4,7 @@ import 'dart:async'; -import 'package:meta/meta.dart'; +import 'package:flutter/foundation.dart'; import 'method_channel_shared_preferences.dart'; diff --git a/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml b/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml index da31497df1c6..9e5d57230761 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml @@ -1,18 +1,17 @@ name: shared_preferences_platform_interface description: A common platform interface for the shared_preferences plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_platform_interface -version: 1.0.5 +version: 2.0.0-nullsafety dependencies: - meta: ^1.0.4 flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.8" diff --git a/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart index 4cc79b058675..d828126168ba 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart @@ -15,7 +15,7 @@ void main() { 'plugins.flutter.io/shared_preferences', ); - const Map kTestValues = { + const Map kTestValues = { 'flutter.String': 'hello world', 'flutter.Bool': true, 'flutter.Int': 42, @@ -23,10 +23,10 @@ void main() { 'flutter.StringList': ['foo', 'bar'], }; - InMemorySharedPreferencesStore testData; + late InMemorySharedPreferencesStore testData; final List log = []; - MethodChannelSharedPreferencesStore store; + late MethodChannelSharedPreferencesStore store; setUp(() async { testData = InMemorySharedPreferencesStore.empty(); @@ -44,9 +44,9 @@ void main() { return await testData.clear(); } final RegExp setterRegExp = RegExp(r'set(.*)'); - final Match match = setterRegExp.matchAsPrefix(methodCall.method); - if (match.groupCount == 1) { - final String valueType = match.group(1); + final Match? match = setterRegExp.matchAsPrefix(methodCall.method); + if (match?.groupCount == 1) { + final String valueType = match!.group(1)!; final String key = methodCall.arguments['key']; final Object value = methodCall.arguments['value']; return await testData.setValue(valueType, key, value); @@ -59,8 +59,6 @@ void main() { tearDown(() async { await testData.clear(); - store = null; - testData = null; }); test('getAll', () async { diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 44e5df9e95ef..3d0676f8b1a5 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -17,6 +17,7 @@ readonly NNBD_PLUGINS_LIST=( "path_provider" "plugin_platform_interface" "share" + "shared_preferences" "url_launcher" "video_player" "webview_flutter" @@ -35,7 +36,6 @@ readonly NON_NNBD_PLUGINS_LIST=( # "in_app_purchase" # "quick_actions" # "sensors" - # "shared_preferences" # "wifi_info_flutter" ) From 30721bed3afe4712b32abad1f2bf3f2ff6c18608 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 1 Feb 2021 18:12:19 -0800 Subject: [PATCH 139/924] Automatically add platform labels (#3487) Tags PRs with platform-* labels based on the platform(s) being edited. This will allow filtering open PRs by OS (e.g., to allow someone focusing on a single platform's plugin implementations to easily find all relevant PRs). --- .github/labeler.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/labeler.yml b/.github/labeler.yml index 66dc68f1fbbe..cdb9ade0e7f8 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -84,3 +84,27 @@ 'p: wifi_info_flutter': - packages/wifi_info_flutter/**/* + +'platform-android': + - packages/*/*_android/**/* + - packages/**/android/**/* + +'platform-ios': + - packages/*/*_ios/**/* + - packages/**/ios/**/* + +'platform-linux': + - packages/*/*_linux/**/* + - packages/**/linux/**/* + +'platform-macos': + - packages/*/*_macos/**/* + - packages/**/macos/**/* + +'platform-web': + - packages/*/*_web/**/* + - packages/**/web/**/* + +'platform-windows': + - packages/*/*_windows/**/* + - packages/**/windows/**/* From a87497f1399cf6b074dc98563168569d8f738348 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 1 Feb 2021 19:46:03 -0800 Subject: [PATCH 140/924] Add plugin issue query to README (#3493) --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 42c64e1c6a50..b65c10e7f381 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ These plugins are also available on Please file any issues, bugs, or feature requests in the [main flutter repo](https://github.com/flutter/flutter/issues/new). +Issues pertaining to this repository are [labeled +"plugin"](https://github.com/flutter/flutter/issues?q=is%3Aopen+is%3Aissue+label%3Aplugin). + ## Contributing If you wish to contribute a new plugin to the Flutter ecosystem, please From a45557608af1c6aada64705884101cada1d6c6d2 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 2 Feb 2021 16:48:11 +0800 Subject: [PATCH 141/924] [camera] Fix example reference in camera's doc (#3472) --- AUTHORS | 3 ++- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/README.md | 2 +- packages/camera/camera/pubspec.yaml | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index dabc20108f28..1f2b9cba2f16 100644 --- a/AUTHORS +++ b/AUTHORS @@ -60,4 +60,5 @@ Eitan Schwartz Chris Rutkowski Juan Alvarez Aleksandr Yurkovskiy -Anton Borries \ No newline at end of file +Anton Borries +Alex Li diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index cc734737182f..35a4d950e510 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+2 + +* Fix example reference in README. + ## 0.7.0+1 * Ensure communication from JAVA to Dart is done on the main UI thread. diff --git a/packages/camera/camera/README.md b/packages/camera/camera/README.md index f7163818aae3..b9fdd7384297 100644 --- a/packages/camera/camera/README.md +++ b/packages/camera/camera/README.md @@ -122,7 +122,7 @@ class _CameraAppState extends State { } ``` -For a more elaborate usage example see [here](https://github.com/flutter/plugins/tree/master/packages/camera/example). +For a more elaborate usage example see [here](https://github.com/flutter/plugins/tree/master/packages/camera/camera/example). *Note*: This plugin is still under development, and some APIs might not be available yet. [Feedback welcome](https://github.com/flutter/flutter/issues) and diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index b406ce5ba64f..2b6d163dfbeb 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+1 +version: 0.7.0+2 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 59086bd4d5f37a4ae9cc94f243d736dbc3b26e97 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 2 Feb 2021 12:51:04 +0100 Subject: [PATCH 142/924] Revert compileSdkVersion to 29 (#3496) --- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/android/build.gradle | 2 +- .../flutter/plugins/camera/DeviceOrientationManager.java | 9 +-------- packages/camera/camera/example/android/app/build.gradle | 2 +- packages/camera/camera/pubspec.yaml | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 35a4d950e510..911d7a1e9920 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.7.0+3 + +* Revert compileSdkVersion back to 29 (from 30) as this is causing problems with add-to-app configurations. + ## 0.7.0+2 * Fix example reference in README. diff --git a/packages/camera/camera/android/build.gradle b/packages/camera/camera/android/build.gradle index 0606738a0a69..0b88fd10fb71 100644 --- a/packages/camera/camera/android/build.gradle +++ b/packages/camera/camera/android/build.gradle @@ -27,7 +27,7 @@ project.getTasks().withType(JavaCompile){ apply plugin: 'com.android.library' android { - compileSdkVersion 30 + compileSdkVersion 29 defaultConfig { minSdkVersion 21 diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java index d39a8da55cc8..7c6011b185fb 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java @@ -11,8 +11,6 @@ import android.content.IntentFilter; import android.content.res.Configuration; import android.hardware.SensorManager; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; import android.provider.Settings; import android.view.Display; import android.view.OrientationEventListener; @@ -191,11 +189,6 @@ private int getDeviceDefaultOrientation() { @SuppressWarnings("deprecation") private Display getDisplay() { - if (VERSION.SDK_INT >= VERSION_CODES.R) { - return activity.getDisplay(); - } else { - return ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)) - .getDefaultDisplay(); - } + return ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); } } diff --git a/packages/camera/camera/example/android/app/build.gradle b/packages/camera/camera/example/android/app/build.gradle index c5eeb246fe30..7d0e281b74e8 100644 --- a/packages/camera/camera/example/android/app/build.gradle +++ b/packages/camera/camera/example/android/app/build.gradle @@ -25,7 +25,7 @@ apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 30 + compileSdkVersion 29 lintOptions { disable 'InvalidPackage' diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 2b6d163dfbeb..cebbb334c8f2 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+2 +version: 0.7.0+3 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From a65d350c3f97fd6b5e4120c2d782f971103987a5 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 2 Feb 2021 10:21:05 -0800 Subject: [PATCH 143/924] Remove cyanglaz from some package code owners (#3495) --- CODEOWNERS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 656bd2604c75..bd774ebe4315 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -8,19 +8,19 @@ packages/android_alarm_manager/** @bkonyi packages/android_intent/** @mklim @matthew-carroll packages/battery/** @matthew-carroll packages/camera/** @bparrishMines -packages/connectivity/** @cyanglaz @matthew-carroll +packages/connectivity/** @matthew-carroll packages/cross_file/** @ditman @mvanbeusekom packages/device_info/** @matthew-carroll packages/espresso/** @collinjackson @adazh packages/file_selector/** @ditman packages/google_maps_flutter/** @cyanglaz -packages/google_sign_in/** @cyanglaz @mehmetf +packages/google_sign_in/** @mehmetf packages/image_picker/** @cyanglaz packages/integration_test/** @dnfield packages/in_app_purchase/** @mklim @cyanglaz @LHLL packages/ios_platform_images/** @gaaclarke -packages/package_info/** @cyanglaz @matthew-carroll +packages/package_info/** @matthew-carroll packages/path_provider/** @matthew-carroll packages/shared_preferences/** @matthew-carroll packages/url_launcher/** @mklim -packages/video_player/** @iskakaushik @cyanglaz +packages/video_player/** @iskakaushik From 42d5325a93ffc80179ab770febcdd79243c3ff87 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Tue, 2 Feb 2021 16:35:32 -0800 Subject: [PATCH 144/924] Run pub global activate before pub global run (#3502) --- .cirrus.yml | 5 ----- script/build_all_plugins_app.sh | 2 +- script/check_publish.sh | 2 +- script/common.sh | 16 ++++++++++++++++ script/incremental_build.sh | 12 +++--------- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index b6a9c4884a22..a4815ec2489e 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -14,7 +14,6 @@ task: - flutter channel master - flutter upgrade - git fetch origin master - activate_script: pub global activate flutter_plugin_tools matrix: - name: publishable script: @@ -122,7 +121,6 @@ task: - flutter channel master - flutter upgrade - git fetch origin master - activate_script: pub global activate flutter_plugin_tools matrix: - name: build-linux+drive-examples install_script: @@ -147,7 +145,6 @@ task: - flutter channel master - flutter upgrade - git fetch origin master - activate_script: pub global activate flutter_plugin_tools create_simulator_script: - xcrun simctl list - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-3 | xargs xcrun simctl boot @@ -201,7 +198,6 @@ task: - flutter channel master - flutter upgrade - git fetch origin master - activate_script: pub global activate flutter_plugin_tools create_simulator_script: - xcrun simctl list - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot @@ -231,7 +227,6 @@ task: - flutter channel master - flutter upgrade - git fetch origin master - activate_script: pub global activate flutter_plugin_tools matrix: - name: build_all_plugins_app script: diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 3e08b914ff86..9d9e38550ed5 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -64,7 +64,7 @@ fi echo "Excluding the following plugins: $ALL_EXCLUDED" -(cd "$REPO_DIR" && pub global run flutter_plugin_tools all-plugins-app --exclude $ALL_EXCLUDED) +(cd "$REPO_DIR" && plugin_tools all-plugins-app --exclude $ALL_EXCLUDED) function error() { echo "$@" 1>&2 diff --git a/script/check_publish.sh b/script/check_publish.sh index 2e53fc80cb47..5584fc601916 100755 --- a/script/check_publish.sh +++ b/script/check_publish.sh @@ -12,7 +12,7 @@ source "$SCRIPT_DIR/common.sh" function check_publish() { local failures=() - for dir in $(pub global run flutter_plugin_tools list --plugins="$1"); do + for dir in $(plugin_tools list --plugins="$1"); do local package_name=$(basename "$dir") echo "Checking that $package_name can be published." diff --git a/script/common.sh b/script/common.sh index 7950a3ea71cd..cd2c1ca3fd83 100644 --- a/script/common.sh +++ b/script/common.sh @@ -45,3 +45,19 @@ function check_changed_packages() { fi return 0 } + +# Normalizes the call to the pub command. +function pub_command() { + if [ "$(expr substr $(uname -s) 1 5)" == "MINGW" ]; then + pub.bat "$@" + else + pub "$@" + fi +} + +# Activates the Flutter plugin tool to ensures that the plugin tools dependencies +# are resolved using the current Dart SDK. +# Finally, runs the tool with the parameters. +function plugin_tools() { + pub_command global activate flutter_plugin_tools && pub_command global run flutter_plugin_tools "$@" +} diff --git a/script/incremental_build.sh b/script/incremental_build.sh index 3911f0a6e9c8..d98e7aac6e30 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -7,12 +7,6 @@ readonly REPO_DIR="$(dirname "$SCRIPT_DIR")" source "$SCRIPT_DIR/common.sh" source "$SCRIPT_DIR/nnbd_plugins.sh" -if [ "$(expr substr $(uname -s) 1 5)" == "MINGW" ]; then - PUB=pub.bat -else - PUB=pub -fi - # Plugins that are excluded from this task. ALL_EXCLUDED=("") # Exclude nnbd plugins from stable. @@ -49,7 +43,7 @@ PLUGIN_SHARDING=($PLUGIN_SHARDING) if [[ "${BRANCH_NAME}" == "master" ]]; then echo "Running for all packages" - (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) + (cd "$REPO_DIR" && plugin_tools "${ACTIONS[@]}" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) else # Sets CHANGED_PACKAGES check_changed_packages @@ -57,10 +51,10 @@ else if [[ "$CHANGED_PACKAGES" == "" ]]; then echo "No changes detected in packages." echo "Running for all packages" - (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) + (cd "$REPO_DIR" && plugin_tools "${ACTIONS[@]}" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) else echo running "${ACTIONS[@]}" - (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools "${ACTIONS[@]}" --plugins="$CHANGED_PACKAGES" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) + (cd "$REPO_DIR" && plugin_tools "${ACTIONS[@]}" --plugins="$CHANGED_PACKAGES" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) echo "Running version check for changed packages" # TODO(egarciad): Enable this check once in master. # (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools version-check --base_sha="$(get_branch_base_sha)") From 9e1d573e1e953ddc2e4c7c823f442244f1ff4ebf Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Wed, 3 Feb 2021 12:50:36 -0800 Subject: [PATCH 145/924] Run activate before run (#3506) --- script/check_publish.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/script/check_publish.sh b/script/check_publish.sh index 5584fc601916..9f435e9ba42c 100755 --- a/script/check_publish.sh +++ b/script/check_publish.sh @@ -12,7 +12,8 @@ source "$SCRIPT_DIR/common.sh" function check_publish() { local failures=() - for dir in $(plugin_tools list --plugins="$1"); do + pub_command global activate flutter_plugin_tools + for dir in $(pub_command global run flutter_plugin_tools list --plugins="$1"); do local package_name=$(basename "$dir") echo "Checking that $package_name can be published." From 782b05782831d8865c100dab60ca7f85d7e46fab Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Wed, 3 Feb 2021 13:32:12 -0800 Subject: [PATCH 146/924] [path_provider] Update macOS for NNBD (#3498) macOS federated plugin implementations that contain no Dart code just need their Dart SDK bumped in order to be considered nullsafe. --- packages/path_provider/path_provider_macos/CHANGELOG.md | 4 ++++ packages/path_provider/path_provider_macos/pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/path_provider/path_provider_macos/CHANGELOG.md b/packages/path_provider/path_provider_macos/CHANGELOG.md index 1380d76a8f3c..2f7290c2ced1 100644 --- a/packages/path_provider/path_provider_macos/CHANGELOG.md +++ b/packages/path_provider/path_provider_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.5-nullsafety + +* Update Dart SDK constraint for null safety. + ## 0.0.4+9 * Remove placeholder Dart file. diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index 9d3a3896903e..a2bbd58b7289 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the path_provider plugin # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.4+9 +version: 0.0.5-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_macos flutter: @@ -13,7 +13,7 @@ flutter: pluginClass: PathProviderPlugin environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.10.0" dependencies: From 61118a7fab0372661575b399c0cba83a51a4dfc5 Mon Sep 17 00:00:00 2001 From: Yash Johri Date: Thu, 4 Feb 2021 03:30:57 +0530 Subject: [PATCH 147/924] [path_provider_linux] Migrate to null safety (#3330) --- .../path_provider_linux/CHANGELOG.md | 4 ++++ .../integration_test/path_provider_test.dart | 21 ++++++++++++------- .../path_provider_linux/example/lib/main.dart | 11 +++++----- .../path_provider_linux/example/pubspec.yaml | 2 +- .../lib/path_provider_linux.dart | 12 +++++------ .../path_provider_linux/pubspec.yaml | 12 +++++------ 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/packages/path_provider/path_provider_linux/CHANGELOG.md b/packages/path_provider/path_provider_linux/CHANGELOG.md index ee382b04710b..2deb84237712 100644 --- a/packages/path_provider/path_provider_linux/CHANGELOG.md +++ b/packages/path_provider/path_provider_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.0-nullsafety + +* Migrate to null safety. + ## 0.1.1+3 * Update Flutter SDK constraint. diff --git a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart index 18ac49debbd4..febd52172759 100644 --- a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart @@ -4,14 +4,15 @@ import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; -import 'package:path_provider/path_provider.dart'; +import 'package:path_provider_linux/path_provider_linux.dart'; import 'package:integration_test/integration_test.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('getTemporaryDirectory', (WidgetTester tester) async { - final Directory result = await getTemporaryDirectory(); + final PathProviderLinux provider = PathProviderLinux(); + final String result = await provider.getTemporaryPath(); _verifySampleFile(result, 'temporaryDirectory'); }); @@ -19,25 +20,29 @@ void main() { if (!Platform.isLinux) { return; } - final Directory result = await getDownloadsDirectory(); + final PathProviderLinux provider = PathProviderLinux(); + final String result = await provider.getDownloadsPath(); _verifySampleFile(result, 'downloadDirectory'); }); testWidgets('getApplicationDocumentsDirectory', (WidgetTester tester) async { - final Directory result = await getApplicationDocumentsDirectory(); + final PathProviderLinux provider = PathProviderLinux(); + final String result = await provider.getApplicationDocumentsPath(); _verifySampleFile(result, 'applicationDocuments'); }); testWidgets('getApplicationSupportDirectory', (WidgetTester tester) async { - final Directory result = await getApplicationSupportDirectory(); + final PathProviderLinux provider = PathProviderLinux(); + final String result = await provider.getApplicationSupportPath(); _verifySampleFile(result, 'applicationSupport'); }); } -/// Verify a file called [name] in [directory] by recreating it with test +/// Verify a file called [name] in [directoryPath] by recreating it with test /// contents when necessary. -void _verifySampleFile(Directory directory, String name) { - final File file = File('${directory.path}/$name'); +void _verifySampleFile(String directoryPath, String name) { + final Directory directory = Directory(directoryPath); + final File file = File('${directory.path}${Platform.pathSeparator}$name'); if (file.existsSync()) { file.deleteSync(); diff --git a/packages/path_provider/path_provider_linux/example/lib/main.dart b/packages/path_provider/path_provider_linux/example/lib/main.dart index 6dc364b77f2a..069308233acb 100644 --- a/packages/path_provider/path_provider_linux/example/lib/main.dart +++ b/packages/path_provider/path_provider_linux/example/lib/main.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'dart:async'; import 'package:flutter/services.dart'; -import 'package:path_provider/path_provider.dart'; +import 'package:path_provider_linux/path_provider_linux.dart'; void main() async { runApp(MyApp()); @@ -19,6 +19,7 @@ class _MyAppState extends State { String _downloadsDirectory = 'Unknown'; String _appSupportDirectory = 'Unknown'; String _documentsDirectory = 'Unknown'; + final PathProviderLinux _provider = PathProviderLinux(); @override void initState() { @@ -34,27 +35,27 @@ class _MyAppState extends State { String documentsDirectory; // Platform messages may fail, so we use a try/catch PlatformException. try { - tempDirectory = (await getTemporaryDirectory()).path; + tempDirectory = await _provider.getTemporaryPath(); } on PlatformException catch (e, stackTrace) { tempDirectory = 'Failed to get temp directory.'; print('$tempDirectory $e $stackTrace'); } try { - downloadsDirectory = (await getDownloadsDirectory()).path; + downloadsDirectory = await _provider.getDownloadsPath(); } on PlatformException catch (e, stackTrace) { downloadsDirectory = 'Failed to get downloads directory.'; print('$downloadsDirectory $e $stackTrace'); } try { - documentsDirectory = (await getApplicationDocumentsDirectory()).path; + documentsDirectory = await _provider.getApplicationDocumentsPath(); } on PlatformException catch (e, stackTrace) { documentsDirectory = 'Failed to get documents directory.'; print('$documentsDirectory $e $stackTrace'); } try { - appSupportDirectory = (await getApplicationSupportDirectory()).path; + appSupportDirectory = await _provider.getApplicationSupportPath(); } on PlatformException catch (e, stackTrace) { appSupportDirectory = 'Failed to get documents directory.'; print('$appSupportDirectory $e $stackTrace'); diff --git a/packages/path_provider/path_provider_linux/example/pubspec.yaml b/packages/path_provider/path_provider_linux/example/pubspec.yaml index 85dbb24bbb29..d66af910c998 100644 --- a/packages/path_provider/path_provider_linux/example/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/example/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: flutter: sdk: flutter - path_provider: ^1.6.10 + path_provider_linux: any # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. diff --git a/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart b/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart index 09d2447c0a6c..e35b73bf3766 100644 --- a/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart +++ b/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart @@ -18,12 +18,12 @@ class PathProviderLinux extends PathProviderPlatform { } @override - Future getTemporaryPath() { + Future getTemporaryPath() { return Future.value("/tmp"); } @override - Future getApplicationSupportPath() async { + Future getApplicationSupportPath() async { final processName = path.basenameWithoutExtension( await File('/proc/self/exe').resolveSymbolicLinks()); final directory = Directory(path.join(xdg.dataHome.path, processName)); @@ -35,12 +35,12 @@ class PathProviderLinux extends PathProviderPlatform { } @override - Future getApplicationDocumentsPath() { - return Future.value(xdg.getUserDirectory('DOCUMENTS').path); + Future getApplicationDocumentsPath() { + return Future.value(xdg.getUserDirectory('DOCUMENTS')?.path); } @override - Future getDownloadsPath() { - return Future.value(xdg.getUserDirectory('DOWNLOAD').path); + Future getDownloadsPath() { + return Future.value(xdg.getUserDirectory('DOWNLOAD')?.path); } } diff --git a/packages/path_provider/path_provider_linux/pubspec.yaml b/packages/path_provider/path_provider_linux/pubspec.yaml index adabbdd45246..df459e12d37f 100644 --- a/packages/path_provider/path_provider_linux/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: path_provider_linux description: linux implementation of the path_provider plugin -version: 0.1.1+3 +version: 0.2.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_linux flutter: @@ -11,17 +11,17 @@ flutter: pluginClass: none environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.10.0" dependencies: - path: ^1.6.4 - xdg_directories: ^0.1.0 - path_provider_platform_interface: ^1.0.1 + path: ^1.8.0-nullsafety.3 + xdg_directories: ^0.2.0-nullsafety.1 + path_provider_platform_interface: ^2.0.0-nullsafety flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.3 From 47a5ea7994daad4cf05eb6fb4f8011f200fa8efe Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 3 Feb 2021 14:01:05 -0800 Subject: [PATCH 148/924] fix google_maps_flutter_platform_interface version (#3500) --- .../google_maps_flutter_platform_interface/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index d8b260a7a3eb..487a54b08e5e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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.0 +version: 1.2.0 dependencies: flutter: From 37d658e7b984c7585e4f7463127e328d63f69236 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 3 Feb 2021 15:36:03 -0800 Subject: [PATCH 149/924] [google_maps_flutter] add tile overlays (#3434) --- .../google_maps_flutter/android/build.gradle | 5 + .../flutter/plugins/googlemaps/Convert.java | 53 +++- .../plugins/googlemaps/GoogleMapBuilder.java | 9 + .../googlemaps/GoogleMapController.java | 41 +++ .../plugins/googlemaps/GoogleMapFactory.java | 4 + .../googlemaps/GoogleMapOptionsSink.java | 4 + .../googlemaps/TileOverlayBuilder.java | 46 ++++ .../googlemaps/TileOverlayController.java | 62 +++++ .../plugins/googlemaps/TileOverlaySink.java | 20 ++ .../googlemaps/TileOverlaysController.java | 120 +++++++++ .../googlemaps/TileProviderController.java | 100 +++++++ .../google_map_inspector.dart | 7 + .../integration_test/google_maps_test.dart | 244 ++++++++++++++++++ .../google_maps_flutter/example/lib/main.dart | 2 + .../example/lib/tile_overlay.dart | 151 +++++++++++ .../FLTGoogleMapTileOverlayController.h | 42 +++ .../FLTGoogleMapTileOverlayController.m | 234 +++++++++++++++++ .../ios/Classes/GoogleMapController.m | 30 +++ .../lib/google_maps_flutter.dart | 6 +- .../lib/src/controller.dart | 24 ++ .../lib/src/google_map.dart | 13 + .../google_maps_flutter/pubspec.yaml | 2 +- .../test/fake_maps_controllers.dart | 79 ++++++ .../test/tile_overlay_updates_test.dart | 210 +++++++++++++++ 24 files changed, 1505 insertions(+), 3 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java create mode 100644 packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java create mode 100644 packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java create mode 100644 packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java create mode 100644 packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java create mode 100644 packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter/android/build.gradle b/packages/google_maps_flutter/google_maps_flutter/android/build.gradle index a1d7da08a8d9..479c100b8293 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/build.gradle +++ b/packages/google_maps_flutter/google_maps_flutter/android/build.gradle @@ -39,6 +39,11 @@ android { androidTestImplementation 'androidx.test:rules:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 4108a1d23bb5..f9e0ed9c32d0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -23,6 +23,7 @@ import com.google.android.gms.maps.model.PatternItem; import com.google.android.gms.maps.model.RoundCap; import com.google.android.gms.maps.model.SquareCap; +import com.google.android.gms.maps.model.Tile; import io.flutter.view.FlutterMain; import java.util.ArrayList; import java.util.Arrays; @@ -78,7 +79,8 @@ private static BitmapDescriptor getBitmapFromBytes(List data) { } } else { throw new IllegalArgumentException( - "fromBytes should have exactly one argument, the bytes. Got: " + data.size()); + "fromBytes should have exactly one argument, interpretTileOverlayOptions the bytes. Got: " + + data.size()); } } @@ -200,6 +202,20 @@ static Object circleIdToJson(String circleId) { return data; } + static Map tileOverlayArgumentsToJson( + String tileOverlayId, int x, int y, int zoom) { + + if (tileOverlayId == null) { + return null; + } + final Map data = new HashMap<>(4); + data.put("tileOverlayId", tileOverlayId); + data.put("x", x); + data.put("y", y); + data.put("zoom", zoom); + return data; + } + static Object latLngToJson(LatLng latLng) { return Arrays.asList(latLng.latitude, latLng.longitude); } @@ -645,4 +661,39 @@ private static Cap toCap(Object o) { throw new IllegalArgumentException("Cannot interpret " + o + " as Cap"); } } + + static String interpretTileOverlayOptions(Map data, TileOverlaySink sink) { + final Object fadeIn = data.get("fadeIn"); + if (fadeIn != null) { + sink.setFadeIn(toBoolean(fadeIn)); + } + final Object transparency = data.get("transparency"); + if (transparency != null) { + sink.setTransparency(toFloat(transparency)); + } + final Object zIndex = data.get("zIndex"); + if (zIndex != null) { + sink.setZIndex(toFloat(zIndex)); + } + final Object visible = data.get("visible"); + if (visible != null) { + sink.setVisible(toBoolean(visible)); + } + final String tileOverlayId = (String) data.get("tileOverlayId"); + if (tileOverlayId == null) { + throw new IllegalArgumentException("tileOverlayId was null"); + } else { + return tileOverlayId; + } + } + + static Tile interpretTile(Map data) { + int width = toInt(data.get("width")); + int height = toInt(data.get("height")); + byte[] dataArray = null; + if (data.get("data") != null) { + dataArray = (byte[]) data.get("data"); + } + return new Tile(width, height, dataArray); + } } diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java index 93a3c3ec9c28..6d5c8c64ae1d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java @@ -10,6 +10,8 @@ import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLngBounds; import io.flutter.plugin.common.BinaryMessenger; +import java.util.List; +import java.util.Map; class GoogleMapBuilder implements GoogleMapOptionsSink { private final GoogleMapOptions options = new GoogleMapOptions(); @@ -23,6 +25,7 @@ class GoogleMapBuilder implements GoogleMapOptionsSink { private Object initialPolygons; private Object initialPolylines; private Object initialCircles; + private List> initialTileOverlays; private Rect padding = new Rect(0, 0, 0, 0); GoogleMapController build( @@ -44,6 +47,7 @@ GoogleMapController build( controller.setInitialPolylines(initialPolylines); controller.setInitialCircles(initialCircles); controller.setPadding(padding.top, padding.left, padding.bottom, padding.right); + controller.setInitialTileOverlays(initialTileOverlays); return controller; } @@ -165,4 +169,9 @@ public void setInitialPolylines(Object initialPolylines) { public void setInitialCircles(Object initialCircles) { this.initialCircles = initialCircles; } + + @Override + public void setInitialTileOverlays(List> initialTileOverlays) { + this.initialTileOverlays = initialTileOverlays; + } } diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index f6b8c3fe1fd1..7db65c56a5e8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -76,10 +76,12 @@ final class GoogleMapController private final PolygonsController polygonsController; private final PolylinesController polylinesController; private final CirclesController circlesController; + private final TileOverlaysController tileOverlaysController; private List initialMarkers; private List initialPolygons; private List initialPolylines; private List initialCircles; + private List> initialTileOverlays; GoogleMapController( int id, @@ -99,6 +101,7 @@ final class GoogleMapController this.polygonsController = new PolygonsController(methodChannel, density); this.polylinesController = new PolylinesController(methodChannel, density); this.circlesController = new CirclesController(methodChannel, density); + this.tileOverlaysController = new TileOverlaysController(methodChannel); } @Override @@ -140,10 +143,12 @@ public void onMapReady(GoogleMap googleMap) { polygonsController.setGoogleMap(googleMap); polylinesController.setGoogleMap(googleMap); circlesController.setGoogleMap(googleMap); + tileOverlaysController.setGoogleMap(googleMap); updateInitialMarkers(); updateInitialPolygons(); updateInitialPolylines(); updateInitialCircles(); + updateInitialTileOverlays(); } @Override @@ -385,6 +390,30 @@ public void onSnapshotReady(Bitmap bitmap) { result.success(mapStyleResult); break; } + case "tileOverlays#update": + { + List> tileOverlaysToAdd = call.argument("tileOverlaysToAdd"); + tileOverlaysController.addTileOverlays(tileOverlaysToAdd); + List> tileOverlaysToChange = call.argument("tileOverlaysToChange"); + tileOverlaysController.changeTileOverlays(tileOverlaysToChange); + List tileOverlaysToRemove = call.argument("tileOverlayIdsToRemove"); + tileOverlaysController.removeTileOverlays(tileOverlaysToRemove); + result.success(null); + break; + } + case "tileOverlays#clearTileCache": + { + String tileOverlayId = call.argument("tileOverlayId"); + tileOverlaysController.clearTileCache(tileOverlayId); + result.success(null); + break; + } + case "map#getTileOverlayInfo": + { + String tileOverlayId = call.argument("tileOverlayId"); + result.success(tileOverlaysController.getTileOverlayInfo(tileOverlayId)); + break; + } default: result.notImplemented(); } @@ -732,6 +761,18 @@ private void updateInitialCircles() { circlesController.addCircles(initialCircles); } + @Override + public void setInitialTileOverlays(List> initialTileOverlays) { + this.initialTileOverlays = initialTileOverlays; + if (googleMap != null) { + updateInitialTileOverlays(); + } + } + + private void updateInitialTileOverlays() { + tileOverlaysController.addTileOverlays(initialTileOverlays); + } + @SuppressLint("MissingPermission") private void updateMyLocationSettings() { if (hasLocationPermission()) { diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java index e56adbbb987a..bf9188ffd1b1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java @@ -10,6 +10,7 @@ import io.flutter.plugin.common.StandardMessageCodec; import io.flutter.plugin.platform.PlatformView; import io.flutter.plugin.platform.PlatformViewFactory; +import java.util.List; import java.util.Map; public class GoogleMapFactory extends PlatformViewFactory { @@ -46,6 +47,9 @@ public PlatformView create(Context context, int id, Object args) { if (params.containsKey("circlesToAdd")) { builder.setInitialCircles(params.get("circlesToAdd")); } + if (params.containsKey("tileOverlaysToAdd")) { + builder.setInitialTileOverlays((List>) params.get("tileOverlaysToAdd")); + } return builder.build(id, context, binaryMessenger, lifecycleProvider); } } diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java index 9e6fa2a27236..03377d4b760e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java @@ -5,6 +5,8 @@ package io.flutter.plugins.googlemaps; import com.google.android.gms.maps.model.LatLngBounds; +import java.util.List; +import java.util.Map; /** Receiver of GoogleMap configuration options. */ interface GoogleMapOptionsSink { @@ -51,4 +53,6 @@ interface GoogleMapOptionsSink { void setInitialPolylines(Object initialPolylines); void setInitialCircles(Object initialCircles); + + void setInitialTileOverlays(List> initialTileOverlays); } diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java new file mode 100644 index 000000000000..1b5593358536 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java @@ -0,0 +1,46 @@ +// Copyright 2018 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. + +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.model.TileOverlayOptions; +import com.google.android.gms.maps.model.TileProvider; + +class TileOverlayBuilder implements TileOverlaySink { + + private final TileOverlayOptions tileOverlayOptions; + + TileOverlayBuilder() { + this.tileOverlayOptions = new TileOverlayOptions(); + } + + TileOverlayOptions build() { + return tileOverlayOptions; + } + + @Override + public void setFadeIn(boolean fadeIn) { + tileOverlayOptions.fadeIn(fadeIn); + } + + @Override + public void setTransparency(float transparency) { + tileOverlayOptions.transparency(transparency); + } + + @Override + public void setZIndex(float zIndex) { + tileOverlayOptions.zIndex(zIndex); + } + + @Override + public void setVisible(boolean visible) { + tileOverlayOptions.visible(visible); + } + + @Override + public void setTileProvider(TileProvider tileProvider) { + tileOverlayOptions.tileProvider(tileProvider); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java new file mode 100644 index 000000000000..1204bcdaafd7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java @@ -0,0 +1,62 @@ +// Copyright 2018 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. + +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.model.TileOverlay; +import com.google.android.gms.maps.model.TileProvider; +import java.util.HashMap; +import java.util.Map; + +class TileOverlayController implements TileOverlaySink { + + private final TileOverlay tileOverlay; + + TileOverlayController(TileOverlay tileOverlay) { + this.tileOverlay = tileOverlay; + } + + void remove() { + tileOverlay.remove(); + } + + void clearTileCache() { + tileOverlay.clearTileCache(); + } + + Map getTileOverlayInfo() { + Map tileOverlayInfo = new HashMap<>(); + tileOverlayInfo.put("fadeIn", tileOverlay.getFadeIn()); + tileOverlayInfo.put("transparency", tileOverlay.getTransparency()); + tileOverlayInfo.put("id", tileOverlay.getId()); + tileOverlayInfo.put("zIndex", tileOverlay.getZIndex()); + tileOverlayInfo.put("visible", tileOverlay.isVisible()); + return tileOverlayInfo; + } + + @Override + public void setFadeIn(boolean fadeIn) { + tileOverlay.setFadeIn(fadeIn); + } + + @Override + public void setTransparency(float transparency) { + tileOverlay.setTransparency(transparency); + } + + @Override + public void setZIndex(float zIndex) { + tileOverlay.setZIndex(zIndex); + } + + @Override + public void setVisible(boolean visible) { + tileOverlay.setVisible(visible); + } + + @Override + public void setTileProvider(TileProvider tileProvider) { + // You can not change tile provider after creation + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java new file mode 100644 index 000000000000..fd611d7c57f3 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java @@ -0,0 +1,20 @@ +// Copyright 2018 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. + +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.model.TileProvider; + +/** Receiver of TileOverlayOptions configuration. */ +interface TileOverlaySink { + void setFadeIn(boolean fadeIn); + + void setTransparency(float transparency); + + void setZIndex(float zIndex); + + void setVisible(boolean visible); + + void setTileProvider(TileProvider tileProvider); +} diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java new file mode 100644 index 000000000000..cd583e247cdd --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java @@ -0,0 +1,120 @@ +// Copyright 2018 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. + +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.model.TileOverlay; +import com.google.android.gms.maps.model.TileOverlayOptions; +import io.flutter.plugin.common.MethodChannel; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class TileOverlaysController { + + private final Map tileOverlayIdToController; + private final MethodChannel methodChannel; + private GoogleMap googleMap; + + TileOverlaysController(MethodChannel methodChannel) { + this.tileOverlayIdToController = new HashMap<>(); + this.methodChannel = methodChannel; + } + + void setGoogleMap(GoogleMap googleMap) { + this.googleMap = googleMap; + } + + void addTileOverlays(List> tileOverlaysToAdd) { + if (tileOverlaysToAdd == null) { + return; + } + for (Map tileOverlayToAdd : tileOverlaysToAdd) { + addTileOverlay(tileOverlayToAdd); + } + } + + void changeTileOverlays(List> tileOverlaysToChange) { + if (tileOverlaysToChange == null) { + return; + } + for (Map tileOverlayToChange : tileOverlaysToChange) { + changeTileOverlay(tileOverlayToChange); + } + } + + void removeTileOverlays(List tileOverlayIdsToRemove) { + if (tileOverlayIdsToRemove == null) { + return; + } + for (String tileOverlayId : tileOverlayIdsToRemove) { + if (tileOverlayId == null) { + continue; + } + removeTileOverlay(tileOverlayId); + } + } + + void clearTileCache(String tileOverlayId) { + if (tileOverlayId == null) { + return; + } + TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); + if (tileOverlayController != null) { + tileOverlayController.clearTileCache(); + } + } + + Map getTileOverlayInfo(String tileOverlayId) { + if (tileOverlayId == null) { + return null; + } + TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); + if (tileOverlayController == null) { + return null; + } + return tileOverlayController.getTileOverlayInfo(); + } + + private void addTileOverlay(Map tileOverlayOptions) { + if (tileOverlayOptions == null) { + return; + } + TileOverlayBuilder tileOverlayOptionsBuilder = new TileOverlayBuilder(); + String tileOverlayId = + Convert.interpretTileOverlayOptions(tileOverlayOptions, tileOverlayOptionsBuilder); + TileProviderController tileProviderController = + new TileProviderController(methodChannel, tileOverlayId); + tileOverlayOptionsBuilder.setTileProvider(tileProviderController); + TileOverlayOptions options = tileOverlayOptionsBuilder.build(); + TileOverlay tileOverlay = googleMap.addTileOverlay(options); + TileOverlayController tileOverlayController = new TileOverlayController(tileOverlay); + tileOverlayIdToController.put(tileOverlayId, tileOverlayController); + } + + private void changeTileOverlay(Map tileOverlayOptions) { + if (tileOverlayOptions == null) { + return; + } + String tileOverlayId = getTileOverlayId(tileOverlayOptions); + TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); + if (tileOverlayController != null) { + Convert.interpretTileOverlayOptions(tileOverlayOptions, tileOverlayController); + } + } + + private void removeTileOverlay(String tileOverlayId) { + TileOverlayController tileOverlayController = tileOverlayIdToController.get(tileOverlayId); + if (tileOverlayController != null) { + tileOverlayController.remove(); + tileOverlayIdToController.remove(tileOverlayId); + } + } + + @SuppressWarnings("unchecked") + private static String getTileOverlayId(Map tileOverlay) { + return (String) tileOverlay.get("tileOverlayId"); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java new file mode 100644 index 000000000000..f28118c91db4 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java @@ -0,0 +1,100 @@ +// Copyright 2018 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. + +package io.flutter.plugins.googlemaps; + +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import androidx.annotation.NonNull; +import com.google.android.gms.maps.model.Tile; +import com.google.android.gms.maps.model.TileProvider; +import io.flutter.plugin.common.MethodChannel; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +class TileProviderController implements TileProvider { + + private static final String TAG = "TileProviderController"; + + private final String tileOverlayId; + private final MethodChannel methodChannel; + private final Handler handler = new Handler(Looper.getMainLooper()); + + TileProviderController(MethodChannel methodChannel, String tileOverlayId) { + this.tileOverlayId = tileOverlayId; + this.methodChannel = methodChannel; + } + + @Override + public Tile getTile(final int x, final int y, final int zoom) { + Worker worker = new Worker(x, y, zoom); + return worker.getTile(); + } + + private final class Worker implements MethodChannel.Result { + + private final CountDownLatch countDownLatch = new CountDownLatch(1); + private final int x; + private final int y; + private final int zoom; + private Map result; + + Worker(int x, int y, int zoom) { + this.x = x; + this.y = y; + this.zoom = zoom; + } + + @NonNull + Tile getTile() { + handler.post( + () -> + methodChannel.invokeMethod( + "tileOverlay#getTile", + Convert.tileOverlayArgumentsToJson(tileOverlayId, x, y, zoom), + this)); + try { + // Because `methodChannel.invokeMethod` is async, we use a `countDownLatch` make it synchronized. + countDownLatch.await(); + } catch (InterruptedException e) { + Log.e( + TAG, + String.format("countDownLatch: can't get tile: x = %d, y= %d, zoom = %d", x, y, zoom), + e); + return TileProvider.NO_TILE; + } + try { + return Convert.interpretTile(result); + } catch (Exception e) { + Log.e(TAG, "Can't parse tile data", e); + return TileProvider.NO_TILE; + } + } + + @Override + public void success(Object data) { + result = (Map) data; + countDownLatch.countDown(); + } + + @Override + public void error(String errorCode, String errorMessage, Object data) { + Log.e( + TAG, + String.format( + "Can't get tile: errorCode = %s, errorMessage = %s, date = %s", + errorCode, errorCode, data)); + result = null; + countDownLatch.countDown(); + } + + @Override + public void notImplemented() { + Log.e(TAG, "Can't get tile: notImplemented"); + result = null; + countDownLatch.countDown(); + } + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart index 2fcfec15713a..0f2dafb80f70 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart @@ -76,4 +76,11 @@ class GoogleMapInspector { Future takeSnapshot() async { return await _channel.invokeMethod('map#takeSnapshot'); } + + Future> getTileOverlayInfo(String id) async { + return await _channel.invokeMapMethod( + 'map#getTileOverlayInfo', { + 'tileOverlayId': id, + }); + } } diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart index 2a5bf80a4578..557337f0c025 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'dart:io'; import 'dart:typed_data'; +import 'dart:ui' as ui; import 'package:integration_test/integration_test.dart'; import 'package:flutter/material.dart'; @@ -987,4 +988,247 @@ void main() { // TODO(cyanglaz): un-skip the test when we can test this on CI with API key enabled. // https://github.com/flutter/flutter/issues/57057 skip: Platform.isAndroid); + + testWidgets( + 'set tileOverlay correctly', + (WidgetTester tester) async { + Completer inspectorCompleter = + Completer(); + final TileOverlay tileOverlay1 = TileOverlay( + tileOverlayId: TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + visible: true, + transparency: 0.2, + fadeIn: true, + ); + + final TileOverlay tileOverlay2 = TileOverlay( + tileOverlayId: TileOverlayId('tile_overlay_2'), + tileProvider: _DebugTileProvider(), + zIndex: 1, + visible: false, + transparency: 0.3, + fadeIn: false, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: GoogleMap( + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1, tileOverlay2}, + onMapCreated: (GoogleMapController controller) { + final GoogleMapInspector inspector = + // ignore: invalid_use_of_visible_for_testing_member + GoogleMapInspector(controller.channel); + inspectorCompleter.complete(inspector); + }, + ), + ), + ); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final GoogleMapInspector inspector = await inspectorCompleter.future; + + Map tileOverlayInfo1 = + await inspector.getTileOverlayInfo('tile_overlay_1'); + Map tileOverlayInfo2 = + await inspector.getTileOverlayInfo('tile_overlay_2'); + + expect(tileOverlayInfo1['visible'], isTrue); + expect(tileOverlayInfo1['fadeIn'], isTrue); + expect(tileOverlayInfo1['transparency'], + moreOrLessEquals(0.2, epsilon: 0.001)); + expect(tileOverlayInfo1['zIndex'], 2); + + expect(tileOverlayInfo2['visible'], isFalse); + expect(tileOverlayInfo2['fadeIn'], isFalse); + expect(tileOverlayInfo2['transparency'], + moreOrLessEquals(0.3, epsilon: 0.001)); + expect(tileOverlayInfo2['zIndex'], 1); + }, + ); + + testWidgets( + 'update tileOverlays correctly', + (WidgetTester tester) async { + Completer inspectorCompleter = + Completer(); + final Key key = GlobalKey(); + final TileOverlay tileOverlay1 = TileOverlay( + tileOverlayId: TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + visible: true, + transparency: 0.2, + fadeIn: true, + ); + + final TileOverlay tileOverlay2 = TileOverlay( + tileOverlayId: TileOverlayId('tile_overlay_2'), + tileProvider: _DebugTileProvider(), + zIndex: 3, + visible: true, + transparency: 0.5, + fadeIn: true, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: GoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1, tileOverlay2}, + onMapCreated: (GoogleMapController controller) { + final GoogleMapInspector inspector = + // ignore: invalid_use_of_visible_for_testing_member + GoogleMapInspector(controller.channel); + inspectorCompleter.complete(inspector); + }, + ), + ), + ); + + final GoogleMapInspector inspector = await inspectorCompleter.future; + + final TileOverlay tileOverlay1New = TileOverlay( + tileOverlayId: TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 1, + visible: false, + transparency: 0.3, + fadeIn: false, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: GoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1New}, + onMapCreated: (GoogleMapController controller) { + fail('update: OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + Map tileOverlayInfo1 = + await inspector.getTileOverlayInfo('tile_overlay_1'); + Map tileOverlayInfo2 = + await inspector.getTileOverlayInfo('tile_overlay_2'); + + expect(tileOverlayInfo1['visible'], isFalse); + expect(tileOverlayInfo1['fadeIn'], isFalse); + expect(tileOverlayInfo1['transparency'], + moreOrLessEquals(0.3, epsilon: 0.001)); + expect(tileOverlayInfo1['zIndex'], 1); + + expect(tileOverlayInfo2, isNull); + }, + ); + + testWidgets( + 'remove tileOverlays correctly', + (WidgetTester tester) async { + Completer inspectorCompleter = + Completer(); + final Key key = GlobalKey(); + final TileOverlay tileOverlay1 = TileOverlay( + tileOverlayId: TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + visible: true, + transparency: 0.2, + fadeIn: true, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: GoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1}, + onMapCreated: (GoogleMapController controller) { + final GoogleMapInspector inspector = + // ignore: invalid_use_of_visible_for_testing_member + GoogleMapInspector(controller.channel); + inspectorCompleter.complete(inspector); + }, + ), + ), + ); + + final GoogleMapInspector inspector = await inspectorCompleter.future; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: GoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (GoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + Map tileOverlayInfo1 = + await inspector.getTileOverlayInfo('tile_overlay_1'); + + expect(tileOverlayInfo1, isNull); + }, + ); +} + +class _DebugTileProvider implements TileProvider { + _DebugTileProvider() { + boxPaint.isAntiAlias = true; + boxPaint.color = Colors.blue; + boxPaint.strokeWidth = 2.0; + boxPaint.style = PaintingStyle.stroke; + } + + static const int width = 100; + static const int height = 100; + static final Paint boxPaint = Paint(); + static final TextStyle textStyle = TextStyle( + color: Colors.red, + fontSize: 20, + ); + + @override + Future getTile(int x, int y, int zoom) async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final Canvas canvas = Canvas(recorder); + final TextSpan textSpan = TextSpan( + text: "$x,$y", + style: textStyle, + ); + final TextPainter textPainter = TextPainter( + text: textSpan, + textDirection: TextDirection.ltr, + ); + textPainter.layout( + minWidth: 0.0, + maxWidth: width.toDouble(), + ); + final Offset offset = const Offset(0, 0); + textPainter.paint(canvas, offset); + canvas.drawRect( + Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), boxPaint); + final ui.Picture picture = recorder.endRecording(); + final Uint8List byteData = await picture + .toImage(width, height) + .then((ui.Image image) => + image.toByteData(format: ui.ImageByteFormat.png)) + .then((ByteData byteData) => byteData.buffer.asUint8List()); + return Tile(width, height, byteData); + } } diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart index 13763edb8216..b795040658e6 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart @@ -20,6 +20,7 @@ import 'place_polygon.dart'; import 'place_polyline.dart'; import 'scrolling_map.dart'; import 'snapshot.dart'; +import 'tile_overlay.dart'; final List _allPages = [ MapUiPage(), @@ -36,6 +37,7 @@ final List _allPages = [ PaddingPage(), SnapshotPage(), LiteModePage(), + TileOverlayPage(), ]; class MapsDemo extends StatelessWidget { diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart new file mode 100644 index 000000000000..354fa06a7ab7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart @@ -0,0 +1,151 @@ +// Copyright 2018 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. + +// ignore_for_file: public_member_api_docs + +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +import 'page.dart'; + +class TileOverlayPage extends GoogleMapExampleAppPage { + TileOverlayPage() : super(const Icon(Icons.map), 'Tile overlay'); + + @override + Widget build(BuildContext context) { + return const TileOverlayBody(); + } +} + +class TileOverlayBody extends StatefulWidget { + const TileOverlayBody(); + + @override + State createState() => TileOverlayBodyState(); +} + +class TileOverlayBodyState extends State { + TileOverlayBodyState(); + + GoogleMapController controller; + TileOverlay _tileOverlay; + + void _onMapCreated(GoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _removeTileOverlay() { + setState(() { + _tileOverlay = null; + }); + } + + void _addTileOverlay() { + final TileOverlay tileOverlay = TileOverlay( + tileOverlayId: TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + ); + setState(() { + _tileOverlay = tileOverlay; + }); + } + + void _clearTileCache() { + if (_tileOverlay != null && controller != null) { + controller.clearTileCache(_tileOverlay.tileOverlayId); + } + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: GoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(59.935460, 30.325177), + zoom: 7.0, + ), + tileOverlays: + _tileOverlay != null ? {_tileOverlay} : null, + onMapCreated: _onMapCreated, + ), + ), + ), + TextButton( + child: const Text('Add tile overlay'), + onPressed: _addTileOverlay, + ), + TextButton( + child: const Text('Remove tile overlay'), + onPressed: _removeTileOverlay, + ), + TextButton( + child: const Text('Clear tile cache'), + onPressed: _clearTileCache, + ), + ], + ); + } +} + +class _DebugTileProvider implements TileProvider { + _DebugTileProvider() { + boxPaint.isAntiAlias = true; + boxPaint.color = Colors.blue; + boxPaint.strokeWidth = 2.0; + boxPaint.style = PaintingStyle.stroke; + } + + static const int width = 100; + static const int height = 100; + static final Paint boxPaint = Paint(); + static final TextStyle textStyle = TextStyle( + color: Colors.red, + fontSize: 20, + ); + + @override + Future getTile(int x, int y, int zoom) async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final Canvas canvas = Canvas(recorder); + final TextSpan textSpan = TextSpan( + text: '$x,$y', + style: textStyle, + ); + final TextPainter textPainter = TextPainter( + text: textSpan, + textDirection: TextDirection.ltr, + ); + textPainter.layout( + minWidth: 0.0, + maxWidth: width.toDouble(), + ); + final Offset offset = const Offset(0, 0); + textPainter.paint(canvas, offset); + canvas.drawRect( + Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), boxPaint); + final ui.Picture picture = recorder.endRecording(); + final Uint8List byteData = await picture + .toImage(width, height) + .then((ui.Image image) => + image.toByteData(format: ui.ImageByteFormat.png)) + .then((ByteData byteData) => byteData.buffer.asUint8List()); + return Tile(width, height, byteData); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h new file mode 100644 index 000000000000..f84ad7c20bb4 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h @@ -0,0 +1,42 @@ +// Copyright 2018 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 +#import + +NS_ASSUME_NONNULL_BEGIN + +// Defines map UI options writable from Flutter. +@protocol FLTGoogleMapTileOverlayOptionsSink +- (void)setFadeIn:(BOOL)fadeIn; +- (void)setTransparency:(float)transparency; +- (void)setZIndex:(int)zIndex; +- (void)setVisible:(BOOL)visible; +- (void)setTileSize:(NSInteger)tileSize; +@end + +@interface FLTGoogleMapTileOverlayController : NSObject +- (instancetype)initWithTileLayer:(GMSTileLayer *)tileLayer mapView:(GMSMapView *)mapView; +- (void)removeTileOverlay; +- (void)clearTileCache; +- (NSDictionary *)getTileOverlayInfo; +@end + +@interface FLTTileProviderController : GMSTileLayer +@property(copy, nonatomic, readonly) NSString *tileOverlayId; +- (instancetype)init:(FlutterMethodChannel *)methodChannel tileOverlayId:(NSString *)tileOverlayId; +@end + +@interface FLTTileOverlaysController : NSObject +- (instancetype)init:(FlutterMethodChannel *)methodChannel + mapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar; +- (void)addTileOverlays:(NSArray *)tileOverlaysToAdd; +- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange; +- (void)removeTileOverlayIds:(NSArray *)tileOverlayIdsToRemove; +- (void)clearTileCache:(NSString *)tileOverlayId; +- (nullable NSDictionary *)getTileOverlayInfo:(NSString *)tileverlayId; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m new file mode 100644 index 000000000000..7fbd7c53b90a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m @@ -0,0 +1,234 @@ +// Copyright 2018 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 "FLTGoogleMapTileOverlayController.h" +#import "JsonConversions.h" + +static void InterpretTileOverlayOptions(NSDictionary* data, + id sink, + NSObject* registrar) { + NSNumber* visible = data[@"visible"]; + if (visible != nil) { + [sink setVisible:visible.boolValue]; + } + + NSNumber* transparency = data[@"transparency"]; + if (transparency != nil) { + [sink setTransparency:transparency.floatValue]; + } + + NSNumber* zIndex = data[@"zIndex"]; + if (zIndex != nil) { + [sink setZIndex:zIndex.intValue]; + } + + NSNumber* fadeIn = data[@"fadeIn"]; + if (fadeIn != nil) { + [sink setFadeIn:fadeIn.boolValue]; + } + + NSNumber* tileSize = data[@"tileSize"]; + if (tileSize != nil) { + [sink setTileSize:tileSize.integerValue]; + } +} + +@interface FLTGoogleMapTileOverlayController () + +@property(strong, nonatomic) GMSTileLayer* layer; +@property(weak, nonatomic) GMSMapView* mapView; + +@end + +@implementation FLTGoogleMapTileOverlayController + +- (instancetype)initWithTileLayer:(GMSTileLayer*)tileLayer mapView:(GMSMapView*)mapView { + self = [super init]; + if (self) { + self.layer = tileLayer; + self.mapView = mapView; + } + return self; +} + +- (void)removeTileOverlay { + self.layer.map = nil; +} + +- (void)clearTileCache { + [self.layer clearTileCache]; +} + +- (NSDictionary*)getTileOverlayInfo { + NSMutableDictionary* info = [[NSMutableDictionary alloc] init]; + BOOL visible = self.layer.map != nil; + info[@"visible"] = @(visible); + info[@"fadeIn"] = @(self.layer.fadeIn); + float transparency = 1.0 - self.layer.opacity; + info[@"transparency"] = @(transparency); + info[@"zIndex"] = @(self.layer.zIndex); + return info; +} + +#pragma mark - FLTGoogleMapTileOverlayOptionsSink methods + +- (void)setFadeIn:(BOOL)fadeIn { + self.layer.fadeIn = fadeIn; +} + +- (void)setTransparency:(float)transparency { + float opacity = 1.0 - transparency; + self.layer.opacity = opacity; +} + +- (void)setVisible:(BOOL)visible { + self.layer.map = visible ? self.mapView : nil; +} + +- (void)setZIndex:(int)zIndex { + self.layer.zIndex = zIndex; +} + +- (void)setTileSize:(NSInteger)tileSize { + self.layer.tileSize = tileSize; +} +@end + +@interface FLTTileProviderController () + +@property(weak, nonatomic) FlutterMethodChannel* methodChannel; +@property(copy, nonatomic, readwrite) NSString* tileOverlayId; + +@end + +@implementation FLTTileProviderController + +- (instancetype)init:(FlutterMethodChannel*)methodChannel tileOverlayId:(NSString*)tileOverlayId { + self = [super init]; + if (self) { + self.methodChannel = methodChannel; + self.tileOverlayId = tileOverlayId; + } + return self; +} + +#pragma mark - GMSTileLayer method + +- (void)requestTileForX:(NSUInteger)x + y:(NSUInteger)y + zoom:(NSUInteger)zoom + receiver:(id)receiver { + [self.methodChannel + invokeMethod:@"tileOverlay#getTile" + arguments:@{ + @"tileOverlayId" : self.tileOverlayId, + @"x" : @(x), + @"y" : @(y), + @"zoom" : @(zoom) + } + result:^(id _Nullable result) { + UIImage* tileImage; + if ([result isKindOfClass:[NSDictionary class]]) { + FlutterStandardTypedData* typedData = (FlutterStandardTypedData*)result[@"data"]; + if (typedData == nil) { + tileImage = kGMSTileLayerNoTile; + } else { + tileImage = [UIImage imageWithData:typedData.data]; + } + } else { + if ([result isKindOfClass:[FlutterError class]]) { + FlutterError* error = (FlutterError*)result; + NSLog(@"Can't get tile: errorCode = %@, errorMessage = %@, details = %@", + [error code], [error message], [error details]); + } + if ([result isKindOfClass:[FlutterMethodNotImplemented class]]) { + NSLog(@"Can't get tile: notImplemented"); + } + tileImage = kGMSTileLayerNoTile; + } + + [receiver receiveTileWithX:x y:y zoom:zoom image:tileImage]; + }]; +} + +@end + +@interface FLTTileOverlaysController () + +@property(strong, nonatomic) NSMutableDictionary* tileOverlayIdToController; +@property(weak, nonatomic) FlutterMethodChannel* methodChannel; +@property(weak, nonatomic) NSObject* registrar; +@property(weak, nonatomic) GMSMapView* mapView; + +@end + +@implementation FLTTileOverlaysController + +- (instancetype)init:(FlutterMethodChannel*)methodChannel + mapView:(GMSMapView*)mapView + registrar:(NSObject*)registrar { + self = [super init]; + if (self) { + self.methodChannel = methodChannel; + self.mapView = mapView; + self.tileOverlayIdToController = [[NSMutableDictionary alloc] init]; + self.registrar = registrar; + } + return self; +} + +- (void)addTileOverlays:(NSArray*)tileOverlaysToAdd { + for (NSDictionary* tileOverlay in tileOverlaysToAdd) { + NSString* tileOverlayId = [FLTTileOverlaysController getTileOverlayId:tileOverlay]; + FLTTileProviderController* tileProvider = + [[FLTTileProviderController alloc] init:self.methodChannel tileOverlayId:tileOverlayId]; + FLTGoogleMapTileOverlayController* controller = + [[FLTGoogleMapTileOverlayController alloc] initWithTileLayer:tileProvider + mapView:self.mapView]; + InterpretTileOverlayOptions(tileOverlay, controller, self.registrar); + self.tileOverlayIdToController[tileOverlayId] = controller; + } +} + +- (void)changeTileOverlays:(NSArray*)tileOverlaysToChange { + for (NSDictionary* tileOverlay in tileOverlaysToChange) { + NSString* tileOverlayId = [FLTTileOverlaysController getTileOverlayId:tileOverlay]; + FLTGoogleMapTileOverlayController* controller = self.tileOverlayIdToController[tileOverlayId]; + if (!controller) { + continue; + } + InterpretTileOverlayOptions(tileOverlay, controller, self.registrar); + } +} +- (void)removeTileOverlayIds:(NSArray*)tileOverlayIdsToRemove { + for (NSString* tileOverlayId in tileOverlayIdsToRemove) { + FLTGoogleMapTileOverlayController* controller = self.tileOverlayIdToController[tileOverlayId]; + if (!controller) { + continue; + } + [controller removeTileOverlay]; + [self.tileOverlayIdToController removeObjectForKey:tileOverlayId]; + } +} + +- (void)clearTileCache:(NSString*)tileOverlayId { + FLTGoogleMapTileOverlayController* controller = self.tileOverlayIdToController[tileOverlayId]; + if (!controller) { + return; + } + [controller clearTileCache]; +} + +- (nullable NSDictionary*)getTileOverlayInfo:(NSString*)tileverlayId { + if (self.tileOverlayIdToController[tileverlayId] == nil) { + return nil; + } + return [self.tileOverlayIdToController[tileverlayId] getTileOverlayInfo]; +} + ++ (NSString*)getTileOverlayId:(NSDictionary*)tileOverlay { + return tileOverlay[@"tileOverlayId"]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m index 321ddd318536..749ce9e84a4e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m @@ -3,6 +3,7 @@ // found in the LICENSE file. #import "GoogleMapController.h" +#import "FLTGoogleMapTileOverlayController.h" #import "JsonConversions.h" #pragma mark - Conversion of JSON-like values sent via platform channels. Forward declarations. @@ -55,6 +56,7 @@ @implementation FLTGoogleMapController { FLTPolygonsController* _polygonsController; FLTPolylinesController* _polylinesController; FLTCirclesController* _circlesController; + FLTTileOverlaysController* _tileOverlaysController; } - (instancetype)initWithFrame:(CGRect)frame @@ -94,6 +96,9 @@ - (instancetype)initWithFrame:(CGRect)frame _circlesController = [[FLTCirclesController alloc] init:_channel mapView:_mapView registrar:registrar]; + _tileOverlaysController = [[FLTTileOverlaysController alloc] init:_channel + mapView:_mapView + registrar:registrar]; id markersToAdd = args[@"markersToAdd"]; if ([markersToAdd isKindOfClass:[NSArray class]]) { [_markersController addMarkers:markersToAdd]; @@ -110,6 +115,10 @@ - (instancetype)initWithFrame:(CGRect)frame if ([circlesToAdd isKindOfClass:[NSArray class]]) { [_circlesController addCircles:circlesToAdd]; } + id tileOverlaysToAdd = args[@"tileOverlaysToAdd"]; + if ([tileOverlaysToAdd isKindOfClass:[NSArray class]]) { + [_tileOverlaysController addTileOverlays:tileOverlaysToAdd]; + } } return self; } @@ -298,6 +307,24 @@ - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [_circlesController removeCircleIds:circleIdsToRemove]; } result(nil); + } else if ([call.method isEqualToString:@"tileOverlays#update"]) { + id tileOverlaysToAdd = call.arguments[@"tileOverlaysToAdd"]; + if ([tileOverlaysToAdd isKindOfClass:[NSArray class]]) { + [_tileOverlaysController addTileOverlays:tileOverlaysToAdd]; + } + id tileOverlaysToChange = call.arguments[@"tileOverlaysToChange"]; + if ([tileOverlaysToChange isKindOfClass:[NSArray class]]) { + [_tileOverlaysController changeTileOverlays:tileOverlaysToChange]; + } + id tileOverlayIdsToRemove = call.arguments[@"tileOverlayIdsToRemove"]; + if ([tileOverlayIdsToRemove isKindOfClass:[NSArray class]]) { + [_tileOverlaysController removeTileOverlayIds:tileOverlayIdsToRemove]; + } + result(nil); + } else if ([call.method isEqualToString:@"tileOverlays#clearTileCache"]) { + id rawTileOverlayId = call.arguments[@"tileOverlayId"]; + [_tileOverlaysController clearTileCache:rawTileOverlayId]; + result(nil); } else if ([call.method isEqualToString:@"map#isCompassEnabled"]) { NSNumber* isCompassEnabled = @(_mapView.settings.compassButton); result(isCompassEnabled); @@ -341,6 +368,9 @@ - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } else { result(@[ @(NO), error ]); } + } else if ([call.method isEqualToString:@"map#getTileOverlayInfo"]) { + NSString* rawTileOverlayId = call.arguments[@"tileOverlayId"]; + result([_tileOverlaysController getTileOverlayInfo:rawTileOverlayId]); } else { result(FlutterMethodNotImplemented); } diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart index 682c901f4d4a..703ba63e5ccc 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart @@ -42,7 +42,11 @@ export 'package:google_maps_flutter_platform_interface/google_maps_flutter_platf PolygonId, Polyline, PolylineId, - ScreenCoordinate; + ScreenCoordinate, + Tile, + TileOverlayId, + TileOverlay, + TileProvider; part 'src/controller.dart'; part 'src/google_map.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart index f47b8e57b049..3967179b0e50 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart @@ -152,6 +152,30 @@ class GoogleMapController { mapId: mapId); } + /// Updates tile overlays configuration. + /// + /// Change listeners are notified once the update has been made on the + /// platform side. + /// + /// The returned [Future] completes after listeners have been notified. + Future _updateTileOverlays(Set newTileOverlays) { + return _googleMapsFlutterPlatform.updateTileOverlays( + newTileOverlays: newTileOverlays, mapId: mapId); + } + + /// Clears the tile cache so that all tiles will be requested again from the + /// [TileProvider]. + /// + /// The current tiles from this tile overlay will also be + /// cleared from the map after calling this method. The API maintains a small + /// in-memory cache of tiles. If you want to cache tiles for longer, you + /// should implement an on-disk cache. + Future clearTileCache(TileOverlayId tileOverlayId) async { + assert(tileOverlayId != null); + return _googleMapsFlutterPlatform.clearTileCache(tileOverlayId, + mapId: mapId); + } + /// Starts an animated change of the map camera position. /// /// The returned [Future] completes after the change has been started on the diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart index d7f0f1a4e280..e7f5e32d61b9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart @@ -50,6 +50,7 @@ class GoogleMap extends StatefulWidget { this.polylines, this.circles, this.onCameraMoveStarted, + this.tileOverlays, this.onCameraMove, this.onCameraIdle, this.onTap, @@ -120,6 +121,9 @@ class GoogleMap extends StatefulWidget { /// Circles to be placed on the map. final Set circles; + /// Tile overlays to be placed on the map. + final Set tileOverlays; + /// Called when the camera starts moving. /// /// This can be initiated by the following: @@ -232,6 +236,7 @@ class _GoogleMapState extends State { 'polylinesToAdd': serializePolylineSet(widget.polylines), 'circlesToAdd': serializeCircleSet(widget.circles), '_webOnlyMapCreationId': _webOnlyMapCreationId, + 'tileOverlaysToAdd': serializeTileOverlaySet(widget.tileOverlays), }; return _googleMapsFlutterPlatform.buildView( @@ -266,6 +271,7 @@ class _GoogleMapState extends State { _updatePolygons(); _updatePolylines(); _updateCircles(); + _updateTileOverlays(); } void _updateOptions() async { @@ -313,6 +319,12 @@ class _GoogleMapState extends State { _circles = keyByCircleId(widget.circles); } + void _updateTileOverlays() async { + final GoogleMapController controller = await _controller.future; + // ignore: unawaited_futures + controller._updateTileOverlays(widget.tileOverlays); + } + Future onPlatformViewCreated(int id) async { final GoogleMapController controller = await GoogleMapController.init( id, @@ -320,6 +332,7 @@ class _GoogleMapState extends State { this, ); _controller.complete(controller); + _updateTileOverlays(); if (widget.onMapCreated != null) { widget.onMapCreated(controller); } diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index ef3a06f5862c..be5c0d449806 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -7,7 +7,7 @@ dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: ^1.0.0 - google_maps_flutter_platform_interface: ^1.1.0 + google_maps_flutter_platform_interface: ^1.2.0 dev_dependencies: flutter_test: diff --git a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart index 9a849bd94e70..d72ac2ebe656 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart @@ -19,6 +19,7 @@ class FakePlatformGoogleMap { updatePolygons(params); updatePolylines(params); updateCircles(params); + updateTileOverlays(Map.castFrom(params)); } MethodChannel channel; @@ -83,6 +84,12 @@ class FakePlatformGoogleMap { Set circlesToChange; + Set tileOverlayIdsToRemove; + + Set tileOverlaysToAdd; + + Set tileOverlaysToChange; + Future onMethodCall(MethodCall call) { switch (call.method) { case 'map#update': @@ -97,6 +104,10 @@ class FakePlatformGoogleMap { case 'polylines#update': updatePolylines(call.arguments); return Future.sync(() {}); + case 'tileOverlays#update': + updateTileOverlays( + Map.castFrom(call.arguments)); + return Future.sync(() {}); case 'circles#update': updateCircles(call.arguments); return Future.sync(() {}); @@ -292,6 +303,31 @@ class FakePlatformGoogleMap { circlesToChange = _deserializeCircles(circleUpdates['circlesToChange']); } + void updateTileOverlays(Map updateTileOverlayUpdates) { + if (updateTileOverlayUpdates == null) { + return; + } + final List> tileOverlaysToAddList = + updateTileOverlayUpdates['tileOverlaysToAdd'] != null + ? List.castFrom>( + updateTileOverlayUpdates['tileOverlaysToAdd']) + : null; + final List tileOverlayIdsToRemoveList = + updateTileOverlayUpdates['tileOverlayIdsToRemove'] != null + ? List.castFrom( + updateTileOverlayUpdates['tileOverlayIdsToRemove']) + : null; + final List> tileOverlaysToChangeList = + updateTileOverlayUpdates['tileOverlaysToChange'] != null + ? List.castFrom>( + updateTileOverlayUpdates['tileOverlaysToChange']) + : null; + tileOverlaysToAdd = _deserializeTileOverlays(tileOverlaysToAddList); + tileOverlayIdsToRemove = + _deserializeTileOverlayIds(tileOverlayIdsToRemoveList); + tileOverlaysToChange = _deserializeTileOverlays(tileOverlaysToChangeList); + } + Set _deserializeCircleIds(List circleIds) { if (circleIds == null) { // TODO(iskakaushik): Remove this when collection literals makes it to stable. @@ -329,6 +365,49 @@ class FakePlatformGoogleMap { return result; } + Set _deserializeTileOverlayIds(List tileOverlayIds) { + if (tileOverlayIds == null || tileOverlayIds.isEmpty) { + // TODO(iskakaushik): Remove this when collection literals makes it to stable. + // https://github.com/flutter/flutter/issues/28312 + // ignore: prefer_collection_literals + return Set(); + } + return tileOverlayIds + .map((String tileOverlayId) => TileOverlayId(tileOverlayId)) + .toSet(); + } + + Set _deserializeTileOverlays( + List> tileOverlays) { + if (tileOverlays == null || tileOverlays.isEmpty) { + // TODO(iskakaushik): Remove this when collection literals makes it to stable. + // https://github.com/flutter/flutter/issues/28312 + // ignore: prefer_collection_literals + return Set(); + } + // TODO(iskakaushik): Remove this when collection literals makes it to stable. + // https://github.com/flutter/flutter/issues/28312 + // ignore: prefer_collection_literals + final Set result = Set(); + for (Map tileOverlayData in tileOverlays) { + final String tileOverlayId = tileOverlayData['tileOverlayId']; + final bool fadeIn = tileOverlayData['fadeIn']; + final double transparency = tileOverlayData['transparency']; + final int zIndex = tileOverlayData['zIndex']; + final bool visible = tileOverlayData['visible']; + + result.add(TileOverlay( + tileOverlayId: TileOverlayId(tileOverlayId), + fadeIn: fadeIn, + transparency: transparency, + zIndex: zIndex, + visible: visible, + )); + } + + return result; + } + void updateOptions(Map options) { if (options.containsKey('compassEnabled')) { compassEnabled = options['compassEnabled']; diff --git a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart new file mode 100644 index 000000000000..b94d4906dec7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart @@ -0,0 +1,210 @@ +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +import 'fake_maps_controllers.dart'; + +Set _toSet({TileOverlay t1, TileOverlay t2, TileOverlay t3}) { + final Set res = Set.identity(); + if (t1 != null) { + res.add(t1); + } + if (t2 != null) { + res.add(t2); + } + if (t3 != null) { + res.add(t3); + } + return res; +} + +Widget _mapWithTileOverlays(Set tileOverlays) { + return Directionality( + textDirection: TextDirection.ltr, + child: GoogleMap( + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + tileOverlays: tileOverlays, + ), + ); +} + +void main() { + final FakePlatformViewsController fakePlatformViewsController = + FakePlatformViewsController(); + + setUpAll(() { + SystemChannels.platform_views.setMockMethodCallHandler( + fakePlatformViewsController.fakePlatformViewsMethodHandler); + }); + + setUp(() { + fakePlatformViewsController.reset(); + }); + + testWidgets('Initializing a tile overlay', (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.tileOverlaysToAdd.length, 1); + + final TileOverlay initializedTileOverlay = + platformGoogleMap.tileOverlaysToAdd.first; + expect(initializedTileOverlay, equals(t1)); + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToChange.isEmpty, true); + }); + + testWidgets("Adding a tile overlay", (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + final TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1, t2: t2))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.tileOverlaysToAdd.length, 1); + + final TileOverlay addedTileOverlay = + platformGoogleMap.tileOverlaysToAdd.first; + expect(addedTileOverlay, equals(t2)); + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + + expect(platformGoogleMap.tileOverlaysToChange.isEmpty, true); + }); + + testWidgets("Removing a tile overlay", (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + await tester.pumpWidget(_mapWithTileOverlays(null)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.tileOverlayIdsToRemove.length, 1); + expect(platformGoogleMap.tileOverlayIdsToRemove.first, + equals(t1.tileOverlayId)); + + expect(platformGoogleMap.tileOverlaysToChange.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); + }); + + testWidgets("Updating a tile overlay", (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + final TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1"), zIndex: 10); + + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t2))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.tileOverlaysToChange.length, 1); + expect(platformGoogleMap.tileOverlaysToChange.first, equals(t2)); + + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); + }); + + testWidgets("Updating a tile overlay", (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + final TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1"), zIndex: 10); + + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t2))); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + expect(platformGoogleMap.tileOverlaysToChange.length, 1); + + final TileOverlay update = platformGoogleMap.tileOverlaysToChange.first; + expect(update, equals(t2)); + expect(update.zIndex, 10); + }); + + testWidgets("Multi Update", (WidgetTester tester) async { + TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + final Set prev = _toSet(t1: t1, t2: t2); + t1 = TileOverlay( + tileOverlayId: TileOverlayId("tile_overlay_1"), visible: false); + t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2"), zIndex: 10); + final Set cur = _toSet(t1: t1, t2: t2); + + await tester.pumpWidget(_mapWithTileOverlays(prev)); + await tester.pumpWidget(_mapWithTileOverlays(cur)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + + expect(platformGoogleMap.tileOverlaysToChange, cur); + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); + }); + + testWidgets("Multi Update", (WidgetTester tester) async { + TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + final TileOverlay t3 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3")); + final Set prev = _toSet(t2: t2, t3: t3); + + // t1 is added, t2 is updated, t3 is removed. + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2"), zIndex: 10); + final Set cur = _toSet(t1: t1, t2: t2); + + await tester.pumpWidget(_mapWithTileOverlays(prev)); + await tester.pumpWidget(_mapWithTileOverlays(cur)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + + expect(platformGoogleMap.tileOverlaysToChange.length, 1); + expect(platformGoogleMap.tileOverlaysToAdd.length, 1); + expect(platformGoogleMap.tileOverlayIdsToRemove.length, 1); + + expect(platformGoogleMap.tileOverlaysToChange.first, equals(t2)); + expect(platformGoogleMap.tileOverlaysToAdd.first, equals(t1)); + expect(platformGoogleMap.tileOverlayIdsToRemove.first, + equals(t3.tileOverlayId)); + }); + + testWidgets("Partial Update", (WidgetTester tester) async { + final TileOverlay t1 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); + final TileOverlay t2 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); + TileOverlay t3 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3")); + final Set prev = _toSet(t1: t1, t2: t2, t3: t3); + t3 = + TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3"), zIndex: 10); + final Set cur = _toSet(t1: t1, t2: t2, t3: t3); + + await tester.pumpWidget(_mapWithTileOverlays(prev)); + await tester.pumpWidget(_mapWithTileOverlays(cur)); + + final FakePlatformGoogleMap platformGoogleMap = + fakePlatformViewsController.lastCreatedView; + + expect(platformGoogleMap.tileOverlaysToChange, _toSet(t3: t3)); + expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); + expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); + }); +} From 956b1ebb2418a2314a25550a6a4c418c6f8ee86e Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 3 Feb 2021 16:34:37 -0800 Subject: [PATCH 150/924] Merge upcoming camera updates (#3501) --- packages/camera/camera/CHANGELOG.md | 5 +---- packages/camera/camera/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 911d7a1e9920..a8dbe65e7453 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,10 +1,7 @@ -# 0.7.0+3 - -* Revert compileSdkVersion back to 29 (from 30) as this is causing problems with add-to-app configurations. - ## 0.7.0+2 * Fix example reference in README. +* Revert compileSdkVersion back to 29 (from 30) as this is causing problems with add-to-app configurations. ## 0.7.0+1 diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index cebbb334c8f2..2b6d163dfbeb 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+3 +version: 0.7.0+2 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 41be560b958f8fe1fabe1124b168cd0813cbc4f3 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 4 Feb 2021 04:18:58 -0800 Subject: [PATCH 151/924] [shared_preferences] Update macOS for NNBD (#3505) macOS federated plugin implementations that contain no Dart code just need their Dart SDK bumped in order to be considered nullsafe. --- .../shared_preferences_macos/CHANGELOG.md | 4 ++++ .../shared_preferences_macos/pubspec.yaml | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md index 3eff6db6949e..ec5c5b4bc502 100644 --- a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2-nullsafety + +* Update Dart SDK constraint for null safety. + ## 0.0.1+12 * Update Flutter SDK constraint. diff --git a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml index afc5b9ec0b4e..912e2f648a26 100644 --- a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml @@ -3,7 +3,7 @@ description: macOS implementation of the shared_preferences plugin. # 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.1+12 +version: 0.0.2-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_macos flutter: @@ -13,11 +13,11 @@ flutter: pluginClass: SharedPreferencesPlugin environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.8" dependencies: - shared_preferences_platform_interface: ^1.0.0 + shared_preferences_platform_interface: ^2.0.0-nullsafety flutter: sdk: flutter dev_dependencies: From e51dd6723b0638ad050b332db929a7f40dc184fc Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 4 Feb 2021 08:52:58 -0800 Subject: [PATCH 152/924] Clean up CODEOWNERS (#3438) --- CODEOWNERS | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index bd774ebe4315..01732888ad89 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -4,23 +4,12 @@ # These names are just suggestions. It is fine to have your changes # reviewed by someone else. -packages/android_alarm_manager/** @bkonyi -packages/android_intent/** @mklim @matthew-carroll -packages/battery/** @matthew-carroll + packages/camera/** @bparrishMines -packages/connectivity/** @matthew-carroll packages/cross_file/** @ditman @mvanbeusekom -packages/device_info/** @matthew-carroll -packages/espresso/** @collinjackson @adazh packages/file_selector/** @ditman packages/google_maps_flutter/** @cyanglaz -packages/google_sign_in/** @mehmetf packages/image_picker/** @cyanglaz packages/integration_test/** @dnfield -packages/in_app_purchase/** @mklim @cyanglaz @LHLL +packages/in_app_purchase/** @cyanglaz @LHLL packages/ios_platform_images/** @gaaclarke -packages/package_info/** @matthew-carroll -packages/path_provider/** @matthew-carroll -packages/shared_preferences/** @matthew-carroll -packages/url_launcher/** @mklim -packages/video_player/** @iskakaushik From 546d6c10377a338d2f0504ab664209ed7db111c6 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 4 Feb 2021 11:36:04 -0800 Subject: [PATCH 153/924] update versino (#3512) --- packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md | 4 ++++ packages/google_maps_flutter/google_maps_flutter/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index 3b6db09ea10b..fd73ad6ca0eb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.2.0 + +* Support custom tiles. + ## 1.1.1 * Fix in example app to properly place polyline at initial camera position. diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index be5c0d449806..20bd56ab57da 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 1.1.1 +version: 1.2.0 dependencies: flutter: From 342d0109e9861b7b413d03e3cc0c29a120213c06 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 4 Feb 2021 12:11:51 -0800 Subject: [PATCH 154/924] Add a note about Plus plugins to CONTRIBUTING.md (#3511) Adds a prominent note to CONTRIBUTING.md about the new policy regarding PRs for plugins for which there is a Flutter Community Plus Plugins equivalent. --- CONTRIBUTING.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b763320b67c9..6c4abd0cb516 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,6 +5,25 @@ _See also: [Flutter's code of conduct](https://github.com/flutter/flutter/blob/master/CODE_OF_CONDUCT.md)_ +## Important note + +As of January 2021, we are no longer accepting non-critical PRs for plugins +for which there is a corresponding [Flutter Community Plus +Plugin](https://plus.fluttercommunity.dev/), as we hope in time to be able +to transition users to those versions of the plugins. If you have a PR for +something other than a critical issue (crashes, build failures, null safety, etc.) +for any of the following plugins, we encourage you to submit it +[there](https://github.com/fluttercommunity/plus_plugins/pulls) instead: +- `android_alarm_manager` +- `android_intent` +- `battery` +- `connectivity` +- `device_info` +- `package_info` +- `sensors` +- `share` +- `wifi_info_flutter` (corresponds to `network_info_plus`) + ## Things you will need From caf7fbf0b6185f7ff91a3c70e66228bc0b26e958 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Thu, 4 Feb 2021 15:51:19 -0600 Subject: [PATCH 155/924] [in_app_purchases] Remove TypeMatcher reference (#3494) --- packages/in_app_purchase/CHANGELOG.md | 4 ++++ packages/in_app_purchase/pubspec.yaml | 2 +- .../google_play_connection_test.dart | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index 3c77e0c313f5..abafaf506f3a 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.5+2 + +* Migrate deprecated references. + ## 0.3.5+1 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 02240ea654db..6a6c525132da 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.3.5+1 +version: 0.3.5+2 dependencies: async: ^2.0.8 diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart index f06c4ff7efef..9294d2b60d1e 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart @@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart' show TestWidgetsFlutterBinding; import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart'; import 'package:test/test.dart'; -import 'package:flutter/widgets.dart' hide TypeMatcher; +import 'package:flutter/widgets.dart' as widgets; import 'package:in_app_purchase/billing_client_wrappers.dart'; import 'package:in_app_purchase/src/billing_client_wrappers/enum_converters.dart'; import 'package:in_app_purchase/src/in_app_purchase/google_play_connection.dart'; @@ -34,7 +34,7 @@ void main() { }); setUp(() { - WidgetsFlutterBinding.ensureInitialized(); + widgets.WidgetsFlutterBinding.ensureInitialized(); const String debugMessage = 'dummy message'; final BillingResponse responseCode = BillingResponse.ok; final BillingResultWrapper expectedBillingResult = BillingResultWrapper( From 7301aa1e25b271b362ae5302f54c3fdf4c16843f Mon Sep 17 00:00:00 2001 From: Tim Sneath Date: Thu, 4 Feb 2021 13:57:13 -0800 Subject: [PATCH 156/924] Remove stray dependency (#3515) --- .../shared_preferences_windows/CHANGELOG.md | 4 ++++ .../shared_preferences_windows/pubspec.yaml | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md index f6a199d52cb0..a8c3a85cd3ce 100644 --- a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2+3 + +* Remove 'ffi' dependency. + ## 0.0.2+2 * Relax 'ffi' version constraint. diff --git a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml index 2970b3ff053e..6123300c9689 100644 --- a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: shared_preferences_windows description: Windows implementation of shared_preferences homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_windows -version: 0.0.2+2 +version: 0.0.2+3 flutter: plugin: @@ -18,7 +18,6 @@ dependencies: shared_preferences_platform_interface: ^1.0.0 flutter: sdk: flutter - ffi: ">=0.1.3 < 0.3.0" file: ">=5.1.0 <7.0.0" meta: ^1.1.7 path: ^1.6.4 From 9e982cf959979098634aee2f5780bc6377e5b2ba Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 4 Feb 2021 14:01:06 -0800 Subject: [PATCH 157/924] [image_picker_platform_interface] migrate to nnbd (#3492) --- .../CHANGELOG.md | 7 + .../method_channel_image_picker.dart | 89 ++--- .../image_picker_platform.dart | 95 +---- .../lib/src/types/lost_data_response.dart | 52 --- .../lib/src/types/picked_file/base.dart | 2 +- .../lib/src/types/picked_file/html.dart | 8 +- .../lib/src/types/picked_file/io.dart | 2 +- .../lib/src/types/picked_file/lost_data.dart | 8 +- .../lib/src/types/types.dart | 1 - .../pubspec.yaml | 13 +- .../method_channel_image_picker_test.dart | 345 ------------------ .../new_method_channel_image_picker_test.dart | 8 +- .../test/picked_file_html_test.dart | 3 +- script/build_all_plugins_app.sh | 1 + script/nnbd_plugins.sh | 1 + 15 files changed, 68 insertions(+), 567 deletions(-) delete mode 100644 packages/image_picker/image_picker_platform_interface/lib/src/types/lost_data_response.dart delete mode 100644 packages/image_picker/image_picker_platform_interface/test/method_channel_image_picker_test.dart diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index 581cf1830610..fc953e4e6333 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 71704b63ced4..8535f9dfb20e 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 @@ class MethodChannelImagePicker extends ImagePickerPlatform { MethodChannel get channel => _channel; @override - Future pickImage({ - @required ImageSource source, - double maxWidth, - double maxHeight, - int imageQuality, + Future 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 @@ class MethodChannelImagePicker extends ImagePickerPlatform { return path != null ? PickedFile(path) : null; } - @override - Future pickImagePath({ - @required ImageSource source, - double maxWidth, - double maxHeight, - int imageQuality, + Future _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 @@ class MethodChannelImagePicker extends ImagePickerPlatform { } @override - Future pickVideo({ - @required ImageSource source, + Future 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 @@ class MethodChannelImagePicker extends ImagePickerPlatform { return path != null ? PickedFile(path) : null; } - @override - Future pickVideoPath({ - @required ImageSource source, + Future _pickVideoPath({ + required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, - Duration maxDuration, + Duration? maxDuration, }) { - assert(source != null); return _channel.invokeMethod( 'pickVideo', { @@ -104,7 +99,7 @@ class MethodChannelImagePicker extends ImagePickerPlatform { @override Future retrieveLostData() async { - final Map result = + final Map? result = await _channel.invokeMapMethod('retrieve'); if (result == null) { @@ -113,23 +108,23 @@ class MethodChannelImagePicker extends ImagePickerPlatform { 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 @@ class MethodChannelImagePicker extends ImagePickerPlatform { type: retrieveType, ); } - - @override - // ignore: deprecated_member_use_from_same_package - Future retrieveLostDataAsDartIoFile() async { - final Map result = - await _channel.invokeMapMethod('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 cbd604187714..44b85f17f3db 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 @@ abstract class ImagePickerPlatform extends PlatformInterface { _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 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 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 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 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// /// 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 pickImage({ - @required ImageSource source, - double maxWidth, - double maxHeight, - int imageQuality, + /// + /// If no images were picked, the return value is null. + Future 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 @@ abstract class ImagePickerPlatform extends PlatformInterface { /// /// 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 pickVideo({ - @required ImageSource source, + /// + /// If no images were picked, the return value is null. + Future 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 d82618b23cd1..000000000000 --- 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 285294efcb3d..2b078ef28190 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 @@ abstract class PickedFileBase { /// 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 openRead([int start, int end]) { + Stream 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 ee5145009dc7..b855eb3fa20d 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 @@ import './base.dart'; /// 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 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 @@ class PickedFile extends PickedFileBase { } @override - Stream openRead([int start, int end]) async* { + Stream 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 dd64558bf044..4b56add0add4 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 @@ class PickedFile extends PickedFileBase { } @override - Stream openRead([int start, int end]) { + Stream 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 b94e69de219e..831c7bd6cb15 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 @@ class LostData { /// 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 @@ class LostData { /// 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 9c44fae1aa9d..f38a4ec74005 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 b9ad12a50eb6..d5f5ce93016b 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 @@ description: A common platform interface for the image_picker plugin. 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 ddaad3d32f41..000000000000 --- 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 log = []; - - 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, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - '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, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - '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, - [ - isMethodCall('pickImage', arguments: { - '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, - [ - isMethodCall('pickImage', arguments: { - '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, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'cameraDevice': 0, - 'maxDuration': null, - }), - isMethodCall('pickVideo', arguments: { - '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, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': null, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 10, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 60, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - '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, - [ - isMethodCall('pickVideo', arguments: { - '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, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': null, - 'cameraDevice': 1, - }), - ], - ); - }); - }); - - group('#retrieveLostDataAsDartIoFile', () { - test('retrieveLostData get success response', () async { - picker.channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - '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 { - '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 { - '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 e7abe37e4838..df35f8fd96b8 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 @@ void main() { // 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 @@ void main() { // 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 49d84ff88f88..ee0edbea03e0 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 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 9d9e38550ed5..7807e6a98bce 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -30,6 +30,7 @@ readonly EXCLUDED_PLUGINS_LIST=( "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 3d0676f8b1a5..b43d11c2fe1d 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -21,6 +21,7 @@ readonly NNBD_PLUGINS_LIST=( "url_launcher" "video_player" "webview_flutter" + "image_picker" ) # This list contains the list of plugins that have *not* been From 60fa97998b439924d64b476ac8f2d8129d527c38 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 4 Feb 2021 15:23:49 -0800 Subject: [PATCH 158/924] [package_info] Migrate to null safety (#3398) --- packages/package_info/CHANGELOG.md | 4 ++++ packages/package_info/lib/package_info.dart | 23 ++++++++++--------- packages/package_info/pubspec.yaml | 6 ++--- .../package_info/test/package_info_test.dart | 2 +- script/nnbd_plugins.sh | 1 + 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/package_info/CHANGELOG.md b/packages/package_info/CHANGELOG.md index f3f7734a4082..91da35966283 100644 --- a/packages/package_info/CHANGELOG.md +++ b/packages/package_info/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.0-nullsafety + +* Migrate to null safety. + ## 0.4.3+4 * Ensure `IntegrationTestPlugin` is registered in `example` app, so Firebase Test Lab tests report test results correctly. [Issue](https://github.com/flutter/flutter/issues/74944). diff --git a/packages/package_info/lib/package_info.dart b/packages/package_info/lib/package_info.dart index eaf28597e56c..51348978ffa5 100644 --- a/packages/package_info/lib/package_info.dart +++ b/packages/package_info/lib/package_info.dart @@ -24,30 +24,31 @@ class PackageInfo { /// See [fromPlatform] for the right API to get a [PackageInfo] that's /// actually populated with real data. PackageInfo({ - this.appName, - this.packageName, - this.version, - this.buildNumber, + required this.appName, + required this.packageName, + required this.version, + required this.buildNumber, }); - static PackageInfo _fromPlatform; + static PackageInfo? _fromPlatform; /// Retrieves package information from the platform. /// The result is cached. static Future fromPlatform() async { - if (_fromPlatform != null) { - return _fromPlatform; - } + PackageInfo? packageInfo = _fromPlatform; + if (packageInfo != null) return packageInfo; final Map map = - await _kChannel.invokeMapMethod('getAll'); - _fromPlatform = PackageInfo( + (await _kChannel.invokeMapMethod('getAll'))!; + + packageInfo = PackageInfo( appName: map["appName"], packageName: map["packageName"], version: map["version"], buildNumber: map["buildNumber"], ); - return _fromPlatform; + _fromPlatform = packageInfo; + return packageInfo; } /// The app name. `CFBundleDisplayName` on iOS, `application/label` on Android. diff --git a/packages/package_info/pubspec.yaml b/packages/package_info/pubspec.yaml index 25e45a6be7bc..f575ad155e4e 100644 --- a/packages/package_info/pubspec.yaml +++ b/packages/package_info/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/package_info # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.3+4 +version: 0.5.0-nullsafety flutter: plugin: @@ -29,8 +29,8 @@ dev_dependencies: sdk: flutter integration_test: path: ../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/package_info/test/package_info_test.dart b/packages/package_info/test/package_info_test.dart index 47d48fde2d2d..cb6967155ca0 100644 --- a/packages/package_info/test/package_info_test.dart +++ b/packages/package_info/test/package_info_test.dart @@ -11,7 +11,7 @@ void main() { const MethodChannel channel = MethodChannel('plugins.flutter.io/package_info'); - List log; + late List log; channel.setMockMethodCallHandler((MethodCall methodCall) async { log.add(methodCall); diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index b43d11c2fe1d..742487ad7bfa 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -15,6 +15,7 @@ readonly NNBD_PLUGINS_LIST=( "google_sign_in" "local_auth" "path_provider" + "package_info" "plugin_platform_interface" "share" "shared_preferences" From 7f5696c88c3e6b6eaba45bed7b6f755258e1ba5c Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 4 Feb 2021 16:37:52 -0800 Subject: [PATCH 159/924] Migrate path_provider to null safety. (#3460) --- .../path_provider/path_provider/CHANGELOG.md | 4 ++ .../integration_test/path_provider_test.dart | 6 +++ .../path_provider/lib/path_provider.dart | 40 +++++++++++-------- .../path_provider/path_provider/pubspec.yaml | 18 ++++----- .../test/path_provider_test.dart | 38 +++++++++--------- 5 files changed, 61 insertions(+), 45 deletions(-) diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index 43e765aaf0b4..7364305333cf 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.6.28 * Drop unused UUID dependency for tests. diff --git a/packages/path_provider/path_provider/integration_test/path_provider_test.dart b/packages/path_provider/path_provider/integration_test/path_provider_test.dart index 18570aeca57e..da368d52b832 100644 --- a/packages/path_provider/path_provider/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider/integration_test/path_provider_test.dart @@ -1,3 +1,9 @@ +// 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. + +// @dart=2.9 + import 'package:flutter_test/flutter_test.dart'; import 'package:path_provider/path_provider.dart'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/path_provider/path_provider/lib/path_provider.dart b/packages/path_provider/path_provider/lib/path_provider.dart index 0fbab57700be..1560c3399e72 100644 --- a/packages/path_provider/path_provider/lib/path_provider.dart +++ b/packages/path_provider/path_provider/lib/path_provider.dart @@ -51,8 +51,8 @@ PathProviderPlatform get _platform { /// On iOS, this uses the `NSCachesDirectory` API. /// /// On Android, this uses the `getCacheDir` API on the context. -Future getTemporaryDirectory() async { - final String path = await _platform.getTemporaryPath(); +Future getTemporaryDirectory() async { + final String? path = await _platform.getTemporaryPath(); if (path == null) { return null; } @@ -69,8 +69,8 @@ Future getTemporaryDirectory() async { /// If this directory does not exist, it is created automatically. /// /// On Android, this function uses the `getFilesDir` API on the context. -Future getApplicationSupportDirectory() async { - final String path = await _platform.getApplicationSupportPath(); +Future getApplicationSupportDirectory() async { + final String? path = await _platform.getApplicationSupportPath(); if (path == null) { return null; } @@ -83,8 +83,8 @@ Future getApplicationSupportDirectory() async { /// /// On Android, this function throws an [UnsupportedError] as no equivalent /// path exists. -Future getLibraryDirectory() async { - final String path = await _platform.getLibraryPath(); +Future getLibraryDirectory() async { + final String? path = await _platform.getLibraryPath(); if (path == null) { return null; } @@ -100,8 +100,8 @@ Future getLibraryDirectory() async { /// On Android, this uses the `getDataDirectory` API on the context. Consider /// using [getExternalStorageDirectory] instead if data is intended to be visible /// to the user. -Future getApplicationDocumentsDirectory() async { - final String path = await _platform.getApplicationDocumentsPath(); +Future getApplicationDocumentsDirectory() async { + final String? path = await _platform.getApplicationDocumentsPath(); if (path == null) { return null; } @@ -116,8 +116,8 @@ Future getApplicationDocumentsDirectory() async { /// to access outside the app's sandbox. /// /// On Android this uses the `getExternalFilesDir(null)`. -Future getExternalStorageDirectory() async { - final String path = await _platform.getExternalStoragePath(); +Future getExternalStorageDirectory() async { + final String? path = await _platform.getExternalStoragePath(); if (path == null) { return null; } @@ -137,8 +137,11 @@ Future getExternalStorageDirectory() async { /// /// On Android this returns Context.getExternalCacheDirs() or /// Context.getExternalCacheDir() on API levels below 19. -Future> getExternalCacheDirectories() async { - final List paths = await _platform.getExternalCachePaths(); +Future?> getExternalCacheDirectories() async { + final List? paths = await _platform.getExternalCachePaths(); + if (paths == null) { + return null; + } return paths.map((String path) => Directory(path)).toList(); } @@ -155,13 +158,16 @@ Future> getExternalCacheDirectories() async { /// /// On Android this returns Context.getExternalFilesDirs(String type) or /// Context.getExternalFilesDir(String type) on API levels below 19. -Future> getExternalStorageDirectories({ +Future?> getExternalStorageDirectories({ /// Optional parameter. See [StorageDirectory] for more informations on /// how this type translates to Android storage directories. - StorageDirectory type, + StorageDirectory? type, }) async { - final List paths = + final List? paths = await _platform.getExternalStoragePaths(type: type); + if (paths == null) { + return null; + } return paths.map((String path) => Directory(path)).toList(); } @@ -171,8 +177,8 @@ Future> getExternalStorageDirectories({ /// /// On Android and on iOS, this function throws an [UnsupportedError] as no equivalent /// path exists. -Future getDownloadsDirectory() async { - final String path = await _platform.getDownloadsPath(); +Future getDownloadsDirectory() async { + final String? path = await _platform.getDownloadsPath(); if (path == null) { return null; } diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index 065c53fec9fd..6c4c851d8103 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 1.6.28 +version: 2.0.0-nullsafety flutter: plugin: @@ -21,10 +21,10 @@ flutter: dependencies: flutter: sdk: flutter - path_provider_platform_interface: ^1.0.1 - path_provider_macos: ^0.0.4 - path_provider_linux: ^0.0.1 - path_provider_windows: ^0.0.4 + path_provider_platform_interface: ^2.0.0-nullsafety + path_provider_macos: ^0.0.5-nullsafety + path_provider_linux: ^0.2.0-nullsafety + path_provider_windows: ^0.1.0-nullsafety dev_dependencies: integration_test: @@ -33,10 +33,10 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - pedantic: ^1.8.0 - mockito: ^4.1.1 - plugin_platform_interface: ^1.0.0 + pedantic: ^1.10.0-nullsafety + mockito: ^5.0.0-nullsafety.0 + plugin_platform_interface: ^1.1.0-nullsafety environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/path_provider/path_provider/test/path_provider_test.dart b/packages/path_provider/path_provider/test/path_provider_test.dart index eb17178b9975..aec5e060f631 100644 --- a/packages/path_provider/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/path_provider/test/path_provider_test.dart @@ -28,45 +28,45 @@ void main() { }); test('getTemporaryDirectory', () async { - Directory result = await getTemporaryDirectory(); - expect(result.path, kTemporaryPath); + Directory? result = await getTemporaryDirectory(); + expect(result?.path, kTemporaryPath); }); test('getApplicationSupportDirectory', () async { - Directory result = await getApplicationSupportDirectory(); - expect(result.path, kApplicationSupportPath); + Directory? result = await getApplicationSupportDirectory(); + expect(result?.path, kApplicationSupportPath); }); test('getLibraryDirectory', () async { - Directory result = await getLibraryDirectory(); - expect(result.path, kLibraryPath); + Directory? result = await getLibraryDirectory(); + expect(result?.path, kLibraryPath); }); test('getApplicationDocumentsDirectory', () async { - Directory result = await getApplicationDocumentsDirectory(); - expect(result.path, kApplicationDocumentsPath); + Directory? result = await getApplicationDocumentsDirectory(); + expect(result?.path, kApplicationDocumentsPath); }); test('getExternalStorageDirectory', () async { - Directory result = await getExternalStorageDirectory(); - expect(result.path, kExternalStoragePath); + Directory? result = await getExternalStorageDirectory(); + expect(result?.path, kExternalStoragePath); }); test('getExternalCacheDirectories', () async { - List result = await getExternalCacheDirectories(); - expect(result.length, 1); - expect(result.first.path, kExternalCachePath); + List? result = await getExternalCacheDirectories(); + expect(result?.length, 1); + expect(result?.first.path, kExternalCachePath); }); test('getExternalStorageDirectories', () async { - List result = await getExternalStorageDirectories(); - expect(result.length, 1); - expect(result.first.path, kExternalStoragePath); + List? result = await getExternalStorageDirectories(); + expect(result?.length, 1); + expect(result?.first.path, kExternalStoragePath); }); test('getDownloadsDirectory', () async { - Directory result = await getDownloadsDirectory(); - expect(result.path, kDownloadsPath); + Directory? result = await getDownloadsDirectory(); + expect(result?.path, kDownloadsPath); }); }); } @@ -99,7 +99,7 @@ class MockPathProviderPlatform extends Mock } Future> getExternalStoragePaths({ - StorageDirectory type, + StorageDirectory? type, }) async { return [kExternalStoragePath]; } From ad308e54ce39cfa91b6f93e7c407d828fd465ebc Mon Sep 17 00:00:00 2001 From: Tim Sneath Date: Fri, 5 Feb 2021 04:01:57 -0800 Subject: [PATCH 160/924] Update to ffi 0.3.0-nullsafety.1 (#3513) ffi 0.3.0 supports the new memory allocation model in Dart 2.12.0-259 and later. --- .../path_provider_windows/CHANGELOG.md | 4 +++ .../example/windows/flutter/CMakeLists.txt | 1 + .../lib/src/path_provider_windows_real.dart | 34 +++++++++---------- .../path_provider_windows/pubspec.yaml | 9 ++--- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index 24304e36dc0c..6190c39457da 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0-nullsafety.2 + +* Bump ffi dependency to 0.3.0-nullsafety.1 + ## 0.1.0-nullsafety.1 * Bump win32 dependency to latest version. diff --git a/packages/path_provider/path_provider_windows/example/windows/flutter/CMakeLists.txt b/packages/path_provider/path_provider_windows/example/windows/flutter/CMakeLists.txt index c7a8c7607d81..744f08a9389b 100644 --- a/packages/path_provider/path_provider_windows/example/windows/flutter/CMakeLists.txt +++ b/packages/path_provider/path_provider_windows/example/windows/flutter/CMakeLists.txt @@ -91,6 +91,7 @@ add_custom_command( ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" windows-x64 $ + VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart index c104343f2502..c88e10a0f9b3 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart @@ -28,17 +28,17 @@ class VersionInfoQuerier { } const kEnUsLanguageCode = '040904e4'; final keyPath = TEXT('\\StringFileInfo\\$kEnUsLanguageCode\\$key'); - final length = allocate(); - final valueAddress = allocate>(); + final length = calloc(); + final valueAddress = calloc>(); try { if (VerQueryValue(versionInfo, keyPath, valueAddress, length) == 0) { return null; } return valueAddress.value.unpackString(length.value); } finally { - free(keyPath); - free(length); - free(valueAddress); + calloc.free(keyPath); + calloc.free(length); + calloc.free(valueAddress); } } } @@ -54,7 +54,7 @@ class PathProviderWindows extends PathProviderPlatform { /// This is typically the same as the TMP environment variable. @override Future getTemporaryPath() async { - final buffer = allocate(count: MAX_PATH + 1).cast(); + final buffer = calloc(MAX_PATH + 1).cast(); String path; try { @@ -82,7 +82,7 @@ class PathProviderWindows extends PathProviderPlatform { return Future.value(path); } finally { - free(buffer); + calloc.free(buffer); } } @@ -115,7 +115,7 @@ class PathProviderWindows extends PathProviderPlatform { /// folderID is a GUID that represents a specific known folder ID, drawn from /// [WindowsKnownFolder]. Future getPath(String folderID) { - final pathPtrPtr = allocate>(); + final pathPtrPtr = calloc>(); final Pointer knownFolderID = calloc()..ref.setGUID(folderID); try { @@ -135,8 +135,8 @@ class PathProviderWindows extends PathProviderPlatform { final path = pathPtrPtr.value.unpackString(MAX_PATH); return Future.value(path); } finally { - free(pathPtrPtr); - free(knownFolderID); + calloc.free(pathPtrPtr); + calloc.free(knownFolderID); } } @@ -155,8 +155,8 @@ class PathProviderWindows extends PathProviderPlatform { String? productName; final Pointer moduleNameBuffer = - allocate(count: MAX_PATH + 1).cast(); - final Pointer unused = allocate(); + calloc(MAX_PATH + 1).cast(); + final Pointer unused = calloc(); Pointer? infoBuffer; try { // Get the module name. @@ -169,10 +169,10 @@ class PathProviderWindows extends PathProviderPlatform { // From that, load the VERSIONINFO resource int infoSize = GetFileVersionInfoSize(moduleNameBuffer, unused); if (infoSize != 0) { - infoBuffer = allocate(count: infoSize); + infoBuffer = calloc(infoSize); if (GetFileVersionInfo(moduleNameBuffer, 0, infoSize, infoBuffer) == 0) { - free(infoBuffer); + calloc.free(infoBuffer); infoBuffer = null; } } @@ -191,10 +191,10 @@ class PathProviderWindows extends PathProviderPlatform { ? path.join(companyName, productName) : productName; } finally { - free(moduleNameBuffer); - free(unused); + calloc.free(moduleNameBuffer); + calloc.free(unused); if (infoBuffer != null) { - free(infoBuffer); + calloc.free(infoBuffer); } } } diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index 578000682e63..922594a9bd2d 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_windows -version: 0.1.0-nullsafety.1 +version: 0.1.0-nullsafety.2 flutter: plugin: @@ -16,8 +16,8 @@ dependencies: path: ^1.8.0-nullsafety.3 flutter: sdk: flutter - ffi: ^0.2.0-nullsafety.1 - win32: ^2.0.0-nullsafety.9 + ffi: '>=0.3.0-nullsafety.1 <2.0.0' + win32: ^2.0.0-nullsafety.10 dev_dependencies: flutter_test: @@ -25,5 +25,6 @@ dev_dependencies: pedantic: ^1.10.0-nullsafety.3 environment: - sdk: '>=2.12.0-0 <3.0.0' + sdk: '>=2.12.0-259.8.beta <3.0.0' flutter: ">=1.12.13+hotfix.4" + From 5aa082f8b2f01df41ae01210d30e254aea9dbea0 Mon Sep 17 00:00:00 2001 From: Hamdi Kahloun <32666446+hamdikahloun@users.noreply.github.com> Date: Fri, 5 Feb 2021 22:23:48 +0100 Subject: [PATCH 161/924] [wifi_info_flutter] Check Permissions in Android O or higher (#3234) * Check Permissions * Format * Update packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java Co-authored-by: Maurice Parrish * Update packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java Co-authored-by: Maurice Parrish * Update packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java Co-authored-by: Maurice Parrish * Update packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java Co-authored-by: Maurice Parrish * Update packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java Co-authored-by: Maurice Parrish * Update packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java Co-authored-by: Maurice Parrish * Update packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java Co-authored-by: Maurice Parrish * Update packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java Co-authored-by: Maurice Parrish Co-authored-by: Maurice Parrish --- .../wifi_info_flutter/CHANGELOG.md | 5 + .../wifi_info_flutter/WifiInfoFlutter.java | 103 +++++++++++++++++- .../WifiInfoFlutterPlugin.java | 2 +- .../android/app/src/main/AndroidManifest.xml | 4 + .../wifi_info_flutter/example/lib/main.dart | 14 +-- .../wifi_info_flutter/pubspec.yaml | 2 +- 6 files changed, 120 insertions(+), 10 deletions(-) diff --git a/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md b/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md index 5c3ea32e8ef9..fa68eed175b7 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md +++ b/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.0.4 + +* Android: Add Log warning for unsatisfied requirement(s) in Android P or higher. +* Android: Update Example project. + ## 1.0.3 * Fix README example. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java index f74e4f0f75e1..e5e33af715ca 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java +++ b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java @@ -4,18 +4,31 @@ package io.flutter.plugins.wifi_info_flutter; +import android.Manifest; +import android.content.Context; +import android.content.pm.PackageManager; +import android.location.LocationManager; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import android.os.Build; +import androidx.core.content.ContextCompat; +import io.flutter.Log; /** Reports wifi information. */ class WifiInfoFlutter { private WifiManager wifiManager; + private Context context; + private static final String TAG = "WifiInfoFlutter"; - WifiInfoFlutter(WifiManager wifiManager) { + WifiInfoFlutter(WifiManager wifiManager, Context context) { this.wifiManager = wifiManager; + this.context = context; } String getWifiName() { + if (!checkPermissions()) { + return null; + } final WifiInfo wifiInfo = getWifiInfo(); String ssid = null; if (wifiInfo != null) ssid = wifiInfo.getSSID(); @@ -25,6 +38,9 @@ String getWifiName() { } String getWifiBSSID() { + if (!checkPermissions()) { + return null; + } final WifiInfo wifiInfo = getWifiInfo(); String bssid = null; if (wifiInfo != null) { @@ -53,4 +69,89 @@ String getWifiIPAddress() { private WifiInfo getWifiInfo() { return wifiManager == null ? null : wifiManager.getConnectionInfo(); } + + private Boolean checkPermissions() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return true; + } + + boolean grantedChangeWifiState = + ContextCompat.checkSelfPermission(context, Manifest.permission.CHANGE_WIFI_STATE) + == PackageManager.PERMISSION_GRANTED; + + boolean grantedAccessFine = + ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED; + + boolean grantedAccessCoarse = + ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) + == PackageManager.PERMISSION_GRANTED; + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P + && !grantedChangeWifiState + && !grantedAccessFine + && !grantedAccessCoarse) { + Log.w( + TAG, + "Attempted to get Wi-Fi data that requires additional permission(s).\n" + + "To successfully get WiFi Name or Wi-Fi BSSID starting with Android O, please ensure your app has one of the following permissions:\n" + + "- CHANGE_WIFI_STATE\n" + + "- ACCESS_FINE_LOCATION\n" + + "- ACCESS_COARSE_LOCATION\n" + + "For more information about Wi-Fi Restrictions in Android 8.0 and above, please consult the following link:\n" + + "https://developer.android.com/guide/topics/connectivity/wifi-scan"); + return false; + } + + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P && !grantedChangeWifiState) { + Log.w( + TAG, + "Attempted to get Wi-Fi data that requires additional permission(s).\n" + + "To successfully get WiFi Name or Wi-Fi BSSID starting with Android P, please ensure your app has the CHANGE_WIFI_STATE permission.\n" + + "For more information about Wi-Fi Restrictions in Android 9.0 and above, please consult the following link:\n" + + "https://developer.android.com/guide/topics/connectivity/wifi-scan"); + return false; + } + + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P + && !grantedAccessFine + && !grantedAccessCoarse) { + Log.w( + TAG, + "Attempted to get Wi-Fi data that requires additional permission(s).\n" + + "To successfully get WiFi Name or Wi-Fi BSSID starting with Android P, additional to CHANGE_WIFI_STATE please ensure your app has one of the following permissions too:\n" + + "- ACCESS_FINE_LOCATION\n" + + "- ACCESS_COARSE_LOCATION\n" + + "For more information about Wi-Fi Restrictions in Android 9.0 and above, please consult the following link:\n" + + "https://developer.android.com/guide/topics/connectivity/wifi-scan"); + return false; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q + && (!grantedAccessFine || !grantedChangeWifiState)) { + Log.w( + TAG, + "Attempted to get Wi-Fi data that requires additional permission(s).\n" + + "To successfully get WiFi Name or Wi-Fi BSSID starting with Android Q, please ensure your app has the CHANGE_WIFI_STATE and ACCESS_FINE_LOCATION permission.\n" + + "For more information about Wi-Fi Restrictions in Android 10.0 and above, please consult the following link:\n" + + "https://developer.android.com/guide/topics/connectivity/wifi-scan"); + return false; + } + + LocationManager locationManager = + (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + + boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !gpsEnabled) { + Log.w( + TAG, + "Attempted to get Wi-Fi data that requires additional permission(s).\n" + + "To successfully get WiFi Name or Wi-Fi BSSID starting with Android P, please ensure Location services are enabled on the device (under Settings > Location).\n" + + "For more information about Wi-Fi Restrictions in Android 9.0 and above, please consult the following link:\n" + + "https://developer.android.com/guide/topics/connectivity/wifi-scan"); + return false; + } + return true; + } } diff --git a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java index ea22e0bc88a5..1346617df53b 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java +++ b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java @@ -37,7 +37,7 @@ private void setupChannels(BinaryMessenger messenger, Context context) { final WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); - final WifiInfoFlutter wifiInfoFlutter = new WifiInfoFlutter(wifiManager); + final WifiInfoFlutter wifiInfoFlutter = new WifiInfoFlutter(wifiManager, context); final WifiInfoFlutterMethodChannelHandler methodChannelHandler = new WifiInfoFlutterMethodChannelHandler(wifiInfoFlutter); diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/AndroidManifest.xml b/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/AndroidManifest.xml index 22158120a33f..bcecab36d14a 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/AndroidManifest.xml +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,9 @@ + + + + diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart b/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart index 17a9e76ad946..8c64c5d9a421 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart @@ -114,12 +114,12 @@ class _MyHomePageState extends State { } if (status == LocationAuthorizationStatus.authorizedAlways || status == LocationAuthorizationStatus.authorizedWhenInUse) { - wifiName = await _connectivity.getWifiName(); + wifiName = await _wifiInfo.getWifiName(); } else { - wifiName = await _connectivity.getWifiName(); + wifiName = await _wifiInfo.getWifiName(); } } else { - wifiName = await _connectivity.getWifiName(); + wifiName = await _wifiInfo.getWifiName(); } } on PlatformException catch (e) { print(e.toString()); @@ -135,12 +135,12 @@ class _MyHomePageState extends State { } if (status == LocationAuthorizationStatus.authorizedAlways || status == LocationAuthorizationStatus.authorizedWhenInUse) { - wifiBSSID = await _connectivity.getWifiBSSID(); + wifiBSSID = await _wifiInfo.getWifiBSSID(); } else { - wifiBSSID = await _connectivity.getWifiBSSID(); + wifiBSSID = await _wifiInfo.getWifiBSSID(); } } else { - wifiBSSID = await _connectivity.getWifiBSSID(); + wifiBSSID = await _wifiInfo.getWifiBSSID(); } } on PlatformException catch (e) { print(e.toString()); @@ -148,7 +148,7 @@ class _MyHomePageState extends State { } try { - wifiIP = await _connectivity.getWifiIP(); + wifiIP = await _wifiInfo.getWifiIP(); } on PlatformException catch (e) { print(e.toString()); wifiIP = "Failed to get Wifi IP"; diff --git a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml index 4f5ecafb50b4..b8306a0696d2 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: wifi_info_flutter description: A new flutter plugin project. -version: 1.0.3 +version: 1.0.4 homepage: https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter/wifi_info_flutter environment: From 654a02589102a9c3cb71e0c43de63bd71c232a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Sat, 6 Feb 2021 09:36:21 +0100 Subject: [PATCH 162/924] [camera_platform_interface] Added stopRecordingVideo (#3518) * Added stopRecordingVideo * Removed deprecation and made stopRecordingVideo return void * Removed unused import * Revert pubspec change * Updated documentation * removed stopRecordingVideo * Update packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart Co-authored-by: Maurits van Beusekom * fixed formatting * Remove coverage folders * Updated documentation * updated version Co-authored-by: Maurits van Beusekom --- .../camera_platform_interface/CHANGELOG.md | 4 ++ .../lib/src/events/camera_event.dart | 46 +++++++++++++++++++ .../method_channel/method_channel_camera.dart | 14 ++++++ .../platform_interface/camera_platform.dart | 8 +++- .../camera_platform_interface/pubspec.yaml | 2 +- 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index d7442d4ac931..ff739918c53b 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.0 + +- Added VideoRecordedEvent to support ending a video recording in the native implementation. + ## 1.5.0 - Introduces interface methods for locking and unlocking the capture orientation. diff --git a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart index d60a0a39f608..ad9958381143 100644 --- a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart +++ b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart @@ -235,3 +235,49 @@ class CameraErrorEvent extends CameraEvent { @override int get hashCode => super.hashCode ^ description.hashCode; } + +/// An event fired when a video has finished recording. +class VideoRecordedEvent extends CameraEvent { + /// XFile of the recorded video. + final XFile file; + + /// Maximum duration of the recorded video. + final Duration maxVideoDuration; + + /// Build a VideoRecordedEvent triggered from the camera with the `cameraId`. + /// + /// The `file` represents the file of the video. + /// The `maxVideoDuration` shows if a maxVideoDuration shows if a maximum + /// video duration was set. + VideoRecordedEvent(int cameraId, this.file, this.maxVideoDuration) + : super(cameraId); + + /// Converts the supplied [Map] to an instance of the [VideoRecordedEvent] + /// class. + VideoRecordedEvent.fromJson(Map json) + : file = XFile(json['path']), + maxVideoDuration = json['maxVideoDuration'] != null + ? Duration(milliseconds: json['maxVideoDuration'] as int) + : null, + super(json['cameraId']); + + /// Converts the [VideoRecordedEvent] instance into a [Map] instance that can be + /// serialized to JSON. + Map toJson() => { + 'cameraId': cameraId, + 'path': file.path, + 'maxVideoDuration': maxVideoDuration?.inMilliseconds + }; + + @override + bool operator ==(Object other) => + identical(this, other) || + super == other && + other is VideoRecordedEvent && + runtimeType == other.runtimeType && + maxVideoDuration == other.maxVideoDuration; + + @override + int get hashCode => + super.hashCode ^ file.hashCode ^ maxVideoDuration.hashCode; +} diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index e6f658c45365..36a2c92645f2 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -156,6 +156,11 @@ class MethodChannelCamera extends CameraPlatform { return _cameraEvents(cameraId).whereType(); } + @override + Stream onVideoRecordedEvent(int cameraId) { + return _cameraEvents(cameraId).whereType(); + } + @override Stream onDeviceOrientationChanged() { return deviceEventStreamController.stream @@ -433,6 +438,15 @@ class MethodChannelCamera extends CameraPlatform { cameraId, )); break; + case 'video_recorded': + cameraEventStreamController.add(VideoRecordedEvent( + cameraId, + XFile(call.arguments['path']), + call.arguments['maxVideoDuration'] != null + ? Duration(milliseconds: call.arguments['maxVideoDuration']) + : null, + )); + break; case 'error': cameraEventStreamController.add(CameraErrorEvent( cameraId, diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index c1d6e09c3263..e1faecf374cd 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -87,6 +87,11 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('onCameraError() is not implemented.'); } + /// The camera finished recording a video + Stream onVideoRecordedEvent(int cameraId) { + throw UnimplementedError('onCameraTimeLimitReached() is not implemented.'); + } + /// The device orientation changed. /// /// Implementations for this: @@ -123,7 +128,8 @@ abstract class CameraPlatform extends PlatformInterface { /// The length of the recording can be limited by specifying the [maxVideoDuration]. /// By default no maximum duration is specified, /// meaning the recording will continue until manually stopped. - /// The video is returned as a [XFile] after calling [stopVideoRecording]. + /// With [maxVideoDuration] set the video is returned in a [VideoRecordedEvent] + /// through the [onVideoRecordedEvent] stream when the set duration is reached. Future startVideoRecording(int cameraId, {Duration maxVideoDuration}) { throw UnimplementedError('startVideoRecording() is not implemented.'); } diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index 2a8d7ce9abe1..c7ec7209c838 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.5.0 +version: 1.6.0 dependencies: flutter: From aa827e30ba37af3f2c49645b337dbe67c3ba9dbe Mon Sep 17 00:00:00 2001 From: max <19898639+vimaxwell@users.noreply.github.com> Date: Sat, 6 Feb 2021 21:16:37 +0700 Subject: [PATCH 163/924] [camera] Clockwise rotation of focus point in android (#3458) --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../src/main/java/io/flutter/plugins/camera/Camera.java | 4 ++-- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index a8dbe65e7453..622bd095b021 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+3 + +* Clockwise rotation of focus point in android + ## 0.7.0+2 * Fix example reference in README. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 1b6cce95d08c..a5f8647afb0b 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -786,7 +786,7 @@ public void setExposurePoint(@NonNull final Result result, Double x, Double y) } // Set the metering rectangle if (x == null || y == null) cameraRegions.resetAutoExposureMeteringRectangle(); - else cameraRegions.setAutoExposureMeteringRectangleFromPoint(x, y); + else cameraRegions.setAutoExposureMeteringRectangleFromPoint(y, 1 - x); // Apply it updateExposure(exposureMode); refreshPreviewCaptureSession( @@ -838,7 +838,7 @@ public void setFocusPoint(@NonNull final Result result, Double x, Double y) if (x == null || y == null) { cameraRegions.resetAutoFocusMeteringRectangle(); } else { - cameraRegions.setAutoFocusMeteringRectangleFromPoint(x, y); + cameraRegions.setAutoFocusMeteringRectangleFromPoint(y, 1 - x); } // Apply the new metering rectangle diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 2b6d163dfbeb..cebbb334c8f2 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+2 +version: 0.7.0+3 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 0cec317a1c67c462dfd56d323aaf3a51e5d20d0a Mon Sep 17 00:00:00 2001 From: Sameer Kashyap <40424087+Sameerkash@users.noreply.github.com> Date: Mon, 8 Feb 2021 21:04:53 +0530 Subject: [PATCH 164/924] [shared_preferences_windows]-Migrate to null safety (#3516) Migrate shared_preferences_windows to null safety --- .../shared_preferences_windows/CHANGELOG.md | 5 +++ .../lib/shared_preferences_windows.dart | 45 +++++++++++-------- .../shared_preferences_windows/pubspec.yaml | 15 ++++--- .../test/shared_preferences_windows_test.dart | 20 ++++----- 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md index a8c3a85cd3ce..41119901f396 100644 --- a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md @@ -1,3 +1,8 @@ + +## 0.0.3-nullsafety + +* Migrate to null-safety. + ## 0.0.2+3 * Remove 'ffi' dependency. diff --git a/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart b/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart index dd9ab8a0c38f..b2678c49782b 100644 --- a/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart +++ b/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart @@ -27,42 +27,51 @@ class SharedPreferencesWindows extends SharedPreferencesStorePlatform { PathProviderWindows pathProvider = PathProviderWindows(); /// Local copy of preferences - Map _cachedPreferences; + Map? _cachedPreferences; /// Cached file for storing preferences. - File _localDataFilePath; + File? _localDataFilePath; /// Gets the file where the preferences are stored. - Future _getLocalDataFile() async { - if (_localDataFilePath == null) { - final directory = await pathProvider.getApplicationSupportPath(); - _localDataFilePath = - fs.file(path.join(directory, 'shared_preferences.json')); + Future _getLocalDataFile() async { + if (_localDataFilePath != null) { + return _localDataFilePath!; } - return _localDataFilePath; + final directory = await pathProvider.getApplicationSupportPath(); + if (directory == null) { + return null; + } + return _localDataFilePath = + fs.file(path.join(directory, 'shared_preferences.json')); } /// Gets the preferences from the stored file. Once read, the preferences are /// maintained in memory. Future> _readPreferences() async { - if (_cachedPreferences == null) { - _cachedPreferences = {}; - File localDataFile = await _getLocalDataFile(); - if (localDataFile.existsSync()) { - String stringMap = localDataFile.readAsStringSync(); - if (stringMap.isNotEmpty) { - _cachedPreferences = json.decode(stringMap) as Map; - } + if (_cachedPreferences != null) { + return _cachedPreferences!; + } + Map preferences = {}; + final File? localDataFile = await _getLocalDataFile(); + if (localDataFile != null && localDataFile.existsSync()) { + String stringMap = localDataFile.readAsStringSync(); + if (stringMap.isNotEmpty) { + preferences = json.decode(stringMap).cast(); } } - return _cachedPreferences; + _cachedPreferences = preferences; + return preferences; } /// Writes the cached preferences to disk. Returns [true] if the operation /// succeeded. Future _writePreferences(Map preferences) async { try { - File localDataFile = await _getLocalDataFile(); + final File? localDataFile = await _getLocalDataFile(); + if (localDataFile == null) { + print("Unable to determine where to write preferences."); + return false; + } if (!localDataFile.existsSync()) { localDataFile.createSync(recursive: true); } diff --git a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml index 6123300c9689..e2cf3d03f00d 100644 --- a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml @@ -1,7 +1,8 @@ name: shared_preferences_windows description: Windows implementation of shared_preferences homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_windows -version: 0.0.2+3 +version: 0.0.3-nullsafety + flutter: plugin: @@ -11,20 +12,20 @@ flutter: pluginClass: none environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.12.8" dependencies: - shared_preferences_platform_interface: ^1.0.0 + shared_preferences_platform_interface: ^2.0.0-nullsafety flutter: sdk: flutter - file: ">=5.1.0 <7.0.0" + file: ^6.0.0-nullsafety.4 meta: ^1.1.7 path: ^1.6.4 - path_provider_platform_interface: ^1.0.3 - path_provider_windows: ^0.0.2 + path_provider_platform_interface: ^2.0.0-nullsafety + path_provider_windows: ^0.1.0-nullsafety.2 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety.3 diff --git a/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart b/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart index b0827ca3b36b..785092f6fa16 100644 --- a/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart @@ -10,8 +10,8 @@ import 'package:path_provider_windows/path_provider_windows.dart'; import 'package:shared_preferences_windows/shared_preferences_windows.dart'; void main() { - MemoryFileSystem fileSystem; - PathProviderWindows pathProvider; + late MemoryFileSystem fileSystem; + late PathProviderWindows pathProvider; setUp(() { fileSystem = MemoryFileSystem.test(); @@ -22,7 +22,7 @@ void main() { Future _getFilePath() async { final directory = await pathProvider.getApplicationSupportPath(); - return path.join(directory, 'shared_preferences.json'); + return path.join(directory!, 'shared_preferences.json'); } _writeTestFile(String value) async { @@ -87,23 +87,23 @@ void main() { /// path it returns is a root path that does not actually exist on Windows. class FakePathProviderWindows extends PathProviderPlatform implements PathProviderWindows { - VersionInfoQuerier versionInfoQuerier; + late VersionInfoQuerier versionInfoQuerier; @override - Future getApplicationSupportPath() async => r'C:\appsupport'; + Future getApplicationSupportPath() async => r'C:\appsupport'; @override - Future getTemporaryPath() async => null; + Future getTemporaryPath() async => null; @override - Future getLibraryPath() async => null; + Future getLibraryPath() async => null; @override - Future getApplicationDocumentsPath() async => null; + Future getApplicationDocumentsPath() async => null; @override - Future getDownloadsPath() async => null; + Future getDownloadsPath() async => null; @override - Future getPath(String folderID) async => null; + Future getPath(String folderID) async => ''; } From 3d704640ed98f8806db95983ce852e3a6538aa21 Mon Sep 17 00:00:00 2001 From: Sameer Kashyap <40424087+Sameerkash@users.noreply.github.com> Date: Mon, 8 Feb 2021 21:11:39 +0530 Subject: [PATCH 165/924] [image_picker] Migrate to null-safety (#3524) Migrate image_picker to null-safety --- .../image_picker/image_picker/CHANGELOG.md | 6 + .../image_picker/example/lib/main.dart | 97 ++--- .../image_picker/example/pubspec.yaml | 9 +- .../old_image_picker_test.dart | 2 + .../image_picker/lib/image_picker.dart | 105 +----- .../image_picker/image_picker/pubspec.yaml | 12 +- .../image_picker/test/image_picker_test.dart | 6 +- .../test/old_image_picker_test.dart | 340 ------------------ 8 files changed, 79 insertions(+), 498 deletions(-) delete mode 100644 packages/image_picker/image_picker/test/old_image_picker_test.dart diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 1a09758d13ef..c6b29f277ec3 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.7.0-nullsafety +* Migrate to nullsafety +* Breaking Changes: + * Removed the deprecated methods: `ImagePicker.pickImage`, `ImagePicker.pickVideo`, +`ImagePicker.retrieveLostData` + ## 0.6.7+22 * iOS: update XCUITests to separate each test session. diff --git a/packages/image_picker/image_picker/example/lib/main.dart b/packages/image_picker/image_picker/example/lib/main.dart index 73327ef0caa6..54e3a1ae4cd2 100755 --- a/packages/image_picker/image_picker/example/lib/main.dart +++ b/packages/image_picker/image_picker/example/lib/main.dart @@ -29,60 +29,63 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, this.title}) : super(key: key); - final String title; + final String? title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { - PickedFile _imageFile; + PickedFile? _imageFile; dynamic _pickImageError; bool isVideo = false; - VideoPlayerController _controller; - VideoPlayerController _toBeDisposed; - String _retrieveDataError; + VideoPlayerController? _controller; + VideoPlayerController? _toBeDisposed; + String? _retrieveDataError; final ImagePicker _picker = ImagePicker(); final TextEditingController maxWidthController = TextEditingController(); final TextEditingController maxHeightController = TextEditingController(); final TextEditingController qualityController = TextEditingController(); - Future _playVideo(PickedFile file) async { + Future _playVideo(PickedFile? file) async { if (file != null && mounted) { await _disposeVideoController(); + late VideoPlayerController controller; if (kIsWeb) { - _controller = VideoPlayerController.network(file.path); - // In web, most browsers won't honor a programmatic call to .play - // if the video has a sound track (and is not muted). - // Mute the video so it auto-plays in web! - // This is not needed if the call to .play is the result of user - // interaction (clicking on a "play" button, for example). - await _controller.setVolume(0.0); + controller = VideoPlayerController.network(file.path); } else { - _controller = VideoPlayerController.file(File(file.path)); - await _controller.setVolume(1.0); + controller = VideoPlayerController.file(File(file.path)); } - await _controller.initialize(); - await _controller.setLooping(true); - await _controller.play(); + _controller = controller; + // In web, most browsers won't honor a programmatic call to .play + // if the video has a sound track (and is not muted). + // Mute the video so it auto-plays in web! + // This is not needed if the call to .play is the result of user + // interaction (clicking on a "play" button, for example). + final double volume = kIsWeb ? 0.0 : 1.0; + await controller.setVolume(volume); + await controller.initialize(); + await controller.setLooping(true); + await controller.play(); setState(() {}); } } - void _onImageButtonPressed(ImageSource source, {BuildContext context}) async { + void _onImageButtonPressed(ImageSource source, + {BuildContext? context}) async { if (_controller != null) { - await _controller.setVolume(0.0); + await _controller!.setVolume(0.0); } if (isVideo) { - final PickedFile file = await _picker.getVideo( + final PickedFile? file = await _picker.getVideo( source: source, maxDuration: const Duration(seconds: 10)); await _playVideo(file); } else { - await _displayPickImageDialog(context, - (double maxWidth, double maxHeight, int quality) async { + await _displayPickImageDialog(context!, + (double? maxWidth, double? maxHeight, int? quality) async { try { final pickedFile = await _picker.getImage( source: source, @@ -105,8 +108,8 @@ class _MyHomePageState extends State { @override void deactivate() { if (_controller != null) { - _controller.setVolume(0.0); - _controller.pause(); + _controller!.setVolume(0.0); + _controller!.pause(); } super.deactivate(); } @@ -122,14 +125,14 @@ class _MyHomePageState extends State { Future _disposeVideoController() async { if (_toBeDisposed != null) { - await _toBeDisposed.dispose(); + await _toBeDisposed!.dispose(); } _toBeDisposed = _controller; _controller = null; } Widget _previewVideo() { - final Text retrieveError = _getRetrieveErrorWidget(); + final Text? retrieveError = _getRetrieveErrorWidget(); if (retrieveError != null) { return retrieveError; } @@ -146,7 +149,7 @@ class _MyHomePageState extends State { } Widget _previewImage() { - final Text retrieveError = _getRetrieveErrorWidget(); + final Text? retrieveError = _getRetrieveErrorWidget(); if (retrieveError != null) { return retrieveError; } @@ -154,10 +157,10 @@ class _MyHomePageState extends State { if (kIsWeb) { // Why network? // See https://pub.dev/packages/image_picker#getting-ready-for-the-web-platform - return Image.network(_imageFile.path); + return Image.network(_imageFile!.path); } else { return Semantics( - child: Image.file(File(_imageFile.path)), + child: Image.file(File(_imageFile!.path)), label: 'image_picker_example_picked_image'); } } else if (_pickImageError != null) { @@ -189,7 +192,7 @@ class _MyHomePageState extends State { }); } } else { - _retrieveDataError = response.exception.code; + _retrieveDataError = response.exception!.code; } } @@ -197,7 +200,7 @@ class _MyHomePageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(widget.title), + title: Text(widget.title!), ), body: Center( child: !kIsWeb && defaultTargetPlatform == TargetPlatform.android @@ -288,9 +291,9 @@ class _MyHomePageState extends State { ); } - Text _getRetrieveErrorWidget() { + Text? _getRetrieveErrorWidget() { if (_retrieveDataError != null) { - final Text result = Text(_retrieveDataError); + final Text result = Text(_retrieveDataError!); _retrieveDataError = null; return result; } @@ -336,13 +339,13 @@ class _MyHomePageState extends State { TextButton( child: const Text('PICK'), onPressed: () { - double width = maxWidthController.text.isNotEmpty + double? width = maxWidthController.text.isNotEmpty ? double.parse(maxWidthController.text) : null; - double height = maxHeightController.text.isNotEmpty + double? height = maxHeightController.text.isNotEmpty ? double.parse(maxHeightController.text) : null; - int quality = qualityController.text.isNotEmpty + int? quality = qualityController.text.isNotEmpty ? int.parse(qualityController.text) : null; onPick(width, height, quality); @@ -355,27 +358,27 @@ class _MyHomePageState extends State { } typedef void OnPickImageCallback( - double maxWidth, double maxHeight, int quality); + double? maxWidth, double? maxHeight, int? quality); class AspectRatioVideo extends StatefulWidget { AspectRatioVideo(this.controller); - final VideoPlayerController controller; + final VideoPlayerController? controller; @override AspectRatioVideoState createState() => AspectRatioVideoState(); } class AspectRatioVideoState extends State { - VideoPlayerController get controller => widget.controller; + VideoPlayerController? get controller => widget.controller; bool initialized = false; void _onVideoControllerUpdate() { if (!mounted) { return; } - if (initialized != controller.value.initialized) { - initialized = controller.value.initialized; + if (initialized != controller!.value.isInitialized) { + initialized = controller!.value.isInitialized; setState(() {}); } } @@ -383,12 +386,12 @@ class AspectRatioVideoState extends State { @override void initState() { super.initState(); - controller.addListener(_onVideoControllerUpdate); + controller!.addListener(_onVideoControllerUpdate); } @override void dispose() { - controller.removeListener(_onVideoControllerUpdate); + controller!.removeListener(_onVideoControllerUpdate); super.dispose(); } @@ -397,8 +400,8 @@ class AspectRatioVideoState extends State { if (initialized) { return Center( child: AspectRatio( - aspectRatio: controller.value?.aspectRatio, - child: VideoPlayer(controller), + aspectRatio: controller!.value.aspectRatio, + child: VideoPlayer(controller!), ), ); } else { diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml index 0ff2f280e2ab..44364a1c19e7 100755 --- a/packages/image_picker/image_picker/example/pubspec.yaml +++ b/packages/image_picker/image_picker/example/pubspec.yaml @@ -3,24 +3,23 @@ description: Demonstrates how to use the image_picker plugin. author: Flutter Team dependencies: - video_player: ^0.10.3 + video_player: ^2.0.0-nullsafety.7 flutter: sdk: flutter - flutter_plugin_android_lifecycle: ^1.0.2 + flutter_plugin_android_lifecycle: ^2.0.0-nullsafety.2 image_picker: path: ../ - image_picker_for_web: ^0.1.0 dev_dependencies: flutter_driver: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.0.0-dev.28.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.10.0 <2.0.0" diff --git a/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart b/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart index d21a4e0cdfa3..76c971c2881b 100644 --- a/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart +++ b/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart @@ -1,3 +1,5 @@ +// @dart=2.9 + import 'package:integration_test/integration_test.dart'; void main() { diff --git a/packages/image_picker/image_picker/lib/image_picker.dart b/packages/image_picker/image_picker/lib/image_picker.dart index 5c0683c3f29f..22315100c961 100755 --- a/packages/image_picker/image_picker/lib/image_picker.dart +++ b/packages/image_picker/image_picker/lib/image_picker.dart @@ -5,7 +5,6 @@ // ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package import 'dart:async'; -import 'dart:io'; import 'package:flutter/foundation.dart'; @@ -18,7 +17,6 @@ export 'package:image_picker_platform_interface/image_picker_platform_interface. ImageSource, CameraDevice, LostData, - LostDataResponse, PickedFile, RetrieveType; @@ -29,46 +27,6 @@ class ImagePicker { @visibleForTesting static ImagePickerPlatform get platform => ImagePickerPlatform.instance; - /// Returns a [File] object pointing to the image that was picked. - /// - /// The returned [File] is intended to be used within a single APP session. Do not save the file path and use it across sessions. - /// - /// 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 supportted for certain - /// image types such as JPEG. If compression is not supported for the image that is picked, - /// an 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 [retrieveLostData] when your app relaunches to retrieve the lost data. - @Deprecated('Use imagePicker.getImage() method instead.') - static Future pickImage( - {@required ImageSource source, - double maxWidth, - double maxHeight, - int imageQuality, - CameraDevice preferredCameraDevice = CameraDevice.rear}) async { - String path = await platform.pickImagePath( - source: source, - maxWidth: maxWidth, - maxHeight: maxHeight, - imageQuality: imageQuality, - preferredCameraDevice: preferredCameraDevice, - ); - - return path == null ? null : File(path); - } - /// Returns a [PickedFile] object wrapping the image that was picked. /// /// The returned [PickedFile] is intended to be used within a single APP session. Do not save the file path and use it across sessions. @@ -96,11 +54,11 @@ class ImagePicker { /// /// 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 [getLostData] when your app relaunches to retrieve the lost data. - Future getImage({ - @required ImageSource source, - double maxWidth, - double maxHeight, - int imageQuality, + Future getImage({ + required ImageSource source, + double? maxWidth, + double? maxHeight, + int? imageQuality, CameraDevice preferredCameraDevice = CameraDevice.rear, }) { return platform.pickImage( @@ -112,36 +70,6 @@ class ImagePicker { ); } - /// Returns a [File] object pointing to the video that was picked. - /// - /// The returned [File] is intended to be used within a single APP session. Do not save the file path and use it across sessions. - /// - /// 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 [retrieveLostData] when your app relaunches to retrieve the lost data. - @Deprecated('Use imagePicker.getVideo() method instead.') - static Future pickVideo( - {@required ImageSource source, - CameraDevice preferredCameraDevice = CameraDevice.rear, - Duration maxDuration}) async { - String path = await platform.pickVideoPath( - source: source, - preferredCameraDevice: preferredCameraDevice, - maxDuration: maxDuration, - ); - - return path == null ? null : File(path); - } - /// Returns a [PickedFile] object wrapping the video that was picked. /// /// The returned [PickedFile] is intended to be used within a single APP session. Do not save the file path and use it across sessions. @@ -158,10 +86,10 @@ class ImagePicker { /// /// 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 [getLostData] when your app relaunches to retrieve the lost data. - Future getVideo({ - @required ImageSource source, + Future getVideo({ + required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, - Duration maxDuration, + Duration? maxDuration, }) { return platform.pickVideo( source: source, @@ -170,23 +98,6 @@ class ImagePicker { ); } - /// Retrieve the lost image file when [pickImage] or [pickVideo] 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. - static Future retrieveLostData() { - return platform.retrieveLostDataAsDartIoFile(); - } - /// Retrieve the lost [PickedFile] when [selectImage] or [selectVideo] 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. diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 075c90627bf4..75f9dca4e0ca 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.6.7+22 +version: 0.7.0-nullsafety flutter: plugin: @@ -16,19 +16,19 @@ flutter: dependencies: flutter: sdk: flutter - flutter_plugin_android_lifecycle: ^1.0.2 - image_picker_platform_interface: ^1.1.0 + flutter_plugin_android_lifecycle: ^2.0.0-nullsafety.2 + image_picker_platform_interface: ^2.0.0-nullsafety dev_dependencies: - video_player: ^0.10.3 + video_player: ^2.0.0-nullsafety.7 flutter_test: sdk: flutter integration_test: path: ../../integration_test - mockito: ^4.1.3 + mockito: ^5.0.0-nullsafety.7 pedantic: ^1.8.0 plugin_platform_interface: ^1.0.3 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.10.0" diff --git a/packages/image_picker/image_picker/test/image_picker_test.dart b/packages/image_picker/image_picker/test/image_picker_test.dart index 7172975ded5d..0508d257016d 100644 --- a/packages/image_picker/image_picker/test/image_picker_test.dart +++ b/packages/image_picker/image_picker/test/image_picker_test.dart @@ -310,7 +310,7 @@ void main() { }); final LostData response = await picker.getLostData(); expect(response.type, RetrieveType.image); - expect(response.file.path, '/example/path'); + expect(response.file!.path, '/example/path'); }); test('retrieveLostData get error response', () async { @@ -323,8 +323,8 @@ void main() { }); final LostData response = await picker.getLostData(); expect(response.type, RetrieveType.video); - expect(response.exception.code, 'test_error_code'); - expect(response.exception.message, 'test_error_message'); + 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/test/old_image_picker_test.dart b/packages/image_picker/image_picker/test/old_image_picker_test.dart deleted file mode 100644 index 8d4e068a261c..000000000000 --- a/packages/image_picker/image_picker/test/old_image_picker_test.dart +++ /dev/null @@ -1,340 +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. - -// ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package - -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:image_picker/image_picker.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - group('$ImagePicker', () { - const MethodChannel channel = - MethodChannel('plugins.flutter.io/image_picker'); - - final List log = []; - - setUp(() { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - return ''; - }); - - log.clear(); - }); - - group('#pickImage', () { - test('passes the image source argument correctly', () async { - await ImagePicker.pickImage(source: ImageSource.camera); - await ImagePicker.pickImage(source: ImageSource.gallery); - - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 1, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - ], - ); - }); - - test('passes the width and height arguments correctly', () async { - await ImagePicker.pickImage(source: ImageSource.camera); - await ImagePicker.pickImage( - source: ImageSource.camera, - maxWidth: 10.0, - ); - await ImagePicker.pickImage( - source: ImageSource.camera, - maxHeight: 10.0, - ); - await ImagePicker.pickImage( - source: ImageSource.camera, - maxWidth: 10.0, - maxHeight: 20.0, - ); - await ImagePicker.pickImage( - source: ImageSource.camera, maxWidth: 10.0, imageQuality: 70); - await ImagePicker.pickImage( - source: ImageSource.camera, maxHeight: 10.0, imageQuality: 70); - await ImagePicker.pickImage( - source: ImageSource.camera, - maxWidth: 10.0, - maxHeight: 20.0, - imageQuality: 70); - - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': null, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': null, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': 10.0, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': 10.0, - 'maxHeight': 20.0, - 'imageQuality': 70, - 'cameraDevice': 0 - }), - ], - ); - }); - - test('does not accept a negative width or height argument', () { - expect( - ImagePicker.pickImage(source: ImageSource.camera, maxWidth: -1.0), - throwsArgumentError, - ); - - expect( - ImagePicker.pickImage(source: ImageSource.camera, maxHeight: -1.0), - throwsArgumentError, - ); - }); - - test('handles a null image path response gracefully', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) => null); - - expect( - await ImagePicker.pickImage(source: ImageSource.gallery), isNull); - expect(await ImagePicker.pickImage(source: ImageSource.camera), isNull); - }); - - test('camera position defaults to back', () async { - await ImagePicker.pickImage(source: ImageSource.camera); - - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 0, - }), - ], - ); - }); - - test('camera position can set to front', () async { - await ImagePicker.pickImage( - source: ImageSource.camera, - preferredCameraDevice: CameraDevice.front); - - expect( - log, - [ - isMethodCall('pickImage', arguments: { - 'source': 0, - 'maxWidth': null, - 'maxHeight': null, - 'imageQuality': null, - 'cameraDevice': 1, - }), - ], - ); - }); - }); - - group('#pickVideo', () { - test('passes the image source argument correctly', () async { - await ImagePicker.pickVideo(source: ImageSource.camera); - await ImagePicker.pickVideo(source: ImageSource.gallery); - - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'cameraDevice': 0, - 'maxDuration': null, - }), - isMethodCall('pickVideo', arguments: { - 'source': 1, - 'cameraDevice': 0, - 'maxDuration': null, - }), - ], - ); - }); - - test('passes the duration argument correctly', () async { - await ImagePicker.pickVideo(source: ImageSource.camera); - await ImagePicker.pickVideo( - source: ImageSource.camera, - maxDuration: const Duration(seconds: 10)); - await ImagePicker.pickVideo( - source: ImageSource.camera, - maxDuration: const Duration(minutes: 1)); - await ImagePicker.pickVideo( - source: ImageSource.camera, maxDuration: const Duration(hours: 1)); - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': null, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 10, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 60, - 'cameraDevice': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': 3600, - 'cameraDevice': 0, - }), - ], - ); - }); - - test('handles a null video path response gracefully', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) => null); - - expect( - await ImagePicker.pickVideo(source: ImageSource.gallery), isNull); - expect(await ImagePicker.pickVideo(source: ImageSource.camera), isNull); - }); - - test('camera position defaults to back', () async { - await ImagePicker.pickVideo(source: ImageSource.camera); - - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'cameraDevice': 0, - 'maxDuration': null, - }), - ], - ); - }); - - test('camera position can set to front', () async { - await ImagePicker.pickVideo( - source: ImageSource.camera, - preferredCameraDevice: CameraDevice.front); - - expect( - log, - [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - 'maxDuration': null, - 'cameraDevice': 1, - }), - ], - ); - }); - }); - - group('#retrieveLostData', () { - test('retrieveLostData get success response', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - 'type': 'image', - 'path': '/example/path', - }; - }); - final LostDataResponse response = await ImagePicker.retrieveLostData(); - expect(response.type, RetrieveType.image); - expect(response.file.path, '/example/path'); - }); - - test('retrieveLostData get error response', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - 'type': 'video', - 'errorCode': 'test_error_code', - 'errorMessage': 'test_error_message', - }; - }); - final LostDataResponse response = await ImagePicker.retrieveLostData(); - 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 { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return null; - }); - expect((await ImagePicker.retrieveLostData()).isEmpty, true); - }); - - test('retrieveLostData get both path and error should throw', () async { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return { - 'type': 'video', - 'errorCode': 'test_error_code', - 'errorMessage': 'test_error_message', - 'path': '/example/path', - }; - }); - expect(ImagePicker.retrieveLostData(), throwsAssertionError); - }); - }); - }); -} From 7adfc2f7cd1276d1dfaf630a965df264c56ff1d7 Mon Sep 17 00:00:00 2001 From: Darshan Rander Date: Mon, 8 Feb 2021 21:12:26 +0530 Subject: [PATCH 166/924] [file_selector_platform_interface] File selector nnbd (#3509) Migrating file_selector_interface to null-safety --- .../CHANGELOG.md | 4 ++ .../method_channel_file_selector.dart | 44 +++++++++---------- .../file_selector_interface.dart | 33 +++++++------- .../src/types/x_type_group/x_type_group.dart | 10 ++--- .../lib/src/web_helpers/web_helpers.dart | 4 +- .../pubspec.yaml | 12 ++--- .../file_selector_web/pubspec.yaml | 4 +- script/nnbd_plugins.sh | 2 +- 8 files changed, 60 insertions(+), 53 deletions(-) diff --git a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md index aafe4db278d8..2fbe18db7bfd 100644 --- a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md +++ b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.0 + +* Migration to null-safety + ## 1.0.3+1 * Bump the [cross_file](https://pub.dev/packages/cross_file) package version. diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart b/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart index 586b1abcae1e..e14239f51690 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart @@ -19,57 +19,57 @@ class MethodChannelFileSelector extends FileSelectorPlatform { /// Load a file from user's computer and return it as an XFile @override - Future openFile({ - List acceptedTypeGroups, - String initialDirectory, - String confirmButtonText, + Future openFile({ + List? acceptedTypeGroups, + String? initialDirectory, + String? confirmButtonText, }) async { - final List path = await _channel.invokeListMethod( + final List? path = await _channel.invokeListMethod( 'openFile', { 'acceptedTypeGroups': - acceptedTypeGroups?.map((group) => group.toJSON())?.toList(), + acceptedTypeGroups?.map((group) => group.toJSON()).toList(), 'initialDirectory': initialDirectory, 'confirmButtonText': confirmButtonText, 'multiple': false, }, ); - return path == null ? null : XFile(path?.first); + return path == null ? null : XFile(path.first); } /// Load multiple files from user's computer and return it as an XFile @override Future> openFiles({ - List acceptedTypeGroups, - String initialDirectory, - String confirmButtonText, + List? acceptedTypeGroups, + String? initialDirectory, + String? confirmButtonText, }) async { - final List pathList = await _channel.invokeListMethod( + final List? pathList = await _channel.invokeListMethod( 'openFile', { 'acceptedTypeGroups': - acceptedTypeGroups?.map((group) => group.toJSON())?.toList(), + acceptedTypeGroups?.map((group) => group.toJSON()).toList(), 'initialDirectory': initialDirectory, 'confirmButtonText': confirmButtonText, 'multiple': true, }, ); - return pathList?.map((path) => XFile(path))?.toList() ?? []; + return pathList?.map((path) => XFile(path)).toList() ?? []; } /// Gets the path from a save dialog @override - Future getSavePath({ - List acceptedTypeGroups, - String initialDirectory, - String suggestedName, - String confirmButtonText, + Future getSavePath({ + List? acceptedTypeGroups, + String? initialDirectory, + String? suggestedName, + String? confirmButtonText, }) async { return _channel.invokeMethod( 'getSavePath', { 'acceptedTypeGroups': - acceptedTypeGroups?.map((group) => group.toJSON())?.toList(), + acceptedTypeGroups?.map((group) => group.toJSON()).toList(), 'initialDirectory': initialDirectory, 'suggestedName': suggestedName, 'confirmButtonText': confirmButtonText, @@ -79,9 +79,9 @@ class MethodChannelFileSelector extends FileSelectorPlatform { /// Gets a directory path from a dialog @override - Future getDirectoryPath({ - String initialDirectory, - String confirmButtonText, + Future getDirectoryPath({ + String? initialDirectory, + String? confirmButtonText, }) async { return _channel.invokeMethod( 'getDirectoryPath', diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart b/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart index e7b32631a58b..0be02c2185dd 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart @@ -38,37 +38,40 @@ abstract class FileSelectorPlatform extends PlatformInterface { } /// Open file dialog for loading files and return a file path - Future openFile({ - List acceptedTypeGroups, - String initialDirectory, - String confirmButtonText, + /// Returns `null` if user cancels the operation. + Future openFile({ + List? acceptedTypeGroups, + String? initialDirectory, + String? confirmButtonText, }) { throw UnimplementedError('openFile() has not been implemented.'); } /// Open file dialog for loading files and return a list of file paths Future> openFiles({ - List acceptedTypeGroups, - String initialDirectory, - String confirmButtonText, + List? acceptedTypeGroups, + String? initialDirectory, + String? confirmButtonText, }) { throw UnimplementedError('openFiles() has not been implemented.'); } /// Open file dialog for saving files and return a file path at which to save - Future getSavePath({ - List acceptedTypeGroups, - String initialDirectory, - String suggestedName, - String confirmButtonText, + /// Returns `null` if user cancels the operation. + Future getSavePath({ + List? acceptedTypeGroups, + String? initialDirectory, + String? suggestedName, + String? confirmButtonText, }) { throw UnimplementedError('getSavePath() has not been implemented.'); } /// Open file dialog for loading directories and return a directory path - Future getDirectoryPath({ - String initialDirectory, - String confirmButtonText, + /// Returns `null` if user cancels the operation. + Future getDirectoryPath({ + String? initialDirectory, + String? confirmButtonText, }) { throw UnimplementedError('getDirectoryPath() has not been implemented.'); } diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart index fb591f2b248a..f3f05e2ab3a6 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart @@ -17,19 +17,19 @@ class XTypeGroup { }); /// The 'name' or reference to this group of types - final String label; + final String? label; /// The extensions for this group - final List extensions; + final List? extensions; /// The MIME types for this group - final List mimeTypes; + final List? mimeTypes; /// The UTIs for this group - final List macUTIs; + final List? macUTIs; /// The web wild cards for this group (ex: image/*, video/*) - final List webWildCards; + final List? webWildCards; /// Converts this object into a JSON formatted object Map toJSON() { diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart b/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart index 9e40e562bc9a..5330c5cf6dcd 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart @@ -1,7 +1,7 @@ import 'dart:html'; /// Create anchor element with download attribute -AnchorElement createAnchorElement(String href, String suggestedName) { +AnchorElement createAnchorElement(String href, String? suggestedName) { final element = AnchorElement(href: href); if (suggestedName == null) { @@ -27,7 +27,7 @@ Element ensureInitialized(String id) { if (target == null) { final Element targetElement = Element.tag('flt-x-file')..id = id; - querySelector('body').children.add(targetElement); + querySelector('body')!.children.add(targetElement); target = targetElement; } return target; diff --git a/packages/file_selector/file_selector_platform_interface/pubspec.yaml b/packages/file_selector/file_selector_platform_interface/pubspec.yaml index f1d0038a5062..9735bced03fb 100644 --- a/packages/file_selector/file_selector_platform_interface/pubspec.yaml +++ b/packages/file_selector/file_selector_platform_interface/pubspec.yaml @@ -3,23 +3,23 @@ description: A common platform interface for the file_selector plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_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.0.3+1 +version: 2.0.0-nullsafety.0 dependencies: flutter: sdk: flutter meta: ^1.0.5 - http: ^0.12.0+1 - plugin_platform_interface: ^1.0.1 - cross_file: ^0.2.0 + http: ^0.13.0-nullsafety.0 + plugin_platform_interface: ^1.1.0-nullsafety.2 + cross_file: ^0.3.0-nullsafety dev_dependencies: test: ^1.15.0 flutter_test: sdk: flutter - mockito: ^4.1.1 + mockito: ^5.0.0-nullsafety.5 pedantic: ^1.8.0 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.9.1+hotfix.4" diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml index a170d5f39607..79181e821cec 100644 --- a/packages/file_selector/file_selector_web/pubspec.yaml +++ b/packages/file_selector/file_selector_web/pubspec.yaml @@ -22,8 +22,8 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - mockito: ^4.1.1 - pedantic: ^1.8.0 + mockito: ^5.0.0-nullsafety.5 + pedantic: ^1.10.0-nullsafety.3 integration_test: path: ../../integration_test diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 742487ad7bfa..1e57db96a648 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -10,6 +10,7 @@ readonly NNBD_PLUGINS_LIST=( "connectivity" "cross_file" "device_info" + "file_selector" "flutter_plugin_android_lifecycle" "flutter_webview" "google_sign_in" @@ -32,7 +33,6 @@ readonly NNBD_PLUGINS_LIST=( readonly NON_NNBD_PLUGINS_LIST=( # "android_alarm_manager" "camera" - # "file_selector" # "google_maps_flutter" # "image_picker" # "in_app_purchase" From 2b6addf678a204d3f09c974e34b49d5b3eb866c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan?= Date: Mon, 8 Feb 2021 19:59:25 +0100 Subject: [PATCH 167/924] [shared_preferences] Migrate platform plugins to null-safety (#3523) Migrates shared_preferences_linux and shared_preferences_web to null-safety. --- .../shared_preferences_linux/CHANGELOG.md | 4 + .../shared_preferences_test.dart | 87 ++++++++++--------- .../example/pubspec.yaml | 7 -- .../lib/shared_preferences_linux.dart | 23 +++-- .../shared_preferences_linux/pubspec.yaml | 12 +-- .../test/shared_preferences_linux_test.dart | 6 +- .../shared_preferences_web/CHANGELOG.md | 4 + .../lib/shared_preferences_web.dart | 21 ++--- .../shared_preferences_web/pubspec.yaml | 6 +- .../test/shared_preferences_web_test.dart | 6 +- 10 files changed, 93 insertions(+), 83 deletions(-) diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md index 9821b79c5cc2..2be9c8ca075a 100644 --- a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.4-nullsafety + +* Migrate to null-safety. + ## 0.0.3+1 * Update Flutter SDK constraint. diff --git a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart index e43d4e3ae0c2..3aedccd0feba 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart @@ -1,12 +1,13 @@ import 'dart:async'; + import 'package:flutter_test/flutter_test.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:integration_test/integration_test.dart'; +import 'package:shared_preferences_linux/shared_preferences_linux.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - group('$SharedPreferences', () { + group('SharedPreferencesLinux', () { const Map kTestValues = { 'flutter.String': 'hello world', 'flutter.bool': true, @@ -23,10 +24,10 @@ void main() { 'flutter.List': ['baz', 'quox'], }; - SharedPreferences preferences; + SharedPreferencesLinux preferences; setUp(() async { - preferences = await SharedPreferences.getInstance(); + preferences = SharedPreferencesLinux.instance; }); tearDown(() { @@ -34,56 +35,62 @@ void main() { }); testWidgets('reading', (WidgetTester _) async { - expect(preferences.get('String'), isNull); - expect(preferences.get('bool'), isNull); - expect(preferences.get('int'), isNull); - expect(preferences.get('double'), isNull); - expect(preferences.get('List'), isNull); - expect(preferences.getString('String'), isNull); - expect(preferences.getBool('bool'), isNull); - expect(preferences.getInt('int'), isNull); - expect(preferences.getDouble('double'), isNull); - expect(preferences.getStringList('List'), isNull); + final all = await preferences.getAll(); + expect(all['String'], isNull); + expect(all['bool'], isNull); + expect(all['int'], isNull); + expect(all['double'], isNull); + expect(all['List'], isNull); }); testWidgets('writing', (WidgetTester _) async { await Future.wait(>[ - preferences.setString('String', kTestValues2['flutter.String']), - preferences.setBool('bool', kTestValues2['flutter.bool']), - preferences.setInt('int', kTestValues2['flutter.int']), - preferences.setDouble('double', kTestValues2['flutter.double']), - preferences.setStringList('List', kTestValues2['flutter.List']) + preferences.setValue( + 'String', 'String', kTestValues2['flutter.String']), + preferences.setValue('Bool', 'bool', kTestValues2['flutter.bool']), + preferences.setValue('Int', 'int', kTestValues2['flutter.int']), + preferences.setValue( + 'Double', 'double', kTestValues2['flutter.double']), + preferences.setValue('StringList', 'List', kTestValues2['flutter.List']) ]); - expect(preferences.getString('String'), kTestValues2['flutter.String']); - expect(preferences.getBool('bool'), kTestValues2['flutter.bool']); - expect(preferences.getInt('int'), kTestValues2['flutter.int']); - expect(preferences.getDouble('double'), kTestValues2['flutter.double']); - expect(preferences.getStringList('List'), kTestValues2['flutter.List']); + final all = await preferences.getAll(); + expect(all['String'], kTestValues2['flutter.String']); + expect(all['bool'], kTestValues2['flutter.bool']); + expect(all['int'], kTestValues2['flutter.int']); + expect(all['double'], kTestValues2['flutter.double']); + expect(all['List'], kTestValues2['flutter.List']); }); testWidgets('removing', (WidgetTester _) async { const String key = 'testKey'; - await preferences.setString(key, kTestValues['flutter.String']); - await preferences.setBool(key, kTestValues['flutter.bool']); - await preferences.setInt(key, kTestValues['flutter.int']); - await preferences.setDouble(key, kTestValues['flutter.double']); - await preferences.setStringList(key, kTestValues['flutter.List']); + + await Future.wait([ + preferences.setValue('String', key, kTestValues['flutter.String']), + preferences.setValue('Bool', key, kTestValues['flutter.bool']), + preferences.setValue('Int', key, kTestValues['flutter.int']), + preferences.setValue('Double', key, kTestValues['flutter.double']), + preferences.setValue('StringList', key, kTestValues['flutter.List']) + ]); await preferences.remove(key); - expect(preferences.get('testKey'), isNull); + final all = await preferences.getAll(); + expect(all['testKey'], isNull); }); testWidgets('clearing', (WidgetTester _) async { - await preferences.setString('String', kTestValues['flutter.String']); - await preferences.setBool('bool', kTestValues['flutter.bool']); - await preferences.setInt('int', kTestValues['flutter.int']); - await preferences.setDouble('double', kTestValues['flutter.double']); - await preferences.setStringList('List', kTestValues['flutter.List']); + await Future.wait(>[ + preferences.setValue('String', 'String', kTestValues['flutter.String']), + preferences.setValue('Bool', 'bool', kTestValues['flutter.bool']), + preferences.setValue('Int', 'int', kTestValues['flutter.int']), + preferences.setValue('Double', 'double', kTestValues['flutter.double']), + preferences.setValue('StringList', 'List', kTestValues['flutter.List']) + ]); await preferences.clear(); - expect(preferences.getString('String'), null); - expect(preferences.getBool('bool'), null); - expect(preferences.getInt('int'), null); - expect(preferences.getDouble('double'), null); - expect(preferences.getStringList('List'), null); + final all = await preferences.getAll(); + expect(all['String'], null); + expect(all['bool'], null); + expect(all['int'], null); + expect(all['double'], null); + expect(all['List'], null); }); }); } diff --git a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml index fb79444dc6cd..591aad4c2c57 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml @@ -4,15 +4,8 @@ description: Demonstrates how to use the shared_preferences_linux plugin. dependencies: flutter: sdk: flutter - shared_preferences: any - shared_preferences_linux: ^0.1.0 - -dependency_overrides: shared_preferences_linux: path: ../ - # Remove this override once the endorsement is published. - shared_preferences: - path: ../../shared_preferences/ dev_dependencies: flutter_driver: diff --git a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart index c975ad1a7544..5a694658cdf5 100644 --- a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart +++ b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart @@ -20,16 +20,17 @@ class SharedPreferencesLinux extends SharedPreferencesStorePlatform { static SharedPreferencesLinux instance = SharedPreferencesLinux(); /// Local copy of preferences - Map _cachedPreferences; + Map? _cachedPreferences; /// File system used to store to disk. Exposed for testing only. @visibleForTesting FileSystem fs = LocalFileSystem(); /// Gets the file where the preferences are stored. - Future _getLocalDataFile() async { + Future _getLocalDataFile() async { final pathProvider = PathProviderLinux(); final directory = await pathProvider.getApplicationSupportPath(); + if (directory == null) return null; return fs.file(path.join(directory, 'shared_preferences.json')); } @@ -37,19 +38,19 @@ class SharedPreferencesLinux extends SharedPreferencesStorePlatform { /// maintained in memory. Future> _readPreferences() async { if (_cachedPreferences != null) { - return _cachedPreferences; + return _cachedPreferences!; } - _cachedPreferences = {}; - var localDataFile = await _getLocalDataFile(); - if (localDataFile.existsSync()) { + Map preferences = {}; + final File? localDataFile = await _getLocalDataFile(); + if (localDataFile != null && localDataFile.existsSync()) { String stringMap = localDataFile.readAsStringSync(); if (stringMap.isNotEmpty) { - _cachedPreferences = json.decode(stringMap) as Map; + preferences = json.decode(stringMap).cast(); } } - - return _cachedPreferences; + _cachedPreferences = preferences; + return preferences; } /// Writes the cached preferences to disk. Returns [true] if the operation @@ -57,6 +58,10 @@ class SharedPreferencesLinux extends SharedPreferencesStorePlatform { Future _writePreferences(Map preferences) async { try { var localDataFile = await _getLocalDataFile(); + if (localDataFile == null) { + print("Unable to determine where to write preferences."); + return false; + } if (!localDataFile.existsSync()) { localDataFile.createSync(recursive: true); } diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml index 50709aac5f8a..df4b5db23b7f 100644 --- a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: shared_preferences_linux description: Linux implementation of the shared_preferences plugin -version: 0.0.3+1 +version: 0.0.4-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux flutter: @@ -11,17 +11,17 @@ flutter: pluginClass: none environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.8" dependencies: - file: ">=5.1.0 <7.0.0" flutter: sdk: flutter + file: ^6.0.0-nullsafety.4 meta: ^1.0.4 - path: ^1.6.4 - path_provider_linux: ^0.0.1 - shared_preferences_platform_interface: ^1.0.0 + path: ^1.8.0-nullsafety.3 + path_provider_linux: ^0.2.0-nullsafety + shared_preferences_platform_interface: ^2.0.0-nullsafety dev_dependencies: flutter_test: diff --git a/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart index 8c659f212aa5..cf0bc80e3ec2 100644 --- a/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart @@ -7,9 +7,9 @@ import 'package:path/path.dart' as path; import 'package:path_provider_linux/path_provider_linux.dart'; import 'package:shared_preferences_linux/shared_preferences_linux.dart'; -MemoryFileSystem fs; - void main() { + late MemoryFileSystem fs; + setUp(() { fs = MemoryFileSystem.test(); }); @@ -19,7 +19,7 @@ void main() { Future _getFilePath() async { final pathProvider = PathProviderLinux(); final directory = await pathProvider.getApplicationSupportPath(); - return path.join(directory, 'shared_preferences.json'); + return path.join(directory!, 'shared_preferences.json'); } _writeTestFile(String value) async { diff --git a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md index 2ba877856da6..0194ef8ade37 100644 --- a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.0-nullsafety + +* Migrate to null-safety. + ## 0.1.2+8 * Update Flutter SDK constraint. diff --git a/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart b/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart index 8a0f137ddcc8..346877e8a120 100644 --- a/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart +++ b/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart @@ -14,7 +14,7 @@ import 'package:shared_preferences_platform_interface/shared_preferences_platfor /// This class implements the `package:shared_preferences` functionality for the web. class SharedPreferencesPlugin extends SharedPreferencesStorePlatform { /// Registers this class as the default instance of [SharedPreferencesStorePlatform]. - static void registerWith(Registrar registrar) { + static void registerWith(Registrar? registrar) { SharedPreferencesStorePlatform.instance = SharedPreferencesPlugin(); } @@ -31,9 +31,9 @@ class SharedPreferencesPlugin extends SharedPreferencesStorePlatform { @override Future> getAll() async { - final Map allData = {}; + final Map allData = {}; for (String key in _storedFlutterKeys) { - allData[key] = _decodeValue(html.window.localStorage[key]); + allData[key] = _decodeValue(html.window.localStorage[key]!); } return allData; } @@ -46,7 +46,7 @@ class SharedPreferencesPlugin extends SharedPreferencesStorePlatform { } @override - Future setValue(String valueType, String key, Object value) async { + Future setValue(String valueType, String key, Object? value) async { _checkPrefix(key); html.window.localStorage[key] = _encodeValue(value); return true; @@ -62,17 +62,12 @@ class SharedPreferencesPlugin extends SharedPreferencesStorePlatform { } } - List get _storedFlutterKeys { - final List keys = []; - for (String key in html.window.localStorage.keys) { - if (key.startsWith('flutter.')) { - keys.add(key); - } - } - return keys; + Iterable get _storedFlutterKeys { + return html.window.localStorage.keys + .where((key) => key.startsWith('flutter.')); } - String _encodeValue(Object value) { + String _encodeValue(Object? value) { return json.encode(value); } diff --git a/packages/shared_preferences/shared_preferences_web/pubspec.yaml b/packages/shared_preferences/shared_preferences_web/pubspec.yaml index d657b2300727..60892bcf277c 100644 --- a/packages/shared_preferences/shared_preferences_web/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_web/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/shared_prefere # 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.2+8 +version: 0.2.0-nullsafety flutter: plugin: @@ -14,7 +14,7 @@ flutter: fileName: shared_preferences_web.dart dependencies: - shared_preferences_platform_interface: ^1.0.0 + shared_preferences_platform_interface: ^2.0.0-nullsafety flutter: sdk: flutter flutter_web_plugins: @@ -27,5 +27,5 @@ dev_dependencies: pedantic: ^1.8.0 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.4" diff --git a/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart b/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart index 951f04cbce5a..c0cf92cc1bf0 100644 --- a/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart +++ b/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@TestOn('chrome') // Uses web-only Flutter SDK - +@TestOn('chrome') import 'dart:convert' show json; import 'dart:html' as html; import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_preferences_platform_interface/method_channel_shared_preferences.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_web/shared_preferences_web.dart'; @@ -26,6 +26,8 @@ void main() { }); test('registers itself', () { + SharedPreferencesStorePlatform.instance = + MethodChannelSharedPreferencesStore(); expect(SharedPreferencesStorePlatform.instance, isNot(isA())); SharedPreferencesPlugin.registerWith(null); From 545c97f30ebec77d8baead2df87ef52c12bb2e69 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Mon, 8 Feb 2021 21:15:45 +0100 Subject: [PATCH 168/924] [camera_platform_interface] Migrate to null safety (#3497) --- .../camera_platform_interface/CHANGELOG.md | 4 + .../lib/src/events/camera_event.dart | 10 +- .../method_channel/method_channel_camera.dart | 165 +++++++++++------- .../platform_interface/camera_platform.dart | 22 ++- .../lib/src/types/camera_description.dart | 6 +- .../lib/src/types/camera_exception.dart | 2 +- .../lib/src/types/exposure_mode.dart | 2 - .../lib/src/types/focus_mode.dart | 2 - .../camera_platform_interface/pubspec.yaml | 18 +- .../test/camera_platform_interface_test.dart | 23 ++- .../method_channel_camera_test.dart | 52 ++++-- .../test/utils/method_channel_mock.dart | 6 +- script/nnbd_plugins.sh | 1 + 13 files changed, 205 insertions(+), 108 deletions(-) diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index ff739918c53b..ab3d559bf2fb 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +- Migrate to null safety. + ## 1.6.0 - Added VideoRecordedEvent to support ending a video recording in the native implementation. diff --git a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart index ad9958381143..20aa41c5ce40 100644 --- a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart +++ b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart @@ -70,12 +70,12 @@ class CameraInitializedEvent extends CameraEvent { CameraInitializedEvent( int cameraId, this.previewWidth, - this.previewHeight, [ + this.previewHeight, this.exposureMode, - this.exposurePointSupported = false, + this.exposurePointSupported, this.focusMode, - this.focusPointSupported = false, - ]) : super(cameraId); + this.focusPointSupported, + ) : super(cameraId); /// Converts the supplied [Map] to an instance of the [CameraInitializedEvent] /// class. @@ -242,7 +242,7 @@ class VideoRecordedEvent extends CameraEvent { final XFile file; /// Maximum duration of the recorded video. - final Duration maxVideoDuration; + final Duration? maxVideoDuration; /// Build a VideoRecordedEvent triggered from the camera with the `cameraId`. /// diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index 36a2c92645f2..3537a5ca40a9 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -11,6 +11,7 @@ import 'package:camera_platform_interface/src/types/focus_mode.dart'; import 'package:camera_platform_interface/src/types/image_format_group.dart'; import 'package:camera_platform_interface/src/utils/utils.dart'; import 'package:cross_file/cross_file.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:meta/meta.dart'; @@ -58,8 +59,13 @@ class MethodChannelCamera extends CameraPlatform { @override Future> availableCameras() async { try { - final List> cameras = await _channel + final cameras = await _channel .invokeListMethod>('availableCameras'); + + if (cameras == null) { + return []; + } + return cameras.map((Map camera) { return CameraDescription( name: camera['name'], @@ -75,30 +81,30 @@ class MethodChannelCamera extends CameraPlatform { @override Future createCamera( CameraDescription cameraDescription, - ResolutionPreset resolutionPreset, { - bool enableAudio, + ResolutionPreset? resolutionPreset, { + bool enableAudio = true, }) async { try { - final Map reply = - await _channel.invokeMapMethod( - 'create', - { - 'cameraName': cameraDescription.name, - 'resolutionPreset': resolutionPreset != null - ? _serializeResolutionPreset(resolutionPreset) - : null, - 'enableAudio': enableAudio, - }, - ); - return reply['cameraId']; + final reply = await _channel + .invokeMapMethod('create', { + 'cameraName': cameraDescription.name, + 'resolutionPreset': resolutionPreset != null + ? _serializeResolutionPreset(resolutionPreset) + : null, + 'enableAudio': enableAudio, + }); + + return reply!['cameraId']; } on PlatformException catch (e) { throw CameraException(e.code, e.message); } } @override - Future initializeCamera(int cameraId, - {ImageFormatGroup imageFormatGroup}) { + Future initializeCamera( + int cameraId, { + ImageFormatGroup imageFormatGroup = ImageFormatGroup.unknown, + }) { _channels.putIfAbsent(cameraId, () { final channel = MethodChannel('flutter.io/cameraPlugin/camera$cameraId'); channel.setMethodCallHandler( @@ -125,15 +131,16 @@ class MethodChannelCamera extends CameraPlatform { @override Future dispose(int cameraId) async { + if (_channels.containsKey(cameraId)) { + final cameraChannel = _channels[cameraId]; + cameraChannel?.setMethodCallHandler(null); + _channels.remove(cameraId); + } + await _channel.invokeMethod( 'dispose', {'cameraId': cameraId}, ); - - if (_channels.containsKey(cameraId)) { - _channels[cameraId].setMethodCallHandler(null); - _channels.remove(cameraId); - } } @override @@ -169,7 +176,9 @@ class MethodChannelCamera extends CameraPlatform { @override Future lockCaptureOrientation( - int cameraId, DeviceOrientation orientation) async { + int cameraId, + DeviceOrientation orientation, + ) async { await _channel.invokeMethod( 'lockCaptureOrientation', { @@ -189,10 +198,18 @@ class MethodChannelCamera extends CameraPlatform { @override Future takePicture(int cameraId) async { - String path = await _channel.invokeMethod( + final path = await _channel.invokeMethod( 'takePicture', {'cameraId': cameraId}, ); + + if (path == null) { + throw CameraException( + 'INVALID_PATH', + 'The platform "$defaultTargetPlatform" did not return a path while reporting success. The platform should always return a valid path or report an error.', + ); + } + return XFile(path); } @@ -202,7 +219,7 @@ class MethodChannelCamera extends CameraPlatform { @override Future startVideoRecording(int cameraId, - {Duration maxVideoDuration}) async { + {Duration? maxVideoDuration}) async { await _channel.invokeMethod( 'startVideoRecording', { @@ -214,10 +231,18 @@ class MethodChannelCamera extends CameraPlatform { @override Future stopVideoRecording(int cameraId) async { - String path = await _channel.invokeMethod( + final path = await _channel.invokeMethod( 'stopVideoRecording', {'cameraId': cameraId}, ); + + if (path == null) { + throw CameraException( + 'INVALID_PATH', + 'The platform "$defaultTargetPlatform" did not return a path while reporting success. The platform should always return a valid path or report an error.', + ); + } + return XFile(path); } @@ -255,9 +280,10 @@ class MethodChannelCamera extends CameraPlatform { ); @override - Future setExposurePoint(int cameraId, Point point) { + Future setExposurePoint(int cameraId, Point? point) { assert(point == null || point.x >= 0 && point.x <= 1); assert(point == null || point.y >= 0 && point.y <= 1); + return _channel.invokeMethod( 'setExposurePoint', { @@ -270,35 +296,47 @@ class MethodChannelCamera extends CameraPlatform { } @override - Future getMinExposureOffset(int cameraId) => - _channel.invokeMethod( - 'getMinExposureOffset', - {'cameraId': cameraId}, - ); + Future getMinExposureOffset(int cameraId) async { + final minExposureOffset = await _channel.invokeMethod( + 'getMinExposureOffset', + {'cameraId': cameraId}, + ); + + return minExposureOffset!; + } @override - Future getMaxExposureOffset(int cameraId) => - _channel.invokeMethod( - 'getMaxExposureOffset', - {'cameraId': cameraId}, - ); + Future getMaxExposureOffset(int cameraId) async { + final maxExposureOffset = await _channel.invokeMethod( + 'getMaxExposureOffset', + {'cameraId': cameraId}, + ); + + return maxExposureOffset!; + } @override - Future getExposureOffsetStepSize(int cameraId) => - _channel.invokeMethod( - 'getExposureOffsetStepSize', - {'cameraId': cameraId}, - ); + Future getExposureOffsetStepSize(int cameraId) async { + final stepSize = await _channel.invokeMethod( + 'getExposureOffsetStepSize', + {'cameraId': cameraId}, + ); + + return stepSize!; + } @override - Future setExposureOffset(int cameraId, double offset) => - _channel.invokeMethod( - 'setExposureOffset', - { - 'cameraId': cameraId, - 'offset': offset, - }, - ); + Future setExposureOffset(int cameraId, double offset) async { + final appliedOffset = await _channel.invokeMethod( + 'setExposureOffset', + { + 'cameraId': cameraId, + 'offset': offset, + }, + ); + + return appliedOffset!; + } @override Future setFocusMode(int cameraId, FocusMode mode) => @@ -311,9 +349,10 @@ class MethodChannelCamera extends CameraPlatform { ); @override - Future setFocusPoint(int cameraId, Point point) { + Future setFocusPoint(int cameraId, Point? point) { assert(point == null || point.x >= 0 && point.x <= 1); assert(point == null || point.y >= 0 && point.y <= 1); + return _channel.invokeMethod( 'setFocusPoint', { @@ -326,16 +365,24 @@ class MethodChannelCamera extends CameraPlatform { } @override - Future getMaxZoomLevel(int cameraId) => _channel.invokeMethod( - 'getMaxZoomLevel', - {'cameraId': cameraId}, - ); + Future getMaxZoomLevel(int cameraId) async { + final maxZoomLevel = await _channel.invokeMethod( + 'getMaxZoomLevel', + {'cameraId': cameraId}, + ); + + return maxZoomLevel!; + } @override - Future getMinZoomLevel(int cameraId) => _channel.invokeMethod( - 'getMinZoomLevel', - {'cameraId': cameraId}, - ); + Future getMinZoomLevel(int cameraId) async { + final minZoomLevel = await _channel.invokeMethod( + 'getMinZoomLevel', + {'cameraId': cameraId}, + ); + + return minZoomLevel!; + } @override Future setZoomLevel(int cameraId, double zoom) async { diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index e1faecf374cd..916922ff29fa 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -51,8 +51,8 @@ abstract class CameraPlatform extends PlatformInterface { /// Creates an uninitialized camera instance and returns the cameraId. Future createCamera( CameraDescription cameraDescription, - ResolutionPreset resolutionPreset, { - bool enableAudio, + ResolutionPreset? resolutionPreset, { + bool enableAudio = true, }) { throw UnimplementedError('createCamera() is not implemented.'); } @@ -62,8 +62,10 @@ abstract class CameraPlatform extends PlatformInterface { /// [imageFormatGroup] is used to specify the image formatting used. /// On Android this defaults to ImageFormat.YUV_420_888 and applies only to the imageStream. /// On iOS this defaults to kCVPixelFormatType_32BGRA. - Future initializeCamera(int cameraId, - {ImageFormatGroup imageFormatGroup}) { + Future initializeCamera( + int cameraId, { + ImageFormatGroup imageFormatGroup = ImageFormatGroup.unknown, + }) { throw UnimplementedError('initializeCamera() is not implemented.'); } @@ -130,7 +132,7 @@ abstract class CameraPlatform extends PlatformInterface { /// meaning the recording will continue until manually stopped. /// With [maxVideoDuration] set the video is returned in a [VideoRecordedEvent] /// through the [onVideoRecordedEvent] stream when the set duration is reached. - Future startVideoRecording(int cameraId, {Duration maxVideoDuration}) { + Future startVideoRecording(int cameraId, {Duration? maxVideoDuration}) { throw UnimplementedError('startVideoRecording() is not implemented.'); } @@ -160,7 +162,10 @@ abstract class CameraPlatform extends PlatformInterface { } /// Sets the exposure point for automatically determining the exposure values. - Future setExposurePoint(int cameraId, Point point) { + /// + /// Supplying `null` for the [point] argument will result in resetting to the + /// original exposure point value. + Future setExposurePoint(int cameraId, Point? point) { throw UnimplementedError('setExposurePoint() is not implemented.'); } @@ -202,7 +207,10 @@ abstract class CameraPlatform extends PlatformInterface { } /// Sets the focus point for automatically determining the focus values. - Future setFocusPoint(int cameraId, Point point) { + /// + /// Supplying `null` for the [point] argument will result in resetting to the + /// original focus point value. + Future setFocusPoint(int cameraId, Point? point) { throw UnimplementedError('setFocusPoint() is not implemented.'); } diff --git a/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart b/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart index c19af1f50d1c..9707bd34d0d2 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart @@ -17,7 +17,11 @@ enum CameraLensDirection { /// Properties of a camera device. class CameraDescription { /// Creates a new camera description with the given properties. - CameraDescription({this.name, this.lensDirection, this.sensorOrientation}); + CameraDescription({ + required this.name, + required this.lensDirection, + required this.sensorOrientation, + }); /// The name of the camera device. final String name; diff --git a/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart b/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart index 3da659f7021d..59f3e4e6647e 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart @@ -13,7 +13,7 @@ class CameraException implements Exception { String code; /// Textual description of the error. - String description; + String? description; @override String toString() => 'CameraException($code, $description)'; diff --git a/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart index 7fbfbaf5f4a9..836f53826479 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart @@ -13,7 +13,6 @@ enum ExposureMode { /// Returns the exposure mode as a String. String serializeExposureMode(ExposureMode exposureMode) { - if (exposureMode == null) return null; switch (exposureMode) { case ExposureMode.locked: return 'locked'; @@ -26,7 +25,6 @@ String serializeExposureMode(ExposureMode exposureMode) { /// Returns the exposure mode for a given String. ExposureMode deserializeExposureMode(String str) { - if (str == null) return null; switch (str) { case "locked": return ExposureMode.locked; diff --git a/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart index ad5e9a2d46f1..8da2a90fa858 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart @@ -13,7 +13,6 @@ enum FocusMode { /// Returns the focus mode as a String. String serializeFocusMode(FocusMode focusMode) { - if (focusMode == null) return null; switch (focusMode) { case FocusMode.locked: return 'locked'; @@ -26,7 +25,6 @@ String serializeFocusMode(FocusMode focusMode) { /// Returns the focus mode for a given String. FocusMode deserializeFocusMode(String str) { - if (str == null) return null; switch (str) { case "locked": return FocusMode.locked; diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index c7ec7209c838..a063765af63b 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,23 +3,23 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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.6.0 +version: 2.0.0-nullsafety dependencies: flutter: sdk: flutter - meta: ^1.0.5 - plugin_platform_interface: ^1.0.1 - cross_file: ^0.1.0 - stream_transform: ^1.2.0 + meta: ^1.3.0-nullsafety.6 + plugin_platform_interface: ^1.1.0-nullsafety.2 + cross_file: ^0.3.0-nullsafety + stream_transform: ^2.0.0-nullsafety.0 dev_dependencies: flutter_test: sdk: flutter - async: ^2.4.2 - mockito: ^4.1.1 - pedantic: ^1.8.0 + async: ^2.5.0-nullsafety.3 + mockito: ^5.0.0-nullsafety.5 + pedantic: ^1.10.0-nullsafety.3 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.22.0" diff --git a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart index 8baf5da34159..a96df845844a 100644 --- a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart +++ b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart @@ -4,6 +4,7 @@ import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -117,7 +118,8 @@ void main() { // Act & Assert expect( - () => cameraPlatform.lockCaptureOrientation(1, null), + () => cameraPlatform.lockCaptureOrientation( + 1, DeviceOrientation.portraitUp), throwsUnimplementedError, ); }); @@ -155,7 +157,14 @@ void main() { // Act & Assert expect( - () => cameraPlatform.createCamera(null, null), + () => cameraPlatform.createCamera( + CameraDescription( + name: 'back', + lensDirection: CameraLensDirection.back, + sensorOrientation: 0, + ), + ResolutionPreset.high, + ), throwsUnimplementedError, ); }); @@ -168,7 +177,7 @@ void main() { // Act & Assert expect( - () => cameraPlatform.initializeCamera(null), + () => cameraPlatform.initializeCamera(1), throwsUnimplementedError, ); }); @@ -220,7 +229,7 @@ void main() { // Act & Assert expect( - () => cameraPlatform.setFlashMode(1, null), + () => cameraPlatform.setFlashMode(1, FlashMode.auto), throwsUnimplementedError, ); }); @@ -233,7 +242,7 @@ void main() { // Act & Assert expect( - () => cameraPlatform.setExposureMode(1, null), + () => cameraPlatform.setExposureMode(1, ExposureMode.auto), throwsUnimplementedError, ); }); @@ -298,7 +307,7 @@ void main() { // Act & Assert expect( - () => cameraPlatform.setExposureOffset(1, null), + () => cameraPlatform.setExposureOffset(1, 2.0), throwsUnimplementedError, ); }); @@ -311,7 +320,7 @@ void main() { // Act & Assert expect( - () => cameraPlatform.setFocusMode(1, null), + () => cameraPlatform.setFocusMode(1, FocusMode.auto), throwsUnimplementedError, ); }); diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index 7e9146344206..7633de8626a6 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -37,7 +37,10 @@ void main() { // Act final cameraId = await camera.createCamera( - CameraDescription(name: 'Test'), + CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.back, + sensorOrientation: 0), ResolutionPreset.high, ); @@ -48,7 +51,7 @@ void main() { arguments: { 'cameraName': 'Test', 'resolutionPreset': 'high', - 'enableAudio': null + 'enableAudio': true }, ), ]); @@ -70,7 +73,11 @@ void main() { // Act expect( () => camera.createCamera( - CameraDescription(name: 'Test'), + CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.back, + sensorOrientation: 0, + ), ResolutionPreset.high, ), throwsA( @@ -97,7 +104,11 @@ void main() { // Act expect( () => camera.createCamera( - CameraDescription(name: 'Test'), + CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.back, + sensorOrientation: 0, + ), ResolutionPreset.high, ), throwsA( @@ -122,7 +133,11 @@ void main() { }); final camera = MethodChannelCamera(); final cameraId = await camera.createCamera( - CameraDescription(name: 'Test'), + CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.back, + sensorOrientation: 0, + ), ResolutionPreset.high, ); @@ -165,7 +180,11 @@ void main() { final camera = MethodChannelCamera(); final cameraId = await camera.createCamera( - CameraDescription(name: 'Test'), + CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.back, + sensorOrientation: 0, + ), ResolutionPreset.high, ); Future initializeFuture = camera.initializeCamera(cameraId); @@ -197,8 +216,8 @@ void main() { }); group('Event Tests', () { - MethodChannelCamera camera; - int cameraId; + late MethodChannelCamera camera; + late int cameraId; setUp(() async { MethodChannelMock( channelName: 'plugins.flutter.io/camera', @@ -209,7 +228,11 @@ void main() { ); camera = MethodChannelCamera(); cameraId = await camera.createCamera( - CameraDescription(name: 'Test'), + CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.back, + sensorOrientation: 0, + ), ResolutionPreset.high, ); Future initializeFuture = camera.initializeCamera(cameraId); @@ -352,8 +375,9 @@ void main() { }); group('Function Tests', () { - MethodChannelCamera camera; - int cameraId; + late MethodChannelCamera camera; + late int cameraId; + setUp(() async { MethodChannelMock( channelName: 'plugins.flutter.io/camera', @@ -364,7 +388,11 @@ void main() { ); camera = MethodChannelCamera(); cameraId = await camera.createCamera( - CameraDescription(name: 'Test'), + CameraDescription( + name: 'Test', + lensDirection: CameraLensDirection.back, + sensorOrientation: 0, + ), ResolutionPreset.high, ); Future initializeFuture = camera.initializeCamera(cameraId); diff --git a/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart b/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart index cdf393f82b5f..fdbd9a18f29c 100644 --- a/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart +++ b/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart @@ -5,15 +5,15 @@ import 'package:flutter/services.dart'; class MethodChannelMock { - final Duration delay; + final Duration? delay; final MethodChannel methodChannel; final Map methods; final log = []; MethodChannelMock({ - String channelName, + required String channelName, this.delay, - this.methods, + required this.methods, }) : methodChannel = MethodChannel(channelName) { methodChannel.setMockMethodCallHandler(_handler); } diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 1e57db96a648..81ec693af41e 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -7,6 +7,7 @@ readonly NNBD_PLUGINS_LIST=( "android_intent" "battery" + "camera" "connectivity" "cross_file" "device_info" From 8d2594dc08514b5410022ef0c6b820a0eb4b9ca3 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 8 Feb 2021 15:23:43 -0800 Subject: [PATCH 169/924] [ios_platform_images] Migrate to null safety (#3381) --- packages/ios_platform_images/CHANGELOG.md | 4 ++ .../ios_platform_images/example/lib/main.dart | 3 +- .../lib/ios_platform_images.dart | 42 ++++++++++++------- packages/ios_platform_images/pubspec.yaml | 6 +-- .../test/ios_platform_images_test.dart | 4 ++ script/nnbd_plugins.sh | 1 + 6 files changed, 41 insertions(+), 19 deletions(-) diff --git a/packages/ios_platform_images/CHANGELOG.md b/packages/ios_platform_images/CHANGELOG.md index 4b11b40f5510..bae98440f668 100644 --- a/packages/ios_platform_images/CHANGELOG.md +++ b/packages/ios_platform_images/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.0-nullsafety + +* Migrate to null safety. + ## 0.1.2+4 * Update Flutter SDK constraint. diff --git a/packages/ios_platform_images/example/lib/main.dart b/packages/ios_platform_images/example/lib/main.dart index 655380f8d125..394d983ab66c 100644 --- a/packages/ios_platform_images/example/lib/main.dart +++ b/packages/ios_platform_images/example/lib/main.dart @@ -14,8 +14,7 @@ class _MyAppState extends State { void initState() { super.initState(); - IosPlatformImages.resolveURL("textfile", null) - .then((value) => print(value)); + IosPlatformImages.resolveURL("textfile").then((value) => print(value)); } @override diff --git a/packages/ios_platform_images/lib/ios_platform_images.dart b/packages/ios_platform_images/lib/ios_platform_images.dart index c7c12616ec36..d4599be94a64 100644 --- a/packages/ios_platform_images/lib/ios_platform_images.dart +++ b/packages/ios_platform_images/lib/ios_platform_images.dart @@ -1,3 +1,7 @@ +// Copyright 2020 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:async'; import 'dart:typed_data'; import 'dart:ui' as ui; @@ -9,13 +13,11 @@ import 'package:flutter/foundation.dart' show SynchronousFuture, describeIdentity; class _FutureImageStreamCompleter extends ImageStreamCompleter { - final Future futureScale; - final InformationCollector informationCollector; - - _FutureImageStreamCompleter( - {Future codec, this.futureScale, this.informationCollector}) - : assert(codec != null), - assert(futureScale != null) { + _FutureImageStreamCompleter({ + required Future codec, + required this.futureScale, + this.informationCollector, + }) { codec.then(_onCodecReady, onError: (dynamic error, StackTrace stack) { reportError( context: ErrorDescription('resolving a single-frame image stream'), @@ -27,6 +29,9 @@ class _FutureImageStreamCompleter extends ImageStreamCompleter { }); } + final Future futureScale; + final InformationCollector? informationCollector; + Future _onCodecReady(ui.Codec codec) async { try { ui.FrameInfo nextFrame = await codec.getNextFrame(); @@ -50,9 +55,7 @@ class _FutureMemoryImage extends ImageProvider<_FutureMemoryImage> { /// Constructor for FutureMemoryImage. [_futureBytes] is the bytes that will /// be loaded into an image and [_futureScale] is the scale that will be applied to /// that image to account for high-resolution images. - const _FutureMemoryImage(this._futureBytes, this._futureScale) - : assert(_futureBytes != null), - assert(_futureScale != null); + const _FutureMemoryImage(this._futureBytes, this._futureScale); final Future _futureBytes; final Future _futureScale; @@ -73,7 +76,9 @@ class _FutureMemoryImage extends ImageProvider<_FutureMemoryImage> { } Future _loadAsync( - _FutureMemoryImage key, DecoderCallback decode) async { + _FutureMemoryImage key, + DecoderCallback decode, + ) async { assert(key == this); return _futureBytes.then((Uint8List bytes) { return decode(bytes); @@ -113,10 +118,19 @@ class IosPlatformImages { /// /// See [https://developer.apple.com/documentation/uikit/uiimage/1624146-imagenamed?language=objc] static ImageProvider load(String name) { - Future loadInfo = _channel.invokeMethod('loadImage', name); + Future loadInfo = _channel.invokeMapMethod('loadImage', name); Completer bytesCompleter = Completer(); Completer scaleCompleter = Completer(); loadInfo.then((map) { + if (map == null) { + scaleCompleter.completeError( + Exception("Image couldn't be found: $name"), + ); + bytesCompleter.completeError( + Exception("Image couldn't be found: $name"), + ); + return; + } scaleCompleter.complete(map["scale"]); bytesCompleter.complete(map["data"]); }); @@ -129,7 +143,7 @@ class IosPlatformImages { /// Returns null if the resource can't be found. /// /// See [https://developer.apple.com/documentation/foundation/nsbundle/1411540-urlforresource?language=objc] - static Future resolveURL(String name, [String ext]) { - return _channel.invokeMethod('resolveURL', [name, ext]); + static Future resolveURL(String name, {String? extension}) { + return _channel.invokeMethod('resolveURL', [name, extension]); } } diff --git a/packages/ios_platform_images/pubspec.yaml b/packages/ios_platform_images/pubspec.yaml index 7049b62cf00a..6284f7c96871 100644 --- a/packages/ios_platform_images/pubspec.yaml +++ b/packages/ios_platform_images/pubspec.yaml @@ -1,10 +1,10 @@ name: ios_platform_images description: A plugin to share images between Flutter and iOS in add-to-app setups. -version: 0.1.2+4 +version: 0.2.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/ios_platform_images/ios_platform_images environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" dependencies: @@ -14,7 +14,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/packages/ios_platform_images/test/ios_platform_images_test.dart b/packages/ios_platform_images/test/ios_platform_images_test.dart index fd87180e9ac0..6ed7714e95c2 100644 --- a/packages/ios_platform_images/test/ios_platform_images_test.dart +++ b/packages/ios_platform_images/test/ios_platform_images_test.dart @@ -1,3 +1,7 @@ +// Copyright 2020 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 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ios_platform_images/ios_platform_images.dart'; diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 81ec693af41e..c6765730ddeb 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -15,6 +15,7 @@ readonly NNBD_PLUGINS_LIST=( "flutter_plugin_android_lifecycle" "flutter_webview" "google_sign_in" + "ios_platform_images" "local_auth" "path_provider" "package_info" From cf49441b00ba1268b627dff117f698b6a1e1384a Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Mon, 8 Feb 2021 15:54:11 -0800 Subject: [PATCH 170/924] [file_selector_web] Fix typo in pubspec. (#3528) (Introduced by mistake in https://github.com/flutter/plugins/pull/3509) --- packages/file_selector/file_selector_web/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml index 79181e821cec..a170d5f39607 100644 --- a/packages/file_selector/file_selector_web/pubspec.yaml +++ b/packages/file_selector/file_selector_web/pubspec.yaml @@ -22,8 +22,8 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - mockito: ^5.0.0-nullsafety.5 - pedantic: ^1.10.0-nullsafety.3 + mockito: ^4.1.1 + pedantic: ^1.8.0 integration_test: path: ../../integration_test From e68b15f218a90a389504b7a486c59bf9115abc31 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 8 Feb 2021 16:37:24 -0800 Subject: [PATCH 171/924] [sensors] Migrate to null safety (#3423) --- packages/sensors/CHANGELOG.md | 4 ++ .../integration_test/sensors_test.dart | 2 + packages/sensors/lib/sensors.dart | 52 ++++++++++++------- packages/sensors/pubspec.yaml | 10 ++-- packages/sensors/test/sensors_test.dart | 10 ++-- script/nnbd_plugins.sh | 1 + 6 files changed, 49 insertions(+), 30 deletions(-) diff --git a/packages/sensors/CHANGELOG.md b/packages/sensors/CHANGELOG.md index 8970f1e76e5d..682d377a6b84 100644 --- a/packages/sensors/CHANGELOG.md +++ b/packages/sensors/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.0-nullsafety + +* Migrate to null safety. + ## 0.4.2+8 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/sensors/integration_test/sensors_test.dart b/packages/sensors/integration_test/sensors_test.dart index ea1db0375f38..348bda00d86e 100644 --- a/packages/sensors/integration_test/sensors_test.dart +++ b/packages/sensors/integration_test/sensors_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:sensors/sensors.dart'; diff --git a/packages/sensors/lib/sensors.dart b/packages/sensors/lib/sensors.dart index 0b6f1b5a6067..8f69255bcec7 100644 --- a/packages/sensors/lib/sensors.dart +++ b/packages/sensors/lib/sensors.dart @@ -121,38 +121,50 @@ GyroscopeEvent _listToGyroscopeEvent(List list) { return GyroscopeEvent(list[0], list[1], list[2]); } -Stream _accelerometerEvents; -Stream _gyroscopeEvents; -Stream _userAccelerometerEvents; +Stream? _accelerometerEvents; +Stream? _gyroscopeEvents; +Stream? _userAccelerometerEvents; /// A broadcast stream of events from the device accelerometer. Stream get accelerometerEvents { - if (_accelerometerEvents == null) { - _accelerometerEvents = _accelerometerEventChannel - .receiveBroadcastStream() - .map( - (dynamic event) => _listToAccelerometerEvent(event.cast())); + Stream? accelerometerEvents = _accelerometerEvents; + if (accelerometerEvents == null) { + accelerometerEvents = + _accelerometerEventChannel.receiveBroadcastStream().map( + (dynamic event) => + _listToAccelerometerEvent(event.cast()), + ); + _accelerometerEvents = accelerometerEvents; } - return _accelerometerEvents; + + return accelerometerEvents; } /// A broadcast stream of events from the device gyroscope. Stream get gyroscopeEvents { - if (_gyroscopeEvents == null) { - _gyroscopeEvents = _gyroscopeEventChannel - .receiveBroadcastStream() - .map((dynamic event) => _listToGyroscopeEvent(event.cast())); + Stream? gyroscopeEvents = _gyroscopeEvents; + if (gyroscopeEvents == null) { + gyroscopeEvents = _gyroscopeEventChannel.receiveBroadcastStream().map( + (dynamic event) => _listToGyroscopeEvent(event.cast()), + ); + _gyroscopeEvents = gyroscopeEvents; } - return _gyroscopeEvents; + + return gyroscopeEvents; } /// Events from the device accelerometer with gravity removed. Stream get userAccelerometerEvents { - if (_userAccelerometerEvents == null) { - _userAccelerometerEvents = _userAccelerometerEventChannel - .receiveBroadcastStream() - .map((dynamic event) => - _listToUserAccelerometerEvent(event.cast())); + Stream? userAccelerometerEvents = + _userAccelerometerEvents; + if (userAccelerometerEvents == null) { + userAccelerometerEvents = + _userAccelerometerEventChannel.receiveBroadcastStream().map( + (dynamic event) => + _listToUserAccelerometerEvent(event.cast()), + ); + _userAccelerometerEvents = userAccelerometerEvents; } - return _userAccelerometerEvents; + + return userAccelerometerEvents; } diff --git a/packages/sensors/pubspec.yaml b/packages/sensors/pubspec.yaml index 35feb4b1ed56..e9b0392bae8d 100644 --- a/packages/sensors/pubspec.yaml +++ b/packages/sensors/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/sensors # 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.2+8 +version: 0.5.0-nullsafety flutter: plugin: @@ -21,14 +21,14 @@ dependencies: sdk: flutter dev_dependencies: - test: ^1.3.0 + test: ^1.16.0-nullsafety flutter_test: sdk: flutter integration_test: path: ../integration_test - mockito: ^4.1.1 - pedantic: ^1.8.0 + mockito: ^5.0.0-nullsafety.0 + pedantic: ^1.10.0-nullsafety environment: - sdk: ">=2.1.0<3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/sensors/test/sensors_test.dart b/packages/sensors/test/sensors_test.dart index 832a2f8524b7..93e0959befed 100644 --- a/packages/sensors/test/sensors_test.dart +++ b/packages/sensors/test/sensors_test.dart @@ -52,16 +52,16 @@ void main() { void _initializeFakeSensorChannel(String channelName, List sensorData) { const StandardMethodCodec standardMethod = StandardMethodCodec(); - void _emitEvent(ByteData event) { - ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage( + void _emitEvent(ByteData? event) { + ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage( channelName, event, - (ByteData reply) {}, + (ByteData? reply) {}, ); } - ServicesBinding.instance.defaultBinaryMessenger - .setMockMessageHandler(channelName, (ByteData message) async { + ServicesBinding.instance!.defaultBinaryMessenger + .setMockMessageHandler(channelName, (ByteData? message) async { final MethodCall methodCall = standardMethod.decodeMethodCall(message); if (methodCall.method == 'listen') { _emitEvent(standardMethod.encodeSuccessEnvelope(sensorData)); diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index c6765730ddeb..0e1d3c4bfac5 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -20,6 +20,7 @@ readonly NNBD_PLUGINS_LIST=( "path_provider" "package_info" "plugin_platform_interface" + "sensors" "share" "shared_preferences" "url_launcher" From bb21db859f26eb3871a555e7ae9720707be2d808 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 8 Feb 2021 19:03:20 -0800 Subject: [PATCH 172/924] [quick_actions] Migrate to null safety (#3421) --- packages/quick_actions/CHANGELOG.md | 4 ++++ packages/quick_actions/lib/quick_actions.dart | 15 ++++++++------- packages/quick_actions/pubspec.yaml | 12 ++++++------ .../quick_actions/test/quick_actions_test.dart | 2 +- script/nnbd_plugins.sh | 1 + 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/quick_actions/CHANGELOG.md b/packages/quick_actions/CHANGELOG.md index a0c1b1f43c66..774ccac1bb44 100644 --- a/packages/quick_actions/CHANGELOG.md +++ b/packages/quick_actions/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.0-nullsafety + +* Migrate to null safety. + ## 0.4.0+12 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/quick_actions/lib/quick_actions.dart b/packages/quick_actions/lib/quick_actions.dart index 933162a1a47c..875661244a74 100644 --- a/packages/quick_actions/lib/quick_actions.dart +++ b/packages/quick_actions/lib/quick_actions.dart @@ -22,8 +22,8 @@ class ShortcutItem { /// /// Only [icon] should be nullable. It will remain `null` if unset. const ShortcutItem({ - @required this.type, - @required this.localizedTitle, + required this.type, + required this.localizedTitle, this.icon, }); @@ -35,7 +35,7 @@ class ShortcutItem { /// Name of native resource (xcassets etc; NOT a Flutter asset) to be /// displayed as the icon for this item. - final String icon; + final String? icon; } /// Quick actions plugin. @@ -65,7 +65,8 @@ class QuickActions { assert(call.method == 'launch'); handler(call.arguments); }); - final String action = await channel.invokeMethod('getLaunchAction'); + final String? action = + await channel.invokeMethod('getLaunchAction'); if (action != null) { handler(action); } @@ -73,7 +74,7 @@ class QuickActions { /// Sets the [ShortcutItem]s to become the app's quick actions. Future setShortcutItems(List items) async { - final List> itemsList = + final List> itemsList = items.map(_serializeItem).toList(); await channel.invokeMethod('setShortcutItems', itemsList); } @@ -82,8 +83,8 @@ class QuickActions { Future clearShortcutItems() => channel.invokeMethod('clearShortcutItems'); - Map _serializeItem(ShortcutItem item) { - return { + Map _serializeItem(ShortcutItem item) { + return { 'type': item.type, 'localizedTitle': item.localizedTitle, 'icon': item.icon, diff --git a/packages/quick_actions/pubspec.yaml b/packages/quick_actions/pubspec.yaml index e76cd9ce8bd2..46bc53e63ce6 100644 --- a/packages/quick_actions/pubspec.yaml +++ b/packages/quick_actions/pubspec.yaml @@ -2,7 +2,7 @@ name: quick_actions description: Flutter plugin for creating shortcuts on home screen, also known as Quick Actions on iOS and App Shortcuts on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/quick_actions -version: 0.4.0+12 +version: 0.5.0-nullsafety flutter: plugin: @@ -16,17 +16,17 @@ flutter: dependencies: flutter: sdk: flutter - meta: ^1.0.5 + meta: ^1.3.0-nullsafety dev_dependencies: - test: ^1.3.0 - mockito: ^3.0.0 + test: ^1.16.0-nullsafety + mockito: ^5.0.0-nullsafety.0 flutter_test: sdk: flutter integration_test: path: ../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0-nullsafety environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/quick_actions/test/quick_actions_test.dart b/packages/quick_actions/test/quick_actions_test.dart index ffb6de1024fd..8066719e5113 100644 --- a/packages/quick_actions/test/quick_actions_test.dart +++ b/packages/quick_actions/test/quick_actions_test.dart @@ -10,7 +10,7 @@ import 'package:quick_actions/quick_actions.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - QuickActions quickActions; + late QuickActions quickActions; final List log = []; setUp(() { diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 0e1d3c4bfac5..447e8742cc8b 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -20,6 +20,7 @@ readonly NNBD_PLUGINS_LIST=( "path_provider" "package_info" "plugin_platform_interface" + "quick_actions" "sensors" "share" "shared_preferences" From 46207ea6d62639c0881b4adf20ec2caa9d252b3c Mon Sep 17 00:00:00 2001 From: shihchanghsiungsonos <44383755+shihchanghsiungsonos@users.noreply.github.com> Date: Tue, 9 Feb 2021 08:11:39 -0800 Subject: [PATCH 173/924] [video_player]: Fix texture unregistration callback signature Flutter's video plugin can cause crashes after a closing a flutter view on simulator model iPhone X or higher Co-authored-by: Mike Diarmid --- packages/video_player/video_player/CHANGELOG.md | 4 ++++ .../video_player/ios/Classes/FLTVideoPlayerPlugin.m | 2 +- packages/video_player/video_player/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 3e8047ced6bc..2e8f7396c618 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.9 + +* Fixed an issue where a crash can occur after a closing a video player view on iOS. + ## 2.0.0-nullsafety.8 * Migrated from deprecated `defaultBinaryMessenger`. diff --git a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m index e6a4f6ccb0b7..c2a1a40aa4fe 100644 --- a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m +++ b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m @@ -392,7 +392,7 @@ - (CVPixelBufferRef)copyPixelBuffer { } } -- (void)onTextureUnregistered { +- (void)onTextureUnregistered:(NSObject*)texture { dispatch_async(dispatch_get_main_queue(), ^{ [self dispose]; }); diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 72fb54b125ea..be005280609c 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for displaying inline video with other Flutter # 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 2.0.0-nullsafety.8 +version: 2.0.0-nullsafety.9 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: From 847749a19e77ca96b9029bc51d040d65ca65cfd0 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Tue, 9 Feb 2021 08:13:23 -0800 Subject: [PATCH 174/924] [wifi_info_flutter] Migrate the platform interface to null safety (#3424) --- .../wifi_info_flutter_platform_interface/CHANGELOG.md | 4 ++++ .../lib/src/method_channel_wifi_info_flutter.dart | 8 ++++---- .../lib/wifi_info_flutter_platform_interface.dart | 6 +++--- .../wifi_info_flutter_platform_interface/pubspec.yaml | 8 ++++---- .../test/method_channel_wifi_info_flutter_test.dart | 8 ++++---- script/nnbd_plugins.sh | 3 ++- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md index 951f8f5f5ae0..043a3d31b68d 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.0.1 * Update Flutter SDK constraint. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart index ef390c3cde1e..ba422ecd7565 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart @@ -17,17 +17,17 @@ class MethodChannelWifiInfoFlutter extends WifiInfoFlutterPlatform { MethodChannel('plugins.flutter.io/wifi_info_flutter'); @override - Future getWifiName() async { + Future getWifiName() async { return methodChannel.invokeMethod('wifiName'); } @override - Future getWifiBSSID() { + Future getWifiBSSID() { return methodChannel.invokeMethod('wifiBSSID'); } @override - Future getWifiIP() { + Future getWifiIP() { return methodChannel.invokeMethod('wifiIPAddress'); } @@ -50,7 +50,7 @@ class MethodChannelWifiInfoFlutter extends WifiInfoFlutterPlatform { } /// Convert a String to a LocationAuthorizationStatus value. -LocationAuthorizationStatus _parseLocationAuthorizationStatus(String result) { +LocationAuthorizationStatus _parseLocationAuthorizationStatus(String? result) { return LocationAuthorizationStatus.values.firstWhere( (LocationAuthorizationStatus status) => result == describeEnum(status), orElse: () => LocationAuthorizationStatus.unknown, diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart index 85034b2cbbff..5115af7e56eb 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart @@ -43,17 +43,17 @@ abstract class WifiInfoFlutterPlatform extends PlatformInterface { } /// Obtains the wifi name (SSID) of the connected network - Future getWifiName() { + Future getWifiName() { throw UnimplementedError('getWifiName() has not been implemented.'); } /// Obtains the wifi BSSID of the connected network. - Future getWifiBSSID() { + Future getWifiBSSID() { throw UnimplementedError('getWifiBSSID() has not been implemented.'); } /// Obtains the IP address of the connected wifi network - Future getWifiIP() { + Future getWifiIP() { throw UnimplementedError('getWifiIP() has not been implemented.'); } diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml index 62bffd0eeeb3..1d830f0af5f6 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml @@ -1,20 +1,20 @@ name: wifi_info_flutter_platform_interface description: A common platform interface for the wifi_info_flutter plugin. -version: 1.0.1 +version: 2.0.0-nullsafety # 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 homepage: https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter/wifi_info_flutter_platform_interface environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.17.0" dependencies: - plugin_platform_interface: ^1.0.3 + plugin_platform_interface: ^1.1.0-nullsafety flutter: sdk: flutter dev_dependencies: - pedantic: ^1.9.2 + pedantic: ^1.10.0-nullsafety flutter_test: sdk: flutter diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart index b48b2c4110bb..33733170c9fb 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart @@ -12,7 +12,7 @@ void main() { group('$MethodChannelWifiInfoFlutter', () { final List log = []; - MethodChannelWifiInfoFlutter methodChannelWifiInfoFlutter; + late MethodChannelWifiInfoFlutter methodChannelWifiInfoFlutter; setUp(() async { methodChannelWifiInfoFlutter = MethodChannelWifiInfoFlutter(); @@ -39,7 +39,7 @@ void main() { }); test('getWifiName', () async { - final String result = await methodChannelWifiInfoFlutter.getWifiName(); + final String? result = await methodChannelWifiInfoFlutter.getWifiName(); expect(result, '1337wifi'); expect( log, @@ -53,7 +53,7 @@ void main() { }); test('getWifiBSSID', () async { - final String result = await methodChannelWifiInfoFlutter.getWifiBSSID(); + final String? result = await methodChannelWifiInfoFlutter.getWifiBSSID(); expect(result, 'c0:ff:33:c0:d3:55'); expect( log, @@ -67,7 +67,7 @@ void main() { }); test('getWifiIP', () async { - final String result = await methodChannelWifiInfoFlutter.getWifiIP(); + final String? result = await methodChannelWifiInfoFlutter.getWifiIP(); expect(result, '127.0.0.1'); expect( log, diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 447e8742cc8b..492c8adf3ad5 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -15,6 +15,7 @@ readonly NNBD_PLUGINS_LIST=( "flutter_plugin_android_lifecycle" "flutter_webview" "google_sign_in" + "image_picker" "ios_platform_images" "local_auth" "path_provider" @@ -27,7 +28,7 @@ readonly NNBD_PLUGINS_LIST=( "url_launcher" "video_player" "webview_flutter" - "image_picker" + "wifi_info_flutter" ) # This list contains the list of plugins that have *not* been From f217be7d7091dd71ef777d6a3016a00216aa23f1 Mon Sep 17 00:00:00 2001 From: nohli <43643339+nohli@users.noreply.github.com> Date: Tue, 9 Feb 2021 19:32:02 +0100 Subject: [PATCH 175/924] [url_launcher] Fix PlatformException introduced in nnbd release (#3333) --- .../url_launcher/test/url_launcher_test.dart | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/url_launcher/url_launcher/test/url_launcher_test.dart b/packages/url_launcher/url_launcher/test/url_launcher_test.dart index 89a7801e1ca8..bb3fd2ad92b5 100644 --- a/packages/url_launcher/url_launcher/test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/test/url_launcher_test.dart @@ -191,6 +191,38 @@ void main() { throwsA(isA())); }); + test('send e-mail', () async { + await launch('mailto:gmail-noreply@google.com?subject=Hello'); + expect( + verify(await mock.launch( + any, + useSafariVC: anyNamed('useSafariVC'), + useWebView: anyNamed('useWebView'), + enableJavaScript: anyNamed('enableJavaScript'), + enableDomStorage: anyNamed('enableDomStorage'), + universalLinksOnly: anyNamed('universalLinksOnly'), + headers: anyNamed('headers'), + )), + isInstanceOf(), + ); + }); + + test('cannot send e-mail with forceSafariVC: true', () async { + expect( + () async => await launch( + 'mailto:gmail-noreply@google.com?subject=Hello', + forceSafariVC: true), + throwsA(isA())); + }); + + test('cannot send e-mail with forceWebView: true', () async { + expect( + () async => await launch( + 'mailto:gmail-noreply@google.com?subject=Hello', + forceWebView: true), + throwsA(isA())); + }); + test('controls system UI when changing statusBarBrightness', () async { final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized(); From 5e87faf3db815ec38efd4c9f268a78d43a881622 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Tue, 9 Feb 2021 10:44:32 -0800 Subject: [PATCH 176/924] Add section about how to use Material components in an app using WebView (#3521) --- packages/webview_flutter/CHANGELOG.md | 4 ++++ packages/webview_flutter/README.md | 9 ++++++--- packages/webview_flutter/pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 9c54b4cc207d..b3218e296d98 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.5 + +* Add section to the wiki explaining how to use Material components. + ## 2.0.0-nullsafety.4 * Update integration test to workaround an iOS 14 issue with `evaluateJavascript`. diff --git a/packages/webview_flutter/README.md b/packages/webview_flutter/README.md index df554eb5123c..94000772ca71 100644 --- a/packages/webview_flutter/README.md +++ b/packages/webview_flutter/README.md @@ -14,8 +14,6 @@ You can now include a WebView widget in your widget tree. See the [WebView](https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebView-class.html) widget's Dartdoc for more details on how to use the widget. - - ## Android Platform Views The WebView is relying on [Platform Views](https://flutter.dev/docs/development/platform-integration/platform-views) to embed @@ -66,5 +64,10 @@ android { // Required by the Flutter WebView plugin. minSdkVersion 19 } - } +} ``` + +#### Enable Material Components for Android + +To use Material Components when the user interacts with input elements in the WebView, +follow the steps described in the [Enabling Material Components instructions](https://flutter.dev/docs/deployment/android#enabling-material-components). diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 11769acce2ba..5d8e512b5aa5 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 2.0.0-nullsafety.4 +version: 2.0.0-nullsafety.5 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter environment: From 44b4b541f890caa0c5e846f09f4b8d64d3abfb0d Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Tue, 9 Feb 2021 10:50:40 -0800 Subject: [PATCH 177/924] Add plugin tools as a git submodule and depend on it directly (#3527) --- .cirrus.yml | 15 +++++++++++++++ .gitmodules | 3 +++ script/check_publish.sh | 3 +-- script/common.sh | 16 +++------------- script/plugin_tools | 1 + 5 files changed, 23 insertions(+), 15 deletions(-) create mode 100644 .gitmodules create mode 160000 script/plugin_tools diff --git a/.cirrus.yml b/.cirrus.yml index a4815ec2489e..a49a8b14ca83 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -14,6 +14,9 @@ task: - flutter channel master - flutter upgrade - git fetch origin master + submodules_script: + - git submodule init + - git submodule update matrix: - name: publishable script: @@ -121,6 +124,9 @@ task: - flutter channel master - flutter upgrade - git fetch origin master + submodules_script: + - git submodule init + - git submodule update matrix: - name: build-linux+drive-examples install_script: @@ -145,6 +151,9 @@ task: - flutter channel master - flutter upgrade - git fetch origin master + submodules_script: + - git submodule init + - git submodule update create_simulator_script: - xcrun simctl list - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-3 | xargs xcrun simctl boot @@ -198,6 +207,9 @@ task: - flutter channel master - flutter upgrade - git fetch origin master + submodules_script: + - git submodule init + - git submodule update create_simulator_script: - xcrun simctl list - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot @@ -227,6 +239,9 @@ task: - flutter channel master - flutter upgrade - git fetch origin master + submodules_script: + - git submodule init + - git submodule update matrix: - name: build_all_plugins_app script: diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000000..d83ab14b23a0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "script/plugin_tools"] + path = script/plugin_tools + url = https://github.com/flutter/plugin_tools.git diff --git a/script/check_publish.sh b/script/check_publish.sh index 9f435e9ba42c..5584fc601916 100755 --- a/script/check_publish.sh +++ b/script/check_publish.sh @@ -12,8 +12,7 @@ source "$SCRIPT_DIR/common.sh" function check_publish() { local failures=() - pub_command global activate flutter_plugin_tools - for dir in $(pub_command global run flutter_plugin_tools list --plugins="$1"); do + for dir in $(plugin_tools list --plugins="$1"); do local package_name=$(basename "$dir") echo "Checking that $package_name can be published." diff --git a/script/common.sh b/script/common.sh index cd2c1ca3fd83..4c8aff9822f6 100644 --- a/script/common.sh +++ b/script/common.sh @@ -46,18 +46,8 @@ function check_changed_packages() { return 0 } -# Normalizes the call to the pub command. -function pub_command() { - if [ "$(expr substr $(uname -s) 1 5)" == "MINGW" ]; then - pub.bat "$@" - else - pub "$@" - fi -} - -# Activates the Flutter plugin tool to ensures that the plugin tools dependencies -# are resolved using the current Dart SDK. -# Finally, runs the tool with the parameters. +# Runs the plugin tools from the plugin_tools git submodule. function plugin_tools() { - pub_command global activate flutter_plugin_tools && pub_command global run flutter_plugin_tools "$@" + (pushd "$REPO_DIR/script/plugin_tools" && dart pub get && popd) >/dev/null + dart run "$REPO_DIR/script/plugin_tools/lib/src/main.dart" "$@" } diff --git a/script/plugin_tools b/script/plugin_tools new file mode 160000 index 000000000000..432c56da3588 --- /dev/null +++ b/script/plugin_tools @@ -0,0 +1 @@ +Subproject commit 432c56da35880e95f6cbb02c40e9da0361771f48 From ea19ea8750691cffa0c376ff065f16ea47b5c00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan?= Date: Tue, 9 Feb 2021 20:22:10 +0100 Subject: [PATCH 178/924] [shared_preferences] Migrate main package to null-safety (#3526) Migrates shared_preferences to nnbd. Fixes flutter/flutter#74876. Note: also recreated the android and macos example applications because the macOS app was apparently a copy of the connectivity app and had connectivity_example as its name, the Android app was using the embedding v1. --- .../shared_preferences/CHANGELOG.md | 8 ++ .../shared_preferences/README.md | 8 -- .../shared_preferences/example/.gitignore | 46 +++++++++ .../shared_preferences/example/.metadata | 10 ++ .../example/android/.gitignore | 11 ++ .../example/android/app/build.gradle | 17 ++-- .../gradle/wrapper/gradle-wrapper.properties | 5 - .../android/app/src/debug/AndroidManifest.xml | 7 ++ .../android/app/src/main/AndroidManifest.xml | 47 ++++++--- .../EmbeddingV1Activity.java | 22 ---- .../EmbeddingV1ActivityTest.java | 15 --- .../FlutterActivityTest.java | 17 ---- .../flutter/plugins/example/MainActivity.kt | 6 ++ .../res/drawable-v21/launch_background.xml | 12 +++ .../main/res/drawable/launch_background.xml | 12 +++ .../app/src/main/res/values-night/styles.xml | 18 ++++ .../app/src/main/res/values/styles.xml | 18 ++++ .../app/src/profile/AndroidManifest.xml | 7 ++ .../example/android/build.gradle | 4 +- .../example/android/gradle.properties | 1 - .../gradle/wrapper/gradle-wrapper.properties | 3 +- .../example/android/settings.gradle | 18 ++-- .../shared_preferences/example/ios/.gitignore | 32 ++++++ .../example/ios/Flutter/Debug.xcconfig | 1 + .../example/ios/Flutter/Release.xcconfig | 1 + .../contents.xcworkspacedata | 7 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++ .../xcshareddata/WorkspaceSettings.xcsettings | 8 ++ .../contents.xcworkspacedata | 7 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++ .../xcshareddata/WorkspaceSettings.xcsettings | 8 ++ .../example/ios/Runner/AppDelegate.swift | 13 +++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../LaunchImage.imageset/Contents.json | 23 +++++ .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../ios/Runner/Runner-Bridging-Header.h | 1 + .../example/macos/.gitignore | 6 ++ .../macos/Flutter/Flutter-Debug.xcconfig | 2 +- .../macos/Flutter/Flutter-Release.xcconfig | 2 +- .../macos/Runner.xcodeproj/project.pbxproj | 96 ++---------------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++ .../xcshareddata/xcschemes/Runner.xcscheme | 22 +--- .../macos/Runner/Configs/AppInfo.xcconfig | 6 +- .../example/web/favicon.png | Bin 0 -> 917 bytes .../example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../example/web/manifest.json | 23 +++++ .../lib/shared_preferences.dart | 74 ++++++-------- .../shared_preferences/pubspec.yaml | 14 +-- .../test/shared_preferences_test.dart | 35 +++---- 53 files changed, 436 insertions(+), 286 deletions(-) create mode 100644 packages/shared_preferences/shared_preferences/example/.gitignore create mode 100644 packages/shared_preferences/shared_preferences/example/.metadata create mode 100644 packages/shared_preferences/shared_preferences/example/android/.gitignore delete mode 100644 packages/shared_preferences/shared_preferences/example/android/app/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/shared_preferences/shared_preferences/example/android/app/src/debug/AndroidManifest.xml delete mode 100644 packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/EmbeddingV1Activity.java delete mode 100644 packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/EmbeddingV1ActivityTest.java delete mode 100644 packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/FlutterActivityTest.java create mode 100644 packages/shared_preferences/shared_preferences/example/android/app/src/main/kotlin/io/flutter/plugins/example/MainActivity.kt create mode 100644 packages/shared_preferences/shared_preferences/example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 packages/shared_preferences/shared_preferences/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 packages/shared_preferences/shared_preferences/example/android/app/src/main/res/values-night/styles.xml create mode 100644 packages/shared_preferences/shared_preferences/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/shared_preferences/shared_preferences/example/android/app/src/profile/AndroidManifest.xml create mode 100644 packages/shared_preferences/shared_preferences/example/ios/.gitignore create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/shared_preferences/shared_preferences/example/macos/.gitignore create mode 100644 packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/shared_preferences/shared_preferences/example/web/favicon.png create mode 100644 packages/shared_preferences/shared_preferences/example/web/icons/Icon-192.png create mode 100644 packages/shared_preferences/shared_preferences/example/web/icons/Icon-512.png create mode 100644 packages/shared_preferences/shared_preferences/example/web/manifest.json diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 5e09b3f87fb0..1f003ef5b133 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.0.0-nullsafety + +* Migrate to null-safety. + +**Breaking changes**: + +* Setters no longer accept null to mean removing values. If you were previously using `set*(key, null)` for removing, use `remove(key)` instead. + ## 0.5.13+2 * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) diff --git a/packages/shared_preferences/shared_preferences/README.md b/packages/shared_preferences/shared_preferences/README.md index 516d7a91b848..e51ddea1c890 100644 --- a/packages/shared_preferences/shared_preferences/README.md +++ b/packages/shared_preferences/shared_preferences/README.md @@ -7,14 +7,6 @@ Wraps platform-specific persistent storage for simple data and there is no guarantee that writes will be persisted to disk after returning, so this plugin must not be used for storing critical data. - -**Please set your constraint to `shared_preferences: '>=0.5.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.5.y+z`. -Please use `shared_preferences: '>=0.5.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage To use this plugin, add `shared_preferences` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels). diff --git a/packages/shared_preferences/shared_preferences/example/.gitignore b/packages/shared_preferences/shared_preferences/example/.gitignore new file mode 100644 index 000000000000..0fa6b675c0a5 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/shared_preferences/shared_preferences/example/.metadata b/packages/shared_preferences/shared_preferences/example/.metadata new file mode 100644 index 000000000000..e0e9530fccc9 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 79b49b9e1057f90ebf797725233c6b311722de69 + channel: dev + +project_type: app diff --git a/packages/shared_preferences/shared_preferences/example/android/.gitignore b/packages/shared_preferences/shared_preferences/example/android/.gitignore new file mode 100644 index 000000000000..0a741cb43d66 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/packages/shared_preferences/shared_preferences/example/android/app/build.gradle b/packages/shared_preferences/shared_preferences/example/android/app/build.gradle index 58a6567a161c..3b7ee369beee 100644 --- a/packages/shared_preferences/shared_preferences/example/android/app/build.gradle +++ b/packages/shared_preferences/shared_preferences/example/android/app/build.gradle @@ -22,22 +22,23 @@ if (flutterVersionName == null) { } apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 29 + compileSdkVersion 30 - lintOptions { - disable 'InvalidPackage' + sourceSets { + main.java.srcDirs += 'src/main/kotlin' } defaultConfig { - applicationId "io.flutter.plugins.sharedpreferencesexample" + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "io.flutter.plugins.example" minSdkVersion 16 - targetSdkVersion 28 + targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -54,7 +55,5 @@ flutter { } dependencies { - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } diff --git a/packages/shared_preferences/shared_preferences/example/android/app/gradle/wrapper/gradle-wrapper.properties b/packages/shared_preferences/shared_preferences/example/android/app/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ee69dd68d1a6..000000000000 --- a/packages/shared_preferences/shared_preferences/example/android/app/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/debug/AndroidManifest.xml b/packages/shared_preferences/shared_preferences/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000000..2d5b32857609 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/main/AndroidManifest.xml b/packages/shared_preferences/shared_preferences/example/android/app/src/main/AndroidManifest.xml index 04a642a4c748..2a12ff8e0009 100644 --- a/packages/shared_preferences/shared_preferences/example/android/app/src/main/AndroidManifest.xml +++ b/packages/shared_preferences/shared_preferences/example/android/app/src/main/AndroidManifest.xml @@ -1,26 +1,41 @@ - - - - - - - + + + + + + - + + diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/EmbeddingV1Activity.java b/packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/EmbeddingV1Activity.java deleted file mode 100644 index 3857aea6ce6b..000000000000 --- a/packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/EmbeddingV1Activity.java +++ /dev/null @@ -1,22 +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. - -package io.flutter.plugins.sharedpreferencesexample; - -import android.os.Bundle; -import dev.flutter.plugins.integration_test.IntegrationTestPlugin; -import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin; - -@SuppressWarnings("deprecation") -public class EmbeddingV1Activity extends io.flutter.app.FlutterActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - IntegrationTestPlugin.registerWith( - registrarFor("dev.flutter.plugins.integration_test.IntegrationTestPlugin")); - SharedPreferencesPlugin.registerWith( - registrarFor("io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin")); - } -} diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/EmbeddingV1ActivityTest.java b/packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/EmbeddingV1ActivityTest.java deleted file mode 100644 index 5b090d0f52c2..000000000000 --- a/packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/EmbeddingV1ActivityTest.java +++ /dev/null @@ -1,15 +0,0 @@ - -package io.flutter.plugins.sharedpreferencesexample; - -import androidx.test.rule.ActivityTestRule; -import dev.flutter.plugins.integration_test.FlutterTestRunner; -import org.junit.Rule; -import org.junit.runner.RunWith; - -@RunWith(FlutterTestRunner.class) -@SuppressWarnings("deprecation") -public class EmbeddingV1ActivityTest { - @Rule - public ActivityTestRule rule = - new ActivityTestRule<>(EmbeddingV1Activity.class); -} diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/FlutterActivityTest.java b/packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/FlutterActivityTest.java deleted file mode 100644 index 7a63d6d90c91..000000000000 --- a/packages/shared_preferences/shared_preferences/example/android/app/src/main/java/io/flutter/plugins/sharedpreferencesexample/FlutterActivityTest.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2019 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. - -package io.flutter.plugins.sharedpreferencesexample; - -import androidx.test.rule.ActivityTestRule; -import dev.flutter.plugins.integration_test.FlutterTestRunner; -import io.flutter.embedding.android.FlutterActivity; -import org.junit.Rule; -import org.junit.runner.RunWith; - -@RunWith(FlutterTestRunner.class) -public class FlutterActivityTest { - @Rule - public ActivityTestRule rule = new ActivityTestRule<>(FlutterActivity.class); -} diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/main/kotlin/io/flutter/plugins/example/MainActivity.kt b/packages/shared_preferences/shared_preferences/example/android/app/src/main/kotlin/io/flutter/plugins/example/MainActivity.kt new file mode 100644 index 000000000000..9059dae9e4c4 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/android/app/src/main/kotlin/io/flutter/plugins/example/MainActivity.kt @@ -0,0 +1,6 @@ +package io.flutter.plugins.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000000..f74085f3f6a2 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/drawable/launch_background.xml b/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000000..304732f88420 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/values-night/styles.xml b/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000000..449a9f930826 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/values/styles.xml b/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000000..d74aa35c2826 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/shared_preferences/shared_preferences/example/android/app/src/profile/AndroidManifest.xml b/packages/shared_preferences/shared_preferences/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000000..2d5b32857609 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/shared_preferences/shared_preferences/example/android/build.gradle b/packages/shared_preferences/shared_preferences/example/android/build.gradle index 54cc96612793..c505a8635265 100644 --- a/packages/shared_preferences/shared_preferences/example/android/build.gradle +++ b/packages/shared_preferences/shared_preferences/example/android/build.gradle @@ -1,11 +1,13 @@ buildscript { + ext.kotlin_version = '1.3.50' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.0' + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/packages/shared_preferences/shared_preferences/example/android/gradle.properties b/packages/shared_preferences/shared_preferences/example/android/gradle.properties index a6738207fd15..94adc3a3f97a 100644 --- a/packages/shared_preferences/shared_preferences/example/android/gradle.properties +++ b/packages/shared_preferences/shared_preferences/example/android/gradle.properties @@ -1,4 +1,3 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true -android.enableR8=true diff --git a/packages/shared_preferences/shared_preferences/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/shared_preferences/shared_preferences/example/android/gradle/wrapper/gradle-wrapper.properties index d757f3d33fcc..bc6a58afdda2 100644 --- a/packages/shared_preferences/shared_preferences/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/shared_preferences/shared_preferences/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/packages/shared_preferences/shared_preferences/example/android/settings.gradle b/packages/shared_preferences/shared_preferences/example/android/settings.gradle index 115da6cb4f4d..44e62bcf06ae 100644 --- a/packages/shared_preferences/shared_preferences/example/android/settings.gradle +++ b/packages/shared_preferences/shared_preferences/example/android/settings.gradle @@ -1,15 +1,11 @@ include ':app' -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withInputStream { stream -> plugins.load(stream) } -} +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/shared_preferences/shared_preferences/example/ios/.gitignore b/packages/shared_preferences/shared_preferences/example/ios/.gitignore new file mode 100644 index 000000000000..e96ef602b8d1 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/shared_preferences/shared_preferences/example/ios/Flutter/Debug.xcconfig b/packages/shared_preferences/shared_preferences/example/ios/Flutter/Debug.xcconfig index 9803018ca79d..d0eccdcaf401 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Flutter/Debug.xcconfig +++ b/packages/shared_preferences/shared_preferences/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1,3 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" diff --git a/packages/shared_preferences/shared_preferences/example/ios/Flutter/Release.xcconfig b/packages/shared_preferences/shared_preferences/example/ios/Flutter/Release.xcconfig index a4a8c604e13d..c751c1d022fa 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Flutter/Release.xcconfig +++ b/packages/shared_preferences/shared_preferences/example/ios/Flutter/Release.xcconfig @@ -1,2 +1,3 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..919434a6254f --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000000..f9b0d7c5ea15 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..1d526a16ed0f --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000000..f9b0d7c5ea15 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift new file mode 100644 index 000000000000..70693e4a8c12 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 zcmeHN2~<R zh`|8`A_PQ1nSu(UMFx?8j8PC!!VDphaL#`F42fd#7Vlc`zIE4n%Y~eiz4y1j|NDpi z?<@|pSJ-HM`qifhf@m%MamgwK83`XpBA<+azdF#2QsT{X@z0A9Bq>~TVErigKH1~P zRX-!h-f0NJ4Mh++{D}J+K>~~rq}d%o%+4dogzXp7RxX4C>Km5XEI|PAFDmo;DFm6G zzjVoB`@qW98Yl0Kvc-9w09^PrsobmG*Eju^=3f?0o-t$U)TL1B3;sZ^!++3&bGZ!o-*6w?;oOhf z=A+Qb$scV5!RbG+&2S}BQ6YH!FKb0``VVX~T$dzzeSZ$&9=X$3)_7Z{SspSYJ!lGE z7yig_41zpQ)%5dr4ff0rh$@ky3-JLRk&DK)NEIHecf9c*?Z1bUB4%pZjQ7hD!A0r-@NF(^WKdr(LXj|=UE7?gBYGgGQV zidf2`ZT@pzXf7}!NH4q(0IMcxsUGDih(0{kRSez&z?CFA0RVXsVFw3^u=^KMtt95q z43q$b*6#uQDLoiCAF_{RFc{!H^moH_cmll#Fc^KXi{9GDl{>%+3qyfOE5;Zq|6#Hb zp^#1G+z^AXfRKaa9HK;%b3Ux~U@q?xg<2DXP%6k!3E)PA<#4$ui8eDy5|9hA5&{?v z(-;*1%(1~-NTQ`Is1_MGdQ{+i*ccd96ab$R$T3=% zw_KuNF@vI!A>>Y_2pl9L{9h1-C6H8<)J4gKI6{WzGBi<@u3P6hNsXG=bRq5c+z;Gc3VUCe;LIIFDmQAGy+=mRyF++u=drBWV8-^>0yE9N&*05XHZpPlE zxu@?8(ZNy7rm?|<+UNe0Vs6&o?l`Pt>P&WaL~M&#Eh%`rg@Mbb)J&@DA-wheQ>hRV z<(XhigZAT z>=M;URcdCaiO3d^?H<^EiEMDV+7HsTiOhoaMX%P65E<(5xMPJKxf!0u>U~uVqnPN7T!X!o@_gs3Ct1 zlZ_$5QXP4{Aj645wG_SNT&6m|O6~Tsl$q?nK*)(`{J4b=(yb^nOATtF1_aS978$x3 zx>Q@s4i3~IT*+l{@dx~Hst21fR*+5}S1@cf>&8*uLw-0^zK(+OpW?cS-YG1QBZ5q! zgTAgivzoF#`cSz&HL>Ti!!v#?36I1*l^mkrx7Y|K6L#n!-~5=d3;K<;Zqi|gpNUn_ z_^GaQDEQ*jfzh;`j&KXb66fWEk1K7vxQIMQ_#Wu_%3 z4Oeb7FJ`8I>Px;^S?)}2+4D_83gHEq>8qSQY0PVP?o)zAv3K~;R$fnwTmI-=ZLK`= zTm+0h*e+Yfr(IlH3i7gUclNH^!MU>id$Jw>O?2i0Cila#v|twub21@e{S2v}8Z13( zNDrTXZVgris|qYm<0NU(tAPouG!QF4ZNpZPkX~{tVf8xY690JqY1NVdiTtW+NqyRP zZ&;T0ikb8V{wxmFhlLTQ&?OP7 z;(z*<+?J2~z*6asSe7h`$8~Se(@t(#%?BGLVs$p``;CyvcT?7Y!{tIPva$LxCQ&4W z6v#F*);|RXvI%qnoOY&i4S*EL&h%hP3O zLsrFZhv&Hu5tF$Lx!8(hs&?!Kx5&L(fdu}UI5d*wn~A`nPUhG&Rv z2#ixiJdhSF-K2tpVL=)5UkXRuPAFrEW}7mW=uAmtVQ&pGE-&az6@#-(Te^n*lrH^m@X-ftVcwO_#7{WI)5v(?>uC9GG{lcGXYJ~Q8q zbMFl7;t+kV;|;KkBW2!P_o%Czhw&Q(nXlxK9ak&6r5t_KH8#1Mr-*0}2h8R9XNkr zto5-b7P_auqTJb(TJlmJ9xreA=6d=d)CVbYP-r4$hDn5|TIhB>SReMfh&OVLkMk-T zYf%$taLF0OqYF?V{+6Xkn>iX@TuqQ?&cN6UjC9YF&%q{Ut3zv{U2)~$>-3;Dp)*(? zg*$mu8^i=-e#acaj*T$pNowo{xiGEk$%DusaQiS!KjJH96XZ-hXv+jk%ard#fu=@Q z$AM)YWvE^{%tDfK%nD49=PI|wYu}lYVbB#a7wtN^Nml@CE@{Gv7+jo{_V?I*jkdLD zJE|jfdrmVbkfS>rN*+`#l%ZUi5_bMS<>=MBDNlpiSb_tAF|Zy`K7kcp@|d?yaTmB^ zo?(vg;B$vxS|SszusORgDg-*Uitzdi{dUV+glA~R8V(?`3GZIl^egW{a919!j#>f` znL1o_^-b`}xnU0+~KIFLQ)$Q6#ym%)(GYC`^XM*{g zv3AM5$+TtDRs%`2TyR^$(hqE7Y1b&`Jd6dS6B#hDVbJlUXcG3y*439D8MrK!2D~6gn>UD4Imctb z+IvAt0iaW73Iq$K?4}H`7wq6YkTMm`tcktXgK0lKPmh=>h+l}Y+pDtvHnG>uqBA)l zAH6BV4F}v$(o$8Gfo*PB>IuaY1*^*`OTx4|hM8jZ?B6HY;F6p4{`OcZZ(us-RVwDx zUzJrCQlp@mz1ZFiSZ*$yX3c_#h9J;yBE$2g%xjmGF4ca z&yL`nGVs!Zxsh^j6i%$a*I3ZD2SoNT`{D%mU=LKaEwbN(_J5%i-6Va?@*>=3(dQy` zOv%$_9lcy9+(t>qohkuU4r_P=R^6ME+wFu&LA9tw9RA?azGhjrVJKy&8=*qZT5Dr8g--d+S8zAyJ$1HlW3Olryt`yE zFIph~Z6oF&o64rw{>lgZISC6p^CBer9C5G6yq%?8tC+)7*d+ib^?fU!JRFxynRLEZ zj;?PwtS}Ao#9whV@KEmwQgM0TVP{hs>dg(1*DiMUOKHdQGIqa0`yZnHk9mtbPfoLx zo;^V6pKUJ!5#n`w2D&381#5#_t}AlTGEgDz$^;u;-vxDN?^#5!zN9ngytY@oTv!nc zp1Xn8uR$1Z;7vY`-<*?DfPHB;x|GUi_fI9@I9SVRv1)qETbNU_8{5U|(>Du84qP#7 z*l9Y$SgA&wGbj>R1YeT9vYjZuC@|{rajTL0f%N@>3$DFU=`lSPl=Iv;EjuGjBa$Gw zHD-;%YOE@<-!7-Mn`0WuO3oWuL6tB2cpPw~Nvuj|KM@))ixuDK`9;jGMe2d)7gHin zS<>k@!x;!TJEc#HdL#RF(`|4W+H88d4V%zlh(7#{q2d0OQX9*FW^`^_<3r$kabWAB z$9BONo5}*(%kx zOXi-yM_cmB3>inPpI~)duvZykJ@^^aWzQ=eQ&STUa}2uT@lV&WoRzkUoE`rR0)`=l zFT%f|LA9fCw>`enm$p7W^E@U7RNBtsh{_-7vVz3DtB*y#*~(L9+x9*wn8VjWw|Q~q zKFsj1Yl>;}%MG3=PY`$g$_mnyhuV&~O~u~)968$0b2!Jkd;2MtAP#ZDYw9hmK_+M$ zb3pxyYC&|CuAbtiG8HZjj?MZJBFbt`ryf+c1dXFuC z0*ZQhBzNBd*}s6K_G}(|Z_9NDV162#y%WSNe|FTDDhx)K!c(mMJh@h87@8(^YdK$&d*^WQe8Z53 z(|@MRJ$Lk-&ii74MPIs80WsOFZ(NX23oR-?As+*aq6b?~62@fSVmM-_*cb1RzZ)`5$agEiL`-E9s7{GM2?(KNPgK1(+c*|-FKoy}X(D_b#etO|YR z(BGZ)0Ntfv-7R4GHoXp?l5g#*={S1{u-QzxCGng*oWr~@X-5f~RA14b8~B+pLKvr4 zfgL|7I>jlak9>D4=(i(cqYf7#318!OSR=^`xxvI!bBlS??`xxWeg?+|>MxaIdH1U~#1tHu zB{QMR?EGRmQ_l4p6YXJ{o(hh-7Tdm>TAX380TZZZyVkqHNzjUn*_|cb?T? zt;d2s-?B#Mc>T-gvBmQZx(y_cfkXZO~{N zT6rP7SD6g~n9QJ)8F*8uHxTLCAZ{l1Y&?6v)BOJZ)=R-pY=Y=&1}jE7fQ>USS}xP#exo57uND0i*rEk@$;nLvRB@u~s^dwRf?G?_enN@$t* zbL%JO=rV(3Ju8#GqUpeE3l_Wu1lN9Y{D4uaUe`g>zlj$1ER$6S6@{m1!~V|bYkhZA z%CvrDRTkHuajMU8;&RZ&itnC~iYLW4DVkP<$}>#&(`UO>!n)Po;Mt(SY8Yb`AS9lt znbX^i?Oe9r_o=?})IHKHoQGKXsps_SE{hwrg?6dMI|^+$CeC&z@*LuF+P`7LfZ*yr+KN8B4{Nzv<`A(wyR@!|gw{zB6Ha ziwPAYh)oJ(nlqSknu(8g9N&1hu0$vFK$W#mp%>X~AU1ay+EKWcFdif{% z#4!4aoVVJ;ULmkQf!ke2}3hqxLK>eq|-d7Ly7-J9zMpT`?dxo6HdfJA|t)?qPEVBDv z{y_b?4^|YA4%WW0VZd8C(ZgQzRI5(I^)=Ub`Y#MHc@nv0w-DaJAqsbEHDWG8Ia6ju zo-iyr*sq((gEwCC&^TYBWt4_@|81?=B-?#P6NMff(*^re zYqvDuO`K@`mjm_Jd;mW_tP`3$cS?R$jR1ZN09$YO%_iBqh5ftzSpMQQtxKFU=FYmP zeY^jph+g<4>YO;U^O>-NFLn~-RqlHvnZl2yd2A{Yc1G@Ga$d+Q&(f^tnPf+Z7serIU};17+2DU_f4Z z@GaPFut27d?!YiD+QP@)T=77cR9~MK@bd~pY%X(h%L={{OIb8IQmf-!xmZkm8A0Ga zQSWONI17_ru5wpHg3jI@i9D+_Y|pCqVuHJNdHUauTD=R$JcD2K_liQisqG$(sm=k9;L* z!L?*4B~ql7uioSX$zWJ?;q-SWXRFhz2Jt4%fOHA=Bwf|RzhwqdXGr78y$J)LR7&3T zE1WWz*>GPWKZ0%|@%6=fyx)5rzUpI;bCj>3RKzNG_1w$fIFCZ&UR0(7S?g}`&Pg$M zf`SLsz8wK82Vyj7;RyKmY{a8G{2BHG%w!^T|Njr!h9TO2LaP^_f22Q1=l$QiU84ao zHe_#{S6;qrC6w~7{y(hs-?-j?lbOfgH^E=XcSgnwW*eEz{_Z<_Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 000000000000..89c2725b70f1 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h b/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 000000000000..308a2a560b42 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/shared_preferences/shared_preferences/example/macos/.gitignore b/packages/shared_preferences/shared_preferences/example/macos/.gitignore new file mode 100644 index 000000000000..d2fd3772308c --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/macos/.gitignore @@ -0,0 +1,6 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/xcuserdata/ diff --git a/packages/shared_preferences/shared_preferences/example/macos/Flutter/Flutter-Debug.xcconfig b/packages/shared_preferences/shared_preferences/example/macos/Flutter/Flutter-Debug.xcconfig index 785633d3a86b..4b81f9b2d200 100644 --- a/packages/shared_preferences/shared_preferences/example/macos/Flutter/Flutter-Debug.xcconfig +++ b/packages/shared_preferences/shared_preferences/example/macos/Flutter/Flutter-Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/packages/shared_preferences/shared_preferences/example/macos/Flutter/Flutter-Release.xcconfig b/packages/shared_preferences/shared_preferences/example/macos/Flutter/Flutter-Release.xcconfig index 5fba960c3af2..5caa9d1579e4 100644 --- a/packages/shared_preferences/shared_preferences/example/macos/Flutter/Flutter-Release.xcconfig +++ b/packages/shared_preferences/shared_preferences/example/macos/Flutter/Flutter-Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/project.pbxproj b/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/project.pbxproj index 0e2413493f6e..cc89c8782812 100644 --- a/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/project.pbxproj @@ -26,11 +26,6 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; }; - 33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - D73912F022F37F9E000D13A0 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; }; - D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - EA473EC5F2038B17A2FE4D78 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 748ADDF1719804343BB18004 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -50,8 +45,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */, - 33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */, ); name = "Bundle Framework"; runOnlyForDeploymentPostprocessing = 0; @@ -61,7 +54,7 @@ /* Begin PBXFileReference section */ 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* connectivity_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = connectivity_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -70,17 +63,11 @@ 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FlutterMacOS.framework; path = Flutter/ephemeral/FlutterMacOS.framework; sourceTree = SOURCE_ROOT; }; 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 748ADDF1719804343BB18004 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 80418F0A2F74D683C63A4D0A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - AA19B00394637215A825CF5E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - D73912EF22F37F9E000D13A0 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/ephemeral/App.framework; sourceTree = SOURCE_ROOT; }; - E960ED3977AF6DF197F74FFA /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -88,9 +75,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D73912F022F37F9E000D13A0 /* App.framework in Frameworks */, - 33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */, - EA473EC5F2038B17A2FE4D78 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -115,14 +99,13 @@ 33CEB47122A05771004F2AC0 /* Flutter */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, - D42EAEE5849744148CC78D83 /* Pods */, ); sourceTree = ""; }; 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( - 33CC10ED2044A3C60003C045 /* connectivity_example.app */, + 33CC10ED2044A3C60003C045 /* example.app */, ); name = Products; sourceTree = ""; @@ -145,8 +128,6 @@ 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - D73912EF22F37F9E000D13A0 /* App.framework */, - 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */, ); path = Flutter; sourceTree = ""; @@ -164,21 +145,9 @@ path = Runner; sourceTree = ""; }; - D42EAEE5849744148CC78D83 /* Pods */ = { - isa = PBXGroup; - children = ( - 80418F0A2F74D683C63A4D0A /* Pods-Runner.debug.xcconfig */, - E960ED3977AF6DF197F74FFA /* Pods-Runner.release.xcconfig */, - AA19B00394637215A825CF5E /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( - 748ADDF1719804343BB18004 /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -190,13 +159,11 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - B24477CAB9D5BDFC8F3553DA /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - 84A8D21305B2F01D093A8F9C /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -205,7 +172,7 @@ ); name = Runner; productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* connectivity_example.app */; + productReference = 33CC10ED2044A3C60003C045 /* example.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -216,7 +183,7 @@ attributes = { LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 0930; - ORGANIZATIONNAME = "Google LLC"; + ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { CreatedOnToolsVersion = 9.2; @@ -235,7 +202,7 @@ }; }; buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 8.0"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -281,7 +248,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename\n"; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; }; 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -301,44 +268,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh\ntouch Flutter/ephemeral/tripwire\n"; - }; - 84A8D21305B2F01D093A8F9C /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - B24477CAB9D5BDFC8F3553DA /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; /* End PBXShellScriptBuildPhase section */ @@ -431,10 +361,6 @@ CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter/ephemeral", - ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -561,10 +487,6 @@ CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter/ephemeral", - ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -585,10 +507,6 @@ CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter/ephemeral", - ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 2a7d3e7f34ac..ae8ff59d97b3 100644 --- a/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/shared_preferences/shared_preferences/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -15,7 +15,7 @@ @@ -27,23 +27,11 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - - - @@ -66,7 +54,7 @@ @@ -75,7 +63,7 @@ diff --git a/packages/shared_preferences/shared_preferences/example/macos/Runner/Configs/AppInfo.xcconfig b/packages/shared_preferences/shared_preferences/example/macos/Runner/Configs/AppInfo.xcconfig index a95148814518..cccda2e8a262 100644 --- a/packages/shared_preferences/shared_preferences/example/macos/Runner/Configs/AppInfo.xcconfig +++ b/packages/shared_preferences/shared_preferences/example/macos/Runner/Configs/AppInfo.xcconfig @@ -5,10 +5,10 @@ // 'flutter create' template. // The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = connectivity_example +PRODUCT_NAME = example // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.connectivityExample +PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.example // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2019 io.flutter.plugins. All rights reserved. +PRODUCT_COPYRIGHT = Copyright © 2021 io.flutter.plugins. All rights reserved. diff --git a/packages/shared_preferences/shared_preferences/example/web/favicon.png b/packages/shared_preferences/shared_preferences/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/packages/shared_preferences/shared_preferences/example/web/icons/Icon-192.png b/packages/shared_preferences/shared_preferences/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/packages/shared_preferences/shared_preferences/example/web/icons/Icon-512.png b/packages/shared_preferences/shared_preferences/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/packages/shared_preferences/shared_preferences/example/web/manifest.json b/packages/shared_preferences/shared_preferences/example/web/manifest.json new file mode 100644 index 000000000000..8c012917dab7 --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart b/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart index c4c8710769df..03619fd14b4f 100644 --- a/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart +++ b/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart @@ -7,10 +7,9 @@ import 'dart:io' show Platform; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:meta/meta.dart'; - import 'package:shared_preferences_linux/shared_preferences_linux.dart'; -import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/method_channel_shared_preferences.dart'; +import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_windows/shared_preferences_windows.dart'; /// Wraps NSUserDefaults (on iOS) and SharedPreferences (on Android), providing @@ -21,7 +20,7 @@ class SharedPreferences { SharedPreferences._(this._preferenceCache); static const String _prefix = 'flutter.'; - static Completer _completer; + static Completer? _completer; static bool _manualDartRegistrationNeeded = true; static SharedPreferencesStorePlatform get _store { @@ -52,21 +51,22 @@ class SharedPreferences { /// performance-sensitive blocks. static Future getInstance() async { if (_completer == null) { - _completer = Completer(); + final completer = Completer(); try { final Map preferencesMap = await _getSharedPreferencesMap(); - _completer.complete(SharedPreferences._(preferencesMap)); + completer.complete(SharedPreferences._(preferencesMap)); } on Exception catch (e) { // If there's an error, explicitly return the future with an error. // then set the completer to null so we can retry. - _completer.completeError(e); - final Future sharedPrefsFuture = _completer.future; + completer.completeError(e); + final Future sharedPrefsFuture = completer.future; _completer = null; return sharedPrefsFuture; } + _completer = completer; } - return _completer.future; + return _completer!.future; } /// The cache that holds all preferences. @@ -83,86 +83,76 @@ class SharedPreferences { Set getKeys() => Set.from(_preferenceCache.keys); /// Reads a value of any type from persistent storage. - dynamic get(String key) => _preferenceCache[key]; + Object? get(String key) => _preferenceCache[key]; /// Reads a value from persistent storage, throwing an exception if it's not a /// bool. - bool getBool(String key) => _preferenceCache[key]; + bool? getBool(String key) => _preferenceCache[key] as bool?; /// Reads a value from persistent storage, throwing an exception if it's not /// an int. - int getInt(String key) => _preferenceCache[key]; + int? getInt(String key) => _preferenceCache[key] as int?; /// Reads a value from persistent storage, throwing an exception if it's not a /// double. - double getDouble(String key) => _preferenceCache[key]; + double? getDouble(String key) => _preferenceCache[key] as double?; /// Reads a value from persistent storage, throwing an exception if it's not a /// String. - String getString(String key) => _preferenceCache[key]; + String? getString(String key) => _preferenceCache[key] as String?; /// Returns true if persistent storage the contains the given [key]. bool containsKey(String key) => _preferenceCache.containsKey(key); /// Reads a set of string values from persistent storage, throwing an /// exception if it's not a string set. - List getStringList(String key) { - List list = _preferenceCache[key]; + List? getStringList(String key) { + List? list = _preferenceCache[key] as List?; if (list != null && list is! List) { list = list.cast().toList(); _preferenceCache[key] = list; } // Make a copy of the list so that later mutations won't propagate - return list?.toList(); + return list?.toList() as List?; } /// Saves a boolean [value] to persistent storage in the background. - /// - /// If [value] is null, this is equivalent to calling [remove()] on the [key]. Future setBool(String key, bool value) => _setValue('Bool', key, value); /// Saves an integer [value] to persistent storage in the background. - /// - /// If [value] is null, this is equivalent to calling [remove()] on the [key]. Future setInt(String key, int value) => _setValue('Int', key, value); /// Saves a double [value] to persistent storage in the background. /// /// Android doesn't support storing doubles, so it will be stored as a float. - /// - /// If [value] is null, this is equivalent to calling [remove()] on the [key]. Future setDouble(String key, double value) => _setValue('Double', key, value); /// Saves a string [value] to persistent storage in the background. - /// - /// If [value] is null, this is equivalent to calling [remove()] on the [key]. Future setString(String key, String value) => _setValue('String', key, value); /// Saves a list of strings [value] to persistent storage in the background. - /// - /// If [value] is null, this is equivalent to calling [remove()] on the [key]. Future setStringList(String key, List value) => _setValue('StringList', key, value); /// Removes an entry from persistent storage. - Future remove(String key) => _setValue(null, key, null); + Future remove(String key) { + final String prefixedKey = '$_prefix$key'; + _preferenceCache.remove(key); + return _store.remove(prefixedKey); + } Future _setValue(String valueType, String key, Object value) { + ArgumentError.checkNotNull(value, 'value'); final String prefixedKey = '$_prefix$key'; - if (value == null) { - _preferenceCache.remove(key); - return _store.remove(prefixedKey); + if (value is List) { + // Make a copy of the list so that later mutations won't propagate + _preferenceCache[key] = value.toList(); } else { - if (value is List) { - // Make a copy of the list so that later mutations won't propagate - _preferenceCache[key] = value.toList(); - } else { - _preferenceCache[key] = value; - } - return _store.setValue(valueType, prefixedKey, value); + _preferenceCache[key] = value; } + return _store.setValue(valueType, prefixedKey, value); } /// Always returns true. @@ -194,7 +184,7 @@ class SharedPreferences { final Map preferencesMap = {}; for (String key in fromSystem.keys) { assert(key.startsWith(_prefix)); - preferencesMap[key.substring(_prefix.length)] = fromSystem[key]; + preferencesMap[key.substring(_prefix.length)] = fromSystem[key]!; } return preferencesMap; } @@ -203,14 +193,14 @@ class SharedPreferences { /// /// If the singleton instance has been initialized already, it is nullified. @visibleForTesting - static void setMockInitialValues(Map values) { - final Map newValues = - values.map((String key, dynamic value) { + static void setMockInitialValues(Map values) { + final Map newValues = + values.map((String key, Object value) { String newKey = key; if (!key.startsWith(_prefix)) { newKey = '$_prefix$key'; } - return MapEntry(newKey, value); + return MapEntry(newKey, value); }); SharedPreferencesStorePlatform.instance = InMemorySharedPreferencesStore.withData(newValues); diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 69689c738b8e..434c9c6bd4c2 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/shared_prefere # 0.5.y+z is compatible with 1.0.0, if you land a breaking change bump # the version to 2.0.0. # See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.5.13+2 +version: 2.0.0-nullsafety flutter: plugin: @@ -26,16 +26,16 @@ dependencies: meta: ^1.0.4 flutter: sdk: flutter - shared_preferences_platform_interface: ^1.0.0 + shared_preferences_platform_interface: ^2.0.0-nullsafety # The design on https://flutter.dev/go/federated-plugins was to leave # this constraint as "any". We cannot do it right now as it fails pub publish # validation, so we set a ^ constraint. # TODO(franciscojma): Revisit this (either update this part in the design or the pub tool). # https://github.com/flutter/flutter/issues/46264 - shared_preferences_linux: ^0.0.2 - shared_preferences_macos: ^0.0.1 - shared_preferences_web: ^0.1.2 - shared_preferences_windows: ^0.0.1 + shared_preferences_linux: ^0.0.4-nullsafety + shared_preferences_macos: ^0.0.2-nullsafety + shared_preferences_web: ^0.2.0-nullsafety + shared_preferences_windows: ^0.0.3-nullsafety dev_dependencies: flutter_test: @@ -47,5 +47,5 @@ dev_dependencies: pedantic: ^1.8.0 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart index 80faba404154..9f6e7203fa85 100755 --- a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -13,7 +11,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('SharedPreferences', () { - const Map kTestValues = { + const Map kTestValues = { 'flutter.String': 'hello world', 'flutter.bool': true, 'flutter.int': 42, @@ -29,8 +27,8 @@ void main() { 'flutter.List': ['baz', 'quox'], }; - FakeSharedPreferencesStore store; - SharedPreferences preferences; + late FakeSharedPreferencesStore store; + late SharedPreferences preferences; setUp(() async { store = FakeSharedPreferencesStore(kTestValues); @@ -107,16 +105,11 @@ void main() { test('removing', () async { const String key = 'testKey'; - await preferences.setString(key, null); - await preferences.setBool(key, null); - await preferences.setInt(key, null); - await preferences.setDouble(key, null); - await preferences.setStringList(key, null); await preferences.remove(key); expect( store.log, List.filled( - 6, + 1, isMethodCall( 'remove', arguments: 'flutter.$key', @@ -145,10 +138,12 @@ void main() { }); test('reloading', () async { - await preferences.setString('String', kTestValues['flutter.String']); + await preferences.setString( + 'String', kTestValues['flutter.String'] as String); expect(preferences.getString('String'), kTestValues['flutter.String']); - SharedPreferences.setMockInitialValues(kTestValues2); + SharedPreferences.setMockInitialValues( + kTestValues2.cast()); expect(preferences.getString('String'), kTestValues['flutter.String']); await preferences.reload(); @@ -167,17 +162,17 @@ void main() { test('test 1', () async { SharedPreferences.setMockInitialValues( - {_prefixedKey: 'my string'}); + {_prefixedKey: 'my string'}); final SharedPreferences prefs = await SharedPreferences.getInstance(); - final String value = prefs.getString(_key); + final String? value = prefs.getString(_key); expect(value, 'my string'); }); test('test 2', () async { SharedPreferences.setMockInitialValues( - {_prefixedKey: 'my other string'}); + {_prefixedKey: 'my other string'}); final SharedPreferences prefs = await SharedPreferences.getInstance(); - final String value = prefs.getString(_key); + final String? value = prefs.getString(_key); expect(value, 'my other string'); }); }); @@ -187,7 +182,7 @@ void main() { await preferences.setStringList("myList", myList); myList.add("foobar"); - final List cachedList = preferences.getStringList('myList'); + final List cachedList = preferences.getStringList('myList')!; expect(cachedList, []); cachedList.add("foobar2"); @@ -197,11 +192,11 @@ void main() { }); test('calling mock initial values with non-prefixed keys succeeds', () async { - SharedPreferences.setMockInitialValues({ + SharedPreferences.setMockInitialValues({ 'test': 'foo', }); final SharedPreferences prefs = await SharedPreferences.getInstance(); - final String value = prefs.getString('test'); + final String? value = prefs.getString('test'); expect(value, 'foo'); }); } From e50f17991d90366cc82c42d38259a35a98785d81 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 9 Feb 2021 12:16:46 -0800 Subject: [PATCH 179/924] Update video_player_platform_interface to latest pigeon (#3507) See https://github.com/flutter/plugins/pull/3281 for context. --- .../CHANGELOG.md | 5 + .../lib/messages.dart | 585 +++++++----------- .../lib/test.dart | 196 ++++++ .../pubspec.yaml | 6 +- .../method_channel_video_player_test.dart | 1 + 5 files changed, 418 insertions(+), 375 deletions(-) create mode 100644 packages/video_player/video_player_platform_interface/lib/test.dart diff --git a/packages/video_player/video_player_platform_interface/CHANGELOG.md b/packages/video_player/video_player_platform_interface/CHANGELOG.md index 446fffd9a60e..34df33664c68 100644 --- a/packages/video_player/video_player_platform_interface/CHANGELOG.md +++ b/packages/video_player/video_player_platform_interface/CHANGELOG.md @@ -1,3 +1,8 @@ +## 4.0.0-nullsafety.0 + +* Update to latest Pigeon. + This includes a breaking change to how the test logic is exposed. + ## 3.0.0-nullsafety.3 * `messages.dart` sets Dart `2.12`. diff --git a/packages/video_player/video_player_platform_interface/lib/messages.dart b/packages/video_player/video_player_platform_interface/lib/messages.dart index 252cad6993ca..3f2d78ef9ed5 100644 --- a/packages/video_player/video_player_platform_interface/lib/messages.dart +++ b/packages/video_player/video_player_platform_interface/lib/messages.dart @@ -1,25 +1,24 @@ -// Autogenerated from Pigeon (v0.1.12), do not edit directly. +// Autogenerated from Pigeon (v0.1.19), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import // @dart = 2.12 import 'dart:async'; -import 'package:flutter/services.dart'; import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; +import 'package:flutter/services.dart'; + class TextureMessage { int? textureId; - // ignore: unused_element - Map _toMap() { - final Map pigeonMap = {}; + + Object encode() { + final Map pigeonMap = {}; pigeonMap['textureId'] = textureId; return pigeonMap; } - // ignore: unused_element - static TextureMessage _fromMap(Map pigeonMap) { - final TextureMessage result = TextureMessage(); - result.textureId = pigeonMap['textureId']; - return result; + static TextureMessage decode(Object message) { + final Map pigeonMap = message as Map; + return TextureMessage()..textureId = pigeonMap['textureId'] as int; } } @@ -28,9 +27,9 @@ class CreateMessage { String? uri; String? packageName; String? formatHint; - // ignore: unused_element - Map _toMap() { - final Map pigeonMap = {}; + + Object encode() { + final Map pigeonMap = {}; pigeonMap['asset'] = asset; pigeonMap['uri'] = uri; pigeonMap['packageName'] = packageName; @@ -38,540 +37,382 @@ class CreateMessage { return pigeonMap; } - // ignore: unused_element - static CreateMessage _fromMap(Map pigeonMap) { - final CreateMessage result = CreateMessage(); - result.asset = pigeonMap['asset']; - result.uri = pigeonMap['uri']; - result.packageName = pigeonMap['packageName']; - result.formatHint = pigeonMap['formatHint']; - return result; + static CreateMessage decode(Object message) { + final Map pigeonMap = message as Map; + return CreateMessage() + ..asset = pigeonMap['asset'] as String + ..uri = pigeonMap['uri'] as String + ..packageName = pigeonMap['packageName'] as String + ..formatHint = pigeonMap['formatHint'] as String; } } class LoopingMessage { int? textureId; bool? isLooping; - // ignore: unused_element - Map _toMap() { - final Map pigeonMap = {}; + + Object encode() { + final Map pigeonMap = {}; pigeonMap['textureId'] = textureId; pigeonMap['isLooping'] = isLooping; return pigeonMap; } - // ignore: unused_element - static LoopingMessage _fromMap(Map pigeonMap) { - final LoopingMessage result = LoopingMessage(); - result.textureId = pigeonMap['textureId']; - result.isLooping = pigeonMap['isLooping']; - return result; + static LoopingMessage decode(Object message) { + final Map pigeonMap = message as Map; + return LoopingMessage() + ..textureId = pigeonMap['textureId'] as int + ..isLooping = pigeonMap['isLooping'] as bool; } } class VolumeMessage { int? textureId; double? volume; - // ignore: unused_element - Map _toMap() { - final Map pigeonMap = {}; + + Object encode() { + final Map pigeonMap = {}; pigeonMap['textureId'] = textureId; pigeonMap['volume'] = volume; return pigeonMap; } - // ignore: unused_element - static VolumeMessage _fromMap(Map pigeonMap) { - final VolumeMessage result = VolumeMessage(); - result.textureId = pigeonMap['textureId']; - result.volume = pigeonMap['volume']; - return result; + static VolumeMessage decode(Object message) { + final Map pigeonMap = message as Map; + return VolumeMessage() + ..textureId = pigeonMap['textureId'] as int + ..volume = pigeonMap['volume'] as double; } } class PlaybackSpeedMessage { int? textureId; double? speed; - // ignore: unused_element - Map _toMap() { - final Map pigeonMap = {}; + + Object encode() { + final Map pigeonMap = {}; pigeonMap['textureId'] = textureId; pigeonMap['speed'] = speed; return pigeonMap; } - // ignore: unused_element - static PlaybackSpeedMessage _fromMap(Map pigeonMap) { - final PlaybackSpeedMessage result = PlaybackSpeedMessage(); - result.textureId = pigeonMap['textureId']; - result.speed = pigeonMap['speed']; - return result; + static PlaybackSpeedMessage decode(Object message) { + final Map pigeonMap = message as Map; + return PlaybackSpeedMessage() + ..textureId = pigeonMap['textureId'] as int + ..speed = pigeonMap['speed'] as double; } } class PositionMessage { int? textureId; int? position; - // ignore: unused_element - Map _toMap() { - final Map pigeonMap = {}; + + Object encode() { + final Map pigeonMap = {}; pigeonMap['textureId'] = textureId; pigeonMap['position'] = position; return pigeonMap; } - // ignore: unused_element - static PositionMessage _fromMap(Map pigeonMap) { - final PositionMessage result = PositionMessage(); - result.textureId = pigeonMap['textureId']; - result.position = pigeonMap['position']; - return result; + static PositionMessage decode(Object message) { + final Map pigeonMap = message as Map; + return PositionMessage() + ..textureId = pigeonMap['textureId'] as int + ..position = pigeonMap['position'] as int; } } class MixWithOthersMessage { bool? mixWithOthers; - // ignore: unused_element - Map _toMap() { - final Map pigeonMap = {}; + + Object encode() { + final Map pigeonMap = {}; pigeonMap['mixWithOthers'] = mixWithOthers; return pigeonMap; } - // ignore: unused_element - static MixWithOthersMessage _fromMap(Map pigeonMap) { - final MixWithOthersMessage result = MixWithOthersMessage(); - result.mixWithOthers = pigeonMap['mixWithOthers']; - return result; + static MixWithOthersMessage decode(Object message) { + final Map pigeonMap = message as Map; + return MixWithOthersMessage() + ..mixWithOthers = pigeonMap['mixWithOthers'] as bool; } } class VideoPlayerApi { Future initialize() async { - const BasicMessageChannel channel = BasicMessageChannel( + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.initialize', StandardMessageCodec()); - - final Map? replyMap = await channel.send(null); + final Map? replyMap = + await channel.send(null) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { // noop } } Future create(CreateMessage arg) async { - final Map requestMap = arg._toMap(); - const BasicMessageChannel channel = BasicMessageChannel( + final Object encoded = arg.encode(); + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec()); - - final Map? replyMap = await channel.send(requestMap); + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { - return TextureMessage._fromMap(replyMap['result']); + return TextureMessage.decode(replyMap['result']!); } } Future dispose(TextureMessage arg) async { - final Map requestMap = arg._toMap(); - const BasicMessageChannel channel = BasicMessageChannel( + final Object encoded = arg.encode(); + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec()); - - final Map? replyMap = await channel.send(requestMap); + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { // noop } } Future setLooping(LoopingMessage arg) async { - final Map requestMap = arg._toMap(); - const BasicMessageChannel channel = BasicMessageChannel( + final Object encoded = arg.encode(); + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.setLooping', StandardMessageCodec()); - - final Map? replyMap = await channel.send(requestMap); + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { // noop } } Future setVolume(VolumeMessage arg) async { - final Map requestMap = arg._toMap(); - const BasicMessageChannel channel = BasicMessageChannel( + final Object encoded = arg.encode(); + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.setVolume', StandardMessageCodec()); - - final Map? replyMap = await channel.send(requestMap); + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { // noop } } Future setPlaybackSpeed(PlaybackSpeedMessage arg) async { - final Map requestMap = arg._toMap(); - const BasicMessageChannel channel = BasicMessageChannel( + final Object encoded = arg.encode(); + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed', StandardMessageCodec()); - - final Map? replyMap = await channel.send(requestMap); + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { // noop } } Future play(TextureMessage arg) async { - final Map requestMap = arg._toMap(); - const BasicMessageChannel channel = BasicMessageChannel( + final Object encoded = arg.encode(); + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec()); - - final Map? replyMap = await channel.send(requestMap); + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { // noop } } Future position(TextureMessage arg) async { - final Map requestMap = arg._toMap(); - const BasicMessageChannel channel = BasicMessageChannel( + final Object encoded = arg.encode(); + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()); - - final Map? replyMap = await channel.send(requestMap); + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { - return PositionMessage._fromMap(replyMap['result']); + return PositionMessage.decode(replyMap['result']!); } } Future seekTo(PositionMessage arg) async { - final Map requestMap = arg._toMap(); - const BasicMessageChannel channel = BasicMessageChannel( + final Object encoded = arg.encode(); + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec()); - - final Map? replyMap = await channel.send(requestMap); + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { // noop } } Future pause(TextureMessage arg) async { - final Map requestMap = arg._toMap(); - const BasicMessageChannel channel = BasicMessageChannel( + final Object encoded = arg.encode(); + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec()); - - final Map? replyMap = await channel.send(requestMap); + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { // noop } } Future setMixWithOthers(MixWithOthersMessage arg) async { - final Map requestMap = arg._toMap(); - const BasicMessageChannel channel = BasicMessageChannel( + final Object encoded = arg.encode(); + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers', StandardMessageCodec()); - - final Map? replyMap = await channel.send(requestMap); + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null); + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); } else if (replyMap['error'] != null) { - final Map error = replyMap['error']; + final Map error = + replyMap['error'] as Map; throw PlatformException( - code: error['code'], - message: error['message'], - details: error['details']); + code: error['code'] as String, + message: error['message'] as String?, + details: error['details'], + ); } else { // noop } } } - -abstract class TestHostVideoPlayerApi { - void initialize(); - TextureMessage create(CreateMessage arg); - void dispose(TextureMessage arg); - void setLooping(LoopingMessage arg); - void setVolume(VolumeMessage arg); - void setPlaybackSpeed(PlaybackSpeedMessage arg); - void play(TextureMessage arg); - PositionMessage position(TextureMessage arg); - void seekTo(PositionMessage arg); - void pause(TextureMessage arg); - void setMixWithOthers(MixWithOthersMessage arg); - static void setup(TestHostVideoPlayerApi? api) { - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.initialize', - StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - api.initialize(); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final CreateMessage input = CreateMessage._fromMap(mapMessage); - final TextureMessage output = api.create(input); - return {'result': output._toMap()}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final TextureMessage input = TextureMessage._fromMap(mapMessage); - api.dispose(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setLooping', - StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final LoopingMessage input = LoopingMessage._fromMap(mapMessage); - api.setLooping(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setVolume', - StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final VolumeMessage input = VolumeMessage._fromMap(mapMessage); - api.setVolume(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed', - StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final PlaybackSpeedMessage input = - PlaybackSpeedMessage._fromMap(mapMessage); - api.setPlaybackSpeed(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final TextureMessage input = TextureMessage._fromMap(mapMessage); - api.play(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final TextureMessage input = TextureMessage._fromMap(mapMessage); - final PositionMessage output = api.position(input); - return {'result': output._toMap()}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final PositionMessage input = PositionMessage._fromMap(mapMessage); - api.seekTo(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final TextureMessage input = TextureMessage._fromMap(mapMessage); - api.pause(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers', - StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((dynamic message) async { - final Map mapMessage = - message as Map; - final MixWithOthersMessage input = - MixWithOthersMessage._fromMap(mapMessage); - api.setMixWithOthers(input); - return {}; - }); - } - } - } -} diff --git a/packages/video_player/video_player_platform_interface/lib/test.dart b/packages/video_player/video_player_platform_interface/lib/test.dart new file mode 100644 index 000000000000..538e9526b111 --- /dev/null +++ b/packages/video_player/video_player_platform_interface/lib/test.dart @@ -0,0 +1,196 @@ +// Autogenerated from Pigeon (v0.1.19), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import +// @dart = 2.12 +import 'dart:async'; +import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'messages.dart'; + +abstract class TestHostVideoPlayerApi { + void initialize(); + TextureMessage create(CreateMessage arg); + void dispose(TextureMessage arg); + void setLooping(LoopingMessage arg); + void setVolume(VolumeMessage arg); + void setPlaybackSpeed(PlaybackSpeedMessage arg); + void play(TextureMessage arg); + PositionMessage position(TextureMessage arg); + void seekTo(PositionMessage arg); + void pause(TextureMessage arg); + void setMixWithOthers(MixWithOthersMessage arg); + static void setup(TestHostVideoPlayerApi? api) { + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.initialize', + StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + // ignore message + api.initialize(); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.VideoPlayerApi.create was null. Expected CreateMessage.'); + final CreateMessage input = CreateMessage.decode(message!); + final TextureMessage output = api.create(input); + return {'result': output.encode()}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.VideoPlayerApi.dispose was null. Expected TextureMessage.'); + final TextureMessage input = TextureMessage.decode(message!); + api.dispose(input); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.setLooping', + StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.VideoPlayerApi.setLooping was null. Expected LoopingMessage.'); + final LoopingMessage input = LoopingMessage.decode(message!); + api.setLooping(input); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.setVolume', + StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.VideoPlayerApi.setVolume was null. Expected VolumeMessage.'); + final VolumeMessage input = VolumeMessage.decode(message!); + api.setVolume(input); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed', + StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed was null. Expected PlaybackSpeedMessage.'); + final PlaybackSpeedMessage input = + PlaybackSpeedMessage.decode(message!); + api.setPlaybackSpeed(input); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.VideoPlayerApi.play was null. Expected TextureMessage.'); + final TextureMessage input = TextureMessage.decode(message!); + api.play(input); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.VideoPlayerApi.position was null. Expected TextureMessage.'); + final TextureMessage input = TextureMessage.decode(message!); + final PositionMessage output = api.position(input); + return {'result': output.encode()}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.VideoPlayerApi.seekTo was null. Expected PositionMessage.'); + final PositionMessage input = PositionMessage.decode(message!); + api.seekTo(input); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.VideoPlayerApi.pause was null. Expected TextureMessage.'); + final TextureMessage input = TextureMessage.decode(message!); + api.pause(input); + return {}; + }); + } + } + { + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers', + StandardMessageCodec()); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers was null. Expected MixWithOthersMessage.'); + final MixWithOthersMessage input = + MixWithOthersMessage.decode(message!); + api.setMixWithOthers(input); + return {}; + }); + } + } + } +} diff --git a/packages/video_player/video_player_platform_interface/pubspec.yaml b/packages/video_player/video_player_platform_interface/pubspec.yaml index ea8d3179cf1d..e493eebd800e 100644 --- a/packages/video_player/video_player_platform_interface/pubspec.yaml +++ b/packages/video_player/video_player_platform_interface/pubspec.yaml @@ -3,16 +3,16 @@ description: A common platform interface for the video_player plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_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: 3.0.0-nullsafety.3 +version: 4.0.0-nullsafety.0 dependencies: flutter: sdk: flutter meta: ^1.3.0-nullsafety.3 - -dev_dependencies: flutter_test: sdk: flutter + +dev_dependencies: mockito: ^4.1.1 pedantic: ^1.10.0-nullsafety.1 diff --git a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart index 7f54c4f24f2c..669fd2839897 100644 --- a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart +++ b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart @@ -12,6 +12,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:video_player_platform_interface/messages.dart'; import 'package:video_player_platform_interface/method_channel_video_player.dart'; +import 'package:video_player_platform_interface/test.dart'; import 'package:video_player_platform_interface/video_player_platform_interface.dart'; class _ApiLogger implements TestHostVideoPlayerApi { From b4378ce9e748cb470807a9dc6482b340dfb56f6f Mon Sep 17 00:00:00 2001 From: Kabirou Agouda <64534846+kagouda@users.noreply.github.com> Date: Tue, 9 Feb 2021 21:24:43 +0000 Subject: [PATCH 180/924] [share] Update README.md (#3300) * Update README.md I just tried to update the links. The old links worked too but redirected to the current links. I just had the idea to put the current links directly. https://pub.dartlang.org/packages/share to https://pub.dev/packages/share/ and https://flutter.io/platform-plugins/ to https://flutter.dev/docs/development/packages-and-plugins/using-packages * Update pubspec.yaml * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: stuartmorgan --- packages/share/CHANGELOG.md | 4 ++++ packages/share/README.md | 4 ++-- packages/share/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/share/CHANGELOG.md b/packages/share/CHANGELOG.md index 855e737a1cd4..ba44db433d17 100644 --- a/packages/share/CHANGELOG.md +++ b/packages/share/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.3 + +* Update README with the new documentation urls. + ## 2.0.0-nullsafety.2 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/share/README.md b/packages/share/README.md index 6ca38b416f03..a6e572258a2b 100644 --- a/packages/share/README.md +++ b/packages/share/README.md @@ -17,7 +17,7 @@ For more details see: https://github.com/flutter/flutter/wiki/Package-migration- ## Usage -To use this plugin, add `share` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels). +To use this plugin, add `share` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/packages-and-plugins/using-packages/). ## Example @@ -44,4 +44,4 @@ To share one or multiple files invoke the static `shareFiles` method anywhere in ``` dart Share.shareFiles(['${directory.path}/image.jpg'], text: 'Great picture'); Share.shareFiles(['${directory.path}/image1.jpg', '${directory.path}/image2.jpg']); -``` \ No newline at end of file +``` diff --git a/packages/share/pubspec.yaml b/packages/share/pubspec.yaml index ca9b506bf35c..4d2b231bbdfb 100644 --- a/packages/share/pubspec.yaml +++ b/packages/share/pubspec.yaml @@ -2,7 +2,7 @@ name: share description: Flutter plugin for sharing content via the platform share UI, using the ACTION_SEND intent on Android and UIActivityViewController on iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/share -version: 2.0.0-nullsafety.2 +version: 2.0.0-nullsafety.3 flutter: plugin: From ca25038288fa6c777e96aa6406d7263393daf833 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 9 Feb 2021 22:53:22 +0100 Subject: [PATCH 181/924] Removed obsolete example folder from camera root (#3503) --- .../example/android/gradle/wrapper/gradle-wrapper.properties | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 packages/camera/example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/camera/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/camera/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index be52383ef49c..000000000000 --- a/packages/camera/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists From 291966048f6627e9a39516b7a7047f21f369e27f Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 9 Feb 2021 23:39:50 +0100 Subject: [PATCH 182/924] [camera_platform_interface] Migrate to null safety (#3530) * Migrate camera_platform_interface to null safety * Added camera to the NNBD plugin list * Correct version number * Convert optional parameters to required for CameraInitializationEvent * Convert CameraId in test to non-nullable * Test for null instead of enforcing non-null * Attempt to fix dependency problem building all plugins * Mark google_maps_flutter as NNBD * Depend on correct Dart SDK version * Attempt to fix dependency problem building all plugins * Attempt to fix dependency problem building all plugins * Attempt to fix dependency problem building all plugins * Attempt to fix dependency problem building all plugins * Add camera_platform_interface to exclude list * Exclude camera from nnbd and non-nnbd * Remove mockito dependency * Make sure enableAudio is default false * Include left-hand type definition * Removed unused import statement --- .../src/method_channel/method_channel_camera.dart | 4 ++-- .../src/platform_interface/camera_platform.dart | 4 +++- .../camera/camera_platform_interface/pubspec.yaml | 1 - .../test/camera_platform_interface_test.dart | 14 -------------- .../method_channel/method_channel_camera_test.dart | 2 +- 5 files changed, 6 insertions(+), 19 deletions(-) diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index 3537a5ca40a9..9f7f723bcd79 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -59,7 +59,7 @@ class MethodChannelCamera extends CameraPlatform { @override Future> availableCameras() async { try { - final cameras = await _channel + final List>? cameras = await _channel .invokeListMethod>('availableCameras'); if (cameras == null) { @@ -82,7 +82,7 @@ class MethodChannelCamera extends CameraPlatform { Future createCamera( CameraDescription cameraDescription, ResolutionPreset? resolutionPreset, { - bool enableAudio = true, + bool enableAudio = false, }) async { try { final reply = await _channel diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 916922ff29fa..39a17e43dc0f 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -44,6 +44,8 @@ abstract class CameraPlatform extends PlatformInterface { } /// Completes with a list of available cameras. + /// + /// This method returns an empty list when no cameras are available. Future> availableCameras() { throw UnimplementedError('availableCameras() is not implemented.'); } @@ -52,7 +54,7 @@ abstract class CameraPlatform extends PlatformInterface { Future createCamera( CameraDescription cameraDescription, ResolutionPreset? resolutionPreset, { - bool enableAudio = true, + bool enableAudio = false, }) { throw UnimplementedError('createCamera() is not implemented.'); } diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index a063765af63b..5817ce5c3fb0 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -17,7 +17,6 @@ dev_dependencies: flutter_test: sdk: flutter async: ^2.5.0-nullsafety.3 - mockito: ^5.0.0-nullsafety.5 pedantic: ^1.10.0-nullsafety.3 environment: diff --git a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart index a96df845844a..f663db9776d1 100644 --- a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart +++ b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart @@ -6,8 +6,6 @@ import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:camera_platform_interface/src/method_channel/method_channel_camera.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -27,11 +25,6 @@ void main() { CameraPlatform.instance = ExtendsCameraPlatform(); }); - test('Can be mocked with `implements`', () { - final mock = MockCameraPlatform(); - CameraPlatform.instance = mock; - }); - test( 'Default implementation of availableCameras() should throw unimplemented error', () { @@ -423,11 +416,4 @@ class ImplementsCameraPlatform implements CameraPlatform { dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); } -class MockCameraPlatform extends Mock - with - // ignore: prefer_mixin - MockPlatformInterfaceMixin - implements - CameraPlatform {} - class ExtendsCameraPlatform extends CameraPlatform {} diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index 7633de8626a6..5248d34c46b9 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -51,7 +51,7 @@ void main() { arguments: { 'cameraName': 'Test', 'resolutionPreset': 'high', - 'enableAudio': true + 'enableAudio': false }, ), ]); From 09d0f79b4f100d884c90f47ab0221f4e9e8671b2 Mon Sep 17 00:00:00 2001 From: Michael Thomsen Date: Wed, 10 Feb 2021 16:25:00 +0100 Subject: [PATCH 183/924] Update pubspecs (#3534) --- packages/android_alarm_manager/example/pubspec.yaml | 2 +- packages/android_intent/example/pubspec.yaml | 2 +- packages/battery/battery/example/pubspec.yaml | 2 +- packages/camera/camera/example/pubspec.yaml | 2 +- packages/connectivity/connectivity/example/pubspec.yaml | 2 +- packages/connectivity/connectivity_macos/example/pubspec.yaml | 2 +- packages/device_info/device_info/example/pubspec.yaml | 2 +- .../google_maps_flutter/example/pubspec.yaml | 2 +- .../example/pubspec.yaml | 2 +- packages/google_sign_in/google_sign_in/example/pubspec.yaml | 2 +- packages/image_picker/image_picker/example/pubspec.yaml | 2 +- packages/in_app_purchase/example/pubspec.yaml | 2 +- packages/integration_test/example/pubspec.yaml | 2 +- packages/local_auth/example/pubspec.yaml | 2 +- packages/package_info/example/pubspec.yaml | 2 +- packages/path_provider/path_provider/example/pubspec.yaml | 2 +- packages/path_provider/path_provider_macos/example/pubspec.yaml | 2 +- .../path_provider/path_provider_windows/example/pubspec.yaml | 2 +- packages/quick_actions/example/pubspec.yaml | 2 +- packages/sensors/example/pubspec.yaml | 2 +- packages/share/example/pubspec.yaml | 2 +- .../shared_preferences/shared_preferences/example/pubspec.yaml | 2 +- .../shared_preferences_linux/example/pubspec.yaml | 2 +- .../shared_preferences_macos/example/pubspec.yaml | 2 +- packages/url_launcher/url_launcher/example/pubspec.yaml | 2 +- packages/url_launcher/url_launcher_linux/example/pubspec.yaml | 2 +- packages/url_launcher/url_launcher_macos/example/pubspec.yaml | 2 +- packages/url_launcher/url_launcher_windows/example/pubspec.yaml | 2 +- packages/video_player/video_player/example/pubspec.yaml | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/packages/android_alarm_manager/example/pubspec.yaml b/packages/android_alarm_manager/example/pubspec.yaml index e636a246376b..140f90a37e79 100644 --- a/packages/android_alarm_manager/example/pubspec.yaml +++ b/packages/android_alarm_manager/example/pubspec.yaml @@ -24,4 +24,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/android_intent/example/pubspec.yaml b/packages/android_intent/example/pubspec.yaml index 84455d99e618..34924d7b133e 100644 --- a/packages/android_intent/example/pubspec.yaml +++ b/packages/android_intent/example/pubspec.yaml @@ -20,4 +20,4 @@ flutter: environment: sdk: ">=2.3.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/battery/battery/example/pubspec.yaml b/packages/battery/battery/example/pubspec.yaml index 748660adf284..fae9f48956d1 100644 --- a/packages/battery/battery/example/pubspec.yaml +++ b/packages/battery/battery/example/pubspec.yaml @@ -19,4 +19,4 @@ flutter: environment: sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/camera/camera/example/pubspec.yaml b/packages/camera/camera/example/pubspec.yaml index 5d59ebf75c62..077c7a6568d9 100644 --- a/packages/camera/camera/example/pubspec.yaml +++ b/packages/camera/camera/example/pubspec.yaml @@ -23,4 +23,4 @@ flutter: environment: sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.9.1+hotfix.4 <2.0.0" + flutter: ">=1.9.1+hotfix.4" diff --git a/packages/connectivity/connectivity/example/pubspec.yaml b/packages/connectivity/connectivity/example/pubspec.yaml index 682f0a2dd08a..bd723cb79cec 100644 --- a/packages/connectivity/connectivity/example/pubspec.yaml +++ b/packages/connectivity/connectivity/example/pubspec.yaml @@ -20,4 +20,4 @@ flutter: environment: sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/connectivity/connectivity_macos/example/pubspec.yaml b/packages/connectivity/connectivity_macos/example/pubspec.yaml index 041c3b364370..a6107fcbf103 100644 --- a/packages/connectivity/connectivity_macos/example/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/example/pubspec.yaml @@ -20,4 +20,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/device_info/device_info/example/pubspec.yaml b/packages/device_info/device_info/example/pubspec.yaml index 09567fd967b2..aa8019fc1022 100644 --- a/packages/device_info/device_info/example/pubspec.yaml +++ b/packages/device_info/device_info/example/pubspec.yaml @@ -19,4 +19,4 @@ flutter: environment: sdk: ">=2.10.0-56.0.dev <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml index e0f79b571cb0..09e4924a03b7 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml @@ -3,7 +3,7 @@ description: Demonstrates how to use the google_maps_flutter plugin. environment: sdk: ">=2.2.0 <3.0.0" - flutter: ">=1.22.0 <2.0.0" + flutter: ">=1.22.0" dependencies: flutter: diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml index 3e64fa2da3f2..e032b14ec7a8 100755 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml @@ -21,4 +21,4 @@ flutter: environment: sdk: ">=2.0.0-dev.28.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4 <2.0.0" + flutter: ">=1.12.13+hotfix.4" diff --git a/packages/google_sign_in/google_sign_in/example/pubspec.yaml b/packages/google_sign_in/google_sign_in/example/pubspec.yaml index ebf8e82719f2..d676add2f1df 100755 --- a/packages/google_sign_in/google_sign_in/example/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/example/pubspec.yaml @@ -20,4 +20,4 @@ flutter: environment: sdk: ">=2.0.0-dev.28.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4 <2.0.0" + flutter: ">=1.12.13+hotfix.4" diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml index 44364a1c19e7..017b2a22a86e 100755 --- a/packages/image_picker/image_picker/example/pubspec.yaml +++ b/packages/image_picker/image_picker/example/pubspec.yaml @@ -22,4 +22,4 @@ flutter: environment: sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/in_app_purchase/example/pubspec.yaml b/packages/in_app_purchase/example/pubspec.yaml index 48359dbc6a06..8f45e0e8e259 100644 --- a/packages/in_app_purchase/example/pubspec.yaml +++ b/packages/in_app_purchase/example/pubspec.yaml @@ -23,4 +23,4 @@ flutter: environment: sdk: ">=2.3.0 <3.0.0" - flutter: ">=1.9.1+hotfix.2 <2.0.0" + flutter: ">=1.9.1+hotfix.2" diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 9384e9763935..84875dcb28fb 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.6.7 <2.0.0" + flutter: ">=1.6.7" dependencies: flutter: diff --git a/packages/local_auth/example/pubspec.yaml b/packages/local_auth/example/pubspec.yaml index 9c7b91e672e6..653ff085ab5f 100644 --- a/packages/local_auth/example/pubspec.yaml +++ b/packages/local_auth/example/pubspec.yaml @@ -19,4 +19,4 @@ flutter: environment: sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/package_info/example/pubspec.yaml b/packages/package_info/example/pubspec.yaml index 605c375e9a8e..dd0bae12c039 100644 --- a/packages/package_info/example/pubspec.yaml +++ b/packages/package_info/example/pubspec.yaml @@ -19,4 +19,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/path_provider/path_provider/example/pubspec.yaml b/packages/path_provider/path_provider/example/pubspec.yaml index 8659da753e15..98a0fd3c1bfb 100644 --- a/packages/path_provider/path_provider/example/pubspec.yaml +++ b/packages/path_provider/path_provider/example/pubspec.yaml @@ -19,4 +19,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/path_provider/path_provider_macos/example/pubspec.yaml b/packages/path_provider/path_provider_macos/example/pubspec.yaml index 01ab42bbe71b..f1363cb4dfc7 100644 --- a/packages/path_provider/path_provider_macos/example/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/example/pubspec.yaml @@ -24,4 +24,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0 <2.0.0" + flutter: ">=1.10.0" diff --git a/packages/path_provider/path_provider_windows/example/pubspec.yaml b/packages/path_provider/path_provider_windows/example/pubspec.yaml index 0e723f502581..1d2b9a7e98da 100644 --- a/packages/path_provider/path_provider_windows/example/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/example/pubspec.yaml @@ -21,4 +21,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4 <2.0.0" + flutter: ">=1.12.13+hotfix.4" diff --git a/packages/quick_actions/example/pubspec.yaml b/packages/quick_actions/example/pubspec.yaml index 6f9c0efd01af..03fc294f7361 100644 --- a/packages/quick_actions/example/pubspec.yaml +++ b/packages/quick_actions/example/pubspec.yaml @@ -19,4 +19,4 @@ flutter: environment: sdk: ">=2.0.0-dev.28.0 <3.0.0" - flutter: ">=1.9.1+hotfix.2 <2.0.0" + flutter: ">=1.9.1+hotfix.2" diff --git a/packages/sensors/example/pubspec.yaml b/packages/sensors/example/pubspec.yaml index eb46c611a43a..2cd1397c3527 100644 --- a/packages/sensors/example/pubspec.yaml +++ b/packages/sensors/example/pubspec.yaml @@ -19,5 +19,5 @@ flutter: environment: sdk: ">=2.0.0-dev.28.0 <3.0.0" - flutter: ">=1.9.1+hotfix.2 <2.0.0" + flutter: ">=1.9.1+hotfix.2" diff --git a/packages/share/example/pubspec.yaml b/packages/share/example/pubspec.yaml index 8b8623910b7a..b96141d40946 100644 --- a/packages/share/example/pubspec.yaml +++ b/packages/share/example/pubspec.yaml @@ -20,4 +20,4 @@ flutter: environment: sdk: ">=2.0.0-dev.28.0 <3.0.0" - flutter: ">=1.9.1+hotfix.2 <2.0.0" + flutter: ">=1.9.1+hotfix.2" diff --git a/packages/shared_preferences/shared_preferences/example/pubspec.yaml b/packages/shared_preferences/shared_preferences/example/pubspec.yaml index cf0fa64fea46..203300140250 100644 --- a/packages/shared_preferences/shared_preferences/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/example/pubspec.yaml @@ -19,5 +19,5 @@ flutter: environment: sdk: ">=2.0.0-dev.28.0 <3.0.0" - flutter: ">=1.9.1+hotfix.2 <2.0.0" + flutter: ">=1.9.1+hotfix.2" diff --git a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml index 591aad4c2c57..5728a918f76f 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml @@ -19,4 +19,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" diff --git a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml index 93d5d42597cd..446dc8e07160 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml @@ -20,4 +20,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml index 7caea27744db..27e09749bc2c 100644 --- a/packages/url_launcher/url_launcher/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher/example/pubspec.yaml @@ -21,4 +21,4 @@ flutter: environment: sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml index 9604637c336c..a0bb317bd417 100644 --- a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml @@ -20,4 +20,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" diff --git a/packages/url_launcher/url_launcher_macos/example/pubspec.yaml b/packages/url_launcher/url_launcher_macos/example/pubspec.yaml index dbf8951ff408..19952ff910de 100644 --- a/packages/url_launcher/url_launcher_macos/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/example/pubspec.yaml @@ -20,4 +20,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" diff --git a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml index 44a5424168c9..3ffbe4b35766 100644 --- a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml @@ -20,4 +20,4 @@ flutter: environment: sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8 <2.0.0" + flutter: ">=1.12.8" diff --git a/packages/video_player/video_player/example/pubspec.yaml b/packages/video_player/video_player/example/pubspec.yaml index fb18d8b75efa..6a3d218e5529 100644 --- a/packages/video_player/video_player/example/pubspec.yaml +++ b/packages/video_player/video_player/example/pubspec.yaml @@ -28,4 +28,4 @@ flutter: environment: sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.13+hotfix.5 <2.0.0" + flutter: ">=1.12.13+hotfix.5" From 7624d9eb7776ce5f670ebc0d749ce8ac4405f950 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 10 Feb 2021 10:01:49 -0800 Subject: [PATCH 184/924] add post merge labeler (#3532) --- .github/post_merge_labeler.yml | 2 ++ .github/workflows/pull_request_label.yml | 23 +++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 .github/post_merge_labeler.yml diff --git a/.github/post_merge_labeler.yml b/.github/post_merge_labeler.yml new file mode 100644 index 000000000000..c02eb411773e --- /dev/null +++ b/.github/post_merge_labeler.yml @@ -0,0 +1,2 @@ +'needs-publishing': + - packages/*/** diff --git a/.github/workflows/pull_request_label.yml b/.github/workflows/pull_request_label.yml index 5016184d6d11..7b048d33e669 100644 --- a/.github/workflows/pull_request_label.yml +++ b/.github/workflows/pull_request_label.yml @@ -1,20 +1,31 @@ # This workflow applies labels to pull requests based on the # paths that are modified in the pull request. # -# Edit `.github/labeler.yml` to configure labels. +# Edit `.github/labeler.yml` and `.github/post_merge_labeler.yml` +# to configure labels. # # For more information, see: https://github.com/actions/labeler name: Pull Request Labeler on: - - pull_request_target + pull_request_target: + types: [opened, synchronize, reopened, closed] jobs: label: runs-on: ubuntu-latest steps: - - uses: actions/labeler@main - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - sync-labels: true + - uses: actions/labeler@v3 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + sync-labels: true + + post_merge_label: + if: github.event.action == 'closed' && github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v3 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + configuration-path: .github/post_merge_labeler.yml From 31a631cb037f9ed0ac12c8de04bd6430820f3d6d Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 11 Feb 2021 16:49:35 -0800 Subject: [PATCH 185/924] [wifi_info_flutter] Migrate to null safety (#3425) --- .../wifi_info_flutter/CHANGELOG.md | 4 +++ .../integration_test/wifi_info_test.dart | 2 ++ .../lib/wifi_info_flutter.dart | 19 +++++-------- .../wifi_info_flutter/pubspec.yaml | 8 +++--- .../test/wifi_info_flutter_test.dart | 27 +++++++++---------- 5 files changed, 29 insertions(+), 31 deletions(-) diff --git a/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md b/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md index fa68eed175b7..c98140eedcf0 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md +++ b/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 1.0.4 * Android: Add Log warning for unsatisfied requirement(s) in Android P or higher. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart index 103dc54a1eaa..4760b88d9019 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 + import 'dart:io'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart b/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart index 1183bf6c74bf..a2a69d161f5a 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart @@ -13,19 +13,14 @@ export 'package:wifi_info_flutter_platform_interface/wifi_info_flutter_platform_ /// Checks WI-FI status and more. class WifiInfo { + WifiInfo._(); + /// Constructs a singleton instance of [WifiInfo]. /// /// [WifiInfo] is designed to work as a singleton. - factory WifiInfo() { - if (_singleton == null) { - _singleton = WifiInfo._(); - } - return _singleton; - } - - WifiInfo._(); + factory WifiInfo() => _singleton; - static WifiInfo _singleton; + static final WifiInfo _singleton = WifiInfo._(); static WifiInfoFlutterPlatform get _platform => WifiInfoFlutterPlatform.instance; @@ -36,7 +31,7 @@ class WifiInfo { /// /// From android 8.0 onwards the GPS must be ON (high accuracy) /// in order to be able to obtain the SSID. - Future getWifiName() { + Future getWifiName() { return _platform.getWifiName(); } @@ -46,12 +41,12 @@ class WifiInfo { /// /// From Android 8.0 onwards the GPS must be ON (high accuracy) /// in order to be able to obtain the BSSID. - Future getWifiBSSID() { + Future getWifiBSSID() { return _platform.getWifiBSSID(); } /// Obtains the IP address of the connected wifi network - Future getWifiIP() { + Future getWifiIP() { return _platform.getWifiIP(); } diff --git a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml index b8306a0696d2..0fbc27866201 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml @@ -1,20 +1,18 @@ name: wifi_info_flutter description: A new flutter plugin project. -version: 1.0.4 +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter/wifi_info_flutter environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.20.0" dependencies: flutter: sdk: flutter - wifi_info_flutter_platform_interface: ^1.0.0 + wifi_info_flutter_platform_interface: ^2.0.0-nullsafety dev_dependencies: - mockito: ^4.1.1 - plugin_platform_interface: ^1.0.0 integration_test: path: ../../integration_test flutter_test: diff --git a/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart index a3a55170bce5..19e84f696f7f 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart @@ -2,13 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:wifi_info_flutter/wifi_info_flutter.dart'; import 'package:wifi_info_flutter_platform_interface/wifi_info_flutter_platform_interface.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'package:mockito/mockito.dart'; const String kWifiNameResult = '1337wifi'; const String kWifiBSSIDResult = 'c0:ff:33:c0:d3:55'; @@ -20,7 +16,7 @@ const LocationAuthorizationStatus kGetLocationResult = void main() { group('$WifiInfo', () { - WifiInfo wifiInfo; + late WifiInfo wifiInfo; MockWifiInfoFlutterPlatform fakePlatform; setUp(() async { @@ -30,17 +26,17 @@ void main() { }); test('getWifiName', () async { - String result = await wifiInfo.getWifiName(); + String? result = await wifiInfo.getWifiName(); expect(result, kWifiNameResult); }); test('getWifiBSSID', () async { - String result = await wifiInfo.getWifiBSSID(); + String? result = await wifiInfo.getWifiBSSID(); expect(result, kWifiBSSIDResult); }); test('getWifiIP', () async { - String result = await wifiInfo.getWifiIP(); + String? result = await wifiInfo.getWifiIP(); expect(result, kWifiIpAddressResult); }); @@ -58,27 +54,30 @@ void main() { }); } -class MockWifiInfoFlutterPlatform extends Mock - with MockPlatformInterfaceMixin - implements WifiInfoFlutterPlatform { - Future getWifiName() async { +class MockWifiInfoFlutterPlatform extends WifiInfoFlutterPlatform { + @override + Future getWifiName() async { return kWifiNameResult; } - Future getWifiBSSID() async { + @override + Future getWifiBSSID() async { return kWifiBSSIDResult; } - Future getWifiIP() async { + @override + Future getWifiIP() async { return kWifiIpAddressResult; } + @override Future requestLocationServiceAuthorization({ bool requestAlwaysLocationUsage = false, }) async { return kRequestLocationResult; } + @override Future getLocationServiceAuthorization() async { return kGetLocationResult; } From acabfe66607ae4e9a5c7ae1d39420fc3dff5ac44 Mon Sep 17 00:00:00 2001 From: Tim Sneath Date: Thu, 11 Feb 2021 17:40:44 -0800 Subject: [PATCH 186/924] Bump ffi dependencies (#3540) * Update to FFI 1.0 * Bump CHANGELOG --- .../path_provider/path_provider_windows/CHANGELOG.md | 5 +++++ .../lib/src/path_provider_windows_real.dart | 10 +++++----- .../path_provider/path_provider_windows/pubspec.yaml | 6 +++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index 6190c39457da..8d365319c32a 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.1.0-nullsafety.3 + +* Bump ffi dependency to 1.0.0 +* Bump win32 dependency to 2.0.0-nullsafety.12 + ## 0.1.0-nullsafety.2 * Bump ffi dependency to 0.3.0-nullsafety.1 diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart index c88e10a0f9b3..db2ad9da207c 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart @@ -34,7 +34,7 @@ class VersionInfoQuerier { if (VerQueryValue(versionInfo, keyPath, valueAddress, length) == 0) { return null; } - return valueAddress.value.unpackString(length.value); + return valueAddress.value.toDartString(); } finally { calloc.free(keyPath); calloc.free(length); @@ -64,7 +64,7 @@ class PathProviderWindows extends PathProviderPlatform { final error = GetLastError(); throw WindowsException(error); } else { - path = buffer.unpackString(length); + path = buffer.toDartString(); // GetTempPath adds a trailing backslash, but SHGetKnownFolderPath does // not. Strip off trailing backslash for consistency with other methods @@ -132,7 +132,7 @@ class PathProviderWindows extends PathProviderPlatform { } } - final path = pathPtrPtr.value.unpackString(MAX_PATH); + final path = pathPtrPtr.value.toDartString(); return Future.value(path); } finally { calloc.free(pathPtrPtr); @@ -183,8 +183,8 @@ class PathProviderWindows extends PathProviderPlatform { // If there was no product name, use the executable name. if (productName == null) { - productName = path.basenameWithoutExtension( - moduleNameBuffer.unpackString(moduleNameLength)); + productName = + path.basenameWithoutExtension(moduleNameBuffer.toDartString()); } return companyName != null diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index 922594a9bd2d..d672ff90cdb9 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_windows -version: 0.1.0-nullsafety.2 +version: 0.1.0-nullsafety.3 flutter: plugin: @@ -16,8 +16,8 @@ dependencies: path: ^1.8.0-nullsafety.3 flutter: sdk: flutter - ffi: '>=0.3.0-nullsafety.1 <2.0.0' - win32: ^2.0.0-nullsafety.10 + ffi: ^1.0.0 + win32: ^2.0.0-nullsafety.12 dev_dependencies: flutter_test: From 99d599c052801c9d3bdf892433be746e58af4bfb Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Fri, 12 Feb 2021 18:16:04 +0100 Subject: [PATCH 187/924] Added comment about path depenendencies (#3542) --- packages/android_alarm_manager/example/pubspec.yaml | 5 +++++ packages/android_intent/example/pubspec.yaml | 5 +++++ packages/battery/battery/example/pubspec.yaml | 5 +++++ packages/camera/camera/example/pubspec.yaml | 5 +++++ packages/connectivity/connectivity/example/pubspec.yaml | 5 +++++ .../connectivity/connectivity_macos/example/pubspec.yaml | 5 +++++ packages/device_info/device_info/example/pubspec.yaml | 5 +++++ packages/espresso/example/pubspec.yaml | 5 +++++ packages/file_selector/file_selector/example/pubspec.yaml | 5 +++++ .../flutter_plugin_android_lifecycle/example/pubspec.yaml | 5 +++++ .../google_maps_flutter/example/pubspec.yaml | 5 +++++ .../example/pubspec.yaml | 5 +++++ packages/google_sign_in/google_sign_in/example/pubspec.yaml | 5 +++++ packages/image_picker/image_picker/example/pubspec.yaml | 5 +++++ packages/in_app_purchase/example/pubspec.yaml | 5 +++++ packages/integration_test/example/pubspec.yaml | 5 +++++ packages/ios_platform_images/example/pubspec.yaml | 5 +++++ packages/local_auth/example/pubspec.yaml | 5 +++++ packages/package_info/example/pubspec.yaml | 5 +++++ packages/path_provider/path_provider/example/pubspec.yaml | 5 +++++ .../path_provider/path_provider_linux/example/pubspec.yaml | 5 +++++ .../path_provider/path_provider_macos/example/pubspec.yaml | 5 +++++ .../path_provider/path_provider_windows/example/pubspec.yaml | 5 +++++ packages/quick_actions/example/pubspec.yaml | 5 +++++ packages/sensors/example/pubspec.yaml | 5 +++++ packages/share/example/pubspec.yaml | 5 +++++ .../shared_preferences/example/pubspec.yaml | 5 +++++ .../shared_preferences_linux/example/pubspec.yaml | 5 +++++ .../shared_preferences_macos/example/pubspec.yaml | 5 +++++ .../shared_preferences_windows/example/pubspec.yaml | 5 +++++ packages/url_launcher/url_launcher/example/pubspec.yaml | 5 +++++ .../url_launcher/url_launcher_linux/example/pubspec.yaml | 5 +++++ .../url_launcher/url_launcher_macos/example/pubspec.yaml | 5 +++++ .../url_launcher/url_launcher_windows/example/pubspec.yaml | 5 +++++ packages/video_player/video_player/example/pubspec.yaml | 5 +++++ packages/webview_flutter/example/pubspec.yaml | 5 +++++ .../wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml | 5 +++++ 37 files changed, 185 insertions(+) diff --git a/packages/android_alarm_manager/example/pubspec.yaml b/packages/android_alarm_manager/example/pubspec.yaml index 140f90a37e79..6fce3464b92a 100644 --- a/packages/android_alarm_manager/example/pubspec.yaml +++ b/packages/android_alarm_manager/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter android_alarm_manager: + # When depending on this package from a real application you should use: + # android_alarm_manager: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ shared_preferences: ^0.5.6 integration_test: diff --git a/packages/android_intent/example/pubspec.yaml b/packages/android_intent/example/pubspec.yaml index 34924d7b133e..7a0814d4acc0 100644 --- a/packages/android_intent/example/pubspec.yaml +++ b/packages/android_intent/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter android_intent: + # When depending on this package from a real application you should use: + # android_intent: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/battery/battery/example/pubspec.yaml b/packages/battery/battery/example/pubspec.yaml index fae9f48956d1..e118a7c21540 100644 --- a/packages/battery/battery/example/pubspec.yaml +++ b/packages/battery/battery/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter battery: + # When depending on this package from a real application you should use: + # battery: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/camera/camera/example/pubspec.yaml b/packages/camera/camera/example/pubspec.yaml index 077c7a6568d9..2a45fd69194c 100644 --- a/packages/camera/camera/example/pubspec.yaml +++ b/packages/camera/camera/example/pubspec.yaml @@ -3,6 +3,11 @@ description: Demonstrates how to use the camera plugin. dependencies: camera: + # When depending on this package from a real application you should use: + # camera: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ path_provider: ^0.5.0 flutter: diff --git a/packages/connectivity/connectivity/example/pubspec.yaml b/packages/connectivity/connectivity/example/pubspec.yaml index bd723cb79cec..b50214619c13 100644 --- a/packages/connectivity/connectivity/example/pubspec.yaml +++ b/packages/connectivity/connectivity/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter connectivity: + # When depending on this package from a real application you should use: + # connectivity: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/connectivity/connectivity_macos/example/pubspec.yaml b/packages/connectivity/connectivity_macos/example/pubspec.yaml index a6107fcbf103..49d24e76b717 100644 --- a/packages/connectivity/connectivity_macos/example/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/example/pubspec.yaml @@ -6,6 +6,11 @@ dependencies: sdk: flutter connectivity: any connectivity_macos: + # When depending on this package from a real application you should use: + # connectivity_macos: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/device_info/device_info/example/pubspec.yaml b/packages/device_info/device_info/example/pubspec.yaml index aa8019fc1022..1f636977c2a9 100644 --- a/packages/device_info/device_info/example/pubspec.yaml +++ b/packages/device_info/device_info/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter device_info: + # When depending on this package from a real application you should use: + # device_info: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/espresso/example/pubspec.yaml b/packages/espresso/example/pubspec.yaml index d2d73da3c0ae..4854d85cb281 100644 --- a/packages/espresso/example/pubspec.yaml +++ b/packages/espresso/example/pubspec.yaml @@ -21,6 +21,11 @@ dev_dependencies: pedantic: ^1.8.0 espresso: + # When depending on this package from a real application you should use: + # espresso: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ # For information on the generic Dart part of this file, see the diff --git a/packages/file_selector/file_selector/example/pubspec.yaml b/packages/file_selector/file_selector/example/pubspec.yaml index 58f0abbf2658..3af2a67e9e93 100644 --- a/packages/file_selector/file_selector/example/pubspec.yaml +++ b/packages/file_selector/file_selector/example/pubspec.yaml @@ -25,6 +25,11 @@ dependencies: sdk: flutter file_selector: + # When depending on this package from a real application you should use: + # file_selector: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ # The following adds the Cupertino Icons font to your application. diff --git a/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml index 4643317c1951..833c2eba4319 100644 --- a/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: + # When depending on this package from a real application you should use: + # flutter_plugin_android_lifecycle: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml index 09e4924a03b7..b3a0ae75daad 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml @@ -13,6 +13,11 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.0 google_maps_flutter: + # When depending on this package from a real application you should use: + # google_maps_flutter: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ flutter_plugin_android_lifecycle: ^1.0.0 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml index e032b14ec7a8..48dfef644a5c 100755 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml @@ -6,6 +6,11 @@ dependencies: sdk: flutter google_sign_in: ^4.4.1 extension_google_sign_in_as_googleapis_auth: + # When depending on this package from a real application you should use: + # extension_google_sign_in_as_googleapis_auth: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ googleapis: ^0.55.0 diff --git a/packages/google_sign_in/google_sign_in/example/pubspec.yaml b/packages/google_sign_in/google_sign_in/example/pubspec.yaml index d676add2f1df..e35aa9ace6a3 100755 --- a/packages/google_sign_in/google_sign_in/example/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter google_sign_in: + # When depending on this package from a real application you should use: + # google_sign_in: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ http: ^0.12.0 diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml index 017b2a22a86e..eed223c1ade7 100755 --- a/packages/image_picker/image_picker/example/pubspec.yaml +++ b/packages/image_picker/image_picker/example/pubspec.yaml @@ -8,6 +8,11 @@ dependencies: sdk: flutter flutter_plugin_android_lifecycle: ^2.0.0-nullsafety.2 image_picker: + # When depending on this package from a real application you should use: + # image_picker: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/in_app_purchase/example/pubspec.yaml b/packages/in_app_purchase/example/pubspec.yaml index 8f45e0e8e259..9b623a15795a 100644 --- a/packages/in_app_purchase/example/pubspec.yaml +++ b/packages/in_app_purchase/example/pubspec.yaml @@ -13,6 +13,11 @@ dev_dependencies: flutter_driver: sdk: flutter in_app_purchase: + # When depending on this package from a real application you should use: + # in_app_purchase: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ integration_test: path: ../../integration_test diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 84875dcb28fb..5ad8be4a818e 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -18,6 +18,11 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: + # When depending on this package from a real application you should use: + # integration_test: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ integration_test_macos: path: ../integration_test_macos diff --git a/packages/ios_platform_images/example/pubspec.yaml b/packages/ios_platform_images/example/pubspec.yaml index fa0f9eb3aac6..7802a2b0fe0a 100644 --- a/packages/ios_platform_images/example/pubspec.yaml +++ b/packages/ios_platform_images/example/pubspec.yaml @@ -18,6 +18,11 @@ dev_dependencies: flutter_test: sdk: flutter ios_platform_images: + # When depending on this package from a real application you should use: + # ios_platform_images: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ pedantic: ^1.8.0 diff --git a/packages/local_auth/example/pubspec.yaml b/packages/local_auth/example/pubspec.yaml index 653ff085ab5f..364f604a31d8 100644 --- a/packages/local_auth/example/pubspec.yaml +++ b/packages/local_auth/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter local_auth: + # When depending on this package from a real application you should use: + # local_auth: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/package_info/example/pubspec.yaml b/packages/package_info/example/pubspec.yaml index dd0bae12c039..0d0e1bae3c1f 100644 --- a/packages/package_info/example/pubspec.yaml +++ b/packages/package_info/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter package_info: + # When depending on this package from a real application you should use: + # package_info: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ integration_test: path: ../../integration_test diff --git a/packages/path_provider/path_provider/example/pubspec.yaml b/packages/path_provider/path_provider/example/pubspec.yaml index 98a0fd3c1bfb..bbb140e8f4bf 100644 --- a/packages/path_provider/path_provider/example/pubspec.yaml +++ b/packages/path_provider/path_provider/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter path_provider: + # When depending on this package from a real application you should use: + # path_provider: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/path_provider/path_provider_linux/example/pubspec.yaml b/packages/path_provider/path_provider_linux/example/pubspec.yaml index d66af910c998..a1a9dde163cf 100644 --- a/packages/path_provider/path_provider_linux/example/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/example/pubspec.yaml @@ -17,6 +17,11 @@ dependencies: dependency_overrides: path_provider_linux: + # When depending on this package from a real application you should use: + # path_provider_linux: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/path_provider/path_provider_macos/example/pubspec.yaml b/packages/path_provider/path_provider_macos/example/pubspec.yaml index f1363cb4dfc7..cb904fa5ea98 100644 --- a/packages/path_provider/path_provider_macos/example/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/example/pubspec.yaml @@ -10,6 +10,11 @@ dependencies: # to depend on it from path: dependency_overrides: path_provider_macos: + # When depending on this package from a real application you should use: + # path_provider_macos: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/path_provider/path_provider_windows/example/pubspec.yaml b/packages/path_provider/path_provider_windows/example/pubspec.yaml index 1d2b9a7e98da..7a34d90c0f6c 100644 --- a/packages/path_provider/path_provider_windows/example/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/example/pubspec.yaml @@ -8,6 +8,11 @@ dependencies: dependency_overrides: path_provider_windows: + # When depending on this package from a real application you should use: + # path_provider_windows: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/quick_actions/example/pubspec.yaml b/packages/quick_actions/example/pubspec.yaml index 03fc294f7361..deba400ccd9f 100644 --- a/packages/quick_actions/example/pubspec.yaml +++ b/packages/quick_actions/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter quick_actions: + # When depending on this package from a real application you should use: + # quick_actions: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/sensors/example/pubspec.yaml b/packages/sensors/example/pubspec.yaml index 2cd1397c3527..d4702ac3aabe 100644 --- a/packages/sensors/example/pubspec.yaml +++ b/packages/sensors/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter sensors: + # When depending on this package from a real application you should use: + # sensors: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/share/example/pubspec.yaml b/packages/share/example/pubspec.yaml index b96141d40946..372633ec19ec 100644 --- a/packages/share/example/pubspec.yaml +++ b/packages/share/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter share: + # When depending on this package from a real application you should use: + # share: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ image_picker: ^0.6.7+4 diff --git a/packages/shared_preferences/shared_preferences/example/pubspec.yaml b/packages/shared_preferences/shared_preferences/example/pubspec.yaml index 203300140250..05f2528af2af 100644 --- a/packages/shared_preferences/shared_preferences/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter shared_preferences: + # When depending on this package from a real application you should use: + # shared_preferences: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml index 5728a918f76f..5fc8ae039812 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter shared_preferences_linux: + # When depending on this package from a real application you should use: + # shared_preferences_linux: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml index 446dc8e07160..5543b4a3b8c2 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml @@ -6,6 +6,11 @@ dependencies: sdk: flutter shared_preferences: any shared_preferences_macos: + # When depending on this package from a real application you should use: + # shared_preferences_macos: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml index 8a44e7874cfb..1af679b4ede3 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml @@ -11,6 +11,11 @@ dependencies: dependency_overrides: shared_preferences_windows: + # When depending on this package from a real application you should use: + # shared_preferences_windows: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml index 27e09749bc2c..520b6863ec2d 100644 --- a/packages/url_launcher/url_launcher/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher/example/pubspec.yaml @@ -5,6 +5,11 @@ dependencies: flutter: sdk: flutter url_launcher: + # When depending on this package from a real application you should use: + # url_launcher: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml index a0bb317bd417..e95bcd0af478 100644 --- a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml @@ -6,6 +6,11 @@ dependencies: sdk: flutter url_launcher: any url_launcher_linux: + # When depending on this package from a real application you should use: + # url_launcher_linux: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/url_launcher/url_launcher_macos/example/pubspec.yaml b/packages/url_launcher/url_launcher_macos/example/pubspec.yaml index 19952ff910de..2e66616101c2 100644 --- a/packages/url_launcher/url_launcher_macos/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/example/pubspec.yaml @@ -6,6 +6,11 @@ dependencies: sdk: flutter url_launcher: any url_launcher_macos: + # When depending on this package from a real application you should use: + # url_launcher_macos: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml index 3ffbe4b35766..2de2bcf14f44 100644 --- a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml @@ -6,6 +6,11 @@ dependencies: sdk: flutter url_launcher_platform_interface: any url_launcher_windows: + # When depending on this package from a real application you should use: + # url_launcher_windows: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/video_player/video_player/example/pubspec.yaml b/packages/video_player/video_player/example/pubspec.yaml index 6a3d218e5529..620186afc880 100644 --- a/packages/video_player/video_player/example/pubspec.yaml +++ b/packages/video_player/video_player/example/pubspec.yaml @@ -7,6 +7,11 @@ dependencies: flutter: sdk: flutter video_player: + # When depending on this package from a real application you should use: + # video_player: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/webview_flutter/example/pubspec.yaml b/packages/webview_flutter/example/pubspec.yaml index 1ace8afe400f..b61b6df590ce 100644 --- a/packages/webview_flutter/example/pubspec.yaml +++ b/packages/webview_flutter/example/pubspec.yaml @@ -8,6 +8,11 @@ dependencies: flutter: sdk: flutter webview_flutter: + # When depending on this package from a real application you should use: + # webview_flutter: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ dev_dependencies: diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml index 7ebc1573ddcf..0f0adbf7b4a1 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml @@ -10,6 +10,11 @@ dependencies: flutter: sdk: flutter wifi_info_flutter: + # When depending on this package from a real application you should use: + # wifi_info_flutter: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. path: ../ cupertino_icons: ^1.0.0 From 197d9761d0a301ddd3e3cc119d5e39ae339b4461 Mon Sep 17 00:00:00 2001 From: Aman Kumar Date: Sat, 13 Feb 2021 02:20:42 +0530 Subject: [PATCH 188/924] [android_alarm_manager] Migrated android_alarm_manager to support null safety #75233 (#3499) Migrated android_alarm_manager to support null safety. Fixes flutter/flutter#75233 --- packages/android_alarm_manager/CHANGELOG.md | 4 +++ packages/android_alarm_manager/README.md | 14 +--------- .../android_alarm_manager_test.dart | 2 ++ .../example/lib/main.dart | 10 +++---- .../example/pubspec.yaml | 6 ++-- .../example/test_driver/integration_test.dart | 2 ++ .../lib/android_alarm_manager.dart | 28 +++++++++---------- packages/android_alarm_manager/pubspec.yaml | 7 ++--- script/nnbd_plugins.sh | 2 +- 9 files changed, 34 insertions(+), 41 deletions(-) diff --git a/packages/android_alarm_manager/CHANGELOG.md b/packages/android_alarm_manager/CHANGELOG.md index df5b7a2fa752..b06f23c45a30 100644 --- a/packages/android_alarm_manager/CHANGELOG.md +++ b/packages/android_alarm_manager/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Migrate to null safety. + ## 0.4.5+20 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/android_alarm_manager/README.md b/packages/android_alarm_manager/README.md index cf02bf66ff11..5a8a55e43641 100644 --- a/packages/android_alarm_manager/README.md +++ b/packages/android_alarm_manager/README.md @@ -5,13 +5,6 @@ A Flutter plugin for accessing the Android AlarmManager service, and running Dart code in the background when alarms fire. -**Please set your constraint to `android_alarm_manager: '>=0.4.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.4.y+z`. -Please use `android_alarm_manager: '>=0.4.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Getting Started After importing this plugin to your project as usual, add the following to your @@ -109,17 +102,12 @@ Which must be reflected in the application's `AndroidManifest.xml`. E.g.: **Note:** Not calling `AlarmService.setPluginRegistrant` will result in an exception being thrown when an alarm eventually fires. -### Flutter Android Embedding V2 (Flutter Version >= 1.12) +### Flutter Android Embedding V2 For the Flutter Android Embedding V2, plugins are registered with the background isolate via reflection so `AlarmService.setPluginRegistrant` does not need to be called. -**NOTE: this plugin is not completely compatible with the V2 embedding on -Flutter versions < 1.12 as the background isolate will not automatically -register plugins. This can be resolved by running `flutter upgrade` to upgrade -to the latest Flutter version.** - For help getting started with Flutter, view our online [documentation](https://flutter.dev/). diff --git a/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart b/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart index 4d2e3201eecf..4d53a5a945e6 100644 --- a/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart +++ b/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; import 'dart:io'; import 'package:android_alarm_manager_example/main.dart' as app; diff --git a/packages/android_alarm_manager/example/lib/main.dart b/packages/android_alarm_manager/example/lib/main.dart index ac27fec2e4c6..dc3779c8cbe2 100644 --- a/packages/android_alarm_manager/example/lib/main.dart +++ b/packages/android_alarm_manager/example/lib/main.dart @@ -22,7 +22,7 @@ const String isolateName = 'isolate'; final ReceivePort port = ReceivePort(); /// Global [SharedPreferences] object. -SharedPreferences prefs; +late SharedPreferences prefs; Future main() async { // TODO(bkonyi): uncomment @@ -54,7 +54,7 @@ class AlarmManagerExampleApp extends StatelessWidget { } class _AlarmHomePage extends StatefulWidget { - _AlarmHomePage({Key key, this.title}) : super(key: key); + _AlarmHomePage({Key? key, required this.title}) : super(key: key); final String title; @override @@ -86,7 +86,7 @@ class _AlarmHomePageState extends State<_AlarmHomePage> { } // The background - static SendPort uiSendPort; + static SendPort? uiSendPort; // The callback for our alarm static Future callback() async { @@ -94,7 +94,7 @@ class _AlarmHomePageState extends State<_AlarmHomePage> { // Get the previous cached count and increment it. final prefs = await SharedPreferences.getInstance(); - int currentCount = prefs.getInt(countKey); + int currentCount = prefs.getInt(countKey) ?? 0; await prefs.setInt(countKey, currentCount + 1); // This will be null if we're running in the background. @@ -140,7 +140,7 @@ class _AlarmHomePageState extends State<_AlarmHomePage> { await AndroidAlarmManager.oneShot( const Duration(seconds: 5), // Ensure we have a unique alarm ID. - Random().nextInt(pow(2, 31)), + Random().nextInt(pow(2, 31).toInt()), callback, exact: true, wakeup: true, diff --git a/packages/android_alarm_manager/example/pubspec.yaml b/packages/android_alarm_manager/example/pubspec.yaml index 6fce3464b92a..029a60493193 100644 --- a/packages/android_alarm_manager/example/pubspec.yaml +++ b/packages/android_alarm_manager/example/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - shared_preferences: ^0.5.6 + shared_preferences: ^2.0.0-nullsafety integration_test: path: ../../integration_test - path_provider: ^1.3.1 + path_provider: ^2.0.0-nullsafety dev_dependencies: espresso: ^0.0.1+3 @@ -28,5 +28,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.12.13+hotfix.5" diff --git a/packages/android_alarm_manager/example/test_driver/integration_test.dart b/packages/android_alarm_manager/example/test_driver/integration_test.dart index ed54518d7d00..4e78d04fa971 100644 --- a/packages/android_alarm_manager/example/test_driver/integration_test.dart +++ b/packages/android_alarm_manager/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/android_alarm_manager/lib/android_alarm_manager.dart b/packages/android_alarm_manager/lib/android_alarm_manager.dart index b8afa134472c..218959bc4bcc 100644 --- a/packages/android_alarm_manager/lib/android_alarm_manager.dart +++ b/packages/android_alarm_manager/lib/android_alarm_manager.dart @@ -31,7 +31,7 @@ void _alarmManagerCallbackDispatcher() { // PluginUtilities.getCallbackFromHandle performs a lookup based on the // callback handle and returns a tear-off of the original callback. - final Function closure = PluginUtilities.getCallbackFromHandle(handle); + final Function? closure = PluginUtilities.getCallbackFromHandle(handle); if (closure == null) { print('Fatal: could not find callback'); @@ -56,7 +56,7 @@ void _alarmManagerCallbackDispatcher() { // A lambda that returns the current instant in the form of a [DateTime]. typedef DateTime _Now(); // A lambda that gets the handle for the given [callback]. -typedef CallbackHandle _GetCallbackHandle(Function callback); +typedef CallbackHandle? _GetCallbackHandle(Function callback); /// A Flutter plugin for registering Dart callbacks with the Android /// AlarmManager service. @@ -77,7 +77,7 @@ class AndroidAlarmManager { /// the plugin. @visibleForTesting static void setTestOverides( - {_Now now, _GetCallbackHandle getCallbackHandle}) { + {_Now? now, _GetCallbackHandle? getCallbackHandle}) { _now = (now ?? _now); _getCallbackHandle = (getCallbackHandle ?? _getCallbackHandle); } @@ -88,12 +88,12 @@ class AndroidAlarmManager { /// Returns a [Future] that resolves to `true` on success and `false` on /// failure. static Future initialize() async { - final CallbackHandle handle = + final CallbackHandle? handle = _getCallbackHandle(_alarmManagerCallbackDispatcher); if (handle == null) { return false; } - final bool r = await _channel.invokeMethod( + final bool? r = await _channel.invokeMethod( 'AlarmService.start', [handle.toRawHandle()]); return r ?? false; } @@ -207,11 +207,11 @@ class AndroidAlarmManager { assert(callback is Function() || callback is Function(int)); assert(id.bitLength < 32); final int startMillis = time.millisecondsSinceEpoch; - final CallbackHandle handle = _getCallbackHandle(callback); + final CallbackHandle? handle = _getCallbackHandle(callback); if (handle == null) { return false; } - final bool r = + final bool? r = await _channel.invokeMethod('Alarm.oneShotAt', [ id, alarmClock, @@ -222,7 +222,7 @@ class AndroidAlarmManager { rescheduleOnReboot, handle.toRawHandle(), ]); - return (r == null) ? false : r; + return r ?? false; } /// Schedules a repeating timer to run `callback` with period `duration`. @@ -262,7 +262,7 @@ class AndroidAlarmManager { Duration duration, int id, Function callback, { - DateTime startAt, + DateTime? startAt, bool exact = false, bool wakeup = false, bool rescheduleOnReboot = false, @@ -274,11 +274,11 @@ class AndroidAlarmManager { final int period = duration.inMilliseconds; final int first = startAt != null ? startAt.millisecondsSinceEpoch : now + period; - final CallbackHandle handle = _getCallbackHandle(callback); + final CallbackHandle? handle = _getCallbackHandle(callback); if (handle == null) { return false; } - final bool r = await _channel.invokeMethod( + final bool? r = await _channel.invokeMethod( 'Alarm.periodic', [ id, exact, @@ -288,7 +288,7 @@ class AndroidAlarmManager { rescheduleOnReboot, handle.toRawHandle() ]); - return (r == null) ? false : r; + return r ?? false; } /// Cancels a timer. @@ -299,8 +299,8 @@ class AndroidAlarmManager { /// Returns a [Future] that resolves to `true` on success and `false` on /// failure. static Future cancel(int id) async { - final bool r = + final bool? r = await _channel.invokeMethod('Alarm.cancel', [id]); - return (r == null) ? false : r; + return r ?? false; } } diff --git a/packages/android_alarm_manager/pubspec.yaml b/packages/android_alarm_manager/pubspec.yaml index d1771c0f0380..ab1937242859 100644 --- a/packages/android_alarm_manager/pubspec.yaml +++ b/packages/android_alarm_manager/pubspec.yaml @@ -1,10 +1,7 @@ name: android_alarm_manager description: Flutter plugin for accessing the Android AlarmManager service, and running Dart code in the background when alarms fire. -# 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.4.5+20 +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/android_alarm_manager dependencies: @@ -24,5 +21,5 @@ flutter: pluginClass: AndroidAlarmManagerPlugin environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.12.13+hotfix.5" diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 492c8adf3ad5..5a54a7ff30d6 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -5,6 +5,7 @@ # null-safe is available on stable. readonly NNBD_PLUGINS_LIST=( + "android_alarm_manager" "android_intent" "battery" "camera" @@ -36,7 +37,6 @@ readonly NNBD_PLUGINS_LIST=( # building the all plugins app. This list should be kept empty. readonly NON_NNBD_PLUGINS_LIST=( - # "android_alarm_manager" "camera" # "google_maps_flutter" # "image_picker" From e0262421d2c9133438c7f5cb5ceea19452665c27 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Fri, 12 Feb 2021 13:46:44 -0800 Subject: [PATCH 189/924] Move plugin tools code (#3544) --- .gitmodules | 3 - script/common.sh | 4 +- script/plugin_tools | 1 - script/tool/README.md | 8 + script/tool/lib/src/analyze_command.dart | 94 ++++ .../tool/lib/src/build_examples_command.dart | 188 +++++++ script/tool/lib/src/common.dart | 466 ++++++++++++++++++ .../src/create_all_plugins_app_command.dart | 200 ++++++++ .../tool/lib/src/drive_examples_command.dart | 210 ++++++++ .../lib/src/firebase_test_lab_command.dart | 264 ++++++++++ script/tool/lib/src/format_command.dart | 147 ++++++ script/tool/lib/src/java_test_command.dart | 89 ++++ .../tool/lib/src/lint_podspecs_command.dart | 146 ++++++ script/tool/lib/src/list_command.dart | 60 +++ script/tool/lib/src/main.dart | 63 +++ .../tool/lib/src/publish_plugin_command.dart | 223 +++++++++ script/tool/lib/src/test_command.dart | 101 ++++ .../tool/lib/src/version_check_command.dart | 220 +++++++++ script/tool/lib/src/xctest_command.dart | 216 ++++++++ script/tool/pubspec.yaml | 25 + 20 files changed, 2722 insertions(+), 6 deletions(-) delete mode 100644 .gitmodules delete mode 160000 script/plugin_tools create mode 100644 script/tool/README.md create mode 100644 script/tool/lib/src/analyze_command.dart create mode 100644 script/tool/lib/src/build_examples_command.dart create mode 100644 script/tool/lib/src/common.dart create mode 100644 script/tool/lib/src/create_all_plugins_app_command.dart create mode 100644 script/tool/lib/src/drive_examples_command.dart create mode 100644 script/tool/lib/src/firebase_test_lab_command.dart create mode 100644 script/tool/lib/src/format_command.dart create mode 100644 script/tool/lib/src/java_test_command.dart create mode 100644 script/tool/lib/src/lint_podspecs_command.dart create mode 100644 script/tool/lib/src/list_command.dart create mode 100644 script/tool/lib/src/main.dart create mode 100644 script/tool/lib/src/publish_plugin_command.dart create mode 100644 script/tool/lib/src/test_command.dart create mode 100644 script/tool/lib/src/version_check_command.dart create mode 100644 script/tool/lib/src/xctest_command.dart create mode 100644 script/tool/pubspec.yaml diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index d83ab14b23a0..000000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "script/plugin_tools"] - path = script/plugin_tools - url = https://github.com/flutter/plugin_tools.git diff --git a/script/common.sh b/script/common.sh index 4c8aff9822f6..28c37540af88 100644 --- a/script/common.sh +++ b/script/common.sh @@ -48,6 +48,6 @@ function check_changed_packages() { # Runs the plugin tools from the plugin_tools git submodule. function plugin_tools() { - (pushd "$REPO_DIR/script/plugin_tools" && dart pub get && popd) >/dev/null - dart run "$REPO_DIR/script/plugin_tools/lib/src/main.dart" "$@" + (pushd "$REPO_DIR/script/tool" && dart pub get && popd) >/dev/null + dart run "$REPO_DIR/script/tool/lib/src/main.dart" "$@" } diff --git a/script/plugin_tools b/script/plugin_tools deleted file mode 160000 index 432c56da3588..000000000000 --- a/script/plugin_tools +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 432c56da35880e95f6cbb02c40e9da0361771f48 diff --git a/script/tool/README.md b/script/tool/README.md new file mode 100644 index 000000000000..162ca0d98a74 --- /dev/null +++ b/script/tool/README.md @@ -0,0 +1,8 @@ +# Flutter Plugin Tools + +To run the tool: + +```sh +dart pub get +dart run lib/src/main.dart +``` diff --git a/script/tool/lib/src/analyze_command.dart b/script/tool/lib/src/analyze_command.dart new file mode 100644 index 000000000000..8cd57fa0b338 --- /dev/null +++ b/script/tool/lib/src/analyze_command.dart @@ -0,0 +1,94 @@ +// 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:async'; + +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; + +import 'common.dart'; + +class AnalyzeCommand extends PluginCommand { + AnalyzeCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + }) : super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addMultiOption(_customAnalysisFlag, + help: + 'Directories (comma seperated) that are allowed to have their own analysis options.', + defaultsTo: []); + } + + static const String _customAnalysisFlag = 'custom-analysis'; + + @override + final String name = 'analyze'; + + @override + final String description = 'Analyzes all packages using package:tuneup.\n\n' + 'This command requires "pub" and "flutter" to be in your path.'; + + @override + Future run() async { + checkSharding(); + + print('Verifying analysis settings...'); + final List files = packagesDir.listSync(recursive: true); + for (final FileSystemEntity file in files) { + if (file.basename != 'analysis_options.yaml' && + file.basename != '.analysis_options') { + continue; + } + + final bool whitelisted = argResults[_customAnalysisFlag].any( + (String directory) => + p.isWithin(p.join(packagesDir.path, directory), file.path)); + if (whitelisted) { + continue; + } + + print('Found an extra analysis_options.yaml in ${file.absolute.path}.'); + print( + 'If this was deliberate, pass the package to the analyze command with the --$_customAnalysisFlag flag and try again.'); + throw ToolExit(1); + } + + print('Activating tuneup package...'); + await processRunner.runAndStream( + 'pub', ['global', 'activate', 'tuneup'], + workingDir: packagesDir, exitOnError: true); + + await for (Directory package in getPackages()) { + if (isFlutterPackage(package, fileSystem)) { + await processRunner.runAndStream('flutter', ['packages', 'get'], + workingDir: package, exitOnError: true); + } else { + await processRunner.runAndStream('pub', ['get'], + workingDir: package, exitOnError: true); + } + } + + final List failingPackages = []; + await for (Directory package in getPlugins()) { + final int exitCode = await processRunner.runAndStream( + 'pub', ['global', 'run', 'tuneup', 'check'], + workingDir: package); + if (exitCode != 0) { + failingPackages.add(p.basename(package.path)); + } + } + + print('\n\n'); + if (failingPackages.isNotEmpty) { + print('The following packages have analyzer errors (see above):'); + failingPackages.forEach((String package) { + print(' * $package'); + }); + throw ToolExit(1); + } + + print('No analyzer errors found!'); + } +} diff --git a/script/tool/lib/src/build_examples_command.dart b/script/tool/lib/src/build_examples_command.dart new file mode 100644 index 000000000000..53da9086abaa --- /dev/null +++ b/script/tool/lib/src/build_examples_command.dart @@ -0,0 +1,188 @@ +// 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:async'; +import 'dart:io' as io; + +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; +import 'package:platform/platform.dart'; + +import 'common.dart'; + +class BuildExamplesCommand extends PluginCommand { + BuildExamplesCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + }) : super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addFlag(kLinux, defaultsTo: false); + argParser.addFlag(kMacos, defaultsTo: false); + argParser.addFlag(kWindows, defaultsTo: false); + argParser.addFlag(kIpa, defaultsTo: io.Platform.isMacOS); + argParser.addFlag(kApk); + argParser.addOption( + kEnableExperiment, + defaultsTo: '', + help: 'Enables the given Dart SDK experiments.', + ); + } + + @override + final String name = 'build-examples'; + + @override + final String description = + 'Builds all example apps (IPA for iOS and APK for Android).\n\n' + 'This command requires "flutter" to be in your path.'; + + @override + Future run() async { + if (!argResults[kIpa] && + !argResults[kApk] && + !argResults[kLinux] && + !argResults[kMacos] && + !argResults[kWindows]) { + print( + 'None of --linux, --macos, --windows, --apk nor --ipa were specified, ' + 'so not building anything.'); + return; + } + final String flutterCommand = + LocalPlatform().isWindows ? 'flutter.bat' : 'flutter'; + + final String enableExperiment = argResults[kEnableExperiment]; + + checkSharding(); + final List failingPackages = []; + await for (Directory plugin in getPlugins()) { + for (Directory example in getExamplesForPlugin(plugin)) { + final String packageName = + p.relative(example.path, from: packagesDir.path); + + if (argResults[kLinux]) { + print('\nBUILDING Linux for $packageName'); + if (isLinuxPlugin(plugin, fileSystem)) { + int buildExitCode = await processRunner.runAndStream( + flutterCommand, + [ + 'build', + kLinux, + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + ], + workingDir: example); + if (buildExitCode != 0) { + failingPackages.add('$packageName (linux)'); + } + } else { + print('Linux is not supported by this plugin'); + } + } + + if (argResults[kMacos]) { + print('\nBUILDING macOS for $packageName'); + if (isMacOsPlugin(plugin, fileSystem)) { + // TODO(https://github.com/flutter/flutter/issues/46236): + // Builing macos without running flutter pub get first results + // in an error. + int exitCode = await processRunner.runAndStream( + flutterCommand, ['pub', 'get'], + workingDir: example); + if (exitCode != 0) { + failingPackages.add('$packageName (macos)'); + } else { + exitCode = await processRunner.runAndStream( + flutterCommand, + [ + 'build', + kMacos, + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + ], + workingDir: example); + if (exitCode != 0) { + failingPackages.add('$packageName (macos)'); + } + } + } else { + print('macOS is not supported by this plugin'); + } + } + + if (argResults[kWindows]) { + print('\nBUILDING Windows for $packageName'); + if (isWindowsPlugin(plugin, fileSystem)) { + int buildExitCode = await processRunner.runAndStream( + flutterCommand, + [ + 'build', + kWindows, + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + ], + workingDir: example); + if (buildExitCode != 0) { + failingPackages.add('$packageName (windows)'); + } + } else { + print('Windows is not supported by this plugin'); + } + } + + if (argResults[kIpa]) { + print('\nBUILDING IPA for $packageName'); + if (isIosPlugin(plugin, fileSystem)) { + final int exitCode = await processRunner.runAndStream( + flutterCommand, + [ + 'build', + 'ios', + '--no-codesign', + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + ], + workingDir: example); + if (exitCode != 0) { + failingPackages.add('$packageName (ipa)'); + } + } else { + print('iOS is not supported by this plugin'); + } + } + + if (argResults[kApk]) { + print('\nBUILDING APK for $packageName'); + if (isAndroidPlugin(plugin, fileSystem)) { + final int exitCode = await processRunner.runAndStream( + flutterCommand, + [ + 'build', + 'apk', + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + ], + workingDir: example); + if (exitCode != 0) { + failingPackages.add('$packageName (apk)'); + } + } else { + print('Android is not supported by this plugin'); + } + } + } + } + print('\n\n'); + + if (failingPackages.isNotEmpty) { + print('The following build are failing (see above for details):'); + for (String package in failingPackages) { + print(' * $package'); + } + throw ToolExit(1); + } + + print('All builds successful!'); + } +} diff --git a/script/tool/lib/src/common.dart b/script/tool/lib/src/common.dart new file mode 100644 index 000000000000..78b91ee8a75b --- /dev/null +++ b/script/tool/lib/src/common.dart @@ -0,0 +1,466 @@ +// 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:async'; +import 'dart:io' as io; +import 'dart:math'; + +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; +import 'package:yaml/yaml.dart'; + +typedef void Print(Object object); + +/// Key for windows platform. +const String kWindows = 'windows'; + +/// Key for macos platform. +const String kMacos = 'macos'; + +/// Key for linux platform. +const String kLinux = 'linux'; + +/// Key for IPA (iOS) platform. +const String kIos = 'ios'; + +/// Key for APK (Android) platform. +const String kAndroid = 'android'; + +/// Key for Web platform. +const String kWeb = 'web'; + +/// Key for IPA. +const String kIpa = 'ipa'; + +/// Key for APK. +const String kApk = 'apk'; + +/// Key for enable experiment. +const String kEnableExperiment = 'enable-experiment'; + +/// Returns whether the given directory contains a Flutter package. +bool isFlutterPackage(FileSystemEntity entity, FileSystem fileSystem) { + if (entity == null || entity is! Directory) { + return false; + } + + try { + final File pubspecFile = + fileSystem.file(p.join(entity.path, 'pubspec.yaml')); + final YamlMap pubspecYaml = loadYaml(pubspecFile.readAsStringSync()); + final YamlMap dependencies = pubspecYaml['dependencies']; + if (dependencies == null) { + return false; + } + return dependencies.containsKey('flutter'); + } on FileSystemException { + return false; + } on YamlException { + return false; + } +} + +/// Returns whether the given directory contains a Flutter [platform] plugin. +/// +/// It checks this by looking for the following pattern in the pubspec: +/// +/// flutter: +/// plugin: +/// platforms: +/// [platform]: +bool pluginSupportsPlatform( + String platform, FileSystemEntity entity, FileSystem fileSystem) { + assert(platform == kIos || + platform == kAndroid || + platform == kWeb || + platform == kMacos || + platform == kWindows || + platform == kLinux); + if (entity == null || entity is! Directory) { + return false; + } + + try { + final File pubspecFile = + fileSystem.file(p.join(entity.path, 'pubspec.yaml')); + final YamlMap pubspecYaml = loadYaml(pubspecFile.readAsStringSync()); + final YamlMap flutterSection = pubspecYaml['flutter']; + if (flutterSection == null) { + return false; + } + final YamlMap pluginSection = flutterSection['plugin']; + if (pluginSection == null) { + return false; + } + final YamlMap platforms = pluginSection['platforms']; + if (platforms == null) { + // Legacy plugin specs are assumed to support iOS and Android. + if (!pluginSection.containsKey('platforms')) { + return platform == kIos || platform == kAndroid; + } + return false; + } + return platforms.containsKey(platform); + } on FileSystemException { + return false; + } on YamlException { + return false; + } +} + +/// Returns whether the given directory contains a Flutter Android plugin. +bool isAndroidPlugin(FileSystemEntity entity, FileSystem fileSystem) { + return pluginSupportsPlatform(kAndroid, entity, fileSystem); +} + +/// Returns whether the given directory contains a Flutter iOS plugin. +bool isIosPlugin(FileSystemEntity entity, FileSystem fileSystem) { + return pluginSupportsPlatform(kIos, entity, fileSystem); +} + +/// Returns whether the given directory contains a Flutter web plugin. +bool isWebPlugin(FileSystemEntity entity, FileSystem fileSystem) { + return pluginSupportsPlatform(kWeb, entity, fileSystem); +} + +/// Returns whether the given directory contains a Flutter Windows plugin. +bool isWindowsPlugin(FileSystemEntity entity, FileSystem fileSystem) { + return pluginSupportsPlatform(kWindows, entity, fileSystem); +} + +/// Returns whether the given directory contains a Flutter macOS plugin. +bool isMacOsPlugin(FileSystemEntity entity, FileSystem fileSystem) { + return pluginSupportsPlatform(kMacos, entity, fileSystem); +} + +/// Returns whether the given directory contains a Flutter linux plugin. +bool isLinuxPlugin(FileSystemEntity entity, FileSystem fileSystem) { + return pluginSupportsPlatform(kLinux, entity, fileSystem); +} + +/// Error thrown when a command needs to exit with a non-zero exit code. +class ToolExit extends Error { + ToolExit(this.exitCode); + + final int exitCode; +} + +abstract class PluginCommand extends Command { + PluginCommand( + this.packagesDir, + this.fileSystem, { + this.processRunner = const ProcessRunner(), + }) { + argParser.addMultiOption( + _pluginsArg, + splitCommas: true, + help: + 'Specifies which plugins the command should run on (before sharding).', + valueHelp: 'plugin1,plugin2,...', + ); + argParser.addOption( + _shardIndexArg, + help: 'Specifies the zero-based index of the shard to ' + 'which the command applies.', + valueHelp: 'i', + defaultsTo: '0', + ); + argParser.addOption( + _shardCountArg, + help: 'Specifies the number of shards into which plugins are divided.', + valueHelp: 'n', + defaultsTo: '1', + ); + argParser.addMultiOption( + _excludeArg, + abbr: 'e', + help: 'Exclude packages from this command.', + defaultsTo: [], + ); + } + + static const String _pluginsArg = 'plugins'; + static const String _shardIndexArg = 'shardIndex'; + static const String _shardCountArg = 'shardCount'; + static const String _excludeArg = 'exclude'; + + /// The directory containing the plugin packages. + final Directory packagesDir; + + /// The file system. + /// + /// This can be overridden for testing. + final FileSystem fileSystem; + + /// The process runner. + /// + /// This can be overridden for testing. + final ProcessRunner processRunner; + + int _shardIndex; + int _shardCount; + + int get shardIndex { + if (_shardIndex == null) { + checkSharding(); + } + return _shardIndex; + } + + int get shardCount { + if (_shardCount == null) { + checkSharding(); + } + return _shardCount; + } + + void checkSharding() { + final int shardIndex = int.tryParse(argResults[_shardIndexArg]); + final int shardCount = int.tryParse(argResults[_shardCountArg]); + if (shardIndex == null) { + usageException('$_shardIndexArg must be an integer'); + } + if (shardCount == null) { + usageException('$_shardCountArg must be an integer'); + } + if (shardCount < 1) { + usageException('$_shardCountArg must be positive'); + } + if (shardIndex < 0 || shardCount <= shardIndex) { + usageException( + '$_shardIndexArg must be in the half-open range [0..$shardCount['); + } + _shardIndex = shardIndex; + _shardCount = shardCount; + } + + /// Returns the root Dart package folders of the plugins involved in this + /// command execution. + Stream getPlugins() async* { + // To avoid assuming consistency of `Directory.list` across command + // invocations, we collect and sort the plugin folders before sharding. + // This is considered an implementation detail which is why the API still + // uses streams. + final List allPlugins = await _getAllPlugins().toList(); + allPlugins.sort((Directory d1, Directory d2) => d1.path.compareTo(d2.path)); + // Sharding 10 elements into 3 shards should yield shard sizes 4, 4, 2. + // Sharding 9 elements into 3 shards should yield shard sizes 3, 3, 3. + // Sharding 2 elements into 3 shards should yield shard sizes 1, 1, 0. + final int shardSize = allPlugins.length ~/ shardCount + + (allPlugins.length % shardCount == 0 ? 0 : 1); + final int start = min(shardIndex * shardSize, allPlugins.length); + final int end = min(start + shardSize, allPlugins.length); + + for (Directory plugin in allPlugins.sublist(start, end)) { + yield plugin; + } + } + + /// Returns the root Dart package folders of the plugins involved in this + /// command execution, assuming there is only one shard. + /// + /// Plugin packages can exist in one of two places relative to the packages + /// directory. + /// + /// 1. As a Dart package in a directory which is a direct child of the + /// packages directory. This is a plugin where all of the implementations + /// exist in a single Dart package. + /// 2. Several plugin packages may live in a directory which is a direct + /// child of the packages directory. This directory groups several Dart + /// packages which implement a single plugin. This directory contains a + /// "client library" package, which declares the API for the plugin, as + /// well as one or more platform-specific implementations. + Stream _getAllPlugins() async* { + final Set plugins = Set.from(argResults[_pluginsArg]); + final Set excludedPlugins = + Set.from(argResults[_excludeArg]); + + await for (FileSystemEntity entity + in packagesDir.list(followLinks: false)) { + // A top-level Dart package is a plugin package. + if (_isDartPackage(entity)) { + if (!excludedPlugins.contains(entity.basename) && + (plugins.isEmpty || plugins.contains(p.basename(entity.path)))) { + yield entity; + } + } else if (entity is Directory) { + // Look for Dart packages under this top-level directory. + await for (FileSystemEntity subdir in entity.list(followLinks: false)) { + if (_isDartPackage(subdir)) { + // If --plugin=my_plugin is passed, then match all federated + // plugins under 'my_plugin'. Also match if the exact plugin is + // passed. + final String relativePath = + p.relative(subdir.path, from: packagesDir.path); + final String basenamePath = p.basename(entity.path); + if (!excludedPlugins.contains(basenamePath) && + !excludedPlugins.contains(relativePath) && + (plugins.isEmpty || + plugins.contains(relativePath) || + plugins.contains(basenamePath))) { + yield subdir; + } + } + } + } + } + } + + /// Returns the example Dart package folders of the plugins involved in this + /// command execution. + Stream getExamples() => + getPlugins().expand(getExamplesForPlugin); + + /// Returns all Dart package folders (typically, plugin + example) of the + /// plugins involved in this command execution. + Stream getPackages() async* { + await for (Directory plugin in getPlugins()) { + yield plugin; + yield* plugin + .list(recursive: true, followLinks: false) + .where(_isDartPackage) + .cast(); + } + } + + /// Returns the files contained, recursively, within the plugins + /// involved in this command execution. + Stream getFiles() { + return getPlugins().asyncExpand((Directory folder) => folder + .list(recursive: true, followLinks: false) + .where((FileSystemEntity entity) => entity is File) + .cast()); + } + + /// Returns whether the specified entity is a directory containing a + /// `pubspec.yaml` file. + bool _isDartPackage(FileSystemEntity entity) { + return entity is Directory && + fileSystem.file(p.join(entity.path, 'pubspec.yaml')).existsSync(); + } + + /// Returns the example Dart packages contained in the specified plugin, or + /// an empty List, if the plugin has no examples. + Iterable getExamplesForPlugin(Directory plugin) { + final Directory exampleFolder = + fileSystem.directory(p.join(plugin.path, 'example')); + if (!exampleFolder.existsSync()) { + return []; + } + if (isFlutterPackage(exampleFolder, fileSystem)) { + return [exampleFolder]; + } + // Only look at the subdirectories of the example directory if the example + // directory itself is not a Dart package, and only look one level below the + // example directory for other dart packages. + return exampleFolder + .listSync() + .where( + (FileSystemEntity entity) => isFlutterPackage(entity, fileSystem)) + .cast(); + } +} + +/// A class used to run processes. +/// +/// We use this instead of directly running the process so it can be overridden +/// in tests. +class ProcessRunner { + const ProcessRunner(); + + /// Run the [executable] with [args] and stream output to stderr and stdout. + /// + /// The current working directory of [executable] can be overridden by + /// passing [workingDir]. + /// + /// If [exitOnError] is set to `true`, then this will throw an error if + /// the [executable] terminates with a non-zero exit code. + /// + /// Returns the exit code of the [executable]. + Future runAndStream( + String executable, + List args, { + Directory workingDir, + bool exitOnError = false, + }) async { + print( + 'Running command: "$executable ${args.join(' ')}" in ${workingDir?.path ?? io.Directory.current.path}'); + final io.Process process = await io.Process.start(executable, args, + workingDirectory: workingDir?.path); + await io.stdout.addStream(process.stdout); + await io.stderr.addStream(process.stderr); + if (exitOnError && await process.exitCode != 0) { + final String error = + _getErrorString(executable, args, workingDir: workingDir); + print('$error See above for details.'); + throw ToolExit(await process.exitCode); + } + return process.exitCode; + } + + /// Run the [executable] with [args]. + /// + /// The current working directory of [executable] can be overridden by + /// passing [workingDir]. + /// + /// If [exitOnError] is set to `true`, then this will throw an error if + /// the [executable] terminates with a non-zero exit code. + /// + /// Returns the [io.ProcessResult] of the [executable]. + Future run(String executable, List args, + {Directory workingDir, + bool exitOnError = false, + stdoutEncoding = io.systemEncoding, + stderrEncoding = io.systemEncoding}) async { + return io.Process.run(executable, args, + workingDirectory: workingDir?.path, + stdoutEncoding: stdoutEncoding, + stderrEncoding: stderrEncoding); + } + + /// Starts the [executable] with [args]. + /// + /// The current working directory of [executable] can be overridden by + /// passing [workingDir]. + /// + /// Returns the started [io.Process]. + Future start(String executable, List args, + {Directory workingDirectory}) async { + final io.Process process = await io.Process.start(executable, args, + workingDirectory: workingDirectory?.path); + return process; + } + + /// Run the [executable] with [args], throwing an error on non-zero exit code. + /// + /// Unlike [runAndStream], this does not stream the process output to stdout. + /// It also unconditionally throws an error on a non-zero exit code. + /// + /// The current working directory of [executable] can be overridden by + /// passing [workingDir]. + /// + /// Returns the [io.ProcessResult] of running the [executable]. + Future runAndExitOnError( + String executable, + List args, { + Directory workingDir, + }) async { + final io.ProcessResult result = await io.Process.run(executable, args, + workingDirectory: workingDir?.path); + if (result.exitCode != 0) { + final String error = + _getErrorString(executable, args, workingDir: workingDir); + print('$error Stderr:\n${result.stdout}'); + throw ToolExit(result.exitCode); + } + return result; + } + + String _getErrorString(String executable, List args, + {Directory workingDir}) { + final String workdir = workingDir == null ? '' : ' in ${workingDir.path}'; + return 'ERROR: Unable to execute "$executable ${args.join(' ')}"$workdir.'; + } +} diff --git a/script/tool/lib/src/create_all_plugins_app_command.dart b/script/tool/lib/src/create_all_plugins_app_command.dart new file mode 100644 index 000000000000..0f1431c5aee0 --- /dev/null +++ b/script/tool/lib/src/create_all_plugins_app_command.dart @@ -0,0 +1,200 @@ +// Copyright 2019 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:async'; +import 'dart:io' as io; + +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; +import 'package:pubspec_parse/pubspec_parse.dart'; + +import 'common.dart'; + +// TODO(cyanglaz): Add tests for this command. +// https://github.com/flutter/flutter/issues/61049 +class CreateAllPluginsAppCommand extends PluginCommand { + CreateAllPluginsAppCommand(Directory packagesDir, FileSystem fileSystem) + : super(packagesDir, fileSystem); + + @override + String get description => + 'Generate Flutter app that includes all plugins in packages.'; + + @override + String get name => 'all-plugins-app'; + + @override + Future run() async { + final int exitCode = await _createPlugin(); + if (exitCode != 0) { + throw ToolExit(exitCode); + } + + await Future.wait(>[ + _genPubspecWithAllPlugins(), + _updateAppGradle(), + _updateManifest(), + ]); + } + + Future _createPlugin() async { + final io.ProcessResult result = io.Process.runSync( + 'flutter', + [ + 'create', + '--template=app', + '--project-name=all_plugins', + '--android-language=java', + './all_plugins', + ], + ); + + print(result.stdout); + print(result.stderr); + return result.exitCode; + } + + Future _updateAppGradle() async { + final File gradleFile = fileSystem.file(p.join( + 'all_plugins', + 'android', + 'app', + 'build.gradle', + )); + if (!gradleFile.existsSync()) { + throw ToolExit(64); + } + + final StringBuffer newGradle = StringBuffer(); + for (String line in gradleFile.readAsLinesSync()) { + newGradle.writeln(line); + if (line.contains('defaultConfig {')) { + newGradle.writeln(' multiDexEnabled true'); + } else if (line.contains('dependencies {')) { + newGradle.writeln( + ' implementation \'com.google.guava:guava:27.0.1-android\'\n', + ); + // Tests for https://github.com/flutter/flutter/issues/43383 + newGradle.writeln( + " implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0-rc01'\n", + ); + } + } + gradleFile.writeAsStringSync(newGradle.toString()); + } + + Future _updateManifest() async { + final File manifestFile = fileSystem.file(p.join( + 'all_plugins', + 'android', + 'app', + 'src', + 'main', + 'AndroidManifest.xml', + )); + if (!manifestFile.existsSync()) { + throw ToolExit(64); + } + + final StringBuffer newManifest = StringBuffer(); + for (String line in manifestFile.readAsLinesSync()) { + if (line.contains('package="com.example.all_plugins"')) { + newManifest + ..writeln('package="com.example.all_plugins"') + ..writeln('xmlns:tools="http://schemas.android.com/tools">') + ..writeln() + ..writeln( + '', + ); + } else { + newManifest.writeln(line); + } + } + manifestFile.writeAsStringSync(newManifest.toString()); + } + + Future _genPubspecWithAllPlugins() async { + final Map pluginDeps = + await _getValidPathDependencies(); + final Pubspec pubspec = Pubspec( + 'all_plugins', + description: 'Flutter app containing all 1st party plugins.', + version: Version.parse('1.0.0+1'), + environment: { + 'sdk': VersionConstraint.compatibleWith( + Version.parse('2.0.0'), + ), + }, + dependencies: { + 'flutter': SdkDependency('flutter'), + }..addAll(pluginDeps), + devDependencies: { + 'flutter_test': SdkDependency('flutter'), + }, + dependencyOverrides: pluginDeps, + ); + final File pubspecFile = + fileSystem.file(p.join('all_plugins', 'pubspec.yaml')); + pubspecFile.writeAsStringSync(_pubspecToString(pubspec)); + } + + Future> _getValidPathDependencies() async { + final Map pathDependencies = + {}; + + await for (Directory package in getPlugins()) { + final String pluginName = package.path.split('/').last; + final File pubspecFile = + fileSystem.file(p.join(package.path, 'pubspec.yaml')); + final Pubspec pubspec = Pubspec.parse(pubspecFile.readAsStringSync()); + + if (pubspec.publishTo != 'none') { + pathDependencies[pluginName] = PathDependency(package.path); + } + } + return pathDependencies; + } + + String _pubspecToString(Pubspec pubspec) { + return ''' +### Generated file. Do not edit. Run `pub global run flutter_plugin_tools gen-pubspec` to update. +name: ${pubspec.name} +description: ${pubspec.description} + +version: ${pubspec.version} + +environment:${_pubspecMapString(pubspec.environment)} + +dependencies:${_pubspecMapString(pubspec.dependencies)} + +dependency_overrides:${_pubspecMapString(pubspec.dependencyOverrides)} + +dev_dependencies:${_pubspecMapString(pubspec.devDependencies)} +###'''; + } + + String _pubspecMapString(Map values) { + final StringBuffer buffer = StringBuffer(); + + for (MapEntry entry in values.entries) { + buffer.writeln(); + if (entry.value is VersionConstraint) { + buffer.write(' ${entry.key}: ${entry.value}'); + } else if (entry.value is SdkDependency) { + final SdkDependency dep = entry.value; + buffer.write(' ${entry.key}: \n sdk: ${dep.sdk}'); + } else if (entry.value is PathDependency) { + final PathDependency dep = entry.value; + buffer.write(' ${entry.key}: \n path: ${dep.path}'); + } else { + throw UnimplementedError( + 'Not available for type: ${entry.value.runtimeType}', + ); + } + } + + return buffer.toString(); + } +} diff --git a/script/tool/lib/src/drive_examples_command.dart b/script/tool/lib/src/drive_examples_command.dart new file mode 100644 index 000000000000..59c642265bae --- /dev/null +++ b/script/tool/lib/src/drive_examples_command.dart @@ -0,0 +1,210 @@ +// Copyright 2019 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:async'; +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; +import 'package:platform/platform.dart'; +import 'common.dart'; + +class DriveExamplesCommand extends PluginCommand { + DriveExamplesCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + }) : super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addFlag(kLinux, + help: 'Runs the Linux implementation of the examples'); + argParser.addFlag(kMacos, + help: 'Runs the macOS implementation of the examples'); + argParser.addFlag(kWindows, + help: 'Runs the Windows implementation of the examples'); + argParser.addFlag(kIos, + help: 'Runs the iOS implementation of the examples'); + argParser.addFlag(kAndroid, + help: 'Runs the Android implementation of the examples'); + argParser.addOption( + kEnableExperiment, + defaultsTo: '', + help: + 'Runs the driver tests in Dart VM with the given experiments enabled.', + ); + } + + @override + final String name = 'drive-examples'; + + @override + final String description = 'Runs driver tests for plugin example apps.\n\n' + 'For each *_test.dart in test_driver/ it drives an application with a ' + 'corresponding name in the test/ or test_driver/ directories.\n\n' + 'For example, test_driver/app_test.dart would match test/app.dart.\n\n' + 'This command requires "flutter" to be in your path.\n\n' + 'If a file with a corresponding name cannot be found, this driver file' + 'will be used to drive the tests that match ' + 'integration_test/*_test.dart.'; + + @override + Future run() async { + checkSharding(); + final List failingTests = []; + final bool isLinux = argResults[kLinux]; + final bool isMacos = argResults[kMacos]; + final bool isWindows = argResults[kWindows]; + await for (Directory plugin in getPlugins()) { + final String flutterCommand = + LocalPlatform().isWindows ? 'flutter.bat' : 'flutter'; + for (Directory example in getExamplesForPlugin(plugin)) { + final String packageName = + p.relative(example.path, from: packagesDir.path); + if (!(await pluginSupportedOnCurrentPlatform(plugin, fileSystem))) { + continue; + } + final Directory driverTests = + fileSystem.directory(p.join(example.path, 'test_driver')); + if (!driverTests.existsSync()) { + // No driver tests available for this example + continue; + } + // Look for driver tests ending in _test.dart in test_driver/ + await for (FileSystemEntity test in driverTests.list()) { + final String driverTestName = + p.relative(test.path, from: driverTests.path); + if (!driverTestName.endsWith('_test.dart')) { + continue; + } + // Try to find a matching app to drive without the _test.dart + final String deviceTestName = driverTestName.replaceAll( + RegExp(r'_test.dart$'), + '.dart', + ); + String deviceTestPath = p.join('test', deviceTestName); + if (!fileSystem + .file(p.join(example.path, deviceTestPath)) + .existsSync()) { + // If the app isn't in test/ folder, look in test_driver/ instead. + deviceTestPath = p.join('test_driver', deviceTestName); + } + + final List targetPaths = []; + if (fileSystem + .file(p.join(example.path, deviceTestPath)) + .existsSync()) { + targetPaths.add(deviceTestPath); + } else { + final Directory integrationTests = + fileSystem.directory(p.join(example.path, 'integration_test')); + + if (await integrationTests.exists()) { + await for (FileSystemEntity integration_test + in integrationTests.list()) { + if (!integration_test.basename.endsWith('_test.dart')) { + continue; + } + targetPaths + .add(p.relative(integration_test.path, from: example.path)); + } + } + + if (targetPaths.isEmpty) { + print(''' +Unable to infer a target application for $driverTestName to drive. +Tried searching for the following: +1. test/$deviceTestName +2. test_driver/$deviceTestName +3. test_driver/*_test.dart +'''); + failingTests.add(p.relative(test.path, from: example.path)); + continue; + } + } + + final List driveArgs = ['drive']; + + final String enableExperiment = argResults[kEnableExperiment]; + if (enableExperiment.isNotEmpty) { + driveArgs.add('--enable-experiment=$enableExperiment'); + } + + if (isLinux && isLinuxPlugin(plugin, fileSystem)) { + driveArgs.addAll([ + '-d', + 'linux', + ]); + } + if (isMacos && isMacOsPlugin(plugin, fileSystem)) { + driveArgs.addAll([ + '-d', + 'macos', + ]); + } + if (isWindows && isWindowsPlugin(plugin, fileSystem)) { + driveArgs.addAll([ + '-d', + 'windows', + ]); + } + + for (final targetPath in targetPaths) { + final int exitCode = await processRunner.runAndStream( + flutterCommand, + [ + ...driveArgs, + '--driver', + p.join('test_driver', driverTestName), + '--target', + targetPath, + ], + workingDir: example, + exitOnError: true); + if (exitCode != 0) { + failingTests.add(p.join(packageName, deviceTestPath)); + } + } + } + } + } + print('\n\n'); + + if (failingTests.isNotEmpty) { + print('The following driver tests are failing (see above for details):'); + for (String test in failingTests) { + print(' * $test'); + } + throw ToolExit(1); + } + + print('All driver tests successful!'); + } + + Future pluginSupportedOnCurrentPlatform( + FileSystemEntity plugin, FileSystem fileSystem) async { + final bool isLinux = argResults[kLinux]; + final bool isMacos = argResults[kMacos]; + final bool isWindows = argResults[kWindows]; + final bool isIOS = argResults[kIos]; + final bool isAndroid = argResults[kAndroid]; + if (isLinux) { + return isLinuxPlugin(plugin, fileSystem); + } + if (isMacos) { + return isMacOsPlugin(plugin, fileSystem); + } + if (isWindows) { + return isWindowsPlugin(plugin, fileSystem); + } + if (isIOS) { + return isIosPlugin(plugin, fileSystem); + } + if (isAndroid) { + return (isAndroidPlugin(plugin, fileSystem)); + } + // When we are here, no flags are specified. Only return true if the plugin supports mobile for legacy command support. + // TODO(cyanglaz): Make mobile platforms flags also required like other platforms (breaking change). + // https://github.com/flutter/flutter/issues/58285 + final bool isMobilePlugin = + isIosPlugin(plugin, fileSystem) || isAndroidPlugin(plugin, fileSystem); + return isMobilePlugin; + } +} diff --git a/script/tool/lib/src/firebase_test_lab_command.dart b/script/tool/lib/src/firebase_test_lab_command.dart new file mode 100644 index 000000000000..0b4b2a471dbc --- /dev/null +++ b/script/tool/lib/src/firebase_test_lab_command.dart @@ -0,0 +1,264 @@ +// Copyright 2018 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:async'; +import 'dart:io' as io; + +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; +import 'package:uuid/uuid.dart'; + +import 'common.dart'; + +class FirebaseTestLabCommand extends PluginCommand { + FirebaseTestLabCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + Print print = print, + }) : _print = print, + super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addOption( + 'project', + defaultsTo: 'flutter-infra', + help: 'The Firebase project name.', + ); + argParser.addOption('service-key', + defaultsTo: + p.join(io.Platform.environment['HOME'], 'gcloud-service-key.json')); + argParser.addOption('test-run-id', + defaultsTo: Uuid().v4(), + help: + 'Optional string to append to the results path, to avoid conflicts. ' + 'Randomly chosen on each invocation if none is provided. ' + 'The default shown here is just an example.'); + argParser.addMultiOption('device', + splitCommas: false, + defaultsTo: [ + 'model=walleye,version=26', + 'model=flame,version=29' + ], + help: + 'Device model(s) to test. See https://cloud.google.com/sdk/gcloud/reference/firebase/test/android/run for more info'); + argParser.addOption('results-bucket', + defaultsTo: 'gs://flutter_firebase_testlab'); + argParser.addOption( + kEnableExperiment, + defaultsTo: '', + help: 'Enables the given Dart SDK experiments.', + ); + } + + @override + final String name = 'firebase-test-lab'; + + @override + final String description = 'Runs the instrumentation tests of the example ' + 'apps on Firebase Test Lab.\n\n' + 'Runs tests in test_instrumentation folder using the ' + 'instrumentation_test package.'; + + static const String _gradleWrapper = 'gradlew'; + + final Print _print; + + Completer _firebaseProjectConfigured; + + Future _configureFirebaseProject() async { + if (_firebaseProjectConfigured != null) { + return _firebaseProjectConfigured.future; + } else { + _firebaseProjectConfigured = Completer(); + } + await processRunner.runAndExitOnError('gcloud', [ + 'auth', + 'activate-service-account', + '--key-file=${argResults['service-key']}', + ]); + int exitCode = await processRunner.runAndStream('gcloud', [ + 'config', + 'set', + 'project', + argResults['project'], + ]); + if (exitCode == 0) { + _print('\nFirebase project configured.'); + return; + } else { + _print( + '\nWarning: gcloud config set returned a non-zero exit code. Continuing anyway.'); + } + _firebaseProjectConfigured.complete(null); + } + + @override + Future run() async { + checkSharding(); + final Stream packagesWithTests = getPackages().where( + (Directory d) => + isFlutterPackage(d, fileSystem) && + fileSystem + .directory(p.join( + d.path, 'example', 'android', 'app', 'src', 'androidTest')) + .existsSync()); + + final List failingPackages = []; + final List missingFlutterBuild = []; + int resultsCounter = + 0; // We use a unique GCS bucket for each Firebase Test Lab run + await for (Directory package in packagesWithTests) { + // See https://github.com/flutter/flutter/issues/38983 + + final Directory exampleDirectory = + fileSystem.directory(p.join(package.path, 'example')); + final String packageName = + p.relative(package.path, from: packagesDir.path); + _print('\nRUNNING FIREBASE TEST LAB TESTS for $packageName'); + + final Directory androidDirectory = + fileSystem.directory(p.join(exampleDirectory.path, 'android')); + + final String enableExperiment = argResults[kEnableExperiment]; + final String encodedEnableExperiment = + Uri.encodeComponent('--enable-experiment=$enableExperiment'); + + // Ensures that gradle wrapper exists + if (!fileSystem + .file(p.join(androidDirectory.path, _gradleWrapper)) + .existsSync()) { + final int exitCode = await processRunner.runAndStream( + 'flutter', + [ + 'build', + 'apk', + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + ], + workingDir: androidDirectory); + + if (exitCode != 0) { + failingPackages.add(packageName); + continue; + } + continue; + } + + await _configureFirebaseProject(); + + int exitCode = await processRunner.runAndStream( + p.join(androidDirectory.path, _gradleWrapper), + [ + 'app:assembleAndroidTest', + '-Pverbose=true', + if (enableExperiment.isNotEmpty) + '-Pextra-front-end-options=$encodedEnableExperiment', + if (enableExperiment.isNotEmpty) + '-Pextra-gen-snapshot-options=$encodedEnableExperiment', + ], + workingDir: androidDirectory); + + if (exitCode != 0) { + failingPackages.add(packageName); + continue; + } + + // Look for tests recursively in folders that start with 'test' and that + // live in the root or example folders. + bool isTestDir(FileSystemEntity dir) { + return p.basename(dir.path).startsWith('test') || + p.basename(dir.path) == 'integration_test'; + } + + final List testDirs = + package.listSync().where(isTestDir).toList(); + final Directory example = + fileSystem.directory(p.join(package.path, 'example')); + testDirs.addAll(example.listSync().where(isTestDir).toList()); + for (Directory testDir in testDirs) { + bool isE2ETest(FileSystemEntity file) { + return file.path.endsWith('_e2e.dart') || + (file.parent.basename == 'integration_test' && + file.path.endsWith('_test.dart')); + } + + final List testFiles = testDir + .listSync(recursive: true, followLinks: true) + .where(isE2ETest) + .toList(); + for (FileSystemEntity test in testFiles) { + exitCode = await processRunner.runAndStream( + p.join(androidDirectory.path, _gradleWrapper), + [ + 'app:assembleDebug', + '-Pverbose=true', + '-Ptarget=${test.path}', + if (enableExperiment.isNotEmpty) + '-Pextra-front-end-options=$encodedEnableExperiment', + if (enableExperiment.isNotEmpty) + '-Pextra-gen-snapshot-options=$encodedEnableExperiment', + ], + workingDir: androidDirectory); + + if (exitCode != 0) { + failingPackages.add(packageName); + continue; + } + final String buildId = io.Platform.environment['CIRRUS_BUILD_ID']; + final String testRunId = argResults['test-run-id']; + final String resultsDir = + 'plugins_android_test/$packageName/$buildId/$testRunId/${resultsCounter++}/'; + final List args = [ + 'firebase', + 'test', + 'android', + 'run', + '--type', + 'instrumentation', + '--app', + 'build/app/outputs/apk/debug/app-debug.apk', + '--test', + 'build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk', + '--timeout', + '5m', + '--results-bucket=${argResults['results-bucket']}', + '--results-dir=${resultsDir}', + ]; + for (String device in argResults['device']) { + args.addAll(['--device', device]); + } + exitCode = await processRunner.runAndStream('gcloud', args, + workingDir: exampleDirectory); + + if (exitCode != 0) { + failingPackages.add(packageName); + continue; + } + } + } + } + + _print('\n\n'); + if (failingPackages.isNotEmpty) { + _print( + 'The instrumentation tests for the following packages are failing (see above for' + 'details):'); + for (String package in failingPackages) { + _print(' * $package'); + } + } + if (missingFlutterBuild.isNotEmpty) { + _print('Run "pub global run flutter_plugin_tools build-examples --apk" on' + 'the following packages before executing tests again:'); + for (String package in missingFlutterBuild) { + _print(' * $package'); + } + } + + if (failingPackages.isNotEmpty || missingFlutterBuild.isNotEmpty) { + throw ToolExit(1); + } + + _print('All Firebase Test Lab tests successful!'); + } +} diff --git a/script/tool/lib/src/format_command.dart b/script/tool/lib/src/format_command.dart new file mode 100644 index 000000000000..ec326b96c1f9 --- /dev/null +++ b/script/tool/lib/src/format_command.dart @@ -0,0 +1,147 @@ +// 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:async'; +import 'dart:convert'; +import 'dart:io' as io; + +import 'package:file/file.dart'; +import 'package:http/http.dart' as http; +import 'package:path/path.dart' as p; +import 'package:quiver/iterables.dart'; + +import 'common.dart'; + +const String _googleFormatterUrl = + 'https://github.com/google/google-java-format/releases/download/google-java-format-1.3/google-java-format-1.3-all-deps.jar'; + +class FormatCommand extends PluginCommand { + FormatCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + }) : super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addFlag('travis', hide: true); + argParser.addOption('clang-format', + defaultsTo: 'clang-format', + help: 'Path to executable of clang-format v5.'); + } + + @override + final String name = 'format'; + + @override + final String description = + 'Formats the code of all packages (Java, Objective-C, C++, and Dart).\n\n' + 'This command requires "git", "flutter" and "clang-format" v5 to be in ' + 'your path.'; + + @override + Future run() async { + checkSharding(); + final String googleFormatterPath = await _getGoogleFormatterPath(); + + await _formatDart(); + await _formatJava(googleFormatterPath); + await _formatCppAndObjectiveC(); + + if (argResults['travis']) { + final bool modified = await _didModifyAnything(); + if (modified) { + throw ToolExit(1); + } + } + } + + Future _didModifyAnything() async { + final io.ProcessResult modifiedFiles = await processRunner + .runAndExitOnError('git', ['ls-files', '--modified'], + workingDir: packagesDir); + + print('\n\n'); + + if (modifiedFiles.stdout.isEmpty) { + print('All files formatted correctly.'); + return false; + } + + print('These files are not formatted correctly (see diff below):'); + LineSplitter.split(modifiedFiles.stdout) + .map((String line) => ' $line') + .forEach(print); + + print('\nTo fix run "pub global activate flutter_plugin_tools && ' + 'pub global run flutter_plugin_tools format" or copy-paste ' + 'this command into your terminal:'); + + print('patch -p1 <['diff'], workingDir: packagesDir); + print(diff.stdout); + print('DONE'); + return true; + } + + Future _formatCppAndObjectiveC() async { + print('Formatting all .cc, .cpp, .mm, .m, and .h files...'); + final Iterable allFiles = [] + ..addAll(await _getFilesWithExtension('.h')) + ..addAll(await _getFilesWithExtension('.m')) + ..addAll(await _getFilesWithExtension('.mm')) + ..addAll(await _getFilesWithExtension('.cc')) + ..addAll(await _getFilesWithExtension('.cpp')); + // Split this into multiple invocations to avoid a + // 'ProcessException: Argument list too long'. + final Iterable> batches = partition(allFiles, 100); + for (List batch in batches) { + await processRunner.runAndStream(argResults['clang-format'], + ['-i', '--style=Google']..addAll(batch), + workingDir: packagesDir, exitOnError: true); + } + } + + Future _formatJava(String googleFormatterPath) async { + print('Formatting all .java files...'); + final Iterable javaFiles = await _getFilesWithExtension('.java'); + await processRunner.runAndStream('java', + ['-jar', googleFormatterPath, '--replace']..addAll(javaFiles), + workingDir: packagesDir, exitOnError: true); + } + + Future _formatDart() async { + // This actually should be fine for non-Flutter Dart projects, no need to + // specifically shell out to dartfmt -w in that case. + print('Formatting all .dart files...'); + final Iterable dartFiles = await _getFilesWithExtension('.dart'); + if (dartFiles.isEmpty) { + print( + 'No .dart files to format. If you set the `--exclude` flag, most likey they were skipped'); + } else { + await processRunner.runAndStream( + 'flutter', ['format']..addAll(dartFiles), + workingDir: packagesDir, exitOnError: true); + } + } + + Future> _getFilesWithExtension(String extension) async => + getFiles() + .where((File file) => p.extension(file.path) == extension) + .map((File file) => file.path) + .toList(); + + Future _getGoogleFormatterPath() async { + final String javaFormatterPath = p.join( + p.dirname(p.fromUri(io.Platform.script)), + 'google-java-format-1.3-all-deps.jar'); + final File javaFormatterFile = fileSystem.file(javaFormatterPath); + + if (!javaFormatterFile.existsSync()) { + print('Downloading Google Java Format...'); + final http.Response response = await http.get(_googleFormatterUrl); + javaFormatterFile.writeAsBytesSync(response.bodyBytes); + } + + return javaFormatterPath; + } +} diff --git a/script/tool/lib/src/java_test_command.dart b/script/tool/lib/src/java_test_command.dart new file mode 100644 index 000000000000..cf605bfc5ce2 --- /dev/null +++ b/script/tool/lib/src/java_test_command.dart @@ -0,0 +1,89 @@ +// Copyright 2018 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:async'; + +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; + +import 'common.dart'; + +class JavaTestCommand extends PluginCommand { + JavaTestCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + }) : super(packagesDir, fileSystem, processRunner: processRunner); + + @override + final String name = 'java-test'; + + @override + final String description = 'Runs the Java tests of the example apps.\n\n' + 'Building the apks of the example apps is required before executing this' + 'command.'; + + static const String _gradleWrapper = 'gradlew'; + + @override + Future run() async { + checkSharding(); + final Stream examplesWithTests = getExamples().where( + (Directory d) => + isFlutterPackage(d, fileSystem) && + fileSystem + .directory(p.join(d.path, 'android', 'app', 'src', 'test')) + .existsSync()); + + final List failingPackages = []; + final List missingFlutterBuild = []; + await for (Directory example in examplesWithTests) { + final String packageName = + p.relative(example.path, from: packagesDir.path); + print('\nRUNNING JAVA TESTS for $packageName'); + + final Directory androidDirectory = + fileSystem.directory(p.join(example.path, 'android')); + if (!fileSystem + .file(p.join(androidDirectory.path, _gradleWrapper)) + .existsSync()) { + print('ERROR: Run "flutter build apk" on example app of $packageName' + 'before executing tests.'); + missingFlutterBuild.add(packageName); + continue; + } + + final int exitCode = await processRunner.runAndStream( + p.join(androidDirectory.path, _gradleWrapper), + ['testDebugUnitTest', '--info'], + workingDir: androidDirectory); + if (exitCode != 0) { + failingPackages.add(packageName); + } + } + + print('\n\n'); + if (failingPackages.isNotEmpty) { + print( + 'The Java tests for the following packages are failing (see above for' + 'details):'); + for (String package in failingPackages) { + print(' * $package'); + } + } + if (missingFlutterBuild.isNotEmpty) { + print('Run "pub global run flutter_plugin_tools build-examples --apk" on' + 'the following packages before executing tests again:'); + for (String package in missingFlutterBuild) { + print(' * $package'); + } + } + + if (failingPackages.isNotEmpty || missingFlutterBuild.isNotEmpty) { + throw ToolExit(1); + } + + print('All Java tests successful!'); + } +} diff --git a/script/tool/lib/src/lint_podspecs_command.dart b/script/tool/lib/src/lint_podspecs_command.dart new file mode 100644 index 000000000000..68fd4b61dd66 --- /dev/null +++ b/script/tool/lib/src/lint_podspecs_command.dart @@ -0,0 +1,146 @@ +// 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:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; +import 'package:platform/platform.dart'; + +import 'common.dart'; + +typedef void Print(Object object); + +/// Lint the CocoaPod podspecs, run the static analyzer on iOS/macOS plugin +/// platform code, and run unit tests. +/// +/// See https://guides.cocoapods.org/terminal/commands.html#pod_lib_lint. +class LintPodspecsCommand extends PluginCommand { + LintPodspecsCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + this.platform = const LocalPlatform(), + Print print = print, + }) : _print = print, + super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addMultiOption('skip', + help: + 'Skip all linting for podspecs with this basename (example: federated plugins with placeholder podspecs)', + valueHelp: 'podspec_file_name'); + argParser.addMultiOption('ignore-warnings', + help: + 'Do not pass --allow-warnings flag to "pod lib lint" for podspecs with this basename (example: plugins with known warnings)', + valueHelp: 'podspec_file_name'); + argParser.addMultiOption('no-analyze', + help: + 'Do not pass --analyze flag to "pod lib lint" for podspecs with this basename (example: plugins with known analyzer warnings)', + valueHelp: 'podspec_file_name'); + } + + @override + final String name = 'podspecs'; + + @override + List get aliases => ['podspec']; + + @override + final String description = + 'Runs "pod lib lint" on all iOS and macOS plugin podspecs.\n\n' + 'This command requires "pod" and "flutter" to be in your path. Runs on macOS only.'; + + final Platform platform; + + final Print _print; + + @override + Future run() async { + if (!platform.isMacOS) { + _print('Detected platform is not macOS, skipping podspec lint'); + return; + } + + checkSharding(); + + await processRunner.runAndExitOnError('which', ['pod'], + workingDir: packagesDir); + + _print('Starting podspec lint test'); + + final List failingPlugins = []; + for (File podspec in await _podspecsToLint()) { + if (!await _lintPodspec(podspec)) { + failingPlugins.add(p.basenameWithoutExtension(podspec.path)); + } + } + + _print('\n\n'); + if (failingPlugins.isNotEmpty) { + _print('The following plugins have podspec errors (see above):'); + failingPlugins.forEach((String plugin) { + _print(' * $plugin'); + }); + throw ToolExit(1); + } + } + + Future> _podspecsToLint() async { + final List podspecs = await getFiles().where((File entity) { + final String filePath = entity.path; + return p.extension(filePath) == '.podspec' && + !argResults['skip'].contains(p.basenameWithoutExtension(filePath)); + }).toList(); + + podspecs.sort( + (File a, File b) => p.basename(a.path).compareTo(p.basename(b.path))); + return podspecs; + } + + Future _lintPodspec(File podspec) async { + // Do not run the static analyzer on plugins with known analyzer issues. + final String podspecPath = podspec.path; + final bool runAnalyzer = !argResults['no-analyze'] + .contains(p.basenameWithoutExtension(podspecPath)); + + final String podspecBasename = p.basename(podspecPath); + if (runAnalyzer) { + _print('Linting and analyzing $podspecBasename'); + } else { + _print('Linting $podspecBasename'); + } + + // Lint plugin as framework (use_frameworks!). + final ProcessResult frameworkResult = await _runPodLint(podspecPath, + runAnalyzer: runAnalyzer, libraryLint: true); + _print(frameworkResult.stdout); + _print(frameworkResult.stderr); + + // Lint plugin as library. + final ProcessResult libraryResult = await _runPodLint(podspecPath, + runAnalyzer: runAnalyzer, libraryLint: false); + _print(libraryResult.stdout); + _print(libraryResult.stderr); + + return frameworkResult.exitCode == 0 && libraryResult.exitCode == 0; + } + + Future _runPodLint(String podspecPath, + {bool runAnalyzer, bool libraryLint}) async { + final bool allowWarnings = argResults['ignore-warnings'] + .contains(p.basenameWithoutExtension(podspecPath)); + final List arguments = [ + 'lib', + 'lint', + podspecPath, + if (allowWarnings) '--allow-warnings', + if (runAnalyzer) '--analyze', + if (libraryLint) '--use-libraries' + ]; + + return processRunner.run('pod', arguments, + workingDir: packagesDir, stdoutEncoding: utf8, stderrEncoding: utf8); + } +} diff --git a/script/tool/lib/src/list_command.dart b/script/tool/lib/src/list_command.dart new file mode 100644 index 000000000000..7f94daac7096 --- /dev/null +++ b/script/tool/lib/src/list_command.dart @@ -0,0 +1,60 @@ +// Copyright 2018 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:async'; + +import 'package:file/file.dart'; + +import 'common.dart'; + +class ListCommand extends PluginCommand { + ListCommand(Directory packagesDir, FileSystem fileSystem) + : super(packagesDir, fileSystem) { + argParser.addOption( + _type, + defaultsTo: _plugin, + allowed: [_plugin, _example, _package, _file], + help: 'What type of file system content to list.', + ); + } + + static const String _type = 'type'; + static const String _plugin = 'plugin'; + static const String _example = 'example'; + static const String _package = 'package'; + static const String _file = 'file'; + + @override + final String name = 'list'; + + @override + final String description = 'Lists packages or files'; + + @override + Future run() async { + checkSharding(); + switch (argResults[_type]) { + case _plugin: + await for (Directory package in getPlugins()) { + print(package.path); + } + break; + case _example: + await for (Directory package in getExamples()) { + print(package.path); + } + break; + case _package: + await for (Directory package in getPackages()) { + print(package.path); + } + break; + case _file: + await for (File file in getFiles()) { + print(file.path); + } + break; + } + } +} diff --git a/script/tool/lib/src/main.dart b/script/tool/lib/src/main.dart new file mode 100644 index 000000000000..bb3f67c0a9e1 --- /dev/null +++ b/script/tool/lib/src/main.dart @@ -0,0 +1,63 @@ +// 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' as io; + +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:flutter_plugin_tools/src/publish_plugin_command.dart'; +import 'package:path/path.dart' as p; + +import 'analyze_command.dart'; +import 'build_examples_command.dart'; +import 'common.dart'; +import 'create_all_plugins_app_command.dart'; +import 'drive_examples_command.dart'; +import 'firebase_test_lab_command.dart'; +import 'format_command.dart'; +import 'java_test_command.dart'; +import 'lint_podspecs_command.dart'; +import 'list_command.dart'; +import 'test_command.dart'; +import 'version_check_command.dart'; +import 'xctest_command.dart'; + +void main(List args) { + final FileSystem fileSystem = const LocalFileSystem(); + + Directory packagesDir = fileSystem + .directory(p.join(fileSystem.currentDirectory.path, 'packages')); + + if (!packagesDir.existsSync()) { + if (p.basename(fileSystem.currentDirectory.path) == 'packages') { + packagesDir = fileSystem.currentDirectory; + } else { + print('Error: Cannot find a "packages" sub-directory'); + io.exit(1); + } + } + + final CommandRunner commandRunner = CommandRunner( + 'pub global run flutter_plugin_tools', + 'Productivity utils for hosting multiple plugins within one repository.') + ..addCommand(AnalyzeCommand(packagesDir, fileSystem)) + ..addCommand(BuildExamplesCommand(packagesDir, fileSystem)) + ..addCommand(CreateAllPluginsAppCommand(packagesDir, fileSystem)) + ..addCommand(DriveExamplesCommand(packagesDir, fileSystem)) + ..addCommand(FirebaseTestLabCommand(packagesDir, fileSystem)) + ..addCommand(FormatCommand(packagesDir, fileSystem)) + ..addCommand(JavaTestCommand(packagesDir, fileSystem)) + ..addCommand(LintPodspecsCommand(packagesDir, fileSystem)) + ..addCommand(ListCommand(packagesDir, fileSystem)) + ..addCommand(PublishPluginCommand(packagesDir, fileSystem)) + ..addCommand(TestCommand(packagesDir, fileSystem)) + ..addCommand(VersionCheckCommand(packagesDir, fileSystem)) + ..addCommand(XCTestCommand(packagesDir, fileSystem)); + + commandRunner.run(args).catchError((Object e) { + final ToolExit toolExit = e; + io.exit(toolExit.exitCode); + }, test: (Object e) => e is ToolExit); +} diff --git a/script/tool/lib/src/publish_plugin_command.dart b/script/tool/lib/src/publish_plugin_command.dart new file mode 100644 index 000000000000..f7e3b5deeecf --- /dev/null +++ b/script/tool/lib/src/publish_plugin_command.dart @@ -0,0 +1,223 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:file/file.dart'; +import 'package:git/git.dart'; +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as p; +import 'package:yaml/yaml.dart'; + +import 'common.dart'; + +/// Wraps pub publish with a few niceties used by the flutter/plugin team. +/// +/// 1. Checks for any modified files in git and refuses to publish if there's an +/// issue. +/// 2. Tags the release with the format -v. +/// 3. Pushes the release to a remote. +/// +/// Both 2 and 3 are optional, see `plugin_tools help publish-plugin` for full +/// usage information. +/// +/// [processRunner], [print], and [stdin] can be overriden for easier testing. +class PublishPluginCommand extends PluginCommand { + PublishPluginCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + Print print = print, + Stdin stdinput, + }) : _print = print, + _stdin = stdinput ?? stdin, + super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addOption( + _packageOption, + help: 'The package to publish.' + 'If the package directory name is different than its pubspec.yaml name, then this should specify the directory.', + ); + argParser.addMultiOption(_pubFlagsOption, + help: + 'A list of options that will be forwarded on to pub. Separate multiple flags with commas.'); + argParser.addFlag( + _tagReleaseOption, + help: 'Whether or not to tag the release.', + defaultsTo: true, + negatable: true, + ); + argParser.addFlag( + _pushTagsOption, + help: + 'Whether or not tags should be pushed to a remote after creation. Ignored if tag-release is false.', + defaultsTo: true, + negatable: true, + ); + argParser.addOption( + _remoteOption, + help: + 'The name of the remote to push the tags to. Ignored if push-tags or tag-release is false.', + // Flutter convention is to use "upstream" for the single source of truth, and "origin" for personal forks. + defaultsTo: 'upstream', + ); + } + + static const String _packageOption = 'package'; + static const String _tagReleaseOption = 'tag-release'; + static const String _pushTagsOption = 'push-tags'; + static const String _pubFlagsOption = 'pub-publish-flags'; + static const String _remoteOption = 'remote'; + + // Version tags should follow -v. For example, + // `flutter_plugin_tools-v0.0.24`. + static const String _tagFormat = '%PACKAGE%-v%VERSION%'; + + @override + final String name = 'publish-plugin'; + + @override + final String description = + 'Attempts to publish the given plugin and tag its release on GitHub.'; + + final Print _print; + final Stdin _stdin; + // The directory of the actual package that we are publishing. + Directory _packageDir; + StreamSubscription _stdinSubscription; + + @override + Future run() async { + checkSharding(); + _print('Checking local repo...'); + _packageDir = _checkPackageDir(); + await _checkGitStatus(); + final bool shouldPushTag = argResults[_pushTagsOption]; + final String remote = argResults[_remoteOption]; + String remoteUrl; + if (shouldPushTag) { + remoteUrl = await _verifyRemote(remote); + } + _print('Local repo is ready!'); + + await _publish(); + _print('Package published!'); + if (!argResults[_tagReleaseOption]) { + return await _finishSuccesfully(); + } + + _print('Tagging release...'); + final String tag = _getTag(); + await processRunner.runAndExitOnError('git', ['tag', tag], + workingDir: _packageDir); + if (!shouldPushTag) { + return await _finishSuccesfully(); + } + + _print('Pushing tag to $remote...'); + await _pushTagToRemote(remote: remote, tag: tag, remoteUrl: remoteUrl); + await _finishSuccesfully(); + } + + Future _finishSuccesfully() async { + await _stdinSubscription.cancel(); + _print('Done!'); + } + + Directory _checkPackageDir() { + final String package = argResults[_packageOption]; + if (package == null) { + _print( + 'Must specify a package to publish. See `plugin_tools help publish-plugin`.'); + throw ToolExit(1); + } + final Directory _packageDir = packagesDir.childDirectory(package); + if (!_packageDir.existsSync()) { + _print('${_packageDir.absolute.path} does not exist.'); + throw ToolExit(1); + } + return _packageDir; + } + + Future _checkGitStatus() async { + if (!await GitDir.isGitDir(packagesDir.path)) { + _print('$packagesDir is not a valid Git repository.'); + throw ToolExit(1); + } + + final ProcessResult statusResult = await processRunner.runAndExitOnError( + 'git', + [ + 'status', + '--porcelain', + '--ignored', + _packageDir.absolute.path + ], + workingDir: _packageDir); + final String statusOutput = statusResult.stdout; + if (statusOutput.isNotEmpty) { + _print( + "There are files in the package directory that haven't been saved in git. Refusing to publish these files:\n\n" + '$statusOutput\n' + 'If the directory should be clean, you can run `git clean -xdf && git reset --hard HEAD` to wipe all local changes.'); + throw ToolExit(1); + } + } + + Future _verifyRemote(String remote) async { + final ProcessResult remoteInfo = await processRunner.runAndExitOnError( + 'git', ['remote', 'get-url', remote], + workingDir: _packageDir); + return remoteInfo.stdout; + } + + Future _publish() async { + final List publishFlags = argResults[_pubFlagsOption]; + _print( + 'Running `pub publish ${publishFlags.join(' ')}` in ${_packageDir.absolute.path}...\n'); + final Process publish = await processRunner.start( + 'flutter', ['pub', 'publish'] + publishFlags, + workingDirectory: _packageDir); + publish.stdout + .transform(utf8.decoder) + .listen((String data) => _print(data)); + publish.stderr + .transform(utf8.decoder) + .listen((String data) => _print(data)); + _stdinSubscription = _stdin + .transform(utf8.decoder) + .listen((String data) => publish.stdin.writeln(data)); + final int result = await publish.exitCode; + if (result != 0) { + _print('Publish failed. Exiting.'); + throw ToolExit(result); + } + } + + String _getTag() { + final File pubspecFile = + fileSystem.file(p.join(_packageDir.path, 'pubspec.yaml')); + final YamlMap pubspecYaml = loadYaml(pubspecFile.readAsStringSync()); + final String name = pubspecYaml['name']; + final String version = pubspecYaml['version']; + // We should have failed to publish if these were unset. + assert(name.isNotEmpty && version.isNotEmpty); + return _tagFormat + .replaceAll('%PACKAGE%', name) + .replaceAll('%VERSION%', version); + } + + Future _pushTagToRemote( + {@required String remote, + @required String tag, + @required String remoteUrl}) async { + assert(remote != null && tag != null && remoteUrl != null); + _print('Ready to push $tag to $remoteUrl (y/n)?'); + final String input = _stdin.readLineSync(); + if (input.toLowerCase() != 'y') { + _print('Tag push canceled.'); + throw ToolExit(1); + } + + await processRunner.runAndExitOnError('git', ['push', remote, tag], + workingDir: packagesDir); + } +} diff --git a/script/tool/lib/src/test_command.dart b/script/tool/lib/src/test_command.dart new file mode 100644 index 000000000000..e938168cfa89 --- /dev/null +++ b/script/tool/lib/src/test_command.dart @@ -0,0 +1,101 @@ +// 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:async'; + +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; + +import 'common.dart'; + +class TestCommand extends PluginCommand { + TestCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + }) : super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addOption( + kEnableExperiment, + defaultsTo: '', + help: 'Runs the tests in Dart VM with the given experiments enabled.', + ); + } + + @override + final String name = 'test'; + + @override + final String description = 'Runs the Dart tests for all packages.\n\n' + 'This command requires "flutter" to be in your path.'; + + @override + Future run() async { + checkSharding(); + final List failingPackages = []; + await for (Directory packageDir in getPackages()) { + final String packageName = + p.relative(packageDir.path, from: packagesDir.path); + if (!fileSystem.directory(p.join(packageDir.path, 'test')).existsSync()) { + print('SKIPPING $packageName - no test subdirectory'); + continue; + } + + print('RUNNING $packageName tests...'); + + final String enableExperiment = argResults[kEnableExperiment]; + + // `flutter test` automatically gets packages. `pub run test` does not. :( + int exitCode = 0; + if (isFlutterPackage(packageDir, fileSystem)) { + final List args = [ + 'test', + '--color', + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + ]; + + if (isWebPlugin(packageDir, fileSystem)) { + args.add('--platform=chrome'); + } + exitCode = await processRunner.runAndStream( + 'flutter', + args, + workingDir: packageDir, + ); + } else { + exitCode = await processRunner.runAndStream( + 'pub', + ['get'], + workingDir: packageDir, + ); + if (exitCode == 0) { + exitCode = await processRunner.runAndStream( + 'pub', + [ + 'run', + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + 'test', + ], + workingDir: packageDir, + ); + } + } + if (exitCode != 0) { + failingPackages.add(packageName); + } + } + + print('\n\n'); + if (failingPackages.isNotEmpty) { + print('Tests for the following packages are failing (see above):'); + failingPackages.forEach((String package) { + print(' * $package'); + }); + throw ToolExit(1); + } + + print('All tests are passing!'); + } +} diff --git a/script/tool/lib/src/version_check_command.dart b/script/tool/lib/src/version_check_command.dart new file mode 100644 index 000000000000..2c6b92bbcb7a --- /dev/null +++ b/script/tool/lib/src/version_check_command.dart @@ -0,0 +1,220 @@ +// 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:async'; +import 'dart:io' as io; + +import 'package:meta/meta.dart'; +import 'package:colorize/colorize.dart'; +import 'package:file/file.dart'; +import 'package:git/git.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:pubspec_parse/pubspec_parse.dart'; +import 'package:yaml/yaml.dart'; + +import 'common.dart'; + +const String _kBaseSha = 'base_sha'; + +class GitVersionFinder { + GitVersionFinder(this.baseGitDir, this.baseSha); + + final GitDir baseGitDir; + final String baseSha; + + static bool isPubspec(String file) { + return file.trim().endsWith('pubspec.yaml'); + } + + Future> getChangedPubSpecs() async { + final io.ProcessResult changedFilesCommand = await baseGitDir + .runCommand(['diff', '--name-only', '$baseSha', 'HEAD']); + final List changedFiles = + changedFilesCommand.stdout.toString().split('\n'); + return changedFiles.where(isPubspec).toList(); + } + + Future getPackageVersion(String pubspecPath, String gitRef) async { + final io.ProcessResult gitShow = + await baseGitDir.runCommand(['show', '$gitRef:$pubspecPath']); + final String fileContent = gitShow.stdout; + final String versionString = loadYaml(fileContent)['version']; + return versionString == null ? null : Version.parse(versionString); + } +} + +enum NextVersionType { + BREAKING_MAJOR, + MAJOR_NULLSAFETY_PRE_RELEASE, + MINOR_NULLSAFETY_PRE_RELEASE, + MINOR, + PATCH, + RELEASE, +} + +Version getNextNullSafetyPreRelease(Version current, Version next) { + String nextNullsafetyPrerelease = 'nullsafety'; + if (current.isPreRelease && + current.preRelease.first is String && + current.preRelease.first == 'nullsafety') { + if (current.preRelease.length == 1) { + nextNullsafetyPrerelease = 'nullsafety.1'; + } else if (current.preRelease.length == 2 && + current.preRelease.last is int) { + nextNullsafetyPrerelease = 'nullsafety.${current.preRelease.last + 1}'; + } + } + return Version( + next.major, + next.minor, + next.patch, + pre: nextNullsafetyPrerelease, + ); +} + +@visibleForTesting +Map getAllowedNextVersions( + Version masterVersion, Version headVersion) { + final Version nextNullSafetyMajor = + getNextNullSafetyPreRelease(masterVersion, masterVersion.nextMajor); + final Version nextNullSafetyMinor = + getNextNullSafetyPreRelease(masterVersion, masterVersion.nextMinor); + final Map allowedNextVersions = + { + masterVersion.nextMajor: NextVersionType.BREAKING_MAJOR, + nextNullSafetyMajor: NextVersionType.MAJOR_NULLSAFETY_PRE_RELEASE, + nextNullSafetyMinor: NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE, + masterVersion.nextMinor: NextVersionType.MINOR, + masterVersion.nextPatch: NextVersionType.PATCH, + }; + + if (masterVersion.major < 1 && headVersion.major < 1) { + int nextBuildNumber = -1; + if (masterVersion.build.isEmpty) { + nextBuildNumber = 1; + } else { + final int currentBuildNumber = masterVersion.build.first; + nextBuildNumber = currentBuildNumber + 1; + } + final Version preReleaseVersion = Version( + masterVersion.major, + masterVersion.minor, + masterVersion.patch, + build: nextBuildNumber.toString(), + ); + allowedNextVersions.clear(); + allowedNextVersions[masterVersion.nextMajor] = NextVersionType.RELEASE; + allowedNextVersions[masterVersion.nextMinor] = + NextVersionType.BREAKING_MAJOR; + allowedNextVersions[masterVersion.nextPatch] = NextVersionType.MINOR; + allowedNextVersions[preReleaseVersion] = NextVersionType.PATCH; + + final Version nextNullSafetyMajor = + getNextNullSafetyPreRelease(masterVersion, masterVersion.nextMinor); + final Version nextNullSafetyMinor = + getNextNullSafetyPreRelease(masterVersion, masterVersion.nextPatch); + + allowedNextVersions[nextNullSafetyMajor] = + NextVersionType.MAJOR_NULLSAFETY_PRE_RELEASE; + allowedNextVersions[nextNullSafetyMinor] = + NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE; + } + return allowedNextVersions; +} + +class VersionCheckCommand extends PluginCommand { + VersionCheckCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + this.gitDir, + }) : super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addOption(_kBaseSha); + } + + /// The git directory to use. By default it uses the parent directory. + /// + /// This can be mocked for testing. + final GitDir gitDir; + + @override + final String name = 'version-check'; + + @override + final String description = + 'Checks if the versions of the plugins have been incremented per pub specification.\n\n' + 'This command requires "pub" and "flutter" to be in your path.'; + + @override + Future run() async { + checkSharding(); + + final String rootDir = packagesDir.parent.absolute.path; + final String baseSha = argResults[_kBaseSha]; + + GitDir baseGitDir = gitDir; + if (baseGitDir == null) { + if (!await GitDir.isGitDir(rootDir)) { + print('$rootDir is not a valid Git repository.'); + throw ToolExit(2); + } + baseGitDir = await GitDir.fromExisting(rootDir); + } + + final GitVersionFinder gitVersionFinder = + GitVersionFinder(baseGitDir, baseSha); + + final List changedPubspecs = + await gitVersionFinder.getChangedPubSpecs(); + + for (final String pubspecPath in changedPubspecs) { + try { + final File pubspecFile = fileSystem.file(pubspecPath); + if (!pubspecFile.existsSync()) { + continue; + } + final Pubspec pubspec = Pubspec.parse(pubspecFile.readAsStringSync()); + if (pubspec.publishTo == 'none') { + continue; + } + + final Version masterVersion = + await gitVersionFinder.getPackageVersion(pubspecPath, baseSha); + final Version headVersion = + await gitVersionFinder.getPackageVersion(pubspecPath, 'HEAD'); + if (headVersion == null) { + continue; // Example apps don't have versions + } + + final Map allowedNextVersions = + getAllowedNextVersions(masterVersion, headVersion); + + if (!allowedNextVersions.containsKey(headVersion)) { + final String error = '$pubspecPath incorrectly updated version.\n' + 'HEAD: $headVersion, master: $masterVersion.\n' + 'Allowed versions: $allowedNextVersions'; + final Colorize redError = Colorize(error)..red(); + print(redError); + throw ToolExit(1); + } + + bool isPlatformInterface = pubspec.name.endsWith("_platform_interface"); + if (isPlatformInterface && + allowedNextVersions[headVersion] == + NextVersionType.BREAKING_MAJOR) { + final String error = '$pubspecPath breaking change detected.\n' + 'Breaking changes to platform interfaces are strongly discouraged.\n'; + final Colorize redError = Colorize(error)..red(); + print(redError); + throw ToolExit(1); + } + } on io.ProcessException { + print('Unable to find pubspec in master for $pubspecPath.' + ' Safe to ignore if the project is new.'); + } + } + + print('No version check errors found!'); + } +} diff --git a/script/tool/lib/src/xctest_command.dart b/script/tool/lib/src/xctest_command.dart new file mode 100644 index 000000000000..d90b7a8fbfea --- /dev/null +++ b/script/tool/lib/src/xctest_command.dart @@ -0,0 +1,216 @@ +// 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:async'; +import 'dart:convert'; +import 'dart:io' as io; + +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; + +import 'common.dart'; + +const String _kiOSDestination = 'ios-destination'; +const String _kTarget = 'target'; +const String _kSkip = 'skip'; +const String _kXcodeBuildCommand = 'xcodebuild'; +const String _kXCRunCommand = 'xcrun'; +const String _kFoundNoSimulatorsMessage = + 'Cannot find any available simulators, tests failed'; + +/// The command to run iOS' XCTests in plugins, this should work for both XCUnitTest and XCUITest targets. +/// The tests target have to be added to the xcode project of the example app. Usually at "example/ios/Runner.xcodeproj". +/// The command takes a "-target" argument which has to match the target of the test target. +/// For information on how to add test target in an xcode project, see https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/UnitTesting.html +class XCTestCommand extends PluginCommand { + XCTestCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + }) : super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addOption( + _kiOSDestination, + help: + 'Specify the destination when running the test, used for -destination flag for xcodebuild command.\n' + 'this is passed to the `-destination` argument in xcodebuild command.\n' + 'See https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT for details on how to specify the destination.', + ); + argParser.addOption(_kTarget, + help: 'The test target.\n' + 'This is the xcode project test target. This is passed to the `-scheme` argument in the xcodebuild command. \n' + 'See https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT for details on how to specify the scheme'); + argParser.addMultiOption(_kSkip, + help: 'Plugins to skip while running this command. \n'); + } + + @override + final String name = 'xctest'; + + @override + final String description = 'Runs the xctests in the iOS example apps.\n\n' + 'This command requires "flutter" to be in your path.'; + + @override + Future run() async { + if (argResults[_kTarget] == null) { + // TODO(cyanglaz): Automatically find all the available testing schemes if this argument is not specified. + // https://github.com/flutter/flutter/issues/68419 + print('--$_kTarget must be specified'); + throw ToolExit(1); + } + + String destination = argResults[_kiOSDestination]; + if (destination == null) { + String simulatorId = await _findAvailableIphoneSimulator(); + if (simulatorId == null) { + print(_kFoundNoSimulatorsMessage); + throw ToolExit(1); + } + destination = 'id=$simulatorId'; + } + + checkSharding(); + + final String target = argResults[_kTarget]; + final List skipped = argResults[_kSkip]; + + List failingPackages = []; + await for (Directory plugin in getPlugins()) { + // Start running for package. + final String packageName = + p.relative(plugin.path, from: packagesDir.path); + print('Start running for $packageName ...'); + if (!isIosPlugin(plugin, fileSystem)) { + print('iOS is not supported by this plugin.'); + print('\n\n'); + continue; + } + if (skipped.contains(packageName)) { + print('$packageName was skipped with the --skip flag.'); + print('\n\n'); + continue; + } + for (Directory example in getExamplesForPlugin(plugin)) { + // Look for the test scheme in the example app. + print('Look for target named: $_kTarget ...'); + final List findSchemeArgs = [ + '-project', + 'ios/Runner.xcodeproj', + '-list', + '-json' + ]; + final String completeFindSchemeCommand = + '$_kXcodeBuildCommand ${findSchemeArgs.join(' ')}'; + print(completeFindSchemeCommand); + final io.ProcessResult xcodeprojListResult = await processRunner + .run(_kXcodeBuildCommand, findSchemeArgs, workingDir: example); + if (xcodeprojListResult.exitCode != 0) { + print('Error occurred while running "$completeFindSchemeCommand":\n' + '${xcodeprojListResult.stderr}'); + failingPackages.add(packageName); + print('\n\n'); + continue; + } + + final String xcodeprojListOutput = xcodeprojListResult.stdout; + Map xcodeprojListOutputJson = + jsonDecode(xcodeprojListOutput); + if (!xcodeprojListOutputJson['project']['targets'].contains(target)) { + failingPackages.add(packageName); + print('$target not configured for $packageName, test failed.'); + print( + 'Please check the scheme for the test target if it matches the name $target.\n' + 'If this plugin does not have an XCTest target, use the $_kSkip flag in the $name command to skip the plugin.'); + print('\n\n'); + continue; + } + // Found the scheme, running tests + print('Running XCTests:$target for $packageName ...'); + final List xctestArgs = [ + 'test', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + target, + '-destination', + destination, + 'CODE_SIGN_IDENTITY=""', + 'CODE_SIGNING_REQUIRED=NO' + ]; + final String completeTestCommand = + '$_kXcodeBuildCommand ${xctestArgs.join(' ')}'; + print(completeTestCommand); + final int exitCode = await processRunner + .runAndStream(_kXcodeBuildCommand, xctestArgs, workingDir: example); + if (exitCode == 0) { + print('Successfully ran xctest for $packageName'); + } else { + failingPackages.add(packageName); + } + } + } + + // Command end, print reports. + if (failingPackages.isEmpty) { + print("All XCTests have passed!"); + } else { + print( + 'The following packages are failing XCTests (see above for details):'); + for (String package in failingPackages) { + print(' * $package'); + } + throw ToolExit(1); + } + } + + Future _findAvailableIphoneSimulator() async { + // Find the first available destination if not specified. + final List findSimulatorsArguments = [ + 'simctl', + 'list', + '--json' + ]; + final String findSimulatorCompleteCommand = + '$_kXCRunCommand ${findSimulatorsArguments.join(' ')}'; + print('Looking for available simulators...'); + print(findSimulatorCompleteCommand); + final io.ProcessResult findSimulatorsResult = + await processRunner.run(_kXCRunCommand, findSimulatorsArguments); + if (findSimulatorsResult.exitCode != 0) { + print('Error occurred while running "$findSimulatorCompleteCommand":\n' + '${findSimulatorsResult.stderr}'); + throw ToolExit(1); + } + final Map simulatorListJson = + jsonDecode(findSimulatorsResult.stdout); + final List runtimes = simulatorListJson['runtimes']; + final Map devices = simulatorListJson['devices']; + if (runtimes.isEmpty || devices.isEmpty) { + return null; + } + String id; + // Looking for runtimes, trying to find one with highest OS version. + for (Map runtimeMap in runtimes.reversed) { + if (!runtimeMap['name'].contains('iOS')) { + continue; + } + final String runtimeID = runtimeMap['identifier']; + final List devicesForRuntime = devices[runtimeID]; + if (devicesForRuntime.isEmpty) { + continue; + } + // Looking for runtimes, trying to find latest version of device. + for (Map device in devicesForRuntime.reversed) { + if (device['availabilityError'] != null || + (device['isAvailable'] as bool == false)) { + continue; + } + id = device['udid']; + print('device selected: $device'); + return id; + } + } + return null; + } +} diff --git a/script/tool/pubspec.yaml b/script/tool/pubspec.yaml new file mode 100644 index 000000000000..d9fce4ad26a7 --- /dev/null +++ b/script/tool/pubspec.yaml @@ -0,0 +1,25 @@ +name: flutter_plugin_tools +description: Productivity utils for hosting multiple plugins within one repository. +publish_to: 'none' + +dependencies: + args: "^1.4.3" + path: "^1.6.1" + http: "^0.12.1" + async: "^2.0.7" + yaml: "^2.1.15" + quiver: "^2.0.2" + pub_semver: ^1.4.2 + colorize: ^2.0.0 + git: ^1.0.0 + platform: ^2.2.0 + pubspec_parse: "^0.1.4" + test: ^1.6.4 + meta: ^1.1.7 + file: ^5.0.10 + uuid: ^2.0.4 + http_multi_server: ^2.2.0 + collection: 1.14.13 + +environment: + sdk: ">=2.3.0 <3.0.0" From c7b9a244a6a5249976ffb986f9f63d92b8608363 Mon Sep 17 00:00:00 2001 From: Sameer Kashyap <40424087+Sameerkash@users.noreply.github.com> Date: Sat, 13 Feb 2021 05:21:03 +0530 Subject: [PATCH 190/924] [image_picker_web] Migrate to null-safety (#3535) --- .../image_picker_for_web/CHANGELOG.md | 4 ++ .../lib/image_picker_for_web.dart | 62 ++++++++++--------- .../image_picker_for_web/pubspec.yaml | 16 +++-- .../test/image_picker_for_web_test.dart | 4 +- 4 files changed, 45 insertions(+), 41 deletions(-) diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md index 4c452ee78de9..37b17b3eef26 100644 --- a/packages/image_picker/image_picker_for_web/CHANGELOG.md +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 2.0.0-nullsafety + +* Migrate to null safety. + # 0.1.0+3 * Update Flutter SDK constraint. diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index e50b4aad3c8d..0c05980172aa 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -13,14 +13,14 @@ final String _kAcceptVideoMimeType = 'video/3gpp,video/x-m4v,video/mp4,video/*'; /// /// This class implements the `package:image_picker` functionality for the web. class ImagePickerPlugin extends ImagePickerPlatform { - final ImagePickerPluginTestOverrides _overrides; + final ImagePickerPluginTestOverrides? _overrides; bool get _hasOverrides => _overrides != null; - html.Element _target; + late html.Element _target; /// A constructor that allows tests to override the function that creates file inputs. ImagePickerPlugin({ - @visibleForTesting ImagePickerPluginTestOverrides overrides, + @visibleForTesting ImagePickerPluginTestOverrides? overrides, }) : _overrides = overrides { _target = _ensureInitialized(_kImagePickerInputsDomId); } @@ -32,23 +32,23 @@ class ImagePickerPlugin extends ImagePickerPlatform { @override Future pickImage({ - @required ImageSource source, - double maxWidth, - double maxHeight, - int imageQuality, + required ImageSource source, + double? maxWidth, + double? maxHeight, + int? imageQuality, CameraDevice preferredCameraDevice = CameraDevice.rear, }) { - String capture = computeCaptureAttribute(source, preferredCameraDevice); + String? capture = computeCaptureAttribute(source, preferredCameraDevice); return pickFile(accept: _kAcceptImageMimeType, capture: capture); } @override Future pickVideo({ - @required ImageSource source, + required ImageSource source, CameraDevice preferredCameraDevice = CameraDevice.rear, - Duration maxDuration, + Duration? maxDuration, }) { - String capture = computeCaptureAttribute(source, preferredCameraDevice); + String? capture = computeCaptureAttribute(source, preferredCameraDevice); return pickFile(accept: _kAcceptVideoMimeType, capture: capture); } @@ -59,10 +59,11 @@ class ImagePickerPlugin extends ImagePickerPlatform { /// See https://caniuse.com/#feat=html-media-capture @visibleForTesting Future pickFile({ - String accept, - String capture, + String? accept, + String? capture, }) { - html.FileUploadInputElement input = createInputElement(accept, capture); + html.FileUploadInputElement input = + createInputElement(accept, capture) as html.FileUploadInputElement; _injectAndActivate(input); return _getSelectedFile(input); } @@ -73,25 +74,26 @@ class ImagePickerPlugin extends ImagePickerPlatform { /// /// See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#capture @visibleForTesting - String computeCaptureAttribute(ImageSource source, CameraDevice device) { + String? computeCaptureAttribute(ImageSource source, CameraDevice device) { if (source == ImageSource.camera) { return (device == CameraDevice.front) ? 'user' : 'environment'; } return null; } - html.File _getFileFromInput(html.FileUploadInputElement input) { + html.File? _getFileFromInput(html.FileUploadInputElement input) { if (_hasOverrides) { - return _overrides.getFileFromInput(input); + return _overrides!.getFileFromInput(input); } - return input?.files?.first; + return input.files?.first; } /// Handles the OnChange event from a FileUploadInputElement object /// Returns the objectURL of the selected file. - String _handleOnChangeEvent(html.Event event) { - final html.FileUploadInputElement input = event?.target; - final html.File file = _getFileFromInput(input); + String? _handleOnChangeEvent(html.Event event) { + final html.FileUploadInputElement input = + event.target as html.FileUploadInputElement; + final html.File? file = _getFileFromInput(input); if (file != null) { return html.Url.createObjectUrl(file); @@ -105,7 +107,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { // Observe the input until we can return something input.onChange.first.then((event) { final objectUrl = _handleOnChangeEvent(event); - if (!_completer.isCompleted) { + if (!_completer.isCompleted && objectUrl != null) { _completer.complete(PickedFile(objectUrl)); } }); @@ -127,7 +129,7 @@ class ImagePickerPlugin extends ImagePickerPlatform { final html.Element targetElement = html.Element.tag('flt-image-picker-inputs')..id = id; - html.querySelector('body').children.add(targetElement); + html.querySelector('body')!.children.add(targetElement); target = targetElement; } return target; @@ -136,9 +138,9 @@ class ImagePickerPlugin extends ImagePickerPlatform { /// Creates an input element that accepts certain file types, and /// allows to `capture` from the device's cameras (where supported) @visibleForTesting - html.Element createInputElement(String accept, String capture) { + html.Element createInputElement(String? accept, String? capture) { if (_hasOverrides) { - return _overrides.createInputElement(accept, capture); + return _overrides!.createInputElement(accept, capture); } html.Element element = html.FileUploadInputElement()..accept = accept; @@ -162,22 +164,22 @@ class ImagePickerPlugin extends ImagePickerPlatform { /// A function that creates a file input with the passed in `accept` and `capture` attributes. @visibleForTesting typedef OverrideCreateInputFunction = html.Element Function( - String accept, - String capture, + String? accept, + String? capture, ); /// A function that extracts a [html.File] from the file `input` passed in. @visibleForTesting typedef OverrideExtractFilesFromInputFunction = html.File Function( - html.Element input, + html.Element? input, ); /// Overrides for some of the functionality above. @visibleForTesting class ImagePickerPluginTestOverrides { /// Override the creation of the input element. - OverrideCreateInputFunction createInputElement; + late OverrideCreateInputFunction createInputElement; /// Override the extraction of the selected file from an input element. - OverrideExtractFilesFromInputFunction getFileFromInput; + late OverrideExtractFilesFromInputFunction getFileFromInput; } diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index b7e079b39ce0..c270cd597c87 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -1,10 +1,8 @@ name: image_picker_for_web description: Web platform implementation of image_picker homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_for_web -# 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.0+3 + +version: 2.0.0-nullsafety flutter: plugin: @@ -14,19 +12,19 @@ flutter: fileName: image_picker_for_web.dart dependencies: - image_picker_platform_interface: ^1.1.0 + image_picker_platform_interface: ^2.0.0-nullsafety flutter: sdk: flutter flutter_web_plugins: sdk: flutter - meta: ^1.1.7 - js: ^0.6.0 + meta: ^1.3.0-nullsafety.6 + js: ^0.6.3-nullsafety.3 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 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_for_web/test/image_picker_for_web_test.dart b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart index 96d048dd2a8e..fcc2c003a10b 100644 --- a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart +++ b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart @@ -13,12 +13,12 @@ import 'package:image_picker_for_web/image_picker_for_web.dart'; import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; final String expectedStringContents = "Hello, world!"; -final Uint8List bytes = utf8.encode(expectedStringContents); +final Uint8List bytes = utf8.encode(expectedStringContents) as Uint8List; final html.File textFile = html.File([bytes], "hello.txt"); void main() { // Under test... - ImagePickerPlugin plugin; + late ImagePickerPlugin plugin; setUp(() { plugin = ImagePickerPlugin(); From aa22656648917816a49459b82f4fd95e8d983fc1 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 12 Feb 2021 17:04:59 -0800 Subject: [PATCH 191/924] Honor, and scrub, the 1.0 compatibility promise (#3545) --- packages/android_intent/README.md | 7 ------- .../connectivity/connectivity_macos/CHANGELOG.md | 4 ++++ .../connectivity/connectivity_macos/README.md | 8 -------- .../connectivity/connectivity_macos/pubspec.yaml | 5 +---- packages/device_info/device_info/pubspec.yaml | 3 --- packages/package_info/CHANGELOG.md | 4 ++++ packages/package_info/README.md | 15 ++++----------- packages/package_info/pubspec.yaml | 5 +---- .../path_provider_linux/CHANGELOG.md | 4 ++++ .../path_provider/path_provider_linux/README.md | 7 ------- .../path_provider_linux/pubspec.yaml | 2 +- .../path_provider_macos/CHANGELOG.md | 4 ++++ .../path_provider/path_provider_macos/README.md | 7 ------- .../path_provider_macos/pubspec.yaml | 5 +---- .../path_provider_windows/CHANGELOG.md | 4 ++++ .../path_provider/path_provider_windows/README.md | 8 -------- .../path_provider_windows/pubspec.yaml | 3 +-- packages/sensors/CHANGELOG.md | 4 ++++ packages/sensors/README.md | 7 ------- packages/sensors/pubspec.yaml | 5 +---- packages/share/README.md | 7 ------- .../shared_preferences/pubspec.yaml | 3 --- .../shared_preferences_linux/CHANGELOG.md | 4 ++++ .../shared_preferences_linux/pubspec.yaml | 2 +- .../shared_preferences_macos/CHANGELOG.md | 4 ++++ .../shared_preferences_macos/README.md | 7 ------- .../shared_preferences_macos/pubspec.yaml | 5 +---- .../shared_preferences_web/CHANGELOG.md | 4 ++++ .../shared_preferences_web/README.md | 7 ------- .../shared_preferences_web/pubspec.yaml | 5 +---- .../shared_preferences_windows/CHANGELOG.md | 4 ++++ .../shared_preferences_windows/pubspec.yaml | 2 +- .../url_launcher/url_launcher_linux/CHANGELOG.md | 4 ++++ .../url_launcher/url_launcher_linux/pubspec.yaml | 2 +- .../url_launcher/url_launcher_macos/CHANGELOG.md | 5 ++++- .../url_launcher/url_launcher_macos/README.md | 7 ------- .../url_launcher/url_launcher_macos/pubspec.yaml | 5 +---- .../url_launcher_windows/CHANGELOG.md | 4 ++++ .../url_launcher/url_launcher_windows/README.md | 7 ------- .../url_launcher_windows/pubspec.yaml | 5 +---- packages/video_player/video_player/pubspec.yaml | 3 --- packages/video_player/video_player_web/README.md | 7 ------- .../video_player/video_player_web/pubspec.yaml | 3 --- 43 files changed, 69 insertions(+), 148 deletions(-) diff --git a/packages/android_intent/README.md b/packages/android_intent/README.md index aabf059ea336..7d097e465926 100644 --- a/packages/android_intent/README.md +++ b/packages/android_intent/README.md @@ -5,13 +5,6 @@ is Android. If the plugin is invoked on iOS, it will crash your app. In checked mode, we assert that the platform should be Android. -**Please set your constraint to `android_intent: '>=0.3.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.3.y+z`. -Please use `android_intent: '>=0.3.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - Use it by specifying action, category, data and extra arguments for the intent. It does not support returning the result of the launched activity. Sample usage: diff --git a/packages/connectivity/connectivity_macos/CHANGELOG.md b/packages/connectivity/connectivity_macos/CHANGELOG.md index 890c8938482f..8547db3441c3 100644 --- a/packages/connectivity/connectivity_macos/CHANGELOG.md +++ b/packages/connectivity/connectivity_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version to (semi-belatedly) meet 1.0-consistency promise. + ## 0.2.0-nullsafety.1 * Remove placeholder Dart file. diff --git a/packages/connectivity/connectivity_macos/README.md b/packages/connectivity/connectivity_macos/README.md index 464f7d79ccd1..6974fd1fcc7e 100644 --- a/packages/connectivity/connectivity_macos/README.md +++ b/packages/connectivity/connectivity_macos/README.md @@ -2,13 +2,6 @@ The macos implementation of [`connectivity`]. -**Please set your constraint to `connectivity_macos: '>=0.1.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.1.y+z`. -Please use `connectivity_macos: '>=0.1.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage ### Import the package @@ -29,4 +22,3 @@ dependencies: ``` Refer to the `connectivity` [documentation](https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity) for more details. - diff --git a/packages/connectivity/connectivity_macos/pubspec.yaml b/packages/connectivity/connectivity_macos/pubspec.yaml index 49c28f081ad7..0a22a8ba5f53 100644 --- a/packages/connectivity/connectivity_macos/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/pubspec.yaml @@ -1,9 +1,6 @@ name: connectivity_macos description: macOS implementation of the connectivity plugin. -# 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.2.0-nullsafety.1 +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_macos flutter: diff --git a/packages/device_info/device_info/pubspec.yaml b/packages/device_info/device_info/pubspec.yaml index 1a222869a632..bcdc7c8b54d1 100644 --- a/packages/device_info/device_info/pubspec.yaml +++ b/packages/device_info/device_info/pubspec.yaml @@ -2,9 +2,6 @@ name: device_info description: Flutter plugin providing detailed information about the device (make, model, etc.), and Android or iOS version the app is running on. homepage: https://github.com/flutter/plugins/tree/master/packages/device_info -# 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 version: 2.0.0-nullsafety.2 flutter: diff --git a/packages/package_info/CHANGELOG.md b/packages/package_info/CHANGELOG.md index 91da35966283..ddf01f0f3999 100644 --- a/packages/package_info/CHANGELOG.md +++ b/packages/package_info/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version to (semi-belatedly) meet 1.0-consistency promise. + ## 0.5.0-nullsafety * Migrate to null safety. diff --git a/packages/package_info/README.md b/packages/package_info/README.md index b5b2405a231a..a09db08dd484 100644 --- a/packages/package_info/README.md +++ b/packages/package_info/README.md @@ -3,13 +3,6 @@ This Flutter plugin provides an API for querying information about an application package. -**Please set your constraint to `package_info: '>=0.4.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The package_info plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.4.y+z`. -Please use `package_info: '>=0.4.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - # Usage You can use the PackageInfo to query information about the @@ -39,10 +32,10 @@ PackageInfo.fromPlatform().then((PackageInfo packageInfo) { ## Known Issue -As noted on [issue 20761](https://github.com/flutter/flutter/issues/20761#issuecomment-493434578), package_info on iOS -requires the Xcode build folder to be rebuilt after changes to the version string in `pubspec.yaml`. -Clean the Xcode build folder with: -`XCode Menu -> Product -> (Holding Option Key) Clean build folder`. +As noted on [issue 20761](https://github.com/flutter/flutter/issues/20761#issuecomment-493434578), package_info on iOS +requires the Xcode build folder to be rebuilt after changes to the version string in `pubspec.yaml`. +Clean the Xcode build folder with: +`XCode Menu -> Product -> (Holding Option Key) Clean build folder`. ## Issues and feedback diff --git a/packages/package_info/pubspec.yaml b/packages/package_info/pubspec.yaml index f575ad155e4e..67fbc5f626db 100644 --- a/packages/package_info/pubspec.yaml +++ b/packages/package_info/pubspec.yaml @@ -2,10 +2,7 @@ name: package_info description: Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/package_info -# 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.5.0-nullsafety +version: 2.0.0-nullsafety flutter: plugin: diff --git a/packages/path_provider/path_provider_linux/CHANGELOG.md b/packages/path_provider/path_provider_linux/CHANGELOG.md index 2deb84237712..126aadcffeb4 100644 --- a/packages/path_provider/path_provider_linux/CHANGELOG.md +++ b/packages/path_provider/path_provider_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version to (semi-belatedly) meet 1.0-consistency promise. + ## 0.2.0-nullsafety * Migrate to null safety. diff --git a/packages/path_provider/path_provider_linux/README.md b/packages/path_provider/path_provider_linux/README.md index 373925d2d96d..ef9e0e855c86 100644 --- a/packages/path_provider/path_provider_linux/README.md +++ b/packages/path_provider/path_provider_linux/README.md @@ -2,13 +2,6 @@ The linux implementation of [`path_provider`]. -**Please set your constraint to `path_provider: '>=0.0.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The `path_provider` plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.0.y+z`. -Please use `path_provider: '>=0.0.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage This package is already included as part of the `path_provider` package dependency, and will diff --git a/packages/path_provider/path_provider_linux/pubspec.yaml b/packages/path_provider/path_provider_linux/pubspec.yaml index df459e12d37f..c6940b1158ee 100644 --- a/packages/path_provider/path_provider_linux/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: path_provider_linux description: linux implementation of the path_provider plugin -version: 0.2.0-nullsafety +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_linux flutter: diff --git a/packages/path_provider/path_provider_macos/CHANGELOG.md b/packages/path_provider/path_provider_macos/CHANGELOG.md index 2f7290c2ced1..de7ab3e94f9d 100644 --- a/packages/path_provider/path_provider_macos/CHANGELOG.md +++ b/packages/path_provider/path_provider_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version to (semi-belatedly) meet 1.0-consistency promise. + ## 0.0.5-nullsafety * Update Dart SDK constraint for null safety. diff --git a/packages/path_provider/path_provider_macos/README.md b/packages/path_provider/path_provider_macos/README.md index b97d9e81b7db..23727fe7f370 100644 --- a/packages/path_provider/path_provider_macos/README.md +++ b/packages/path_provider/path_provider_macos/README.md @@ -2,13 +2,6 @@ The macos implementation of [`path_provider`]. -**Please set your constraint to `path_provider_macos: '>=0.0.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.0.y+z`. -Please use `path_provider_macos: '>=0.0.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage ### Import the package diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index a2bbd58b7289..bab79c27a94c 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -1,9 +1,6 @@ name: path_provider_macos description: macOS implementation of the path_provider plugin -# 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.5-nullsafety +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_macos flutter: diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index 8d365319c32a..2e1701cc53bf 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version to (semi-belatedly) meet 1.0-consistency promise. + ## 0.1.0-nullsafety.3 * Bump ffi dependency to 1.0.0 diff --git a/packages/path_provider/path_provider_windows/README.md b/packages/path_provider/path_provider_windows/README.md index 66a05f9e7347..6d452e770469 100644 --- a/packages/path_provider/path_provider_windows/README.md +++ b/packages/path_provider/path_provider_windows/README.md @@ -2,14 +2,6 @@ The Windows implementation of [`path_provider`][1]. -**Please set your constraint to `path_provider_windows: '>=0.0.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming - -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.0.y+z`. -Please use `path_provider_windows: '>=0.0.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage ### Import the package diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index d672ff90cdb9..384eae94f5e5 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_windows -version: 0.1.0-nullsafety.3 +version: 2.0.0-nullsafety flutter: plugin: @@ -27,4 +27,3 @@ dev_dependencies: environment: sdk: '>=2.12.0-259.8.beta <3.0.0' flutter: ">=1.12.13+hotfix.4" - diff --git a/packages/sensors/CHANGELOG.md b/packages/sensors/CHANGELOG.md index 682d377a6b84..8ff904bf3943 100644 --- a/packages/sensors/CHANGELOG.md +++ b/packages/sensors/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* * Update version to (semi-belatedly) meet 1.0-consistency promise. + ## 0.5.0-nullsafety * Migrate to null safety. diff --git a/packages/sensors/README.md b/packages/sensors/README.md index 08a9b2ea2b8c..8c5ab008419b 100644 --- a/packages/sensors/README.md +++ b/packages/sensors/README.md @@ -1,12 +1,5 @@ # sensors -**Please set your constraint to `sensors: '>=0.4.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The sensors plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.4.y+z`. -Please use `sensors: '>=0.4.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - A Flutter plugin to access the accelerometer and gyroscope sensors. diff --git a/packages/sensors/pubspec.yaml b/packages/sensors/pubspec.yaml index e9b0392bae8d..0416779f1292 100644 --- a/packages/sensors/pubspec.yaml +++ b/packages/sensors/pubspec.yaml @@ -2,10 +2,7 @@ name: sensors description: Flutter plugin for accessing the Android and iOS accelerometer and gyroscope sensors. homepage: https://github.com/flutter/plugins/tree/master/packages/sensors -# 0.4.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.5.0-nullsafety +version: 2.0.0-nullsafety flutter: plugin: diff --git a/packages/share/README.md b/packages/share/README.md index a6e572258a2b..59cfbf7c5665 100644 --- a/packages/share/README.md +++ b/packages/share/README.md @@ -8,13 +8,6 @@ share dialog. Wraps the ACTION_SEND Intent on Android and UIActivityViewController on iOS. -**Please set your constraint to `share: '>=0.6.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.6.y+z`. -Please use `share: '>=0.6.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage To use this plugin, add `share` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/packages-and-plugins/using-packages/). diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 434c9c6bd4c2..1bf314cadcfa 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -2,9 +2,6 @@ name: shared_preferences description: Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences -# 0.5.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 version: 2.0.0-nullsafety flutter: diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md index 2be9c8ca075a..1d287cf57401 100644 --- a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version for consistency. + ## 0.0.4-nullsafety * Migrate to null-safety. diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml index df4b5db23b7f..ee2288a79b4a 100644 --- a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: shared_preferences_linux description: Linux implementation of the shared_preferences plugin -version: 0.0.4-nullsafety +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux flutter: diff --git a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md index ec5c5b4bc502..002e1b7224ea 100644 --- a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version to (semi-belatedly) meet 1.0-consistency promise. + ## 0.0.2-nullsafety * Update Dart SDK constraint for null safety. diff --git a/packages/shared_preferences/shared_preferences_macos/README.md b/packages/shared_preferences/shared_preferences_macos/README.md index c2949c9f5d33..170a8270c402 100644 --- a/packages/shared_preferences/shared_preferences_macos/README.md +++ b/packages/shared_preferences/shared_preferences_macos/README.md @@ -2,13 +2,6 @@ The macos implementation of [`shared_preferences`][1]. -**Please set your constraint to `shared_preferences_macos: '>=0.0.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.0.y+z`. -Please use `shared_preferences_macos: '>=0.0.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage ### Import the package diff --git a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml index 912e2f648a26..754cf14f18f0 100644 --- a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml @@ -1,9 +1,6 @@ name: shared_preferences_macos description: macOS implementation of the shared_preferences plugin. -# 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.0.2-nullsafety +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_macos flutter: diff --git a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md index 0194ef8ade37..2526ffe4447d 100644 --- a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version to (semi-belatedly) meet 1.0-consistency promise. + ## 0.2.0-nullsafety * Migrate to null-safety. diff --git a/packages/shared_preferences/shared_preferences_web/README.md b/packages/shared_preferences/shared_preferences_web/README.md index 2bb8a9316d86..8f9d22d86ef5 100644 --- a/packages/shared_preferences/shared_preferences_web/README.md +++ b/packages/shared_preferences/shared_preferences_web/README.md @@ -2,13 +2,6 @@ The web implementation of [`shared_preferences`][1]. -**Please set your constraint to `shared_preferences_web: '>=0.1.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.1.y+z`. -Please use `shared_preferences_web: '>=0.1.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage ### Import the package diff --git a/packages/shared_preferences/shared_preferences_web/pubspec.yaml b/packages/shared_preferences/shared_preferences_web/pubspec.yaml index 60892bcf277c..33970f4d857d 100644 --- a/packages/shared_preferences/shared_preferences_web/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_web/pubspec.yaml @@ -1,10 +1,7 @@ name: shared_preferences_web description: Web platform implementation of shared_preferences homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_web -# 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.2.0-nullsafety +version: 2.0.0-nullsafety flutter: plugin: diff --git a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md index 41119901f396..d6a5fb336fe5 100644 --- a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md @@ -1,4 +1,8 @@ +## 2.0.0-nullsafety + +* Update version for consistency. + ## 0.0.3-nullsafety * Migrate to null-safety. diff --git a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml index e2cf3d03f00d..0b95c0c0d14a 100644 --- a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: shared_preferences_windows description: Windows implementation of shared_preferences homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_windows -version: 0.0.3-nullsafety +version: 2.0.0-nullsafety flutter: diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md index 2d5a9a7d05af..bd3c15cb31fb 100644 --- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version for consistency with other implementations. + ## 0.1.0-nullsafety.3 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml index c7aac06b88e5..37a074a57436 100644 --- a/packages/url_launcher/url_launcher_linux/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: url_launcher_linux description: Linux implementation of the url_launcher plugin. -version: 0.1.0-nullsafety.3 +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux flutter: diff --git a/packages/url_launcher/url_launcher_macos/CHANGELOG.md b/packages/url_launcher/url_launcher_macos/CHANGELOG.md index a5477a1b1501..5835c15f64e0 100644 --- a/packages/url_launcher/url_launcher_macos/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version to (semi-belatedly) meet 1.0-consistency promise. + # 0.1.0-nullsafety.2 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. @@ -58,4 +62,3 @@ # 0.0.1 * Initial open source release. - diff --git a/packages/url_launcher/url_launcher_macos/README.md b/packages/url_launcher/url_launcher_macos/README.md index e0c326ba86bf..28aa18817d6c 100644 --- a/packages/url_launcher/url_launcher_macos/README.md +++ b/packages/url_launcher/url_launcher_macos/README.md @@ -2,13 +2,6 @@ The macos implementation of [`url_launcher`][1]. -**Please set your constraint to `url_launcher_macos: '>=0.0.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.0.y+z`. -Please use `url_launcher_macos: '>=0.0.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage ### Import the package diff --git a/packages/url_launcher/url_launcher_macos/pubspec.yaml b/packages/url_launcher/url_launcher_macos/pubspec.yaml index be2dd2739298..bd918bfda24e 100644 --- a/packages/url_launcher/url_launcher_macos/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/pubspec.yaml @@ -1,9 +1,6 @@ name: url_launcher_macos description: macOS implementation of the url_launcher plugin. -# 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.0-nullsafety.2 +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos flutter: diff --git a/packages/url_launcher/url_launcher_windows/CHANGELOG.md b/packages/url_launcher/url_launcher_windows/CHANGELOG.md index a1998c92e2e2..b57785524d08 100644 --- a/packages/url_launcher/url_launcher_windows/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety + +* Update version to (semi-belatedly) meet 1.0-consistency promise. + ## 0.1.0-nullsafety.2 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/url_launcher/url_launcher_windows/README.md b/packages/url_launcher/url_launcher_windows/README.md index fb5ad6700d26..4cebb7ed91fb 100644 --- a/packages/url_launcher/url_launcher_windows/README.md +++ b/packages/url_launcher/url_launcher_windows/README.md @@ -2,13 +2,6 @@ The Windows implementation of [`url_launcher`][1]. -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.0.y+z`. If you use -url_launcher_windows directly, rather than as an implementation detail -of `url_launcher`, please use `url_launcher_windows: '>=0.0.y+x <2.0.0'` -as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage ### Import the package diff --git a/packages/url_launcher/url_launcher_windows/pubspec.yaml b/packages/url_launcher/url_launcher_windows/pubspec.yaml index f7c96bf4a1bd..368c3f831c2a 100644 --- a/packages/url_launcher/url_launcher_windows/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/pubspec.yaml @@ -1,9 +1,6 @@ name: url_launcher_windows description: Windows implementation of the url_launcher plugin. -# 0.0.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.0-nullsafety.2 +version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows flutter: diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index be005280609c..47b8f601e711 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,9 +1,6 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -# 0.10.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 version: 2.0.0-nullsafety.9 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player diff --git a/packages/video_player/video_player_web/README.md b/packages/video_player/video_player_web/README.md index 216b926bf26e..4f222be914eb 100644 --- a/packages/video_player/video_player_web/README.md +++ b/packages/video_player/video_player_web/README.md @@ -3,13 +3,6 @@ The web implementation of [`video_player`][1]. -**Please set your constraint to `video_player_web: '>=0.1.y+x <2.0.0'`** - -## Backward compatible 1.0.0 version is coming -The plugin has reached a stable API, we guarantee that version `1.0.0` will be backward compatible with `0.1.y+z`. -Please use `video_player_web: '>=0.1.y+x <2.0.0'` as your dependency constraint to allow a smoother ecosystem migration. -For more details see: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 - ## Usage This package is the endorsed implementation of `video_player` for the web platform since version `0.10.5`, so it gets automatically added to your application by depending on `video_player: ^0.10.5`. diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml index 9333ac0ac6f0..157ab9f1cf2f 100644 --- a/packages/video_player/video_player_web/pubspec.yaml +++ b/packages/video_player/video_player_web/pubspec.yaml @@ -1,9 +1,6 @@ name: video_player_web description: Web platform implementation of video_player. homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_web -# 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 version: 2.0.0-nullsafety.2 flutter: From 10b40ddae933068914df0794953805d1a9283516 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Sat, 13 Feb 2021 14:23:43 -0800 Subject: [PATCH 192/924] Update video_player_web to point to new video_player_interface (#3536) --- packages/video_player/video_player_web/CHANGELOG.md | 4 ++++ packages/video_player/video_player_web/pubspec.yaml | 6 ++---- .../video_player_web/test/video_player_web_test.dart | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/video_player/video_player_web/CHANGELOG.md b/packages/video_player/video_player_web/CHANGELOG.md index 2becf5b85e0a..7b3fc7871628 100644 --- a/packages/video_player/video_player_web/CHANGELOG.md +++ b/packages/video_player/video_player_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.3 + +* Updated to video_player_platform_interface 4.0. + ## 2.0.0-nullsafety.2 * Fixed an issue where `isBuffering` was not updating on Web. diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml index 157ab9f1cf2f..df5f4564bf4a 100644 --- a/packages/video_player/video_player_web/pubspec.yaml +++ b/packages/video_player/video_player_web/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player_web description: Web platform implementation of video_player. homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_web -version: 2.0.0-nullsafety.2 +version: 2.0.0-nullsafety.3 flutter: plugin: @@ -16,13 +16,11 @@ dependencies: flutter_web_plugins: sdk: flutter meta: ^1.3.0-nullsafety.3 - video_player_platform_interface: ^3.0.0-nullsafety.3 + video_player_platform_interface: ^4.0.0-nullsafety.0 dev_dependencies: flutter_test: sdk: flutter - video_player: - path: ../video_player pedantic: ^1.10.0-nullsafety.1 environment: diff --git a/packages/video_player/video_player_web/test/video_player_web_test.dart b/packages/video_player/video_player_web/test/video_player_web_test.dart index c433d82027f0..94b788872b03 100644 --- a/packages/video_player/video_player_web/test/video_player_web_test.dart +++ b/packages/video_player/video_player_web/test/video_player_web_test.dart @@ -1,6 +1,7 @@ // Copyright 2019 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. + @TestOn('browser') import 'dart:async'; @@ -8,7 +9,6 @@ import 'dart:async'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:video_player/video_player.dart'; import 'package:video_player_platform_interface/video_player_platform_interface.dart'; import 'package:video_player_web/video_player_web.dart'; From b3369c3d11df1b33b901cba2106f23e2ab792aa5 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Sun, 14 Feb 2021 13:15:22 -0800 Subject: [PATCH 193/924] [google_maps_flutter] Migrate platform interface to null safety (#3539) Part of flutter/flutter#75236 Includes a significant refactor of the various overlay objects to remove a lot of identical code across the objects. --- .../CHANGELOG.md | 9 + .../method_channel_google_maps_flutter.dart | 288 +++++++----------- .../google_maps_flutter_platform.dart | 89 +++--- .../lib/src/types/bitmap.dart | 93 +++--- .../lib/src/types/camera.dart | 46 +-- .../lib/src/types/cap.dart | 12 +- .../lib/src/types/circle.dart | 60 ++-- .../lib/src/types/circle_updates.dart | 98 +----- .../lib/src/types/location.dart | 22 +- .../lib/src/types/maps_object.dart | 49 +++ .../lib/src/types/maps_object_updates.dart | 126 ++++++++ .../lib/src/types/marker.dart | 105 +++---- .../lib/src/types/marker_updates.dart | 98 +----- .../lib/src/types/pattern_item.dart | 10 +- .../lib/src/types/polygon.dart | 72 ++--- .../lib/src/types/polygon_updates.dart | 98 +----- .../lib/src/types/polyline.dart | 80 ++--- .../lib/src/types/polyline_updates.dart | 100 +----- .../lib/src/types/screen_coordinate.dart | 8 +- .../lib/src/types/tile.dart | 8 +- .../lib/src/types/tile_overlay.dart | 53 ++-- .../lib/src/types/tile_overlay_updates.dart | 114 +------ .../lib/src/types/tile_provider.dart | 2 +- .../lib/src/types/types.dart | 2 + .../lib/src/types/ui.dart | 18 +- .../lib/src/types/utils/circle.dart | 14 +- .../lib/src/types/utils/maps_object.dart | 18 ++ .../lib/src/types/utils/marker.dart | 14 +- .../lib/src/types/utils/polygon.dart | 14 +- .../lib/src/types/utils/polyline.dart | 17 +- .../lib/src/types/utils/tile_overlay.dart | 23 +- .../pubspec.yaml | 10 +- .../test/types/maps_object_test.dart | 45 +++ .../test/types/maps_object_updates_test.dart | 160 ++++++++++ .../test/types/test_maps_object.dart | 46 +++ .../test/types/tile_overlay_test.dart | 16 +- .../test/types/tile_overlay_updates_test.dart | 12 +- .../test/types/tile_test.dart | 21 +- script/nnbd_plugins.sh | 3 +- 39 files changed, 961 insertions(+), 1112 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index 4273f596cf39..c530c31e488d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,12 @@ +## 2.0.0-nullsafety + +* Migrated to null-safety. +* BREAKING CHANGE: Removed deprecated APIs. +* BREAKING CHANGE: Many sets in APIs that used to treat null and empty set as + equivalent now require passing an empty set. +* BREAKING CHANGE: toJson now always returns an `Object`; the details of the + object type and structure should be treated as an implementation detail. + ## 1.2.0 * Add TileOverlay support. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index 8b7af2cc3515..3d16127ab7a9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -15,6 +15,26 @@ import 'package:stream_transform/stream_transform.dart'; import '../types/tile_overlay_updates.dart'; import '../types/utils/tile_overlay.dart'; +/// Error thrown when an unknown map ID is provided to a method channel API. +class UnknownMapIDError extends Error { + /// Creates an assertion error with the provided [mapId] and optional + /// [message]. + UnknownMapIDError(this.mapId, [this.message]); + + /// The unknown ID. + final int mapId; + + /// Message describing the assertion error. + final Object? message; + + String toString() { + if (message != null) { + return "Unknown map ID $mapId: ${Error.safeToString(message)}"; + } + return "Unknown map ID $mapId"; + } +} + /// An implementation of [GoogleMapsFlutterPlatform] that uses [MethodChannel] to communicate with the native code. /// /// The `google_maps_flutter` plugin code itself never talks to the native code directly. It delegates @@ -32,19 +52,20 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { /// Accesses the MethodChannel associated to the passed mapId. MethodChannel channel(int mapId) { - return _channels[mapId]; + MethodChannel? channel = _channels[mapId]; + if (channel == null) { + throw UnknownMapIDError(mapId); + } + return channel; } // Keep a collection of mapId to a map of TileOverlays. final Map> _tileOverlays = {}; - /// Initializes the platform interface with [id]. - /// - /// This method is called when the plugin is first initialized. @override Future init(int mapId) { - MethodChannel channel; - if (!_channels.containsKey(mapId)) { + MethodChannel? channel = _channels[mapId]; + if (channel == null) { channel = MethodChannel('plugins.flutter.io/google_maps_$mapId'); channel.setMethodCallHandler( (MethodCall call) => _handleMethodCall(call, mapId)); @@ -53,9 +74,8 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { return channel.invokeMethod('map#waitForMap'); } - /// Dispose of the native resources. @override - void dispose({int mapId}) { + void dispose({required int mapId}) { // Noop! } @@ -72,57 +92,57 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { _mapEventStreamController.stream.where((event) => event.mapId == mapId); @override - Stream onCameraMoveStarted({@required int mapId}) { + Stream onCameraMoveStarted({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onCameraMove({@required int mapId}) { + Stream onCameraMove({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onCameraIdle({@required int mapId}) { + Stream onCameraIdle({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onMarkerTap({@required int mapId}) { + Stream onMarkerTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onInfoWindowTap({@required int mapId}) { + Stream onInfoWindowTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onMarkerDragEnd({@required int mapId}) { + Stream onMarkerDragEnd({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onPolylineTap({@required int mapId}) { + Stream onPolylineTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onPolygonTap({@required int mapId}) { + Stream onPolygonTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onCircleTap({@required int mapId}) { + Stream onCircleTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onTap({@required int mapId}) { + Stream onTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onLongPress({@required int mapId}) { + Stream onLongPress({required int mapId}) { return _events(mapId).whereType(); } @@ -134,7 +154,7 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { case 'camera#onMove': _mapEventStreamController.add(CameraMoveEvent( mapId, - CameraPosition.fromMap(call.arguments['position']), + CameraPosition.fromMap(call.arguments['position'])!, )); break; case 'camera#onIdle': @@ -149,7 +169,7 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { case 'marker#onDragEnd': _mapEventStreamController.add(MarkerDragEndEvent( mapId, - LatLng.fromJson(call.arguments['position']), + LatLng.fromJson(call.arguments['position'])!, MarkerId(call.arguments['markerId']), )); break; @@ -180,26 +200,26 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { case 'map#onTap': _mapEventStreamController.add(MapTapEvent( mapId, - LatLng.fromJson(call.arguments['position']), + LatLng.fromJson(call.arguments['position'])!, )); break; case 'map#onLongPress': _mapEventStreamController.add(MapLongPressEvent( mapId, - LatLng.fromJson(call.arguments['position']), + LatLng.fromJson(call.arguments['position'])!, )); break; case 'tileOverlay#getTile': - final Map tileOverlaysForThisMap = + final Map? tileOverlaysForThisMap = _tileOverlays[mapId]; final String tileOverlayId = call.arguments['tileOverlayId']; - final TileOverlay tileOverlay = - tileOverlaysForThisMap[TileOverlayId(tileOverlayId)]; - Tile tile; - if (tileOverlay == null || tileOverlay.tileProvider == null) { + final TileOverlay? tileOverlay = + tileOverlaysForThisMap?[TileOverlayId(tileOverlayId)]; + TileProvider? tileProvider = tileOverlay?.tileProvider; + if (tileProvider == null) { return TileProvider.noTile.toJson(); } - tile = await tileOverlay.tileProvider.getTile( + final Tile tile = await tileProvider.getTile( call.arguments['x'], call.arguments['y'], call.arguments['zoom'], @@ -210,16 +230,10 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { } } - /// Updates configuration options of the map user interface. - /// - /// Change listeners are notified once the update has been made on the - /// platform side. - /// - /// The returned [Future] completes after listeners have been notified. @override Future updateMapOptions( Map optionsUpdate, { - @required int mapId, + required int mapId, }) { assert(optionsUpdate != null); return channel(mapId).invokeMethod( @@ -230,16 +244,10 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { ); } - /// Updates marker configuration. - /// - /// Change listeners are notified once the update has been made on the - /// platform side. - /// - /// The returned [Future] completes after listeners have been notified. @override Future updateMarkers( MarkerUpdates markerUpdates, { - @required int mapId, + required int mapId, }) { assert(markerUpdates != null); return channel(mapId).invokeMethod( @@ -248,16 +256,10 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { ); } - /// Updates polygon configuration. - /// - /// Change listeners are notified once the update has been made on the - /// platform side. - /// - /// The returned [Future] completes after listeners have been notified. @override Future updatePolygons( PolygonUpdates polygonUpdates, { - @required int mapId, + required int mapId, }) { assert(polygonUpdates != null); return channel(mapId).invokeMethod( @@ -266,16 +268,10 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { ); } - /// Updates polyline configuration. - /// - /// Change listeners are notified once the update has been made on the - /// platform side. - /// - /// The returned [Future] completes after listeners have been notified. @override Future updatePolylines( PolylineUpdates polylineUpdates, { - @required int mapId, + required int mapId, }) { assert(polylineUpdates != null); return channel(mapId).invokeMethod( @@ -284,16 +280,10 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { ); } - /// Updates circle configuration. - /// - /// Change listeners are notified once the update has been made on the - /// platform side. - /// - /// The returned [Future] completes after listeners have been notified. @override Future updateCircles( CircleUpdates circleUpdates, { - @required int mapId, + required int mapId, }) { assert(circleUpdates != null); return channel(mapId).invokeMethod( @@ -302,23 +292,16 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { ); } - /// Updates tile overlay configuration. - /// - /// Change listeners are notified once the update has been made on the - /// platform side. - /// - /// The returned [Future] completes after listeners have been notified. - /// - /// If `newTileOverlays` is null, all the [TileOverlays] are removed for the Map with `mapId`. @override Future updateTileOverlays({ - Set newTileOverlays, - @required int mapId, + required Set newTileOverlays, + required int mapId, }) { - final Map currentTileOverlays = + final Map? currentTileOverlays = _tileOverlays[mapId]; - Set previousSet = - currentTileOverlays != null ? currentTileOverlays.values.toSet() : null; + Set previousSet = currentTileOverlays != null + ? currentTileOverlays.values.toSet() + : {}; final TileOverlayUpdates updates = TileOverlayUpdates.from(previousSet, newTileOverlays); _tileOverlays[mapId] = keyTileOverlayId(newTileOverlays); @@ -328,203 +311,152 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { ); } - /// Clears the tile cache so that all tiles will be requested again from the - /// [TileProvider]. - /// - /// The current tiles from this tile overlay will also be - /// cleared from the map after calling this method. The Google Map SDK maintains a small - /// in-memory cache of tiles. If you want to cache tiles for longer, you - /// should implement an on-disk cache. @override Future clearTileCache( TileOverlayId tileOverlayId, { - @required int mapId, + required int mapId, }) { return channel(mapId) - .invokeMethod('tileOverlays#clearTileCache', { + .invokeMethod('tileOverlays#clearTileCache', { 'tileOverlayId': tileOverlayId.value, }); } - /// Starts an animated change of the map camera position. - /// - /// The returned [Future] completes after the change has been started on the - /// platform side. @override Future animateCamera( CameraUpdate cameraUpdate, { - @required int mapId, + required int mapId, }) { - return channel(mapId) - .invokeMethod('camera#animate', { + return channel(mapId).invokeMethod('camera#animate', { 'cameraUpdate': cameraUpdate.toJson(), }); } - /// Changes the map camera position. - /// - /// The returned [Future] completes after the change has been made on the - /// platform side. @override Future moveCamera( CameraUpdate cameraUpdate, { - @required int mapId, + required int mapId, }) { return channel(mapId).invokeMethod('camera#move', { 'cameraUpdate': cameraUpdate.toJson(), }); } - /// Sets the styling of the base map. - /// - /// Set to `null` to clear any previous custom styling. - /// - /// If problems were detected with the [mapStyle], including un-parsable - /// styling JSON, unrecognized feature type, unrecognized element type, or - /// invalid styler keys: [MapStyleException] is thrown and the current - /// style is left unchanged. - /// - /// The style string can be generated using [map style tool](https://mapstyle.withgoogle.com/). - /// Also, refer [iOS](https://developers.google.com/maps/documentation/ios-sdk/style-reference) - /// and [Android](https://developers.google.com/maps/documentation/android-sdk/style-reference) - /// style reference for more information regarding the supported styles. @override Future setMapStyle( - String mapStyle, { - @required int mapId, + String? mapStyle, { + required int mapId, }) async { - final List successAndError = await channel(mapId) - .invokeMethod>('map#setStyle', mapStyle); + final List successAndError = (await channel(mapId) + .invokeMethod>('map#setStyle', mapStyle))!; final bool success = successAndError[0]; if (!success) { throw MapStyleException(successAndError[1]); } } - /// Return the region that is visible in a map. @override Future getVisibleRegion({ - @required int mapId, + required int mapId, }) async { - final Map latLngBounds = await channel(mapId) - .invokeMapMethod('map#getVisibleRegion'); - final LatLng southwest = LatLng.fromJson(latLngBounds['southwest']); - final LatLng northeast = LatLng.fromJson(latLngBounds['northeast']); + final Map latLngBounds = (await channel(mapId) + .invokeMapMethod('map#getVisibleRegion'))!; + final LatLng southwest = LatLng.fromJson(latLngBounds['southwest'])!; + final LatLng northeast = LatLng.fromJson(latLngBounds['northeast'])!; return LatLngBounds(northeast: northeast, southwest: southwest); } - /// Return point [Map] of the [screenCoordinateInJson] in the current map view. - /// - /// A projection is used to translate between on screen location and geographic coordinates. - /// Screen location is in screen pixels (not display pixels) with respect to the top left corner - /// of the map, not necessarily of the whole screen. @override Future getScreenCoordinate( LatLng latLng, { - @required int mapId, + required int mapId, }) async { - final Map point = await channel(mapId) + final Map point = (await channel(mapId) .invokeMapMethod( - 'map#getScreenCoordinate', latLng.toJson()); + 'map#getScreenCoordinate', latLng.toJson()))!; - return ScreenCoordinate(x: point['x'], y: point['y']); + return ScreenCoordinate(x: point['x']!, y: point['y']!); } - /// Returns [LatLng] corresponding to the [ScreenCoordinate] in the current map view. - /// - /// Returned [LatLng] corresponds to a screen location. The screen location is specified in screen - /// pixels (not display pixels) relative to the top left of the map, not top left of the whole screen. @override Future getLatLng( ScreenCoordinate screenCoordinate, { - @required int mapId, + required int mapId, }) async { - final List latLng = await channel(mapId) + final List latLng = (await channel(mapId) .invokeMethod>( - 'map#getLatLng', screenCoordinate.toJson()); + 'map#getLatLng', screenCoordinate.toJson()))!; return LatLng(latLng[0], latLng[1]); } - /// Programmatically show the Info Window for a [Marker]. - /// - /// The `markerId` must match one of the markers on the map. - /// An invalid `markerId` triggers an "Invalid markerId" error. - /// - /// * See also: - /// * [hideMarkerInfoWindow] to hide the Info Window. - /// * [isMarkerInfoWindowShown] to check if the Info Window is showing. @override Future showMarkerInfoWindow( MarkerId markerId, { - @required int mapId, + required int mapId, }) { assert(markerId != null); return channel(mapId).invokeMethod( 'markers#showInfoWindow', {'markerId': markerId.value}); } - /// Programmatically hide the Info Window for a [Marker]. - /// - /// The `markerId` must match one of the markers on the map. - /// An invalid `markerId` triggers an "Invalid markerId" error. - /// - /// * See also: - /// * [showMarkerInfoWindow] to show the Info Window. - /// * [isMarkerInfoWindowShown] to check if the Info Window is showing. @override Future hideMarkerInfoWindow( MarkerId markerId, { - @required int mapId, + required int mapId, }) { assert(markerId != null); return channel(mapId).invokeMethod( 'markers#hideInfoWindow', {'markerId': markerId.value}); } - /// Returns `true` when the [InfoWindow] is showing, `false` otherwise. - /// - /// The `markerId` must match one of the markers on the map. - /// An invalid `markerId` triggers an "Invalid markerId" error. - /// - /// * See also: - /// * [showMarkerInfoWindow] to show the Info Window. - /// * [hideMarkerInfoWindow] to hide the Info Window. @override Future isMarkerInfoWindowShown( MarkerId markerId, { - @required int mapId, + required int mapId, }) { assert(markerId != null); return channel(mapId).invokeMethod('markers#isInfoWindowShown', - {'markerId': markerId.value}); + {'markerId': markerId.value}) as Future; } - /// Returns the current zoom level of the map @override Future getZoomLevel({ - @required int mapId, + required int mapId, }) { - return channel(mapId).invokeMethod('map#getZoomLevel'); + return channel(mapId).invokeMethod('map#getZoomLevel') + as Future; } - /// Returns the image bytes of the map @override - Future takeSnapshot({ - @required int mapId, + Future takeSnapshot({ + required int mapId, }) { return channel(mapId).invokeMethod('map#takeSnapshot'); } - /// This method builds the appropriate platform view where the map - /// can be rendered. - /// The `mapId` is passed as a parameter from the framework on the - /// `onPlatformViewCreated` callback. @override Widget buildView( - Map creationParams, - Set> gestureRecognizers, - PlatformViewCreatedCallback onPlatformViewCreated) { + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required CameraPosition initialCameraPosition, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set>? gestureRecognizers, + Map mapOptions = const {}, + }) { + final Map creationParams = { + 'initialCameraPosition': initialCameraPosition.toMap(), + 'options': mapOptions, + 'markersToAdd': serializeMarkerSet(markers), + 'polygonsToAdd': serializePolygonSet(polygons), + 'polylinesToAdd': serializePolylineSet(polylines), + 'circlesToAdd': serializeCircleSet(circles), + 'tileOverlaysToAdd': serializeTileOverlaySet(tileOverlays), + }; if (defaultTargetPlatform == TargetPlatform.android) { return AndroidView( viewType: 'plugins.flutter.io/google_maps', diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart index b9d3fecc0d0a..a363fc30f83c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart @@ -58,7 +58,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// The returned [Future] completes after listeners have been notified. Future updateMapOptions( Map optionsUpdate, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('updateMapOptions() has not been implemented.'); } @@ -71,7 +71,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// The returned [Future] completes after listeners have been notified. Future updateMarkers( MarkerUpdates markerUpdates, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('updateMarkers() has not been implemented.'); } @@ -84,7 +84,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// The returned [Future] completes after listeners have been notified. Future updatePolygons( PolygonUpdates polygonUpdates, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('updatePolygons() has not been implemented.'); } @@ -97,7 +97,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// The returned [Future] completes after listeners have been notified. Future updatePolylines( PolylineUpdates polylineUpdates, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('updatePolylines() has not been implemented.'); } @@ -110,7 +110,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// The returned [Future] completes after listeners have been notified. Future updateCircles( CircleUpdates circleUpdates, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('updateCircles() has not been implemented.'); } @@ -122,8 +122,8 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// /// The returned [Future] completes after listeners have been notified. Future updateTileOverlays({ - Set newTileOverlays, - @required int mapId, + required Set newTileOverlays, + required int mapId, }) { throw UnimplementedError('updateTileOverlays() has not been implemented.'); } @@ -137,7 +137,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// should implement an on-disk cache. Future clearTileCache( TileOverlayId tileOverlayId, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('clearTileCache() has not been implemented.'); } @@ -148,7 +148,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// platform side. Future animateCamera( CameraUpdate cameraUpdate, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('animateCamera() has not been implemented.'); } @@ -159,7 +159,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// platform side. Future moveCamera( CameraUpdate cameraUpdate, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('moveCamera() has not been implemented.'); } @@ -175,15 +175,15 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// /// The style string can be generated using [map style tool](https://mapstyle.withgoogle.com/). Future setMapStyle( - String mapStyle, { - @required int mapId, + String? mapStyle, { + required int mapId, }) { throw UnimplementedError('setMapStyle() has not been implemented.'); } /// Return the region that is visible in a map. Future getVisibleRegion({ - @required int mapId, + required int mapId, }) { throw UnimplementedError('getVisibleRegion() has not been implemented.'); } @@ -195,7 +195,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// of the map, not necessarily of the whole screen. Future getScreenCoordinate( LatLng latLng, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('getScreenCoordinate() has not been implemented.'); } @@ -207,7 +207,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// of the map, not necessarily of the whole screen. Future getLatLng( ScreenCoordinate screenCoordinate, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('getLatLng() has not been implemented.'); } @@ -222,7 +222,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// * [isMarkerInfoWindowShown] to check if the Info Window is showing. Future showMarkerInfoWindow( MarkerId markerId, { - @required int mapId, + required int mapId, }) { throw UnimplementedError( 'showMarkerInfoWindow() has not been implemented.'); @@ -238,7 +238,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// * [isMarkerInfoWindowShown] to check if the Info Window is showing. Future hideMarkerInfoWindow( MarkerId markerId, { - @required int mapId, + required int mapId, }) { throw UnimplementedError( 'hideMarkerInfoWindow() has not been implemented.'); @@ -254,21 +254,23 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { /// * [hideMarkerInfoWindow] to hide the Info Window. Future isMarkerInfoWindowShown( MarkerId markerId, { - @required int mapId, + required int mapId, }) { throw UnimplementedError('updateMapOptions() has not been implemented.'); } - /// Returns the current zoom level of the map + /// Returns the current zoom level of the map. Future getZoomLevel({ - @required int mapId, + required int mapId, }) { throw UnimplementedError('getZoomLevel() has not been implemented.'); } - /// Returns the image bytes of the map - Future takeSnapshot({ - @required int mapId, + /// Returns the image bytes of the map. + /// + /// Returns null if a snapshot cannot be created. + Future takeSnapshot({ + required int mapId, }) { throw UnimplementedError('takeSnapshot() has not been implemented.'); } @@ -277,70 +279,81 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { // into the plugin /// The Camera started moving. - Stream onCameraMoveStarted({@required int mapId}) { + Stream onCameraMoveStarted({required int mapId}) { throw UnimplementedError('onCameraMoveStarted() has not been implemented.'); } /// The Camera finished moving to a new [CameraPosition]. - Stream onCameraMove({@required int mapId}) { + Stream onCameraMove({required int mapId}) { throw UnimplementedError('onCameraMove() has not been implemented.'); } /// The Camera is now idle. - Stream onCameraIdle({@required int mapId}) { + Stream onCameraIdle({required int mapId}) { throw UnimplementedError('onCameraMove() has not been implemented.'); } /// A [Marker] has been tapped. - Stream onMarkerTap({@required int mapId}) { + Stream onMarkerTap({required int mapId}) { throw UnimplementedError('onMarkerTap() has not been implemented.'); } /// An [InfoWindow] has been tapped. - Stream onInfoWindowTap({@required int mapId}) { + Stream onInfoWindowTap({required int mapId}) { throw UnimplementedError('onInfoWindowTap() has not been implemented.'); } /// A [Marker] has been dragged to a different [LatLng] position. - Stream onMarkerDragEnd({@required int mapId}) { + Stream onMarkerDragEnd({required int mapId}) { throw UnimplementedError('onMarkerDragEnd() has not been implemented.'); } /// A [Polyline] has been tapped. - Stream onPolylineTap({@required int mapId}) { + Stream onPolylineTap({required int mapId}) { throw UnimplementedError('onPolylineTap() has not been implemented.'); } /// A [Polygon] has been tapped. - Stream onPolygonTap({@required int mapId}) { + Stream onPolygonTap({required int mapId}) { throw UnimplementedError('onPolygonTap() has not been implemented.'); } /// A [Circle] has been tapped. - Stream onCircleTap({@required int mapId}) { + Stream onCircleTap({required int mapId}) { throw UnimplementedError('onCircleTap() has not been implemented.'); } /// A Map has been tapped at a certain [LatLng]. - Stream onTap({@required int mapId}) { + Stream onTap({required int mapId}) { throw UnimplementedError('onTap() has not been implemented.'); } /// A Map has been long-pressed at a certain [LatLng]. - Stream onLongPress({@required int mapId}) { + Stream onLongPress({required int mapId}) { throw UnimplementedError('onLongPress() has not been implemented.'); } /// Dispose of whatever resources the `mapId` is holding on to. - void dispose({@required int mapId}) { + void dispose({required int mapId}) { throw UnimplementedError('dispose() has not been implemented.'); } /// Returns a widget displaying the map view Widget buildView( - Map creationParams, - Set> gestureRecognizers, - PlatformViewCreatedCallback onPlatformViewCreated) { + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required CameraPosition initialCameraPosition, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set>? gestureRecognizers = + const >{}, + // TODO: Replace with a structured type that's part of the interface. + // See https://github.com/flutter/flutter/issues/70330. + Map mapOptions = const {}, + }) { throw UnimplementedError('buildView() has not been implemented.'); } } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart index e10481e321f5..cc9887512d0e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart @@ -4,6 +4,7 @@ import 'dart:async' show Future; import 'dart:typed_data' show Uint8List; +import 'dart:ui' show Size; import 'package:flutter/material.dart' show ImageConfiguration, AssetImage, AssetBundleImageKey; @@ -61,28 +62,14 @@ class BitmapDescriptor { /// Creates a BitmapDescriptor that refers to the default marker image. static const BitmapDescriptor defaultMarker = - BitmapDescriptor._([_defaultMarker]); + BitmapDescriptor._([_defaultMarker]); /// Creates a BitmapDescriptor that refers to a colorization of the default /// marker image. For convenience, there is a predefined set of hue values. /// See e.g. [hueYellow]. static BitmapDescriptor defaultMarkerWithHue(double hue) { assert(0.0 <= hue && hue < 360.0); - return BitmapDescriptor._([_defaultMarker, hue]); - } - - /// Creates a BitmapDescriptor using the name of a bitmap image in the assets - /// directory. - /// - /// Use [fromAssetImage]. This method does not respect the screen dpi when - /// picking an asset image. - @Deprecated("Use fromAssetImage instead") - static BitmapDescriptor fromAsset(String assetName, {String package}) { - if (package == null) { - return BitmapDescriptor._([_fromAsset, assetName]); - } else { - return BitmapDescriptor._([_fromAsset, assetName, package]); - } + return BitmapDescriptor._([_defaultMarker, hue]); } /// Creates a [BitmapDescriptor] from an asset image. @@ -95,29 +82,31 @@ class BitmapDescriptor { static Future fromAssetImage( ImageConfiguration configuration, String assetName, { - AssetBundle bundle, - String package, + AssetBundle? bundle, + String? package, bool mipmaps = true, }) async { - if (!mipmaps && configuration.devicePixelRatio != null) { - return BitmapDescriptor._([ + double? devicePixelRatio = configuration.devicePixelRatio; + if (!mipmaps && devicePixelRatio != null) { + return BitmapDescriptor._([ _fromAssetImage, assetName, - configuration.devicePixelRatio, + devicePixelRatio, ]); } final AssetImage assetImage = AssetImage(assetName, package: package, bundle: bundle); final AssetBundleImageKey assetBundleImageKey = await assetImage.obtainKey(configuration); - return BitmapDescriptor._([ + final Size? size = configuration.size; + return BitmapDescriptor._([ _fromAssetImage, assetBundleImageKey.name, assetBundleImageKey.scale, - if (kIsWeb && configuration?.size != null) + if (kIsWeb && size != null) [ - configuration.size.width, - configuration.size.height, + size.width, + size.height, ], ]); } @@ -125,45 +114,47 @@ class BitmapDescriptor { /// Creates a BitmapDescriptor using an array of bytes that must be encoded /// as PNG. static BitmapDescriptor fromBytes(Uint8List byteData) { - return BitmapDescriptor._([_fromBytes, byteData]); + return BitmapDescriptor._([_fromBytes, byteData]); } /// The inverse of .toJson. // This is needed in Web to re-hydrate BitmapDescriptors that have been // transformed to JSON for transport. // TODO(https://github.com/flutter/flutter/issues/70330): Clean this up. - BitmapDescriptor.fromJson(dynamic json) : _json = json { - assert(_validTypes.contains(_json[0])); - switch (_json[0]) { + BitmapDescriptor.fromJson(Object json) : _json = json { + assert(_json is List); + final jsonList = json as List; + assert(_validTypes.contains(jsonList[0])); + switch (jsonList[0]) { case _defaultMarker: - assert(_json.length <= 2); - if (_json.length == 2) { - assert(_json[1] is num); - assert(0 <= _json[1] && _json[1] < 360); + assert(jsonList.length <= 2); + if (jsonList.length == 2) { + assert(jsonList[1] is num); + assert(0 <= jsonList[1] && jsonList[1] < 360); } break; case _fromBytes: - assert(_json.length == 2); - assert(_json[1] != null && _json[1] is List); - assert((_json[1] as List).isNotEmpty); + assert(jsonList.length == 2); + assert(jsonList[1] != null && jsonList[1] is List); + assert((jsonList[1] as List).isNotEmpty); break; case _fromAsset: - assert(_json.length <= 3); - assert(_json[1] != null && _json[1] is String); - assert((_json[1] as String).isNotEmpty); - if (_json.length == 3) { - assert(_json[2] != null && _json[2] is String); - assert((_json[2] as String).isNotEmpty); + assert(jsonList.length <= 3); + assert(jsonList[1] != null && jsonList[1] is String); + assert((jsonList[1] as String).isNotEmpty); + if (jsonList.length == 3) { + assert(jsonList[2] != null && jsonList[2] is String); + assert((jsonList[2] as String).isNotEmpty); } break; case _fromAssetImage: - assert(_json.length <= 4); - assert(_json[1] != null && _json[1] is String); - assert((_json[1] as String).isNotEmpty); - assert(_json[2] != null && _json[2] is double); - if (_json.length == 4) { - assert(_json[3] != null && _json[3] is List); - assert((_json[3] as List).length == 2); + assert(jsonList.length <= 4); + assert(jsonList[1] != null && jsonList[1] is String); + assert((jsonList[1] as String).isNotEmpty); + assert(jsonList[2] != null && jsonList[2] is double); + if (jsonList.length == 4) { + assert(jsonList[3] != null && jsonList[3] is List); + assert((jsonList[3] as List).length == 2); } break; default: @@ -171,8 +162,8 @@ class BitmapDescriptor { } } - final dynamic _json; + final Object _json; /// Convert the object to a Json format. - dynamic toJson() => _json; + Object toJson() => _json; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart index 10ea1e98846a..bdb039572624 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart @@ -4,8 +4,6 @@ import 'dart:ui' show hashValues, Offset; -import 'package:meta/meta.dart' show required; - import 'types.dart'; /// The position of the map "camera", the view point from which the world is shown in the map view. @@ -19,7 +17,7 @@ class CameraPosition { /// null. const CameraPosition({ this.bearing = 0.0, - @required this.target, + required this.target, this.tilt = 0.0, this.zoom = 0.0, }) : assert(bearing != null), @@ -63,7 +61,7 @@ class CameraPosition { /// Serializes [CameraPosition]. /// /// Mainly for internal use when calling [CameraUpdate.newCameraPosition]. - dynamic toMap() => { + Object toMap() => { 'bearing': bearing, 'target': target.toJson(), 'tilt': tilt, @@ -73,23 +71,27 @@ class CameraPosition { /// Deserializes [CameraPosition] from a map. /// /// Mainly for internal use. - static CameraPosition fromMap(dynamic json) { - if (json == null) { + static CameraPosition? fromMap(Object? json) { + if (json == null || !(json is Map)) { + return null; + } + final LatLng? target = LatLng.fromJson(json['target']); + if (target == null) { return null; } return CameraPosition( bearing: json['bearing'], - target: LatLng.fromJson(json['target']), + target: target, tilt: json['tilt'], zoom: json['zoom'], ); } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { if (identical(this, other)) return true; if (runtimeType != other.runtimeType) return false; - final CameraPosition typedOther = other; + final CameraPosition typedOther = other as CameraPosition; return bearing == typedOther.bearing && target == typedOther.target && tilt == typedOther.tilt && @@ -112,14 +114,14 @@ class CameraUpdate { /// Returns a camera update that moves the camera to the specified position. static CameraUpdate newCameraPosition(CameraPosition cameraPosition) { return CameraUpdate._( - ['newCameraPosition', cameraPosition.toMap()], + ['newCameraPosition', cameraPosition.toMap()], ); } /// Returns a camera update that moves the camera target to the specified /// geographical location. static CameraUpdate newLatLng(LatLng latLng) { - return CameraUpdate._(['newLatLng', latLng.toJson()]); + return CameraUpdate._(['newLatLng', latLng.toJson()]); } /// Returns a camera update that transforms the camera so that the specified @@ -127,7 +129,7 @@ class CameraUpdate { /// possible zoom level. A non-zero [padding] insets the bounding box from the /// map view's edges. The camera's new tilt and bearing will both be 0.0. static CameraUpdate newLatLngBounds(LatLngBounds bounds, double padding) { - return CameraUpdate._([ + return CameraUpdate._([ 'newLatLngBounds', bounds.toJson(), padding, @@ -138,7 +140,7 @@ class CameraUpdate { /// geographical location and zoom level. static CameraUpdate newLatLngZoom(LatLng latLng, double zoom) { return CameraUpdate._( - ['newLatLngZoom', latLng.toJson(), zoom], + ['newLatLngZoom', latLng.toJson(), zoom], ); } @@ -150,18 +152,18 @@ class CameraUpdate { /// 75 to the south of the current location, measured in screen coordinates. static CameraUpdate scrollBy(double dx, double dy) { return CameraUpdate._( - ['scrollBy', dx, dy], + ['scrollBy', dx, dy], ); } /// Returns a camera update that modifies the camera zoom level by the /// specified amount. The optional [focus] is a screen point whose underlying /// geographical location should be invariant, if possible, by the movement. - static CameraUpdate zoomBy(double amount, [Offset focus]) { + static CameraUpdate zoomBy(double amount, [Offset? focus]) { if (focus == null) { - return CameraUpdate._(['zoomBy', amount]); + return CameraUpdate._(['zoomBy', amount]); } else { - return CameraUpdate._([ + return CameraUpdate._([ 'zoomBy', amount, [focus.dx, focus.dy], @@ -174,7 +176,7 @@ class CameraUpdate { /// /// Equivalent to the result of calling `zoomBy(1.0)`. static CameraUpdate zoomIn() { - return CameraUpdate._(['zoomIn']); + return CameraUpdate._(['zoomIn']); } /// Returns a camera update that zooms the camera out, bringing the camera @@ -182,16 +184,16 @@ class CameraUpdate { /// /// Equivalent to the result of calling `zoomBy(-1.0)`. static CameraUpdate zoomOut() { - return CameraUpdate._(['zoomOut']); + return CameraUpdate._(['zoomOut']); } /// Returns a camera update that sets the camera zoom level. static CameraUpdate zoomTo(double zoom) { - return CameraUpdate._(['zoomTo', zoom]); + return CameraUpdate._(['zoomTo', zoom]); } - final dynamic _json; + final Object _json; /// Converts this object to something serializable in JSON. - dynamic toJson() => _json; + Object toJson() => _json; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart index 68bf14c36408..c88923a59404 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart @@ -17,16 +17,16 @@ class Cap { /// /// This is the default cap type at start and end vertices of Polylines with /// solid stroke pattern. - static const Cap buttCap = Cap._(['buttCap']); + static const Cap buttCap = Cap._(['buttCap']); /// Cap that is a semicircle with radius equal to half the stroke width, /// centered at the start or end vertex of a [Polyline] with solid stroke /// pattern. - static const Cap roundCap = Cap._(['roundCap']); + static const Cap roundCap = Cap._(['roundCap']); /// Cap that is squared off after extending half the stroke width beyond the /// start or end vertex of a [Polyline] with solid stroke pattern. - static const Cap squareCap = Cap._(['squareCap']); + static const Cap squareCap = Cap._(['squareCap']); /// Constructs a new CustomCap with a bitmap overlay centered at the start or /// end vertex of a [Polyline], orientated according to the direction of the line's @@ -45,11 +45,11 @@ class Cap { }) { assert(bitmapDescriptor != null); assert(refWidth > 0.0); - return Cap._(['customCap', bitmapDescriptor.toJson(), refWidth]); + return Cap._(['customCap', bitmapDescriptor.toJson(), refWidth]); } - final dynamic _json; + final Object _json; /// Converts this object to something serializable in JSON. - dynamic toJson() => _json; + Object toJson() => _json; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart index d1418a4c30b1..e3198dfd6512 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart @@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart' show VoidCallback; import 'package:flutter/material.dart' show Color, Colors; -import 'package:meta/meta.dart' show immutable, required; +import 'package:meta/meta.dart' show immutable; import 'types.dart'; @@ -12,36 +12,17 @@ import 'types.dart'; /// /// This does not have to be globally unique, only unique among the list. @immutable -class CircleId { +class CircleId extends MapsObjectId { /// Creates an immutable identifier for a [Circle]. - CircleId(this.value) : assert(value != null); - - /// value of the [CircleId]. - final String value; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other.runtimeType != runtimeType) return false; - final CircleId typedOther = other; - return value == typedOther.value; - } - - @override - int get hashCode => value.hashCode; - - @override - String toString() { - return 'CircleId{value: $value}'; - } + CircleId(String value) : super(value); } /// Draws a circle on the map. @immutable -class Circle { +class Circle implements MapsObject { /// Creates an immutable representation of a [Circle] to draw on [GoogleMap]. const Circle({ - @required this.circleId, + required this.circleId, this.consumeTapEvents = false, this.fillColor = Colors.transparent, this.center = const LatLng(0.0, 0.0), @@ -56,6 +37,9 @@ class Circle { /// Uniquely identifies a [Circle]. final CircleId circleId; + @override + CircleId get mapsId => circleId; + /// True if the [Circle] consumes tap events. /// /// If this is false, [onTap] callback will not be triggered. @@ -91,20 +75,20 @@ class Circle { final int zIndex; /// Callbacks to receive tap events for circle placed on this map. - final VoidCallback onTap; + final VoidCallback? onTap; /// Creates a new [Circle] object whose values are the same as this instance, /// unless overwritten by the specified parameters. Circle copyWith({ - bool consumeTapEventsParam, - Color fillColorParam, - LatLng centerParam, - double radiusParam, - Color strokeColorParam, - int strokeWidthParam, - bool visibleParam, - int zIndexParam, - VoidCallback onTapParam, + bool? consumeTapEventsParam, + Color? fillColorParam, + LatLng? centerParam, + double? radiusParam, + Color? strokeColorParam, + int? strokeWidthParam, + bool? visibleParam, + int? zIndexParam, + VoidCallback? onTapParam, }) { return Circle( circleId: circleId, @@ -124,10 +108,10 @@ class Circle { Circle clone() => copyWith(); /// Converts this object to something serializable in JSON. - dynamic toJson() { - final Map json = {}; + Object toJson() { + final Map json = {}; - void addIfPresent(String fieldName, dynamic value) { + void addIfPresent(String fieldName, Object? value) { if (value != null) { json[fieldName] = value; } @@ -150,7 +134,7 @@ class Circle { bool operator ==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; - final Circle typedOther = other; + final Circle typedOther = other as Circle; return circleId == typedOther.circleId && consumeTapEvents == typedOther.consumeTapEvents && fillColor == typedOther.fillColor && diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart index 6f494423a38f..a0b064b7be2a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart @@ -2,109 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show hashValues; - -import 'package:flutter/foundation.dart' show setEquals; - import 'types.dart'; -import 'utils/circle.dart'; /// [Circle] update events to be applied to the [GoogleMap]. /// /// Used in [GoogleMapController] when the map is updated. // (Do not re-export) -class CircleUpdates { +class CircleUpdates extends MapsObjectUpdates { /// Computes [CircleUpdates] given previous and current [Circle]s. - CircleUpdates.from(Set previous, Set current) { - if (previous == null) { - previous = Set.identity(); - } - - if (current == null) { - current = Set.identity(); - } - - final Map previousCircles = keyByCircleId(previous); - final Map currentCircles = keyByCircleId(current); - - final Set prevCircleIds = previousCircles.keys.toSet(); - final Set currentCircleIds = currentCircles.keys.toSet(); - - Circle idToCurrentCircle(CircleId id) { - return currentCircles[id]; - } - - final Set _circleIdsToRemove = - prevCircleIds.difference(currentCircleIds); - - final Set _circlesToAdd = currentCircleIds - .difference(prevCircleIds) - .map(idToCurrentCircle) - .toSet(); - - /// Returns `true` if [current] is not equals to previous one with the - /// same id. - bool hasChanged(Circle current) { - final Circle previous = previousCircles[current.circleId]; - return current != previous; - } - - final Set _circlesToChange = currentCircleIds - .intersection(prevCircleIds) - .map(idToCurrentCircle) - .where(hasChanged) - .toSet(); - - circlesToAdd = _circlesToAdd; - circleIdsToRemove = _circleIdsToRemove; - circlesToChange = _circlesToChange; - } + CircleUpdates.from(Set previous, Set current) + : super.from(previous, current, objectName: 'circle'); /// Set of Circles to be added in this update. - Set circlesToAdd; + Set get circlesToAdd => objectsToAdd; /// Set of CircleIds to be removed in this update. - Set circleIdsToRemove; + Set get circleIdsToRemove => objectIdsToRemove.cast(); /// Set of Circles to be changed in this update. - Set circlesToChange; - - /// Converts this object to something serializable in JSON. - Map toJson() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull('circlesToAdd', serializeCircleSet(circlesToAdd)); - addIfNonNull('circlesToChange', serializeCircleSet(circlesToChange)); - addIfNonNull('circleIdsToRemove', - circleIdsToRemove.map((CircleId m) => m.value).toList()); - - return updateMap; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other.runtimeType != runtimeType) return false; - final CircleUpdates typedOther = other; - return setEquals(circlesToAdd, typedOther.circlesToAdd) && - setEquals(circleIdsToRemove, typedOther.circleIdsToRemove) && - setEquals(circlesToChange, typedOther.circlesToChange); - } - - @override - int get hashCode => - hashValues(circlesToAdd, circleIdsToRemove, circlesToChange); - - @override - String toString() { - return '_CircleUpdates{circlesToAdd: $circlesToAdd, ' - 'circleIdsToRemove: $circleIdsToRemove, ' - 'circlesToChange: $circlesToChange}'; - } + Set get circlesToChange => objectsToChange; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart index 6b76a6d496ac..a719f0bc741f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart @@ -29,16 +29,18 @@ class LatLng { final double longitude; /// Converts this object to something serializable in JSON. - dynamic toJson() { + Object toJson() { return [latitude, longitude]; } /// Initialize a LatLng from an \[lat, lng\] array. - static LatLng fromJson(dynamic json) { + static LatLng? fromJson(Object? json) { if (json == null) { return null; } - return LatLng(json[0], json[1]); + assert(json is List && json.length == 2); + final list = json as List; + return LatLng(list[0], list[1]); } @override @@ -66,7 +68,7 @@ class LatLngBounds { /// /// The latitude of the southwest corner cannot be larger than the /// latitude of the northeast corner. - LatLngBounds({@required this.southwest, @required this.northeast}) + LatLngBounds({required this.southwest, required this.northeast}) : assert(southwest != null), assert(northeast != null), assert(southwest.latitude <= northeast.latitude); @@ -78,8 +80,8 @@ class LatLngBounds { final LatLng northeast; /// Converts this object to something serializable in JSON. - dynamic toJson() { - return [southwest.toJson(), northeast.toJson()]; + Object toJson() { + return [southwest.toJson(), northeast.toJson()]; } /// Returns whether this rectangle contains the given [LatLng]. @@ -102,13 +104,15 @@ class LatLngBounds { /// Converts a list to [LatLngBounds]. @visibleForTesting - static LatLngBounds fromList(dynamic json) { + static LatLngBounds? fromList(Object? json) { if (json == null) { return null; } + assert(json is List && json.length == 2); + final list = json as List; return LatLngBounds( - southwest: LatLng.fromJson(json[0]), - northeast: LatLng.fromJson(json[1]), + southwest: LatLng.fromJson(list[0])!, + northeast: LatLng.fromJson(list[1])!, ); } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart new file mode 100644 index 000000000000..545d46272215 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart @@ -0,0 +1,49 @@ +// Copyright 2019 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 'package:flutter/foundation.dart' show objectRuntimeType; +import 'package:meta/meta.dart' show immutable; + +/// Uniquely identifies object an among [GoogleMap] collections of a specific +/// type. +/// +/// This does not have to be globally unique, only unique among the collection. +@immutable +class MapsObjectId { + /// Creates an immutable object representing a [T] among [GoogleMap] Ts. + /// + /// An [AssertionError] will be thrown if [value] is null. + MapsObjectId(this.value) : assert(value != null); + + /// The value of the id. + final String value; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other.runtimeType != runtimeType) return false; + final MapsObjectId typedOther = other as MapsObjectId; + return value == typedOther.value; + } + + @override + int get hashCode => value.hashCode; + + @override + String toString() { + return '${objectRuntimeType(this, 'MapsObjectId')}($value)'; + } +} + +/// A common interface for maps types. +abstract class MapsObject { + /// A identifier for this object. + MapsObjectId get mapsId; + + /// Returns a duplicate of this object. + T clone(); + + /// Converts this object to something serializable in JSON. + Object toJson(); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart new file mode 100644 index 000000000000..01cf967f54e3 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart @@ -0,0 +1,126 @@ +// Copyright 2018 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:ui' show hashValues, hashList; + +import 'package:flutter/foundation.dart' show objectRuntimeType, setEquals; + +import 'maps_object.dart'; +import 'utils/maps_object.dart'; + +/// Update specification for a set of objects. +class MapsObjectUpdates { + /// Computes updates given previous and current object sets. + /// + /// [objectName] is the prefix to use when serializing the updates into a JSON + /// dictionary. E.g., 'circle' will give 'circlesToAdd', 'circlesToUpdate', + /// 'circleIdsToRemove'. + MapsObjectUpdates.from( + Set previous, + Set current, { + required this.objectName, + }) { + final Map, T> previousObjects = keyByMapsObjectId(previous); + final Map, T> currentObjects = keyByMapsObjectId(current); + + final Set> previousObjectIds = previousObjects.keys.toSet(); + final Set> currentObjectIds = currentObjects.keys.toSet(); + + /// Maps an ID back to a [T] in [currentObjects]. + /// + /// It is a programming error to call this with an ID that is not guaranteed + /// to be in [currentObjects]. + T _idToCurrentObject(MapsObjectId id) { + return currentObjects[id]!; + } + + _objectIdsToRemove = previousObjectIds.difference(currentObjectIds); + + _objectsToAdd = currentObjectIds + .difference(previousObjectIds) + .map(_idToCurrentObject) + .toSet(); + + // Returns `true` if [current] is not equals to previous one with the + // same id. + bool hasChanged(T current) { + final T? previous = previousObjects[current.mapsId as MapsObjectId]; + return current != previous; + } + + _objectsToChange = currentObjectIds + .intersection(previousObjectIds) + .map(_idToCurrentObject) + .where(hasChanged) + .toSet(); + } + + /// The name of the objects being updated, for use in serialization. + final String objectName; + + /// Set of objects to be added in this update. + Set get objectsToAdd { + return _objectsToAdd; + } + + late Set _objectsToAdd; + + /// Set of objects to be removed in this update. + Set> get objectIdsToRemove { + return _objectIdsToRemove; + } + + late Set> _objectIdsToRemove; + + /// Set of objects to be changed in this update. + Set get objectsToChange { + return _objectsToChange; + } + + late Set _objectsToChange; + + /// Converts this object to JSON. + Object toJson() { + final Map updateMap = {}; + + void addIfNonNull(String fieldName, Object? value) { + if (value != null) { + updateMap[fieldName] = value; + } + } + + addIfNonNull('${objectName}sToAdd', serializeMapsObjectSet(_objectsToAdd)); + addIfNonNull( + '${objectName}sToChange', serializeMapsObjectSet(_objectsToChange)); + addIfNonNull( + '${objectName}IdsToRemove', + _objectIdsToRemove + .map((MapsObjectId m) => m.value) + .toList()); + + return updateMap; + } + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) { + return false; + } + return other is MapsObjectUpdates && + setEquals(_objectsToAdd, other._objectsToAdd) && + setEquals(_objectIdsToRemove, other._objectIdsToRemove) && + setEquals(_objectsToChange, other._objectsToChange); + } + + @override + int get hashCode => hashValues(hashList(_objectsToAdd), + hashList(_objectIdsToRemove), hashList(_objectsToChange)); + + @override + String toString() { + return '${objectRuntimeType(this, 'MapsObjectUpdates')}(add: $objectsToAdd, ' + 'remove: $objectIdsToRemove, ' + 'change: $objectsToChange)'; + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart index 9b57f9676334..15351d58168b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart @@ -5,15 +5,12 @@ import 'dart:ui' show hashValues, Offset; import 'package:flutter/foundation.dart' show ValueChanged, VoidCallback; -import 'package:meta/meta.dart' show immutable, required; +import 'package:meta/meta.dart' show immutable; import 'types.dart'; -dynamic _offsetToJson(Offset offset) { - if (offset == null) { - return null; - } - return [offset.dx, offset.dy]; +Object _offsetToJson(Offset offset) { + return [offset.dx, offset.dy]; } /// Text labels for a [Marker] info window. @@ -32,12 +29,12 @@ class InfoWindow { /// Text displayed in an info window when the user taps the marker. /// /// A null value means no title. - final String title; + final String? title; /// Additional text displayed below the [title]. /// /// A null value means no additional text. - final String snippet; + final String? snippet; /// The icon image point that will be the anchor of the info window when /// displayed. @@ -48,15 +45,15 @@ class InfoWindow { final Offset anchor; /// onTap callback for this [InfoWindow]. - final VoidCallback onTap; + final VoidCallback? onTap; /// Creates a new [InfoWindow] object whose values are the same as this instance, /// unless overwritten by the specified parameters. InfoWindow copyWith({ - String titleParam, - String snippetParam, - Offset anchorParam, - VoidCallback onTapParam, + String? titleParam, + String? snippetParam, + Offset? anchorParam, + VoidCallback? onTapParam, }) { return InfoWindow( title: titleParam ?? title, @@ -66,10 +63,10 @@ class InfoWindow { ); } - dynamic _toJson() { - final Map json = {}; + Object _toJson() { + final Map json = {}; - void addIfPresent(String fieldName, dynamic value) { + void addIfPresent(String fieldName, Object? value) { if (value != null) { json[fieldName] = value; } @@ -86,7 +83,7 @@ class InfoWindow { bool operator ==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; - final InfoWindow typedOther = other; + final InfoWindow typedOther = other as InfoWindow; return title == typedOther.title && snippet == typedOther.snippet && anchor == typedOther.anchor; @@ -105,28 +102,9 @@ class InfoWindow { /// /// This does not have to be globally unique, only unique among the list. @immutable -class MarkerId { +class MarkerId extends MapsObjectId { /// Creates an immutable identifier for a [Marker]. - MarkerId(this.value) : assert(value != null); - - /// value of the [MarkerId]. - final String value; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other.runtimeType != runtimeType) return false; - final MarkerId typedOther = other; - return value == typedOther.value; - } - - @override - int get hashCode => value.hashCode; - - @override - String toString() { - return 'MarkerId{value: $value}'; - } + MarkerId(String value) : super(value); } /// Marks a geographical location on the map. @@ -135,7 +113,7 @@ class MarkerId { /// the map's surface; that is, it will not necessarily change orientation /// due to map rotations, tilting, or zooming. @immutable -class Marker { +class Marker implements MapsObject { /// Creates a set of marker configuration options. /// /// Default marker options. @@ -156,7 +134,7 @@ class Marker { /// * reports [onTap] events /// * reports [onDragEnd] events const Marker({ - @required this.markerId, + required this.markerId, this.alpha = 1.0, this.anchor = const Offset(0.5, 1.0), this.consumeTapEvents = false, @@ -175,6 +153,9 @@ class Marker { /// Uniquely identifies a [Marker]. final MarkerId markerId; + @override + MarkerId get mapsId => markerId; + /// The opacity of the marker, between 0.0 and 1.0 inclusive. /// /// 0.0 means fully transparent, 1.0 means fully opaque. @@ -224,27 +205,27 @@ class Marker { final double zIndex; /// Callbacks to receive tap events for markers placed on this map. - final VoidCallback onTap; + final VoidCallback? onTap; /// Signature reporting the new [LatLng] at the end of a drag event. - final ValueChanged onDragEnd; + final ValueChanged? onDragEnd; /// Creates a new [Marker] object whose values are the same as this instance, /// unless overwritten by the specified parameters. Marker copyWith({ - double alphaParam, - Offset anchorParam, - bool consumeTapEventsParam, - bool draggableParam, - bool flatParam, - BitmapDescriptor iconParam, - InfoWindow infoWindowParam, - LatLng positionParam, - double rotationParam, - bool visibleParam, - double zIndexParam, - VoidCallback onTapParam, - ValueChanged onDragEndParam, + double? alphaParam, + Offset? anchorParam, + bool? consumeTapEventsParam, + bool? draggableParam, + bool? flatParam, + BitmapDescriptor? iconParam, + InfoWindow? infoWindowParam, + LatLng? positionParam, + double? rotationParam, + bool? visibleParam, + double? zIndexParam, + VoidCallback? onTapParam, + ValueChanged? onDragEndParam, }) { return Marker( markerId: markerId, @@ -268,10 +249,10 @@ class Marker { Marker clone() => copyWith(); /// Converts this object to something serializable in JSON. - Map toJson() { - final Map json = {}; + Object toJson() { + final Map json = {}; - void addIfPresent(String fieldName, dynamic value) { + void addIfPresent(String fieldName, Object? value) { if (value != null) { json[fieldName] = value; } @@ -283,9 +264,9 @@ class Marker { addIfPresent('consumeTapEvents', consumeTapEvents); addIfPresent('draggable', draggable); addIfPresent('flat', flat); - addIfPresent('icon', icon?.toJson()); - addIfPresent('infoWindow', infoWindow?._toJson()); - addIfPresent('position', position?.toJson()); + addIfPresent('icon', icon.toJson()); + addIfPresent('infoWindow', infoWindow._toJson()); + addIfPresent('position', position.toJson()); addIfPresent('rotation', rotation); addIfPresent('visible', visible); addIfPresent('zIndex', zIndex); @@ -296,7 +277,7 @@ class Marker { bool operator ==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; - final Marker typedOther = other; + final Marker typedOther = other as Marker; return markerId == typedOther.markerId && alpha == typedOther.alpha && anchor == typedOther.anchor && diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart index bb6ea8813ea3..9c96ab63af18 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart @@ -2,109 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show hashValues; - -import 'package:flutter/foundation.dart' show setEquals; - import 'types.dart'; -import 'utils/marker.dart'; /// [Marker] update events to be applied to the [GoogleMap]. /// /// Used in [GoogleMapController] when the map is updated. // (Do not re-export) -class MarkerUpdates { +class MarkerUpdates extends MapsObjectUpdates { /// Computes [MarkerUpdates] given previous and current [Marker]s. - MarkerUpdates.from(Set previous, Set current) { - if (previous == null) { - previous = Set.identity(); - } - - if (current == null) { - current = Set.identity(); - } - - final Map previousMarkers = keyByMarkerId(previous); - final Map currentMarkers = keyByMarkerId(current); - - final Set prevMarkerIds = previousMarkers.keys.toSet(); - final Set currentMarkerIds = currentMarkers.keys.toSet(); - - Marker idToCurrentMarker(MarkerId id) { - return currentMarkers[id]; - } - - final Set _markerIdsToRemove = - prevMarkerIds.difference(currentMarkerIds); - - final Set _markersToAdd = currentMarkerIds - .difference(prevMarkerIds) - .map(idToCurrentMarker) - .toSet(); - - /// Returns `true` if [current] is not equals to previous one with the - /// same id. - bool hasChanged(Marker current) { - final Marker previous = previousMarkers[current.markerId]; - return current != previous; - } - - final Set _markersToChange = currentMarkerIds - .intersection(prevMarkerIds) - .map(idToCurrentMarker) - .where(hasChanged) - .toSet(); - - markersToAdd = _markersToAdd; - markerIdsToRemove = _markerIdsToRemove; - markersToChange = _markersToChange; - } + MarkerUpdates.from(Set previous, Set current) + : super.from(previous, current, objectName: 'marker'); /// Set of Markers to be added in this update. - Set markersToAdd; + Set get markersToAdd => objectsToAdd; /// Set of MarkerIds to be removed in this update. - Set markerIdsToRemove; + Set get markerIdsToRemove => objectIdsToRemove.cast(); /// Set of Markers to be changed in this update. - Set markersToChange; - - /// Converts this object to something serializable in JSON. - Map toJson() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull('markersToAdd', serializeMarkerSet(markersToAdd)); - addIfNonNull('markersToChange', serializeMarkerSet(markersToChange)); - addIfNonNull('markerIdsToRemove', - markerIdsToRemove.map((MarkerId m) => m.value).toList()); - - return updateMap; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other.runtimeType != runtimeType) return false; - final MarkerUpdates typedOther = other; - return setEquals(markersToAdd, typedOther.markersToAdd) && - setEquals(markerIdsToRemove, typedOther.markerIdsToRemove) && - setEquals(markersToChange, typedOther.markersToChange); - } - - @override - int get hashCode => - hashValues(markersToAdd, markerIdsToRemove, markersToChange); - - @override - String toString() { - return '_MarkerUpdates{markersToAdd: $markersToAdd, ' - 'markerIdsToRemove: $markerIdsToRemove, ' - 'markersToChange: $markersToChange}'; - } + Set get markersToChange => objectsToChange; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart index 28c7ce9d33dd..f1cd7f4cb8eb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart @@ -10,14 +10,14 @@ class PatternItem { const PatternItem._(this._json); /// A dot used in the stroke pattern for a [Polyline]. - static const PatternItem dot = PatternItem._(['dot']); + static const PatternItem dot = PatternItem._(['dot']); /// A dash used in the stroke pattern for a [Polyline]. /// /// [length] has to be non-negative. static PatternItem dash(double length) { assert(length >= 0.0); - return PatternItem._(['dash', length]); + return PatternItem._(['dash', length]); } /// A gap used in the stroke pattern for a [Polyline]. @@ -25,11 +25,11 @@ class PatternItem { /// [length] has to be non-negative. static PatternItem gap(double length) { assert(length >= 0.0); - return PatternItem._(['gap', length]); + return PatternItem._(['gap', length]); } - final dynamic _json; + final Object _json; /// Converts this object to something serializable in JSON. - dynamic toJson() => _json; + Object toJson() => _json; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart index 96b39157418d..4e5e9bf13d84 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart @@ -5,7 +5,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart' show listEquals, VoidCallback; import 'package:flutter/material.dart' show Color, Colors; -import 'package:meta/meta.dart' show immutable, required; +import 'package:meta/meta.dart' show immutable; import 'types.dart'; @@ -13,36 +13,17 @@ import 'types.dart'; /// /// This does not have to be globally unique, only unique among the list. @immutable -class PolygonId { +class PolygonId extends MapsObjectId { /// Creates an immutable identifier for a [Polygon]. - PolygonId(this.value) : assert(value != null); - - /// value of the [PolygonId]. - final String value; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other.runtimeType != runtimeType) return false; - final PolygonId typedOther = other; - return value == typedOther.value; - } - - @override - int get hashCode => value.hashCode; - - @override - String toString() { - return 'PolygonId{value: $value}'; - } + PolygonId(String value) : super(value); } /// Draws a polygon through geographical locations on the map. @immutable -class Polygon { +class Polygon implements MapsObject { /// Creates an immutable representation of a polygon through geographical locations on the map. const Polygon({ - @required this.polygonId, + required this.polygonId, this.consumeTapEvents = false, this.fillColor = Colors.black, this.geodesic = false, @@ -58,6 +39,9 @@ class Polygon { /// Uniquely identifies a [Polygon]. final PolygonId polygonId; + @override + PolygonId get mapsId => polygonId; + /// True if the [Polygon] consumes tap events. /// /// If this is false, [onTap] callback will not be triggered. @@ -107,21 +91,21 @@ class Polygon { final int zIndex; /// Callbacks to receive tap events for polygon placed on this map. - final VoidCallback onTap; + final VoidCallback? onTap; /// Creates a new [Polygon] object whose values are the same as this instance, /// unless overwritten by the specified parameters. Polygon copyWith({ - bool consumeTapEventsParam, - Color fillColorParam, - bool geodesicParam, - List pointsParam, - List> holesParam, - Color strokeColorParam, - int strokeWidthParam, - bool visibleParam, - int zIndexParam, - VoidCallback onTapParam, + bool? consumeTapEventsParam, + Color? fillColorParam, + bool? geodesicParam, + List? pointsParam, + List>? holesParam, + Color? strokeColorParam, + int? strokeWidthParam, + bool? visibleParam, + int? zIndexParam, + VoidCallback? onTapParam, }) { return Polygon( polygonId: polygonId, @@ -144,10 +128,10 @@ class Polygon { } /// Converts this object to something serializable in JSON. - dynamic toJson() { - final Map json = {}; + Object toJson() { + final Map json = {}; - void addIfPresent(String fieldName, dynamic value) { + void addIfPresent(String fieldName, Object? value) { if (value != null) { json[fieldName] = value; } @@ -177,7 +161,7 @@ class Polygon { bool operator ==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; - final Polygon typedOther = other; + final Polygon typedOther = other as Polygon; return polygonId == typedOther.polygonId && consumeTapEvents == typedOther.consumeTapEvents && fillColor == typedOther.fillColor && @@ -193,18 +177,18 @@ class Polygon { @override int get hashCode => polygonId.hashCode; - dynamic _pointsToJson() { - final List result = []; + Object _pointsToJson() { + final List result = []; for (final LatLng point in points) { result.add(point.toJson()); } return result; } - List> _holesToJson() { - final List> result = >[]; + List> _holesToJson() { + final List> result = >[]; for (final List hole in holes) { - final List jsonHole = []; + final List jsonHole = []; for (final LatLng point in hole) { jsonHole.add(point.toJson()); } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart index cc8b8e26c896..29b74aecbd66 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart @@ -2,109 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show hashValues; - -import 'package:flutter/foundation.dart' show setEquals; - import 'types.dart'; -import 'utils/polygon.dart'; /// [Polygon] update events to be applied to the [GoogleMap]. /// /// Used in [GoogleMapController] when the map is updated. // (Do not re-export) -class PolygonUpdates { +class PolygonUpdates extends MapsObjectUpdates { /// Computes [PolygonUpdates] given previous and current [Polygon]s. - PolygonUpdates.from(Set previous, Set current) { - if (previous == null) { - previous = Set.identity(); - } - - if (current == null) { - current = Set.identity(); - } - - final Map previousPolygons = keyByPolygonId(previous); - final Map currentPolygons = keyByPolygonId(current); - - final Set prevPolygonIds = previousPolygons.keys.toSet(); - final Set currentPolygonIds = currentPolygons.keys.toSet(); - - Polygon idToCurrentPolygon(PolygonId id) { - return currentPolygons[id]; - } - - final Set _polygonIdsToRemove = - prevPolygonIds.difference(currentPolygonIds); - - final Set _polygonsToAdd = currentPolygonIds - .difference(prevPolygonIds) - .map(idToCurrentPolygon) - .toSet(); - - /// Returns `true` if [current] is not equals to previous one with the - /// same id. - bool hasChanged(Polygon current) { - final Polygon previous = previousPolygons[current.polygonId]; - return current != previous; - } - - final Set _polygonsToChange = currentPolygonIds - .intersection(prevPolygonIds) - .map(idToCurrentPolygon) - .where(hasChanged) - .toSet(); - - polygonsToAdd = _polygonsToAdd; - polygonIdsToRemove = _polygonIdsToRemove; - polygonsToChange = _polygonsToChange; - } + PolygonUpdates.from(Set previous, Set current) + : super.from(previous, current, objectName: 'polygon'); /// Set of Polygons to be added in this update. - Set polygonsToAdd; + Set get polygonsToAdd => objectsToAdd; /// Set of PolygonIds to be removed in this update. - Set polygonIdsToRemove; + Set get polygonIdsToRemove => objectIdsToRemove.cast(); /// Set of Polygons to be changed in this update. - Set polygonsToChange; - - /// Converts this object to something serializable in JSON. - Map toJson() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull('polygonsToAdd', serializePolygonSet(polygonsToAdd)); - addIfNonNull('polygonsToChange', serializePolygonSet(polygonsToChange)); - addIfNonNull('polygonIdsToRemove', - polygonIdsToRemove.map((PolygonId m) => m.value).toList()); - - return updateMap; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other.runtimeType != runtimeType) return false; - final PolygonUpdates typedOther = other; - return setEquals(polygonsToAdd, typedOther.polygonsToAdd) && - setEquals(polygonIdsToRemove, typedOther.polygonIdsToRemove) && - setEquals(polygonsToChange, typedOther.polygonsToChange); - } - - @override - int get hashCode => - hashValues(polygonsToAdd, polygonIdsToRemove, polygonsToChange); - - @override - String toString() { - return '_PolygonUpdates{polygonsToAdd: $polygonsToAdd, ' - 'polygonIdsToRemove: $polygonIdsToRemove, ' - 'polygonsToChange: $polygonsToChange}'; - } + Set get polygonsToChange => objectsToChange; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart index ae5c3b976352..3f87395164f6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart @@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart' show listEquals, VoidCallback; import 'package:flutter/material.dart' show Color, Colors; -import 'package:meta/meta.dart' show immutable, required; +import 'package:meta/meta.dart' show immutable; import 'types.dart'; @@ -12,38 +12,19 @@ import 'types.dart'; /// /// This does not have to be globally unique, only unique among the list. @immutable -class PolylineId { +class PolylineId extends MapsObjectId { /// Creates an immutable object representing a [PolylineId] among [GoogleMap] polylines. /// /// An [AssertionError] will be thrown if [value] is null. - PolylineId(this.value) : assert(value != null); - - /// value of the [PolylineId]. - final String value; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other.runtimeType != runtimeType) return false; - final PolylineId typedOther = other; - return value == typedOther.value; - } - - @override - int get hashCode => value.hashCode; - - @override - String toString() { - return 'PolylineId{value: $value}'; - } + PolylineId(String value) : super(value); } /// Draws a line through geographical locations on the map. @immutable -class Polyline { +class Polyline implements MapsObject { /// Creates an immutable object representing a line drawn through geographical locations on the map. const Polyline({ - @required this.polylineId, + required this.polylineId, this.consumeTapEvents = false, this.color = Colors.black, this.endCap = Cap.buttCap, @@ -61,6 +42,9 @@ class Polyline { /// Uniquely identifies a [Polyline]. final PolylineId polylineId; + @override + PolylineId get mapsId => polylineId; + /// True if the [Polyline] consumes tap events. /// /// If this is false, [onTap] callback will not be triggered. @@ -129,23 +113,23 @@ class Polyline { final int zIndex; /// Callbacks to receive tap events for polyline placed on this map. - final VoidCallback onTap; + final VoidCallback? onTap; /// Creates a new [Polyline] object whose values are the same as this instance, /// unless overwritten by the specified parameters. Polyline copyWith({ - Color colorParam, - bool consumeTapEventsParam, - Cap endCapParam, - bool geodesicParam, - JointType jointTypeParam, - List patternsParam, - List pointsParam, - Cap startCapParam, - bool visibleParam, - int widthParam, - int zIndexParam, - VoidCallback onTapParam, + Color? colorParam, + bool? consumeTapEventsParam, + Cap? endCapParam, + bool? geodesicParam, + JointType? jointTypeParam, + List? patternsParam, + List? pointsParam, + Cap? startCapParam, + bool? visibleParam, + int? widthParam, + int? zIndexParam, + VoidCallback? onTapParam, }) { return Polyline( polylineId: polylineId, @@ -174,10 +158,10 @@ class Polyline { } /// Converts this object to something serializable in JSON. - dynamic toJson() { - final Map json = {}; + Object toJson() { + final Map json = {}; - void addIfPresent(String fieldName, dynamic value) { + void addIfPresent(String fieldName, Object? value) { if (value != null) { json[fieldName] = value; } @@ -186,10 +170,10 @@ class Polyline { addIfPresent('polylineId', polylineId.value); addIfPresent('consumeTapEvents', consumeTapEvents); addIfPresent('color', color.value); - addIfPresent('endCap', endCap?.toJson()); + addIfPresent('endCap', endCap.toJson()); addIfPresent('geodesic', geodesic); - addIfPresent('jointType', jointType?.value); - addIfPresent('startCap', startCap?.toJson()); + addIfPresent('jointType', jointType.value); + addIfPresent('startCap', startCap.toJson()); addIfPresent('visible', visible); addIfPresent('width', width); addIfPresent('zIndex', zIndex); @@ -209,7 +193,7 @@ class Polyline { bool operator ==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; - final Polyline typedOther = other; + final Polyline typedOther = other as Polyline; return polylineId == typedOther.polylineId && consumeTapEvents == typedOther.consumeTapEvents && color == typedOther.color && @@ -227,16 +211,16 @@ class Polyline { @override int get hashCode => polylineId.hashCode; - dynamic _pointsToJson() { - final List result = []; + Object _pointsToJson() { + final List result = []; for (final LatLng point in points) { result.add(point.toJson()); } return result; } - dynamic _patternToJson() { - final List result = []; + Object _patternToJson() { + final List result = []; for (final PatternItem patternItem in patterns) { if (patternItem != null) { result.add(patternItem.toJson()); diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart index f871928c0ac4..60e0bfe6c7ce 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart @@ -2,110 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show hashValues; - -import 'package:flutter/foundation.dart' show setEquals; - -import 'utils/polyline.dart'; import 'types.dart'; /// [Polyline] update events to be applied to the [GoogleMap]. /// /// Used in [GoogleMapController] when the map is updated. // (Do not re-export) -class PolylineUpdates { +class PolylineUpdates extends MapsObjectUpdates { /// Computes [PolylineUpdates] given previous and current [Polyline]s. - PolylineUpdates.from(Set previous, Set current) { - if (previous == null) { - previous = Set.identity(); - } - - if (current == null) { - current = Set.identity(); - } - - final Map previousPolylines = - keyByPolylineId(previous); - final Map currentPolylines = keyByPolylineId(current); - - final Set prevPolylineIds = previousPolylines.keys.toSet(); - final Set currentPolylineIds = currentPolylines.keys.toSet(); - - Polyline idToCurrentPolyline(PolylineId id) { - return currentPolylines[id]; - } - - final Set _polylineIdsToRemove = - prevPolylineIds.difference(currentPolylineIds); - - final Set _polylinesToAdd = currentPolylineIds - .difference(prevPolylineIds) - .map(idToCurrentPolyline) - .toSet(); - - /// Returns `true` if [current] is not equals to previous one with the - /// same id. - bool hasChanged(Polyline current) { - final Polyline previous = previousPolylines[current.polylineId]; - return current != previous; - } - - final Set _polylinesToChange = currentPolylineIds - .intersection(prevPolylineIds) - .map(idToCurrentPolyline) - .where(hasChanged) - .toSet(); - - polylinesToAdd = _polylinesToAdd; - polylineIdsToRemove = _polylineIdsToRemove; - polylinesToChange = _polylinesToChange; - } + PolylineUpdates.from(Set previous, Set current) + : super.from(previous, current, objectName: 'polyline'); /// Set of Polylines to be added in this update. - Set polylinesToAdd; + Set get polylinesToAdd => objectsToAdd; /// Set of PolylineIds to be removed in this update. - Set polylineIdsToRemove; + Set get polylineIdsToRemove => + objectIdsToRemove.cast(); /// Set of Polylines to be changed in this update. - Set polylinesToChange; - - /// Converts this object to something serializable in JSON. - Map toJson() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull('polylinesToAdd', serializePolylineSet(polylinesToAdd)); - addIfNonNull('polylinesToChange', serializePolylineSet(polylinesToChange)); - addIfNonNull('polylineIdsToRemove', - polylineIdsToRemove.map((PolylineId m) => m.value).toList()); - - return updateMap; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other.runtimeType != runtimeType) return false; - final PolylineUpdates typedOther = other; - return setEquals(polylinesToAdd, typedOther.polylinesToAdd) && - setEquals(polylineIdsToRemove, typedOther.polylineIdsToRemove) && - setEquals(polylinesToChange, typedOther.polylinesToChange); - } - - @override - int get hashCode => - hashValues(polylinesToAdd, polylineIdsToRemove, polylinesToChange); - - @override - String toString() { - return '_PolylineUpdates{polylinesToAdd: $polylinesToAdd, ' - 'polylineIdsToRemove: $polylineIdsToRemove, ' - 'polylinesToChange: $polylinesToChange}'; - } + Set get polylinesToChange => objectsToChange; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart index 965db7969bc2..af7a951a149c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart @@ -4,7 +4,7 @@ import 'dart:ui' show hashValues; -import 'package:meta/meta.dart' show immutable, required; +import 'package:meta/meta.dart' show immutable; /// Represents a point coordinate in the [GoogleMap]'s view. /// @@ -15,8 +15,8 @@ import 'package:meta/meta.dart' show immutable, required; class ScreenCoordinate { /// Creates an immutable representation of a point coordinate in the [GoogleMap]'s view. const ScreenCoordinate({ - @required this.x, - @required this.y, + required this.x, + required this.y, }); /// Represents the number of pixels from the left of the [GoogleMap]. @@ -26,7 +26,7 @@ class ScreenCoordinate { final int y; /// Converts this object to something serializable in JSON. - dynamic toJson() { + Object toJson() { return { "x": x, "y": y, diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart index a992b41fb6c0..bfc322856b5a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart @@ -21,13 +21,13 @@ class Tile { /// /// The image data format must be natively supported for decoding by the platform. /// e.g on Android it can only be one of the [supported image formats for decoding](https://developer.android.com/guide/topics/media/media-formats#image-formats). - final Uint8List data; + final Uint8List? data; /// Converts this object to JSON. - Map toJson() { - final Map json = {}; + Object toJson() { + final Map json = {}; - void addIfPresent(String fieldName, dynamic value) { + void addIfPresent(String fieldName, Object? value) { if (value != null) { json[fieldName] = value; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart index 3978f23f05f8..e31bfb461fb4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart @@ -6,30 +6,13 @@ import 'dart:ui' show hashValues; import 'package:flutter/foundation.dart'; import 'types.dart'; -import 'package:meta/meta.dart' show immutable, required; +import 'package:meta/meta.dart' show immutable; /// Uniquely identifies a [TileOverlay] among [GoogleMap] tile overlays. @immutable -class TileOverlayId { +class TileOverlayId extends MapsObjectId { /// Creates an immutable identifier for a [TileOverlay]. - TileOverlayId(this.value) : assert(value != null); - - /// The value of the [TileOverlayId]. - final String value; - - @override - bool operator ==(Object other) { - if (other.runtimeType != runtimeType) { - return false; - } - return other is TileOverlayId && other.value == value; - } - - @override - int get hashCode => value.hashCode; - - @override - String toString() => '${objectRuntimeType(this, 'TileOverlayId')}($value)'; + TileOverlayId(String value) : super(value); } /// A set of images which are displayed on top of the base map tiles. @@ -61,14 +44,14 @@ class TileOverlayId { /// At zoom level N, the x values of the tile coordinates range from 0 to 2N - 1 and increase from /// west to east and the y values range from 0 to 2N - 1 and increase from north to south. /// -class TileOverlay { +class TileOverlay implements MapsObject { /// Creates an immutable representation of a [TileOverlay] to draw on [GoogleMap]. const TileOverlay({ - @required this.tileOverlayId, + required this.tileOverlayId, this.fadeIn = true, this.tileProvider, this.transparency = 0.0, - this.zIndex, + this.zIndex = 0, this.visible = true, this.tileSize = 256, }) : assert(transparency >= 0.0 && transparency <= 1.0); @@ -76,11 +59,14 @@ class TileOverlay { /// Uniquely identifies a [TileOverlay]. final TileOverlayId tileOverlayId; + @override + TileOverlayId get mapsId => tileOverlayId; + /// Whether the tiles should fade in. The default is true. final bool fadeIn; /// The tile provider to use for this tile overlay. - final TileProvider tileProvider; + final TileProvider? tileProvider; /// The transparency of the tile overlay. The default transparency is 0 (opaque). final double transparency; @@ -104,12 +90,11 @@ class TileOverlay { /// Creates a new [TileOverlay] object whose values are the same as this instance, /// unless overwritten by the specified parameters. TileOverlay copyWith({ - TileOverlayId tileOverlayId, - bool fadeInParam, - double transparencyParam, - int zIndexParam, - bool visibleParam, - int tileSizeParam, + bool? fadeInParam, + double? transparencyParam, + int? zIndexParam, + bool? visibleParam, + int? tileSizeParam, }) { return TileOverlay( tileOverlayId: tileOverlayId, @@ -121,11 +106,13 @@ class TileOverlay { ); } + TileOverlay clone() => copyWith(); + /// Converts this object to JSON. - Map toJson() { - final Map json = {}; + Object toJson() { + final Map json = {}; - void addIfPresent(String fieldName, dynamic value) { + void addIfPresent(String fieldName, Object? value) { if (value != null) { json[fieldName] = value; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart index 2910fc37d495..1436880e9626 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart @@ -2,121 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/foundation.dart' show objectRuntimeType, setEquals; -import 'dart:ui' show hashValues, hashList; - -import 'utils/tile_overlay.dart'; import 'types.dart'; /// Update specification for a set of [TileOverlay]s. -class TileOverlayUpdates { +class TileOverlayUpdates extends MapsObjectUpdates { /// Computes [TileOverlayUpdates] given previous and current [TileOverlay]s. - TileOverlayUpdates.from(Set previous, Set current) { - if (previous == null) { - previous = Set.identity(); - } - - if (current == null) { - current = Set.identity(); - } - - final Map previousTileOverlays = - keyTileOverlayId(previous); - final Map currentTileOverlays = - keyTileOverlayId(current); - - final Set prevTileOverlayIds = - previousTileOverlays.keys.toSet(); - final Set currentTileOverlayIds = - currentTileOverlays.keys.toSet(); - - TileOverlay idToCurrentTileOverlay(TileOverlayId id) { - return currentTileOverlays[id]; - } - - _tileOverlayIdsToRemove = - prevTileOverlayIds.difference(currentTileOverlayIds); - - _tileOverlaysToAdd = currentTileOverlayIds - .difference(prevTileOverlayIds) - .map(idToCurrentTileOverlay) - .toSet(); - - // Returns `true` if [current] is not equals to previous one with the - // same id. - bool hasChanged(TileOverlay current) { - final TileOverlay previous = previousTileOverlays[current.tileOverlayId]; - return current != previous; - } - - _tileOverlaysToChange = currentTileOverlayIds - .intersection(prevTileOverlayIds) - .map(idToCurrentTileOverlay) - .where(hasChanged) - .toSet(); - } + TileOverlayUpdates.from(Set previous, Set current) + : super.from(previous, current, objectName: 'tileOverlay'); /// Set of TileOverlays to be added in this update. - Set get tileOverlaysToAdd { - return _tileOverlaysToAdd; - } - - Set _tileOverlaysToAdd; + Set get tileOverlaysToAdd => objectsToAdd; /// Set of TileOverlayIds to be removed in this update. - Set get tileOverlayIdsToRemove { - return _tileOverlayIdsToRemove; - } - - Set _tileOverlayIdsToRemove; + Set get tileOverlayIdsToRemove => + objectIdsToRemove.cast(); /// Set of TileOverlays to be changed in this update. - Set get tileOverlaysToChange { - return _tileOverlaysToChange; - } - - Set _tileOverlaysToChange; - - /// Converts this object to JSON. - Map toJson() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull( - 'tileOverlaysToAdd', serializeTileOverlaySet(_tileOverlaysToAdd)); - addIfNonNull( - 'tileOverlaysToChange', serializeTileOverlaySet(_tileOverlaysToChange)); - addIfNonNull( - 'tileOverlayIdsToRemove', - _tileOverlayIdsToRemove - .map((TileOverlayId m) => m.value) - .toList()); - - return updateMap; - } - - @override - bool operator ==(Object other) { - if (other.runtimeType != runtimeType) { - return false; - } - return other is TileOverlayUpdates && - setEquals(_tileOverlaysToAdd, other._tileOverlaysToAdd) && - setEquals(_tileOverlayIdsToRemove, other._tileOverlayIdsToRemove) && - setEquals(_tileOverlaysToChange, other._tileOverlaysToChange); - } - - @override - int get hashCode => hashValues(hashList(_tileOverlaysToAdd), - hashList(_tileOverlayIdsToRemove), hashList(_tileOverlaysToChange)); - - @override - String toString() { - return '${objectRuntimeType(this, 'TileOverlayUpdates')}($_tileOverlaysToAdd, $_tileOverlayIdsToRemove, $_tileOverlaysToChange)'; - } + Set get tileOverlaysToChange => objectsToChange; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart index c3c4f807e283..abaf38ba719d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart @@ -12,5 +12,5 @@ abstract class TileProvider { /// Returns the tile to be used for this tile coordinate. /// /// See [TileOverlay] for the specification of tile coordinates. - Future getTile(int x, int y, int zoom); + Future getTile(int x, int y, int? zoom); } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart index 3e2002f80ae3..9b7da87f2cb0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart @@ -11,6 +11,8 @@ export 'circle_updates.dart'; export 'circle.dart'; export 'joint_type.dart'; export 'location.dart'; +export 'maps_object_updates.dart'; +export 'maps_object.dart'; export 'marker_updates.dart'; export 'marker.dart'; export 'pattern_item.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart index 8d84171bac03..1c030e338353 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart @@ -39,19 +39,19 @@ class CameraTargetBounds { /// The geographical bounding box for the map camera target. /// /// A null value means the camera target is unbounded. - final LatLngBounds bounds; + final LatLngBounds? bounds; /// Unbounded camera target. static const CameraTargetBounds unbounded = CameraTargetBounds(null); /// Converts this object to something serializable in JSON. - dynamic toJson() => [bounds?.toJson()]; + Object toJson() => [bounds?.toJson()]; @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { if (identical(this, other)) return true; if (runtimeType != other.runtimeType) return false; - final CameraTargetBounds typedOther = other; + final CameraTargetBounds typedOther = other as CameraTargetBounds; return bounds == typedOther.bounds; } @@ -76,23 +76,23 @@ class MinMaxZoomPreference { : assert(minZoom == null || maxZoom == null || minZoom <= maxZoom); /// The preferred minimum zoom level or null, if unbounded from below. - final double minZoom; + final double? minZoom; /// The preferred maximum zoom level or null, if unbounded from above. - final double maxZoom; + final double? maxZoom; /// Unbounded zooming. static const MinMaxZoomPreference unbounded = MinMaxZoomPreference(null, null); /// Converts this object to something serializable in JSON. - dynamic toJson() => [minZoom, maxZoom]; + Object toJson() => [minZoom, maxZoom]; @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { if (identical(this, other)) return true; if (runtimeType != other.runtimeType) return false; - final MinMaxZoomPreference typedOther = other; + final MinMaxZoomPreference typedOther = other as MinMaxZoomPreference; return minZoom == typedOther.minZoom && maxZoom == typedOther.maxZoom; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart index 5c3af96f8e02..18bd31ec7df6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart @@ -3,20 +3,14 @@ // found in the LICENSE file. import '../types.dart'; +import 'maps_object.dart'; /// Converts an [Iterable] of Circles in a Map of CircleId -> Circle. Map keyByCircleId(Iterable circles) { - if (circles == null) { - return {}; - } - return Map.fromEntries(circles.map((Circle circle) => - MapEntry(circle.circleId, circle.clone()))); + return keyByMapsObjectId(circles).cast(); } /// Converts a Set of Circles into something serializable in JSON. -List> serializeCircleSet(Set circles) { - if (circles == null) { - return null; - } - return circles.map>((Circle p) => p.toJson()).toList(); +Object serializeCircleSet(Set circles) { + return serializeMapsObjectSet(circles); } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart new file mode 100644 index 000000000000..fa5a7e7591ee --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart @@ -0,0 +1,18 @@ +// Copyright 2019 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 '../maps_object.dart'; + +/// Converts an [Iterable] of [MapsObject]s in a Map of [MapObjectId] -> [MapObject]. +Map, T> keyByMapsObjectId( + Iterable objects) { + return Map, T>.fromEntries(objects.map((T object) => + MapEntry, T>( + object.mapsId as MapsObjectId, object.clone()))); +} + +/// Converts a Set of [MapsObject]s into something serializable in JSON. +Object serializeMapsObjectSet(Set mapsObjects) { + return mapsObjects.map((MapsObject p) => p.toJson()).toList(); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart index 7a2c76d8055b..057bebdc8b8a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart @@ -3,20 +3,14 @@ // found in the LICENSE file. import '../types.dart'; +import 'maps_object.dart'; /// Converts an [Iterable] of Markers in a Map of MarkerId -> Marker. Map keyByMarkerId(Iterable markers) { - if (markers == null) { - return {}; - } - return Map.fromEntries(markers.map((Marker marker) => - MapEntry(marker.markerId, marker.clone()))); + return keyByMapsObjectId(markers).cast(); } /// Converts a Set of Markers into something serializable in JSON. -List> serializeMarkerSet(Set markers) { - if (markers == null) { - return null; - } - return markers.map>((Marker m) => m.toJson()).toList(); +Object serializeMarkerSet(Set markers) { + return serializeMapsObjectSet(markers); } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart index 9434ddaa077d..050ecafce31f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart @@ -3,20 +3,14 @@ // found in the LICENSE file. import '../types.dart'; +import 'maps_object.dart'; /// Converts an [Iterable] of Polygons in a Map of PolygonId -> Polygon. Map keyByPolygonId(Iterable polygons) { - if (polygons == null) { - return {}; - } - return Map.fromEntries(polygons.map((Polygon polygon) => - MapEntry(polygon.polygonId, polygon.clone()))); + return keyByMapsObjectId(polygons).cast(); } /// Converts a Set of Polygons into something serializable in JSON. -List> serializePolygonSet(Set polygons) { - if (polygons == null) { - return null; - } - return polygons.map>((Polygon p) => p.toJson()).toList(); +Object serializePolygonSet(Set polygons) { + return serializeMapsObjectSet(polygons); } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart index 9cef6319ddb5..8f4098feedf7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart @@ -3,23 +3,14 @@ // found in the LICENSE file. import '../types.dart'; +import 'maps_object.dart'; /// Converts an [Iterable] of Polylines in a Map of PolylineId -> Polyline. Map keyByPolylineId(Iterable polylines) { - if (polylines == null) { - return {}; - } - return Map.fromEntries(polylines.map( - (Polyline polyline) => MapEntry( - polyline.polylineId, polyline.clone()))); + return keyByMapsObjectId(polylines).cast(); } /// Converts a Set of Polylines into something serializable in JSON. -List> serializePolylineSet(Set polylines) { - if (polylines == null) { - return null; - } - return polylines - .map>((Polyline p) => p.toJson()) - .toList(); +Object serializePolylineSet(Set polylines) { + return serializeMapsObjectSet(polylines); } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart index 0736c836481f..336f814d329a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart @@ -1,23 +1,18 @@ +// Copyright 2019 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 '../types.dart'; +import 'maps_object.dart'; /// Converts an [Iterable] of TileOverlay in a Map of TileOverlayId -> TileOverlay. Map keyTileOverlayId( Iterable tileOverlays) { - if (tileOverlays == null) { - return {}; - } - return Map.fromEntries(tileOverlays.map( - (TileOverlay tileOverlay) => MapEntry( - tileOverlay.tileOverlayId, tileOverlay))); + return keyByMapsObjectId(tileOverlays) + .cast(); } /// Converts a Set of TileOverlays into something serializable in JSON. -List> serializeTileOverlaySet( - Set tileOverlays) { - if (tileOverlays == null) { - return null; - } - return tileOverlays - .map>((TileOverlay p) => p.toJson()) - .toList(); +Object serializeTileOverlaySet(Set tileOverlays) { + return serializeMapsObjectSet(tileOverlays); } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index 487a54b08e5e..8b31feeb94a2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,22 +3,22 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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.2.0 +version: 2.0.0-nullsafety dependencies: flutter: sdk: flutter meta: ^1.0.5 - plugin_platform_interface: ^1.0.1 - stream_transform: ^1.2.0 + plugin_platform_interface: ^1.1.0-nullsafety.2 + stream_transform: ^2.0.0-nullsafety.0 collection: ^1.14.13 dev_dependencies: flutter_test: sdk: flutter - mockito: ^4.1.1 + mockito: ^5.0.0-nullsafety.0 pedantic: ^1.8.0 environment: - sdk: ">=2.3.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.9.1+hotfix.4" diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart new file mode 100644 index 000000000000..65692bd2a385 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart @@ -0,0 +1,45 @@ +// 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 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/utils/maps_object.dart'; + +import 'test_maps_object.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + test('keyByMapsObjectId', () async { + final MapsObjectId id1 = MapsObjectId('1'); + final MapsObjectId id2 = MapsObjectId('2'); + final MapsObjectId id3 = MapsObjectId('3'); + final TestMapsObject object1 = TestMapsObject(id1); + final TestMapsObject object2 = TestMapsObject(id2, data: 2); + final TestMapsObject object3 = TestMapsObject(id3); + expect( + keyByMapsObjectId({object1, object2, object3}), + , TestMapsObject>{ + id1: object1, + id2: object2, + id3: object3, + }); + }); + + test('serializeMapsObjectSet', () async { + final MapsObjectId id1 = MapsObjectId('1'); + final MapsObjectId id2 = MapsObjectId('2'); + final MapsObjectId id3 = MapsObjectId('3'); + final TestMapsObject object1 = TestMapsObject(id1); + final TestMapsObject object2 = TestMapsObject(id2, data: 2); + final TestMapsObject object3 = TestMapsObject(id3); + expect( + serializeMapsObjectSet({object1, object2, object3}), + >[ + {'id': '1'}, + {'id': '2'}, + {'id': '3'} + ]); + }); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart new file mode 100644 index 000000000000..68f4c587c2f2 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart @@ -0,0 +1,160 @@ +// 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:ui' show hashValues, hashList; + +import 'package:flutter/rendering.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/utils/maps_object.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/maps_object_updates.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/maps_object.dart'; + +import 'test_maps_object.dart'; + +class TestMapsObjectUpdate extends MapsObjectUpdates { + TestMapsObjectUpdate.from( + Set previous, Set current) + : super.from(previous, current, objectName: 'testObject'); +} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('tile overlay updates tests', () { + test('Correctly set toRemove, toAdd and toChange', () async { + final TestMapsObject to1 = + TestMapsObject(MapsObjectId('id1')); + final TestMapsObject to2 = + TestMapsObject(MapsObjectId('id2')); + final TestMapsObject to3 = + TestMapsObject(MapsObjectId('id3')); + final TestMapsObject to3Changed = + TestMapsObject(MapsObjectId('id3'), data: 2); + final TestMapsObject to4 = + TestMapsObject(MapsObjectId('id4')); + final Set previous = + Set.from([to1, to2, to3]); + final Set current = + Set.from([to2, to3Changed, to4]); + final TestMapsObjectUpdate updates = + TestMapsObjectUpdate.from(previous, current); + + final Set> toRemove = Set.from( + >[MapsObjectId('id1')]); + expect(updates.objectIdsToRemove, toRemove); + + final Set toAdd = Set.from([to4]); + expect(updates.objectsToAdd, toAdd); + + final Set toChange = + Set.from([to3Changed]); + expect(updates.objectsToChange, toChange); + }); + + test('toJson', () async { + final TestMapsObject to1 = + TestMapsObject(MapsObjectId('id1')); + final TestMapsObject to2 = + TestMapsObject(MapsObjectId('id2')); + final TestMapsObject to3 = + TestMapsObject(MapsObjectId('id3')); + final TestMapsObject to3Changed = + TestMapsObject(MapsObjectId('id3'), data: 2); + final TestMapsObject to4 = + TestMapsObject(MapsObjectId('id4')); + final Set previous = + Set.from([to1, to2, to3]); + final Set current = + Set.from([to2, to3Changed, to4]); + final TestMapsObjectUpdate updates = + TestMapsObjectUpdate.from(previous, current); + + final Object json = updates.toJson(); + expect(json, { + 'testObjectsToAdd': serializeMapsObjectSet(updates.objectsToAdd), + 'testObjectsToChange': serializeMapsObjectSet(updates.objectsToChange), + 'testObjectIdsToRemove': updates.objectIdsToRemove + .map((MapsObjectId m) => m.value) + .toList() + }); + }); + + test('equality', () async { + final TestMapsObject to1 = + TestMapsObject(MapsObjectId('id1')); + final TestMapsObject to2 = + TestMapsObject(MapsObjectId('id2')); + final TestMapsObject to3 = + TestMapsObject(MapsObjectId('id3')); + final TestMapsObject to3Changed = + TestMapsObject(MapsObjectId('id3'), data: 2); + final TestMapsObject to4 = + TestMapsObject(MapsObjectId('id4')); + final Set previous = + Set.from([to1, to2, to3]); + final Set current1 = + Set.from([to2, to3Changed, to4]); + final Set current2 = + Set.from([to2, to3Changed, to4]); + final Set current3 = Set.from([to2, to4]); + final TestMapsObjectUpdate updates1 = + TestMapsObjectUpdate.from(previous, current1); + final TestMapsObjectUpdate updates2 = + TestMapsObjectUpdate.from(previous, current2); + final TestMapsObjectUpdate updates3 = + TestMapsObjectUpdate.from(previous, current3); + expect(updates1, updates2); + expect(updates1, isNot(updates3)); + }); + + test('hashCode', () async { + final TestMapsObject to1 = + TestMapsObject(MapsObjectId('id1')); + final TestMapsObject to2 = + TestMapsObject(MapsObjectId('id2')); + final TestMapsObject to3 = + TestMapsObject(MapsObjectId('id3')); + final TestMapsObject to3Changed = + TestMapsObject(MapsObjectId('id3'), data: 2); + final TestMapsObject to4 = + TestMapsObject(MapsObjectId('id4')); + final Set previous = + Set.from([to1, to2, to3]); + final Set current = + Set.from([to2, to3Changed, to4]); + final TestMapsObjectUpdate updates = + TestMapsObjectUpdate.from(previous, current); + expect( + updates.hashCode, + hashValues( + hashList(updates.objectsToAdd), + hashList(updates.objectIdsToRemove), + hashList(updates.objectsToChange))); + }); + + test('toString', () async { + final TestMapsObject to1 = + TestMapsObject(MapsObjectId('id1')); + final TestMapsObject to2 = + TestMapsObject(MapsObjectId('id2')); + final TestMapsObject to3 = + TestMapsObject(MapsObjectId('id3')); + final TestMapsObject to3Changed = + TestMapsObject(MapsObjectId('id3'), data: 2); + final TestMapsObject to4 = + TestMapsObject(MapsObjectId('id4')); + final Set previous = + Set.from([to1, to2, to3]); + final Set current = + Set.from([to2, to3Changed, to4]); + final TestMapsObjectUpdate updates = + TestMapsObjectUpdate.from(previous, current); + expect( + updates.toString(), + 'TestMapsObjectUpdate(add: ${updates.objectsToAdd}, ' + 'remove: ${updates.objectIdsToRemove}, ' + 'change: ${updates.objectsToChange})'); + }); + }); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart new file mode 100644 index 000000000000..e15c73f08a54 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart @@ -0,0 +1,46 @@ +// 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:ui' show hashValues; +import 'package:flutter/rendering.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/maps_object_updates.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/maps_object.dart'; + +/// A trivial TestMapsObject implementation for testing updates with. +class TestMapsObject implements MapsObject { + TestMapsObject(this.mapsId, {this.data = 1}); + + final MapsObjectId mapsId; + + final int data; + + @override + TestMapsObject clone() { + return TestMapsObject(mapsId, data: data); + } + + @override + Object toJson() { + return {'id': mapsId.value}; + } + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) { + return false; + } + return other is TestMapsObject && + mapsId == other.mapsId && + data == other.data; + } + + @override + int get hashCode => hashValues(mapsId, data); +} + +class TestMapsObjectUpdate extends MapsObjectUpdates { + TestMapsObjectUpdate.from( + Set previous, Set current) + : super.from(previous, current, objectName: 'testObject'); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart index bb0621d23ae3..87380fdd651b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart @@ -34,13 +34,15 @@ void main() { zIndex: 1, visible: false, tileSize: 128); - final Map json = tileOverlay.toJson(); - expect(json['tileOverlayId'], 'id'); - expect(json['fadeIn'], false); - expect(json['transparency'], moreOrLessEquals(0.1)); - expect(json['zIndex'], 1); - expect(json['visible'], false); - expect(json['tileSize'], 128); + final Object json = tileOverlay.toJson(); + expect(json, { + 'tileOverlayId': 'id', + 'fadeIn': false, + 'transparency': moreOrLessEquals(0.1), + 'zIndex': 1, + 'visible': false, + 'tileSize': 128, + }); }); test('invalid transparency throws', () async { diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart index 980a203f709e..f622ca5213ef 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart @@ -49,13 +49,13 @@ void main() { final TileOverlayUpdates updates = TileOverlayUpdates.from(previous, current); - final Map json = updates.toJson(); - expect(json, { + final Object json = updates.toJson(); + expect(json, { 'tileOverlaysToAdd': serializeTileOverlaySet(updates.tileOverlaysToAdd), 'tileOverlaysToChange': serializeTileOverlaySet(updates.tileOverlaysToChange), 'tileOverlayIdsToRemove': updates.tileOverlayIdsToRemove - .map((TileOverlayId m) => m.value) + .map((TileOverlayId m) => m.value) .toList() }); }); @@ -117,9 +117,9 @@ void main() { TileOverlayUpdates.from(previous, current); expect( updates.toString(), - 'TileOverlayUpdates(${updates.tileOverlaysToAdd}, ' - '${updates.tileOverlayIdsToRemove}, ' - '${updates.tileOverlaysToChange})'); + 'TileOverlayUpdates(add: ${updates.tileOverlaysToAdd}, ' + 'remove: ${updates.tileOverlayIdsToRemove}, ' + 'change: ${updates.tileOverlaysToChange})'); }); }); } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart index 0be9a7cea8f0..3e0fe99ec18c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart @@ -13,16 +13,21 @@ void main() { test('toJson returns correct format', () async { final Uint8List data = Uint8List.fromList([0, 1]); final Tile tile = Tile(100, 200, data); - final Map json = tile.toJson(); - expect(json['width'], 100); - expect(json['height'], 200); - expect(json['data'], data); + final Object json = tile.toJson(); + expect(json, { + 'width': 100, + 'height': 200, + 'data': data, + }); }); - test('toJson returns empty if nothing presents', () async { - final Tile tile = Tile(null, null, null); - final Map json = tile.toJson(); - expect(json.isEmpty, true); + test('toJson handles null data', () async { + final Tile tile = Tile(0, 0, null); + final Object json = tile.toJson(); + expect(json, { + 'width': 0, + 'height': 0, + }); }); }); } diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 5a54a7ff30d6..3e82ac202a43 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -15,6 +15,7 @@ readonly NNBD_PLUGINS_LIST=( "file_selector" "flutter_plugin_android_lifecycle" "flutter_webview" + "google_maps_flutter" "google_sign_in" "image_picker" "ios_platform_images" @@ -38,7 +39,7 @@ readonly NNBD_PLUGINS_LIST=( readonly NON_NNBD_PLUGINS_LIST=( "camera" - # "google_maps_flutter" + "google_maps_flutter" # half migrated # "image_picker" # "in_app_purchase" # "quick_actions" From d054fa9a19bc4cb8165d8963f7323bf29a58cf19 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Sun, 14 Feb 2021 18:56:19 -0800 Subject: [PATCH 194/924] Enable CI tests on beta (#3538) --- .cirrus.yml | 12 ++++++++++++ script/build_all_plugins_app.sh | 8 +++----- script/nnbd_plugins.sh | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index a49a8b14ca83..c7323742e6e4 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -11,6 +11,8 @@ task: upgrade_script: - flutter channel stable - flutter upgrade + - flutter channel beta + - flutter upgrade - flutter channel master - flutter upgrade - git fetch origin master @@ -33,6 +35,7 @@ task: env: matrix: CHANNEL: "master" + CHANNEL: "beta" CHANNEL: "stable" test_script: # TODO(jackson): Allow web plugins once supported on stable @@ -44,12 +47,14 @@ task: env: matrix: CHANNEL: "master" + CHANNEL: "beta" CHANNEL: "stable" script: ./script/incremental_build.sh analyze - name: build_all_plugins_apk env: matrix: CHANNEL: "master" + CHANNEL: "beta" CHANNEL: "stable" script: # TODO(jackson): Allow web plugins once supported on stable @@ -79,6 +84,7 @@ task: PLUGIN_SHARDING: "--shardIndex 3 --shardCount 4" matrix: CHANNEL: "master" + CHANNEL: "beta" CHANNEL: "stable" MAPS_API_KEY: ENCRYPTED[596a9f6bca436694625ac50851dc5da6b4d34cba8025f7db5bc9465142e8cd44e15f69e3507787753accebfc4910d550] GCLOUD_FIREBASE_TESTLAB_KEY: ENCRYPTED[07586610af1fdfc894e5969f70ef2458341b9b7e9c3b7c4225a663b4a48732b7208a4d91c3b7d45305a6b55fa2a37fc4] @@ -121,6 +127,8 @@ task: upgrade_script: - flutter channel stable - flutter upgrade + - flutter channel beta + - flutter upgrade - flutter channel master - flutter upgrade - git fetch origin master @@ -148,6 +156,8 @@ task: - sudo gem install cocoapods - flutter channel stable - flutter upgrade + - flutter channel beta + - flutter upgrade - flutter channel master - flutter upgrade - git fetch origin master @@ -162,6 +172,7 @@ task: env: matrix: CHANNEL: "master" + CHANNEL: "beta" CHANNEL: "stable" script: # TODO(jackson): Allow web plugins once supported on stable @@ -180,6 +191,7 @@ task: PLUGIN_SHARDING: "--shardIndex 3 --shardCount 4" matrix: CHANNEL: "master" + CHANNEL: "beta" CHANNEL: "stable" SIMCTL_CHILD_MAPS_API_KEY: ENCRYPTED[596a9f6bca436694625ac50851dc5da6b4d34cba8025f7db5bc9465142e8cd44e15f69e3507787753accebfc4910d550] build_script: diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 7807e6a98bce..399f1f1b79f7 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -54,13 +54,11 @@ readonly EXCLUDED_PLUGINS_LIST=( readonly EXCLUDED=$(IFS=, ; echo "${EXCLUDED_PLUGINS_LIST[*]}") ALL_EXCLUDED=($EXCLUDED) -# Exclude nnbd plugins from stable. +# Exclude nnbd plugins from stable, and conflicting plugins otherwise. if [ "$CHANNEL" == "stable" ]; then ALL_EXCLUDED=("$EXCLUDED,$EXCLUDED_PLUGINS_FROM_STABLE") -fi -# Exclude non-nnbd plugins from master. -if [ "$CHANNEL" != "stable" ]; then - ALL_EXCLUDED=("$EXCLUDED,$EXCLUDED_PLUGINS_FROM_MASTER") +else + ALL_EXCLUDED=("$EXCLUDED,$EXCLUDED_PLUGINS_FOR_NNBD") fi echo "Excluding the following plugins: $ALL_EXCLUDED" diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 3e82ac202a43..a2c22c67948a 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -48,4 +48,4 @@ readonly NON_NNBD_PLUGINS_LIST=( ) export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}") -export EXCLUDED_PLUGINS_FROM_MASTER=$(IFS=, ; echo "${NON_NNBD_PLUGINS_LIST[*]}") +export EXCLUDED_PLUGINS_FOR_NNBD=$(IFS=, ; echo "${NON_NNBD_PLUGINS_LIST[*]}") From 57a40bf15a040d9c42a36d001918d724cca31fc2 Mon Sep 17 00:00:00 2001 From: hemanthrajdc <49126054+hemanthrajdc@users.noreply.github.com> Date: Mon, 15 Feb 2021 13:21:49 +0530 Subject: [PATCH 195/924] [camera] Fixes crash on takePicture() (#3537) * Fixes #75133 * Updated pubspec.yaml and change log * Fix format --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../io/flutter/plugins/camera/DeviceOrientationManager.java | 6 ++++++ packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 622bd095b021..e365e76cbafd 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0+4 + +* Fix crash when taking picture with orientation lock + ## 0.7.0+3 * Clockwise rotation of focus point in android diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java index 7c6011b185fb..b2a504b629d6 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java @@ -55,6 +55,12 @@ public int getMediaOrientation() { public int getMediaOrientation(PlatformChannel.DeviceOrientation orientation) { int angle = 0; + + // Fallback to device orientation when the orientation value is null + if (orientation == null) { + orientation = getUIOrientation(); + } + switch (orientation) { case PORTRAIT_UP: angle = 0; diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index cebbb334c8f2..5ac4b57a15ef 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+3 +version: 0.7.0+4 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 7e9c79b2282838149cc0a5c0b94243689bd5f6f8 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Mon, 15 Feb 2021 10:00:19 +0100 Subject: [PATCH 196/924] [camera] NNBD migration of the camera plugin (#3533) * Migrate camera_platform_interface to null safety * Exclude camera_platform_interface from all plugins script * Convert CameraId in test to non-nullable * Migrate to nullsafety * Attempt to fix dependency problem building all plugins * Update version information * Fix type * Make exposureMode and focusMode non-nullable * Mark google_maps_flutter as non-NNBD * Update dependencies * Added missing entry to CHANGELOG.md * Rebased on master --- packages/camera/camera/CHANGELOG.md | 4 + .../camera/example/ios/Flutter/Debug.xcconfig | 1 + .../example/ios/Flutter/Release.xcconfig | 1 + .../ios/Runner.xcodeproj/project.pbxproj | 19 -- .../contents.xcworkspacedata | 2 +- .../camera/lib/src/camera_controller.dart | 97 ++++---- .../camera/camera/lib/src/camera_image.dart | 6 +- .../camera/camera/lib/src/camera_preview.dart | 6 +- packages/camera/camera/pubspec.yaml | 21 +- packages/camera/camera/test/camera_test.dart | 225 ++++++++++++++---- .../camera/camera/test/camera_value_test.dart | 8 +- .../test/utils/method_channel_mock.dart | 6 +- script/nnbd_plugins.sh | 5 +- 13 files changed, 270 insertions(+), 131 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index e365e76cbafd..aee3774087ba 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.0-nullsafety + +* Migrated to null safety. + ## 0.7.0+4 * Fix crash when taking picture with orientation lock diff --git a/packages/camera/camera/example/ios/Flutter/Debug.xcconfig b/packages/camera/camera/example/ios/Flutter/Debug.xcconfig index e8efba114687..b2f5fae9c254 100644 --- a/packages/camera/camera/example/ios/Flutter/Debug.xcconfig +++ b/packages/camera/camera/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1,3 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/packages/camera/camera/example/ios/Flutter/Release.xcconfig b/packages/camera/camera/example/ios/Flutter/Release.xcconfig index 399e9340e6f6..88c29144c836 100644 --- a/packages/camera/camera/example/ios/Flutter/Release.xcconfig +++ b/packages/camera/camera/example/ios/Flutter/Release.xcconfig @@ -1,2 +1,3 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj index d51240a02c14..3f71bb69d6b6 100644 --- a/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj @@ -147,7 +147,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - FE224661708E6DA2A0F8B952 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -252,24 +251,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - FE224661708E6DA2A0F8B952 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../Flutter/Flutter.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/packages/camera/camera/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/camera/camera/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16ed0f..919434a6254f 100644 --- a/packages/camera/camera/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/packages/camera/camera/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index 80e83c867954..bb976d1c85fe 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -32,19 +32,19 @@ Future> availableCameras() async { class CameraValue { /// Creates a new camera controller state. const CameraValue({ - this.isInitialized, + required this.isInitialized, this.errorDescription, this.previewSize, - this.isRecordingVideo, - this.isTakingPicture, - this.isStreamingImages, - bool isRecordingPaused, - this.flashMode, - this.exposureMode, - this.focusMode, - this.exposurePointSupported, - this.focusPointSupported, - this.deviceOrientation, + required this.isRecordingVideo, + required this.isTakingPicture, + required this.isStreamingImages, + required bool isRecordingPaused, + required this.flashMode, + required this.exposureMode, + required this.focusMode, + required this.exposurePointSupported, + required this.focusPointSupported, + required this.deviceOrientation, this.lockedCaptureOrientation, this.recordingOrientation, }) : _isRecordingPaused = isRecordingPaused; @@ -58,7 +58,9 @@ class CameraValue { isStreamingImages: false, isRecordingPaused: false, flashMode: FlashMode.auto, + exposureMode: ExposureMode.auto, exposurePointSupported: false, + focusMode: FocusMode.auto, focusPointSupported: false, deviceOrientation: DeviceOrientation.portraitUp, ); @@ -84,17 +86,17 @@ class CameraValue { /// /// This is null while the controller is not in an error state. /// When [hasError] is true this contains the error description. - final String errorDescription; + final String? errorDescription; /// The size of the preview in pixels. /// - /// Is `null` until [isInitialized] is `true`. - final Size previewSize; + /// Is `null` until [isInitialized] is `true`. + final Size? previewSize; /// Convenience getter for `previewSize.width / previewSize.height`. /// /// Can only be called when [initialize] is done. - double get aspectRatio => previewSize.width / previewSize.height; + double get aspectRatio => previewSize!.width / previewSize!.height; /// Whether the controller is in an error state. /// @@ -120,34 +122,34 @@ class CameraValue { final DeviceOrientation deviceOrientation; /// The currently locked capture orientation. - final DeviceOrientation lockedCaptureOrientation; + final DeviceOrientation? lockedCaptureOrientation; /// Whether the capture orientation is currently locked. bool get isCaptureOrientationLocked => lockedCaptureOrientation != null; /// The orientation of the currently running video recording. - final DeviceOrientation recordingOrientation; + final DeviceOrientation? recordingOrientation; /// Creates a modified copy of the object. /// /// Explicitly specified fields get the specified value, all other fields get /// the same value of the current object. CameraValue copyWith({ - bool isInitialized, - bool isRecordingVideo, - bool isTakingPicture, - bool isStreamingImages, - String errorDescription, - Size previewSize, - bool isRecordingPaused, - FlashMode flashMode, - ExposureMode exposureMode, - FocusMode focusMode, - bool exposurePointSupported, - bool focusPointSupported, - DeviceOrientation deviceOrientation, - Optional lockedCaptureOrientation, - Optional recordingOrientation, + bool? isInitialized, + bool? isRecordingVideo, + bool? isTakingPicture, + bool? isStreamingImages, + String? errorDescription, + Size? previewSize, + bool? isRecordingPaused, + FlashMode? flashMode, + ExposureMode? exposureMode, + FocusMode? focusMode, + bool? exposurePointSupported, + bool? focusPointSupported, + DeviceOrientation? deviceOrientation, + Optional? lockedCaptureOrientation, + Optional? recordingOrientation, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -225,13 +227,17 @@ class CameraController extends ValueNotifier { /// The [ImageFormatGroup] describes the output of the raw image format. /// /// When null the imageFormat will fallback to the platforms default. - final ImageFormatGroup imageFormatGroup; + final ImageFormatGroup? imageFormatGroup; + + /// The id of a camera that hasn't been initialized. + @visibleForTesting + static const int kUninitializedCameraId = -1; + int _cameraId = kUninitializedCameraId; - int _cameraId; bool _isDisposed = false; - StreamSubscription _imageStreamSubscription; - FutureOr _initCalled; - StreamSubscription _deviceOrientationSubscription; + StreamSubscription? _imageStreamSubscription; + FutureOr? _initCalled; + StreamSubscription? _deviceOrientationSubscription; /// Checks whether [CameraController.dispose] has completed successfully. /// @@ -278,7 +284,7 @@ class CameraController extends ValueNotifier { await CameraPlatform.instance.initializeCamera( _cameraId, - imageFormatGroup: imageFormatGroup, + imageFormatGroup: imageFormatGroup ?? ImageFormatGroup.unknown, ); value = value.copyWith( @@ -422,7 +428,7 @@ class CameraController extends ValueNotifier { throw CameraException(e.code, e.message); } - await _imageStreamSubscription.cancel(); + await _imageStreamSubscription?.cancel(); _imageStreamSubscription = null; } @@ -583,12 +589,16 @@ class CameraController extends ValueNotifier { } /// Sets the exposure point for automatically determining the exposure value. - Future setExposurePoint(Offset point) async { + /// + /// Supplying a `null` value will reset the exposure point to it's default + /// value. + Future setExposurePoint(Offset? point) async { if (point != null && (point.dx < 0 || point.dx > 1 || point.dy < 0 || point.dy > 1)) { throw ArgumentError( 'The values of point should be anywhere between (0,0) and (1,1).'); } + try { await CameraPlatform.instance.setExposurePoint( _cameraId, @@ -682,7 +692,7 @@ class CameraController extends ValueNotifier { /// Locks the capture orientation. /// /// If [orientation] is omitted, the current device orientation is used. - Future lockCaptureOrientation([DeviceOrientation orientation]) async { + Future lockCaptureOrientation([DeviceOrientation? orientation]) async { try { await CameraPlatform.instance.lockCaptureOrientation( _cameraId, orientation ?? value.deviceOrientation); @@ -715,7 +725,10 @@ class CameraController extends ValueNotifier { } /// Sets the focus point for automatically determining the focus value. - Future setFocusPoint(Offset point) async { + /// + /// Supplying a `null` value will reset the focus point to it's default + /// value. + Future setFocusPoint(Offset? point) async { if (point != null && (point.dx < 0 || point.dx > 1 || point.dy < 0 || point.dy > 1)) { throw ArgumentError( diff --git a/packages/camera/camera/lib/src/camera_image.dart b/packages/camera/camera/lib/src/camera_image.dart index dffa5066d14f..46aa2a6e3091 100644 --- a/packages/camera/camera/lib/src/camera_image.dart +++ b/packages/camera/camera/lib/src/camera_image.dart @@ -26,7 +26,7 @@ class Plane { /// The distance between adjacent pixel samples on Android, in bytes. /// /// Will be `null` on iOS. - final int bytesPerPixel; + final int? bytesPerPixel; /// The row stride for this color plane, in bytes. final int bytesPerRow; @@ -34,12 +34,12 @@ class Plane { /// Height of the pixel buffer on iOS. /// /// Will be `null` on Android - final int height; + final int? height; /// Width of the pixel buffer on iOS. /// /// Will be `null` on Android. - final int width; + final int? width; } /// Describes how pixels are represented in an image. diff --git a/packages/camera/camera/lib/src/camera_preview.dart b/packages/camera/camera/lib/src/camera_preview.dart index 05e969004233..f6d357b41b77 100644 --- a/packages/camera/camera/lib/src/camera_preview.dart +++ b/packages/camera/camera/lib/src/camera_preview.dart @@ -17,7 +17,7 @@ class CameraPreview extends StatelessWidget { final CameraController controller; /// A widget to overlay on top of the camera preview - final Widget child; + final Widget? child; @override Widget build(BuildContext context) { @@ -43,7 +43,7 @@ class CameraPreview extends StatelessWidget { DeviceOrientation _getApplicableOrientation() { return controller.value.isRecordingVideo - ? controller.value.recordingOrientation + ? controller.value.recordingOrientation! : (controller.value.lockedCaptureOrientation ?? controller.value.deviceOrientation); } @@ -61,6 +61,6 @@ class CameraPreview extends StatelessWidget { DeviceOrientation.portraitDown: 2, DeviceOrientation.landscapeRight: 3, }; - return turns[_getApplicableOrientation()] + platformOffset; + return turns[_getApplicableOrientation()]! + platformOffset; } } diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 5ac4b57a15ef..7ed08d892de8 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,25 +2,26 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.7.0+4 +version: 0.8.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: flutter: sdk: flutter - camera_platform_interface: ^1.5.0 - pedantic: ^1.8.0 - quiver: ^2.1.5 + + camera_platform_interface: ^2.0.0-nullsafety + + pedantic: ^1.10.0 + quiver: ^3.0.0-nullsafety.3 dev_dependencies: - path_provider: ^0.5.0 - video_player: ^0.10.0 + video_player: ^2.0.0-nullsafety.7 flutter_test: sdk: flutter flutter_driver: sdk: flutter - mockito: ^4.1.3 - plugin_platform_interface: ^1.0.3 + mockito: ^5.0.0-nullsafety.5 + plugin_platform_interface: ^1.1.0-nullsafety.2 flutter: plugin: @@ -32,5 +33,5 @@ flutter: pluginClass: CameraPlugin environment: - sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5" + sdk: '>=2.12.0-0 <3.0.0' + flutter: ">=1.22.0" diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index d0b09fae1304..b37b7701a14f 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -426,10 +426,10 @@ void main() { await cameraController.initialize(); when(CameraPlatform.instance.getMaxZoomLevel(mockInitializeCamera)) - .thenThrow(PlatformException( - code: 'TEST_ERROR', - message: 'This is a test error messge', - details: null)); + .thenThrow(CameraException( + 'TEST_ERROR', + 'This is a test error messge', + )); expect( cameraController.getMaxZoomLevel, @@ -526,10 +526,10 @@ void main() { await cameraController.initialize(); when(CameraPlatform.instance.getMinZoomLevel(mockInitializeCamera)) - .thenThrow(PlatformException( - code: 'TEST_ERROR', - message: 'This is a test error messge', - details: null)); + .thenThrow(CameraException( + 'TEST_ERROR', + 'This is a test error messge', + )); expect( cameraController.getMinZoomLevel, @@ -625,10 +625,10 @@ void main() { await cameraController.initialize(); when(CameraPlatform.instance.setZoomLevel(mockInitializeCamera, 42.0)) - .thenThrow(PlatformException( - code: 'TEST_ERROR', - message: 'This is a test error messge', - details: null)); + .thenThrow(CameraException( + 'TEST_ERROR', + 'This is a test error messge', + )); expect( () => cameraController.setZoomLevel(42), @@ -804,6 +804,10 @@ void main() { ResolutionPreset.max); await cameraController.initialize(); + when(CameraPlatform.instance + .getMinExposureOffset(cameraController.cameraId)) + .thenAnswer((_) => Future.value(0.0)); + await cameraController.getMinExposureOffset(); verify(CameraPlatform.instance @@ -824,10 +828,9 @@ void main() { when(CameraPlatform.instance .getMinExposureOffset(cameraController.cameraId)) .thenThrow( - PlatformException( - code: 'TEST_ERROR', - message: 'This is a test error message', - details: null, + CameraException( + 'TEST_ERROR', + 'This is a test error message', ), ); @@ -849,6 +852,10 @@ void main() { ResolutionPreset.max); await cameraController.initialize(); + when(CameraPlatform.instance + .getMaxExposureOffset(cameraController.cameraId)) + .thenAnswer((_) => Future.value(1.0)); + await cameraController.getMaxExposureOffset(); verify(CameraPlatform.instance @@ -869,10 +876,9 @@ void main() { when(CameraPlatform.instance .getMaxExposureOffset(cameraController.cameraId)) .thenThrow( - PlatformException( - code: 'TEST_ERROR', - message: 'This is a test error message', - details: null, + CameraException( + 'TEST_ERROR', + 'This is a test error message', ), ); @@ -894,10 +900,14 @@ void main() { ResolutionPreset.max); await cameraController.initialize(); + when(CameraPlatform.instance + .getExposureOffsetStepSize(cameraController.cameraId)) + .thenAnswer((_) => Future.value(0.0)); + await cameraController.getExposureOffsetStepSize(); verify(CameraPlatform.instance - .getMinExposureOffset(cameraController.cameraId)) + .getExposureOffsetStepSize(cameraController.cameraId)) .called(1); }); @@ -915,10 +925,9 @@ void main() { when(CameraPlatform.instance .getExposureOffsetStepSize(cameraController.cameraId)) .thenThrow( - PlatformException( - code: 'TEST_ERROR', - message: 'This is a test error message', - details: null, + CameraException( + 'TEST_ERROR', + 'This is a test error message', ), ); @@ -948,6 +957,9 @@ void main() { when(CameraPlatform.instance .getExposureOffsetStepSize(cameraController.cameraId)) .thenAnswer((_) async => 1.0); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 1.0)) + .thenAnswer((_) async => 1.0); await cameraController.setExposureOffset(1.0); @@ -977,10 +989,9 @@ void main() { when(CameraPlatform.instance .setExposureOffset(cameraController.cameraId, 1.0)) .thenThrow( - PlatformException( - code: 'TEST_ERROR', - message: 'This is a test error message', - details: null, + CameraException( + 'TEST_ERROR', + 'This is a test error message', ), ); @@ -1012,6 +1023,15 @@ void main() { when(CameraPlatform.instance .getExposureOffsetStepSize(cameraController.cameraId)) .thenAnswer((_) async => 1.0); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 0.0)) + .thenAnswer((_) async => 0.0); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, -1.0)) + .thenAnswer((_) async => 0.0); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 2.0)) + .thenAnswer((_) async => 0.0); expect( cameraController.setExposureOffset(3.0), @@ -1028,17 +1048,18 @@ void main() { 'The provided exposure offset was outside the supported range for this device.', ))); - await cameraController.setExposureOffset(2.0); + await cameraController.setExposureOffset(0.0); await cameraController.setExposureOffset(-1.0); - await cameraController.setExposureOffset(-0.0); + await cameraController.setExposureOffset(2.0); + verify(CameraPlatform.instance - .setExposureOffset(cameraController.cameraId, 2.0)) + .setExposureOffset(cameraController.cameraId, 0.0)) .called(1); verify(CameraPlatform.instance .setExposureOffset(cameraController.cameraId, -1.0)) .called(1); verify(CameraPlatform.instance - .setExposureOffset(cameraController.cameraId, 0.0)) + .setExposureOffset(cameraController.cameraId, 2.0)) .called(1); }); @@ -1052,19 +1073,38 @@ void main() { await cameraController.initialize(); when(CameraPlatform.instance .getMinExposureOffset(cameraController.cameraId)) - .thenAnswer((_) async => -1.0); + .thenAnswer((_) async => -1.2); when(CameraPlatform.instance .getMaxExposureOffset(cameraController.cameraId)) - .thenAnswer((_) async => 1.0); + .thenAnswer((_) async => 1.2); when(CameraPlatform.instance .getExposureOffsetStepSize(cameraController.cameraId)) .thenAnswer((_) async => 0.4); + when(CameraPlatform.instance - .setExposureOffset(cameraController.cameraId, 1.0)) - .thenAnswer((_) async => 1.0); + .setExposureOffset(cameraController.cameraId, -1.2)) + .thenAnswer((_) async => -1.2); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, -0.8)) + .thenAnswer((_) async => -0.8); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, -0.4)) + .thenAnswer((_) async => -0.4); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 0.0)) + .thenAnswer((_) async => 0.0); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 0.4)) + .thenAnswer((_) async => 0.4); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 0.8)) + .thenAnswer((_) async => 0.8); + when(CameraPlatform.instance + .setExposureOffset(cameraController.cameraId, 1.2)) + .thenAnswer((_) async => 1.2); - await cameraController.setExposureOffset(1.0); - await cameraController.setExposureOffset(-1.0); + await cameraController.setExposureOffset(1.2); + await cameraController.setExposureOffset(-1.2); await cameraController.setExposureOffset(0.1); await cameraController.setExposureOffset(0.2); await cameraController.setExposureOffset(0.3); @@ -1082,10 +1122,10 @@ void main() { verify(CameraPlatform.instance .setExposureOffset(cameraController.cameraId, 0.8)) - .called(3); + .called(2); verify(CameraPlatform.instance .setExposureOffset(cameraController.cameraId, -0.8)) - .called(3); + .called(2); verify(CameraPlatform.instance .setExposureOffset(cameraController.cameraId, 0.0)) .called(2); @@ -1203,8 +1243,22 @@ class MockCameraPlatform extends Mock with MockPlatformInterfaceMixin implements CameraPlatform { @override - Future initializeCamera(int cameraId, - {ImageFormatGroup imageFormatGroup}); + Future initializeCamera( + int? cameraId, { + ImageFormatGroup? imageFormatGroup = ImageFormatGroup.unknown, + }) async => + super.noSuchMethod(Invocation.method( + #initializeCamera, + [cameraId], + { + #imageFormatGroup: imageFormatGroup, + }, + )); + + @override + Future dispose(int? cameraId) async { + return super.noSuchMethod(Invocation.method(#dispose, [cameraId])); + } @override Future> availableCameras() => @@ -1213,8 +1267,8 @@ class MockCameraPlatform extends Mock @override Future createCamera( CameraDescription description, - ResolutionPreset resolutionPreset, { - bool enableAudio, + ResolutionPreset? resolutionPreset, { + bool enableAudio = true, }) => mockPlatformException ? throw PlatformException(code: 'foo', message: 'bar') @@ -1241,13 +1295,92 @@ class MockCameraPlatform extends Mock ? throw PlatformException(code: 'foo', message: 'bar') : Future.value(mockTakePicture); + @override + Future prepareForVideoRecording() async => + super.noSuchMethod(Invocation.method(#prepareForVideoRecording, null)); + @override Future startVideoRecording(int cameraId, - {Duration maxVideoDuration}) => + {Duration? maxVideoDuration}) => Future.value(mockVideoRecordingXFile); + + @override + Future lockCaptureOrientation( + int? cameraId, DeviceOrientation? orientation) async => + super.noSuchMethod( + Invocation.method(#lockCaptureOrientation, [cameraId, orientation])); + + @override + Future unlockCaptureOrientation(int? cameraId) async => super + .noSuchMethod(Invocation.method(#unlockCaptureOrientation, [cameraId])); + + @override + Future getMaxZoomLevel(int? cameraId) async => super.noSuchMethod( + Invocation.method(#getMaxZoomLevel, [cameraId]), + returnValue: 1.0, + ); + + @override + Future getMinZoomLevel(int? cameraId) async => super.noSuchMethod( + Invocation.method(#getMinZoomLevel, [cameraId]), + returnValue: 0.0, + ); + + @override + Future setZoomLevel(int? cameraId, double? zoom) async => + super.noSuchMethod(Invocation.method(#setZoomLevel, [cameraId, zoom])); + + @override + Future setFlashMode(int? cameraId, FlashMode? mode) async => + super.noSuchMethod(Invocation.method(#setFlashMode, [cameraId, mode])); + + @override + Future setExposureMode(int? cameraId, ExposureMode? mode) async => + super.noSuchMethod(Invocation.method(#setExposureMode, [cameraId, mode])); + + @override + Future setExposurePoint(int? cameraId, Point? point) async => + super.noSuchMethod( + Invocation.method(#setExposurePoint, [cameraId, point])); + + @override + Future getMinExposureOffset(int? cameraId) async => + super.noSuchMethod( + Invocation.method(#getMinExposureOffset, [cameraId]), + returnValue: 0.0, + ); + + @override + Future getMaxExposureOffset(int? cameraId) async => + super.noSuchMethod( + Invocation.method(#getMaxExposureOffset, [cameraId]), + returnValue: 1.0, + ); + + @override + Future getExposureOffsetStepSize(int? cameraId) async => + super.noSuchMethod( + Invocation.method(#getExposureOffsetStepSize, [cameraId]), + returnValue: 1.0, + ); + + @override + Future setExposureOffset(int? cameraId, double? offset) async => + super.noSuchMethod( + Invocation.method(#setExposureOffset, [cameraId, offset]), + returnValue: 1.0, + ); } class MockCameraDescription extends CameraDescription { + /// Creates a new camera description with the given properties. + MockCameraDescription() + : super( + name: 'Test', + lensDirection: CameraLensDirection.back, + sensorOrientation: 0, + ); + @override CameraLensDirection get lensDirection => CameraLensDirection.back; diff --git a/packages/camera/camera/test/camera_value_test.dart b/packages/camera/camera/test/camera_value_test.dart index c365f6ddb9de..de7971d963c0 100644 --- a/packages/camera/camera/test/camera_value_test.dart +++ b/packages/camera/camera/test/camera_value_test.dart @@ -24,9 +24,11 @@ void main() { flashMode: FlashMode.auto, exposureMode: ExposureMode.auto, exposurePointSupported: true, + focusMode: FocusMode.auto, deviceOrientation: DeviceOrientation.portraitUp, lockedCaptureOrientation: DeviceOrientation.portraitUp, recordingOrientation: DeviceOrientation.portraitUp, + focusPointSupported: true, ); expect(cameraValue, isA()); @@ -58,8 +60,9 @@ void main() { expect(cameraValue.isTakingPicture, isFalse); expect(cameraValue.isStreamingImages, isFalse); expect(cameraValue.flashMode, FlashMode.auto); - expect(cameraValue.exposureMode, null); + expect(cameraValue.exposureMode, ExposureMode.auto); expect(cameraValue.exposurePointSupported, false); + expect(cameraValue.focusMode, FocusMode.auto); expect(cameraValue.deviceOrientation, DeviceOrientation.portraitUp); expect(cameraValue.lockedCaptureOrientation, null); expect(cameraValue.recordingOrientation, null); @@ -78,7 +81,8 @@ void main() { expect(cameraValue.isTakingPicture, isFalse); expect(cameraValue.isStreamingImages, isFalse); expect(cameraValue.flashMode, FlashMode.auto); - expect(cameraValue.exposureMode, null); + expect(cameraValue.focusMode, FocusMode.auto); + expect(cameraValue.exposureMode, ExposureMode.auto); expect(cameraValue.exposurePointSupported, false); expect(cameraValue.deviceOrientation, DeviceOrientation.portraitUp); expect(cameraValue.lockedCaptureOrientation, null); diff --git a/packages/camera/camera/test/utils/method_channel_mock.dart b/packages/camera/camera/test/utils/method_channel_mock.dart index cdf393f82b5f..fdbd9a18f29c 100644 --- a/packages/camera/camera/test/utils/method_channel_mock.dart +++ b/packages/camera/camera/test/utils/method_channel_mock.dart @@ -5,15 +5,15 @@ import 'package:flutter/services.dart'; class MethodChannelMock { - final Duration delay; + final Duration? delay; final MethodChannel methodChannel; final Map methods; final log = []; MethodChannelMock({ - String channelName, + required String channelName, this.delay, - this.methods, + required this.methods, }) : methodChannel = MethodChannel(channelName) { methodChannel.setMockMethodCallHandler(_handler); } diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index a2c22c67948a..9a8f771352ad 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -9,6 +9,7 @@ readonly NNBD_PLUGINS_LIST=( "android_intent" "battery" "camera" + "camera_platform_interface" "connectivity" "cross_file" "device_info" @@ -38,8 +39,8 @@ readonly NNBD_PLUGINS_LIST=( # building the all plugins app. This list should be kept empty. readonly NON_NNBD_PLUGINS_LIST=( - "camera" - "google_maps_flutter" # half migrated + #"camera" + "google_maps_flutter" # "image_picker" # "in_app_purchase" # "quick_actions" From 907d8d3e90131f10d6b9dc8fbb3115201f1441ba Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 16 Feb 2021 06:41:53 -0800 Subject: [PATCH 197/924] Fix the build-all exclusion list (#3552) build_all_plugins_app.sh contains an exclusion list, which currently contains almost all of the non-app-facing plugins. However, the script those exclusions are passed to expects federated plugin exclusions to be of the form plugin_name/plugin_name_subplugin_name, not just plugin_name_subplugin_name, so in practice almost nothing on that list has actually been doing anything. This fixes the script to allow either mode of exclusion (since clearly people expect using just the name to work), and scrubs everything from the list that clearly wasn't actually needed. --- script/build_all_plugins_app.sh | 42 ++++++++++----------------------- script/nnbd_plugins.sh | 9 ++----- script/tool/lib/src/common.dart | 2 ++ 3 files changed, 16 insertions(+), 37 deletions(-) diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 399f1f1b79f7..0cd6f4888e79 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -18,37 +18,19 @@ source "$SCRIPT_DIR/nnbd_plugins.sh" check_changed_packages > /dev/null +# This list should be kept as short as possible, and things should remain here +# only as long as necessary, since in general the goal is for all of the latest +# versions of plugins to be mutually compatible. +# +# An example use case for this list would be to temporarily add plugins while +# updating multiple plugins for a breaking change in a common dependency in +# cases where using a relaxed version constraint isn't possible. readonly EXCLUDED_PLUGINS_LIST=( - "connectivity_macos" - "connectivity_platform_interface" - "connectivity_web" - "extension_google_sign_in_as_googleapis_auth" - "file_selector" # currently out of sync with camera - "flutter_plugin_android_lifecycle" - "google_maps_flutter_platform_interface" - "google_maps_flutter_web" - "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" - "path_provider_macos" - "path_provider_platform_interface" - "path_provider_web" - "plugin_platform_interface" - "shared_preferences_linux" - "shared_preferences_macos" - "shared_preferences_platform_interface" - "shared_preferences_web" - "shared_preferences_windows" - "url_launcher_linux" - "url_launcher_macos" - "url_launcher_platform_interface" - "url_launcher_web" - "video_player_platform_interface" - "video_player_web" + # "file_selector" # currently out of sync with camera + # "flutter_plugin_android_lifecycle" + # "image_picker" + # "local_auth" # flutter_plugin_android_lifecycle conflict + "plugin_platform_interface" # This should never be a direct app dependency. ) # Comma-separated string of the list above readonly EXCLUDED=$(IFS=, ; echo "${EXCLUDED_PLUGINS_LIST[*]}") diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 9a8f771352ad..112dccfcbba8 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -39,13 +39,8 @@ readonly NNBD_PLUGINS_LIST=( # building the all plugins app. This list should be kept empty. readonly NON_NNBD_PLUGINS_LIST=( - #"camera" - "google_maps_flutter" - # "image_picker" - # "in_app_purchase" - # "quick_actions" - # "sensors" - # "wifi_info_flutter" + "extension_google_sign_in_as_googleapis_auth" + "google_maps_flutter" # partially migrated ) export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}") diff --git a/script/tool/lib/src/common.dart b/script/tool/lib/src/common.dart index 78b91ee8a75b..08622df281b4 100644 --- a/script/tool/lib/src/common.dart +++ b/script/tool/lib/src/common.dart @@ -294,8 +294,10 @@ abstract class PluginCommand extends Command { // passed. final String relativePath = p.relative(subdir.path, from: packagesDir.path); + final String packageName = p.basename(subdir.path); final String basenamePath = p.basename(entity.path); if (!excludedPlugins.contains(basenamePath) && + !excludedPlugins.contains(packageName) && !excludedPlugins.contains(relativePath) && (plugins.isEmpty || plugins.contains(relativePath) || From 9136b68bd1b11b01515f82d35660530af552c2f2 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 16 Feb 2021 09:16:47 -0800 Subject: [PATCH 198/924] [path_provider] Update Windows implementation version (#3541) --- packages/path_provider/path_provider/CHANGELOG.md | 5 +++++ packages/path_provider/path_provider/pubspec.yaml | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index 7364305333cf..a52711bf0736 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.0-nullsafety.1 + +* Require latest path_provider_windows to avoid potential issues + with breaking changes in `ffi` and `win32`. + ## 2.0.0-nullsafety * Migrate to null safety. diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index 6c4c851d8103..3d79c99e2223 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 2.0.0-nullsafety +version: 2.0.0-nullsafety.1 flutter: plugin: @@ -24,7 +24,7 @@ dependencies: path_provider_platform_interface: ^2.0.0-nullsafety path_provider_macos: ^0.0.5-nullsafety path_provider_linux: ^0.2.0-nullsafety - path_provider_windows: ^0.1.0-nullsafety + path_provider_windows: ^0.1.0-nullsafety.3 dev_dependencies: integration_test: From 7a3b4ae8c3d96cd2ef49bdbe5db04f5d2fdc8e24 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 16 Feb 2021 10:48:46 -0800 Subject: [PATCH 199/924] [google_maps_flutter] Fix CameraPosition regression (#3547) The nullability conversion added a type check when recreating a CameraPosition from JSON that was too restrictive, and regressed the app-facing package. This relaxes that assertion, and adds a test to catch the issue. --- .../CHANGELOG.md | 4 ++++ .../lib/src/types/camera.dart | 2 +- .../pubspec.yaml | 2 +- .../test/types/camera_test.dart | 23 +++++++++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index c530c31e488d..7b2268395caf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.1 + +* Fix overly-restrictive type check. + ## 2.0.0-nullsafety * Migrated to null-safety. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart index bdb039572624..28acf35962b6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart @@ -72,7 +72,7 @@ class CameraPosition { /// /// Mainly for internal use. static CameraPosition? fromMap(Object? json) { - if (json == null || !(json is Map)) { + if (json == null || !(json is Map)) { return null; } final LatLng? target = LatLng.fromJson(json['target']); diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index 8b31feeb94a2..2ec9e449a335 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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: 2.0.0-nullsafety +version: 2.0.0-nullsafety.1 dependencies: flutter: diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart new file mode 100644 index 000000000000..3b6d237e05d4 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart @@ -0,0 +1,23 @@ +// 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 'package:flutter_test/flutter_test.dart'; + +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + test('toMap / fromMap', () { + final cameraPosition = CameraPosition( + target: LatLng(10.0, 15.0), bearing: 0.5, tilt: 30.0, zoom: 1.5); + // Cast to to ensure that recreating from JSON, where + // type information will have likely been lost, still works. + final json = (cameraPosition.toMap() as Map) + .cast(); + final cameraPositionFromJson = CameraPosition.fromMap(json); + + expect(cameraPosition, cameraPositionFromJson); + }); +} From 4df088098be04f9b26be528bc3f250aca9a76d27 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 16 Feb 2021 11:41:46 -0800 Subject: [PATCH 200/924] [url_launcher_web] Migrate to null-safety (#3522) This version uses auto-generated Mocks from mockito5 for its tests. For now, tests only run in the `master` channel. Co-authored-by: Maurits van Beusekom --- analysis_options.yaml | 1 + .../url_launcher_web/CHANGELOG.md | 4 + .../url_launcher_web/example/README.md | 31 + .../url_launcher_web/example/build.yaml | 6 + .../integration_test/link_widget_test.dart | 150 ++++ .../url_launcher_web_test.dart} | 178 +---- .../url_launcher_web_test.mocks.dart | 660 ++++++++++++++++++ .../{test => example}/lib/main.dart | 0 .../{test => example}/pubspec.yaml | 16 +- .../url_launcher_web/example/run_test.sh | 23 + .../test_driver/integration_test_driver.dart} | 1 - .../{test => example}/web/index.html | 0 .../url_launcher_web/lib/src/link.dart | 54 +- .../lib/url_launcher_web.dart | 20 +- .../url_launcher_web/pubspec.yaml | 28 +- .../url_launcher_web/test/README.md | 18 +- .../url_launcher_web/test/run_test | 17 - .../test/tests_exist_elsewhere_test.dart | 10 + 18 files changed, 956 insertions(+), 261 deletions(-) create mode 100644 packages/url_launcher/url_launcher_web/example/README.md create mode 100644 packages/url_launcher/url_launcher_web/example/build.yaml create mode 100644 packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart rename packages/url_launcher/url_launcher_web/{test/test_driver/url_launcher_web_integration.dart => example/integration_test/url_launcher_web_test.dart} (53%) create mode 100644 packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart rename packages/url_launcher/url_launcher_web/{test => example}/lib/main.dart (100%) rename packages/url_launcher/url_launcher_web/{test => example}/pubspec.yaml (61%) create mode 100755 packages/url_launcher/url_launcher_web/example/run_test.sh rename packages/url_launcher/url_launcher_web/{test/test_driver/url_launcher_web_integration_test.dart => example/test_driver/integration_test_driver.dart} (94%) rename packages/url_launcher/url_launcher_web/{test => example}/web/index.html (100%) delete mode 100755 packages/url_launcher/url_launcher_web/test/run_test create mode 100644 packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 47cdbd2f98dc..2b62a6a9e2b9 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -4,6 +4,7 @@ analyzer: # Ignore generated files - '**/*.g.dart' - 'lib/src/generated/*.dart' + - '**/*.mocks.dart' # Mockito @GenerateMocks errors: always_require_non_null_named_parameters: false # not needed with nnbd unnecessary_null_comparison: false # Turned as long as nnbd mix-mode is supported. diff --git a/packages/url_launcher/url_launcher_web/CHANGELOG.md b/packages/url_launcher/url_launcher_web/CHANGELOG.md index 0416c033bf2b..49d72457ecd9 100644 --- a/packages/url_launcher/url_launcher_web/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 2.0.0-nullsafety + +- Migrate to null safety. + # 0.1.5+3 - Fix Link misalignment [issue](https://github.com/flutter/flutter/issues/70053). diff --git a/packages/url_launcher/url_launcher_web/example/README.md b/packages/url_launcher/url_launcher_web/example/README.md new file mode 100644 index 000000000000..b75df09c33f1 --- /dev/null +++ b/packages/url_launcher/url_launcher_web/example/README.md @@ -0,0 +1,31 @@ +# Testing + +This package utilizes the `integration_test` package to run its tests in a web browser. + +See [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests) for more info. + +## Running the tests + +Make sure you have updated to the latest Flutter master. + +1. Check what version of Chrome is running on the machine you're running tests on. + +2. Download and install driver for that version from here: + * + +3. Start the driver using `chromedriver --port=4444` + +4. Run tests: `flutter drive -d web-server --browser-name=chrome --driver=test_driver/integration_test_driver.dart --target=integration_test/TEST_NAME.dart`, or (in Linux): + + * Single: `./run_test.sh integration_test/TEST_NAME.dart` + * All: `./run_test.sh` + +## Mocks + +There's `.mocks.dart` files next to the test files that use them. + +They're [generated by Mockito](https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md#code-generation). + +Mocks might be manually re-generated with the following command: `flutter pub run build_runner build`. If there are any changes in the mocks, feel free to commit them. + +(Mocks will be auto-generated by the `run_test.sh` script as well.) diff --git a/packages/url_launcher/url_launcher_web/example/build.yaml b/packages/url_launcher/url_launcher_web/example/build.yaml new file mode 100644 index 000000000000..db3104bb04c6 --- /dev/null +++ b/packages/url_launcher/url_launcher_web/example/build.yaml @@ -0,0 +1,6 @@ +targets: + $default: + sources: + - integration_test/*.dart + - lib/$lib$ + - $package$ diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart b/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart new file mode 100644 index 000000000000..3c1dbd8b1b89 --- /dev/null +++ b/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart @@ -0,0 +1,150 @@ +// Copyright 2019 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:html' as html; +import 'dart:js_util'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:url_launcher_platform_interface/link.dart'; +import 'package:url_launcher_web/src/link.dart'; +import 'package:integration_test/integration_test.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('Link Widget', () { + testWidgets('creates anchor with correct attributes', + (WidgetTester tester) async { + final Uri uri = Uri.parse('http://foobar/example?q=1'); + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: WebLinkDelegate(TestLinkInfo( + uri: uri, + target: LinkTarget.blank, + builder: (BuildContext context, FollowLink? followLink) { + return Container(width: 100, height: 100); + }, + )), + )); + // Platform view creation happens asynchronously. + await tester.pumpAndSettle(); + + final html.Element anchor = _findSingleAnchor(); + expect(anchor.getAttribute('href'), uri.toString()); + expect(anchor.getAttribute('target'), '_blank'); + + final Uri uri2 = Uri.parse('http://foobar2/example?q=2'); + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: WebLinkDelegate(TestLinkInfo( + uri: uri2, + target: LinkTarget.self, + builder: (BuildContext context, FollowLink? followLink) { + return Container(width: 100, height: 100); + }, + )), + )); + await tester.pumpAndSettle(); + + // Check that the same anchor has been updated. + expect(anchor.getAttribute('href'), uri2.toString()); + expect(anchor.getAttribute('target'), '_self'); + }); + + testWidgets('sizes itself correctly', (WidgetTester tester) async { + final Key containerKey = GlobalKey(); + final Uri uri = Uri.parse('http://foobar'); + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: ConstrainedBox( + constraints: BoxConstraints.tight(Size(100.0, 100.0)), + child: WebLinkDelegate(TestLinkInfo( + uri: uri, + target: LinkTarget.blank, + builder: (BuildContext context, FollowLink? followLink) { + return Container( + key: containerKey, + child: SizedBox(width: 50.0, height: 50.0), + ); + }, + )), + ), + ), + )); + await tester.pumpAndSettle(); + + final Size containerSize = tester.getSize(find.byKey(containerKey)); + // The Stack widget inserted by the `WebLinkDelegate` shouldn't loosen the + // constraints before passing them to the inner container. So the inner + // container should respect the tight constraints given by the ancestor + // `ConstrainedBox` widget. + expect(containerSize.width, 100.0); + expect(containerSize.height, 100.0); + }); + + // See: https://github.com/flutter/plugins/pull/3522#discussion_r574703724 + testWidgets('uri can be null', (WidgetTester tester) async { + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: WebLinkDelegate(TestLinkInfo( + uri: null, + target: LinkTarget.defaultTarget, + builder: (BuildContext context, FollowLink? followLink) { + return Container(width: 100, height: 100); + }, + )), + )); + // Platform view creation happens asynchronously. + await tester.pumpAndSettle(); + + final html.Element anchor = _findSingleAnchor(); + expect(anchor.hasAttribute('href'), false); + }); + }); +} + +html.Element _findSingleAnchor() { + final List foundAnchors = []; + for (final html.Element anchor in html.document.querySelectorAll('a')) { + if (hasProperty(anchor, linkViewIdProperty)) { + foundAnchors.add(anchor); + } + } + + // Search inside platform views with shadow roots as well. + for (final html.Element platformView + in html.document.querySelectorAll('flt-platform-view')) { + final html.ShadowRoot shadowRoot = platformView.shadowRoot!; + if (shadowRoot != null) { + for (final html.Element anchor in shadowRoot.querySelectorAll('a')) { + if (hasProperty(anchor, linkViewIdProperty)) { + foundAnchors.add(anchor); + } + } + } + } + + return foundAnchors.single; +} + +class TestLinkInfo extends LinkInfo { + @override + final LinkWidgetBuilder builder; + + @override + final Uri? uri; + + @override + final LinkTarget target; + + @override + bool get isDisabled => uri == null; + + TestLinkInfo({ + required this.uri, + required this.target, + required this.builder, + }); +} diff --git a/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration.dart b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart similarity index 53% rename from packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration.dart rename to packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart index bfa94821e41a..f7ea35667530 100644 --- a/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration.dart +++ b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart @@ -2,35 +2,36 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 import 'dart:html' as html; -import 'dart:js_util'; -import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:url_launcher_platform_interface/link.dart'; +import 'package:mockito/annotations.dart'; import 'package:url_launcher_web/url_launcher_web.dart'; -import 'package:url_launcher_web/src/link.dart'; import 'package:mockito/mockito.dart'; import 'package:integration_test/integration_test.dart'; -class _MockWindow extends Mock implements html.Window {} - -class _MockNavigator extends Mock implements html.Navigator {} +import 'url_launcher_web_test.mocks.dart'; +@GenerateMocks([html.Window, html.Navigator]) void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('UrlLauncherPlugin', () { - _MockWindow mockWindow; - _MockNavigator mockNavigator; + late MockWindow mockWindow; + late MockNavigator mockNavigator; - UrlLauncherPlugin plugin; + late UrlLauncherPlugin plugin; setUp(() { - mockWindow = _MockWindow(); - mockNavigator = _MockNavigator(); + mockWindow = MockWindow(); + mockNavigator = MockNavigator(); when(mockWindow.navigator).thenReturn(mockNavigator); + // Simulate that window.open does something. + when(mockWindow.open(any, any)).thenReturn(MockWindow()); + + when(mockNavigator.vendor).thenReturn('Google LLC'); + when(mockNavigator.appVersion).thenReturn('Mock version!'); + plugin = UrlLauncherPlugin(debugWindow: mockWindow); }); @@ -60,27 +61,10 @@ void main() { }); group('launch', () { - setUp(() { - // Simulate that window.open does something. - when(mockWindow.open('https://www.google.com', '')) - .thenReturn(_MockWindow()); - when(mockWindow.open('mailto:name@mydomain.com', '')) - .thenReturn(_MockWindow()); - when(mockWindow.open('tel:5551234567', '')).thenReturn(_MockWindow()); - when(mockWindow.open('sms:+19725551212?body=hello%20there', '')) - .thenReturn(_MockWindow()); - }); - testWidgets('launching a URL returns true', (WidgetTester _) async { expect( plugin.launch( 'https://www.google.com', - useSafariVC: null, - useWebView: null, - universalLinksOnly: null, - enableDomStorage: null, - enableJavaScript: null, - headers: null, ), completion(isTrue)); }); @@ -89,12 +73,6 @@ void main() { expect( plugin.launch( 'mailto:name@mydomain.com', - useSafariVC: null, - useWebView: null, - universalLinksOnly: null, - enableDomStorage: null, - enableJavaScript: null, - headers: null, ), completion(isTrue)); }); @@ -103,12 +81,6 @@ void main() { expect( plugin.launch( 'tel:5551234567', - useSafariVC: null, - useWebView: null, - universalLinksOnly: null, - enableDomStorage: null, - enableJavaScript: null, - headers: null, ), completion(isTrue)); }); @@ -117,12 +89,6 @@ void main() { expect( plugin.launch( 'sms:+19725551212?body=hello%20there', - useSafariVC: null, - useWebView: null, - universalLinksOnly: null, - enableDomStorage: null, - enableJavaScript: null, - headers: null, ), completion(isTrue)); }); @@ -233,120 +199,4 @@ void main() { }); }); }); - - group('link', () { - testWidgets('creates anchor with correct attributes', - (WidgetTester tester) async { - final Uri uri = Uri.parse('http://foobar/example?q=1'); - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: WebLinkDelegate(TestLinkInfo( - uri: uri, - target: LinkTarget.blank, - builder: (BuildContext context, FollowLink followLink) { - return Container(width: 100, height: 100); - }, - )), - )); - // Platform view creation happens asynchronously. - await tester.pumpAndSettle(); - - final html.Element anchor = _findSingleAnchor(); - expect(anchor.getAttribute('href'), uri.toString()); - expect(anchor.getAttribute('target'), '_blank'); - - final Uri uri2 = Uri.parse('http://foobar2/example?q=2'); - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: WebLinkDelegate(TestLinkInfo( - uri: uri2, - target: LinkTarget.self, - builder: (BuildContext context, FollowLink followLink) { - return Container(width: 100, height: 100); - }, - )), - )); - await tester.pumpAndSettle(); - - // Check that the same anchor has been updated. - expect(anchor.getAttribute('href'), uri2.toString()); - expect(anchor.getAttribute('target'), '_self'); - }); - - testWidgets('sizes itself correctly', (WidgetTester tester) async { - final Key containerKey = GlobalKey(); - final Uri uri = Uri.parse('http://foobar'); - await tester.pumpWidget(Directionality( - textDirection: TextDirection.ltr, - child: Center( - child: ConstrainedBox( - constraints: BoxConstraints.tight(Size(100.0, 100.0)), - child: WebLinkDelegate(TestLinkInfo( - uri: uri, - target: LinkTarget.blank, - builder: (BuildContext context, FollowLink followLink) { - return Container( - key: containerKey, - child: SizedBox(width: 50.0, height: 50.0), - ); - }, - )), - ), - ), - )); - await tester.pumpAndSettle(); - - final Size containerSize = tester.getSize(find.byKey(containerKey)); - // The Stack widget inserted by the `WebLinkDelegate` shouldn't loosen the - // constraints before passing them to the inner container. So the inner - // container should respect the tight constraints given by the ancestor - // `ConstrainedBox` widget. - expect(containerSize.width, 100.0); - expect(containerSize.height, 100.0); - }); - }); -} - -html.Element _findSingleAnchor() { - final List foundAnchors = []; - for (final html.Element anchor in html.document.querySelectorAll('a')) { - if (hasProperty(anchor, linkViewIdProperty)) { - foundAnchors.add(anchor); - } - } - - // Search inside platform views with shadow roots as well. - for (final html.Element platformView - in html.document.querySelectorAll('flt-platform-view')) { - final html.ShadowRoot shadowRoot = platformView.shadowRoot; - if (shadowRoot != null) { - for (final html.Element anchor in shadowRoot.querySelectorAll('a')) { - if (hasProperty(anchor, linkViewIdProperty)) { - foundAnchors.add(anchor); - } - } - } - } - - return foundAnchors.single; -} - -class TestLinkInfo extends LinkInfo { - @override - final LinkWidgetBuilder builder; - - @override - final Uri uri; - - @override - final LinkTarget target; - - @override - bool get isDisabled => uri == null; - - TestLinkInfo({ - @required this.uri, - @required this.target, - @required this.builder, - }); } diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart new file mode 100644 index 000000000000..73d3bf355d67 --- /dev/null +++ b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart @@ -0,0 +1,660 @@ +import 'dart:async' as _i4; +import 'dart:html' as _i2; +import 'dart:math' as _i5; +import 'dart:web_sql' as _i3; + +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: comment_references + +// ignore_for_file: unnecessary_parenthesis + +class _FakeDocument extends _i1.Fake implements _i2.Document {} + +class _FakeLocation extends _i1.Fake implements _i2.Location {} + +class _FakeConsole extends _i1.Fake implements _i2.Console {} + +class _FakeHistory extends _i1.Fake implements _i2.History {} + +class _FakeStorage extends _i1.Fake implements _i2.Storage {} + +class _FakeNavigator extends _i1.Fake implements _i2.Navigator {} + +class _FakePerformance extends _i1.Fake implements _i2.Performance {} + +class _FakeEvents extends _i1.Fake implements _i2.Events {} + +class _FakeType extends _i1.Fake implements Type {} + +class _FakeWindowBase extends _i1.Fake implements _i2.WindowBase {} + +class _FakeFileSystem extends _i1.Fake implements _i2.FileSystem {} + +class _FakeStylePropertyMapReadonly extends _i1.Fake + implements _i2.StylePropertyMapReadonly {} + +class _FakeMediaQueryList extends _i1.Fake implements _i2.MediaQueryList {} + +class _FakeEntry extends _i1.Fake implements _i2.Entry {} + +class _FakeSqlDatabase extends _i1.Fake implements _i3.SqlDatabase {} + +class _FakeGeolocation extends _i1.Fake implements _i2.Geolocation {} + +class _FakeMediaStream extends _i1.Fake implements _i2.MediaStream {} + +class _FakeRelatedApplication extends _i1.Fake + implements _i2.RelatedApplication {} + +/// A class which mocks [Window]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockWindow extends _i1.Mock implements _i2.Window { + MockWindow() { + _i1.throwOnMissingStub(this); + } + + @override + _i4.Future get animationFrame => + (super.noSuchMethod(Invocation.getter(#animationFrame), Future.value(0)) + as _i4.Future); + @override + _i2.Document get document => + (super.noSuchMethod(Invocation.getter(#document), _FakeDocument()) + as _i2.Document); + @override + _i2.Location get location => + (super.noSuchMethod(Invocation.getter(#location), _FakeLocation()) + as _i2.Location); + @override + set location(_i2.LocationBase? value) => + super.noSuchMethod(Invocation.setter(#location, value)); + @override + _i2.Console get console => + (super.noSuchMethod(Invocation.getter(#console), _FakeConsole()) + as _i2.Console); + @override + num get devicePixelRatio => + (super.noSuchMethod(Invocation.getter(#devicePixelRatio), 0) as num); + @override + _i2.History get history => + (super.noSuchMethod(Invocation.getter(#history), _FakeHistory()) + as _i2.History); + @override + _i2.Storage get localStorage => + (super.noSuchMethod(Invocation.getter(#localStorage), _FakeStorage()) + as _i2.Storage); + @override + _i2.Navigator get navigator => + (super.noSuchMethod(Invocation.getter(#navigator), _FakeNavigator()) + as _i2.Navigator); + @override + int get outerHeight => + (super.noSuchMethod(Invocation.getter(#outerHeight), 0) as int); + @override + int get outerWidth => + (super.noSuchMethod(Invocation.getter(#outerWidth), 0) as int); + @override + _i2.Performance get performance => + (super.noSuchMethod(Invocation.getter(#performance), _FakePerformance()) + as _i2.Performance); + @override + _i2.Storage get sessionStorage => + (super.noSuchMethod(Invocation.getter(#sessionStorage), _FakeStorage()) + as _i2.Storage); + @override + _i4.Stream<_i2.Event> get onContentLoaded => (super.noSuchMethod( + Invocation.getter(#onContentLoaded), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onAbort => (super + .noSuchMethod(Invocation.getter(#onAbort), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onBlur => + (super.noSuchMethod(Invocation.getter(#onBlur), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onCanPlay => (super.noSuchMethod( + Invocation.getter(#onCanPlay), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onCanPlayThrough => (super.noSuchMethod( + Invocation.getter(#onCanPlayThrough), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onChange => (super + .noSuchMethod(Invocation.getter(#onChange), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.MouseEvent> get onClick => (super.noSuchMethod( + Invocation.getter(#onClick), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onContextMenu => (super.noSuchMethod( + Invocation.getter(#onContextMenu), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.Event> get onDoubleClick => (super.noSuchMethod( + Invocation.getter(#onDoubleClick), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.DeviceMotionEvent> get onDeviceMotion => (super.noSuchMethod( + Invocation.getter(#onDeviceMotion), + Stream<_i2.DeviceMotionEvent>.empty()) + as _i4.Stream<_i2.DeviceMotionEvent>); + @override + _i4.Stream<_i2.DeviceOrientationEvent> get onDeviceOrientation => + (super.noSuchMethod(Invocation.getter(#onDeviceOrientation), + Stream<_i2.DeviceOrientationEvent>.empty()) + as _i4.Stream<_i2.DeviceOrientationEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDrag => (super.noSuchMethod( + Invocation.getter(#onDrag), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDragEnd => (super.noSuchMethod( + Invocation.getter(#onDragEnd), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDragEnter => (super.noSuchMethod( + Invocation.getter(#onDragEnter), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDragLeave => (super.noSuchMethod( + Invocation.getter(#onDragLeave), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDragOver => (super.noSuchMethod( + Invocation.getter(#onDragOver), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDragStart => (super.noSuchMethod( + Invocation.getter(#onDragStart), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDrop => (super.noSuchMethod( + Invocation.getter(#onDrop), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.Event> get onDurationChange => (super.noSuchMethod( + Invocation.getter(#onDurationChange), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onEmptied => (super.noSuchMethod( + Invocation.getter(#onEmptied), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onEnded => (super + .noSuchMethod(Invocation.getter(#onEnded), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onError => (super + .noSuchMethod(Invocation.getter(#onError), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onFocus => (super + .noSuchMethod(Invocation.getter(#onFocus), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onHashChange => (super.noSuchMethod( + Invocation.getter(#onHashChange), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onInput => (super + .noSuchMethod(Invocation.getter(#onInput), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onInvalid => (super.noSuchMethod( + Invocation.getter(#onInvalid), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.KeyboardEvent> get onKeyDown => (super.noSuchMethod( + Invocation.getter(#onKeyDown), Stream<_i2.KeyboardEvent>.empty()) + as _i4.Stream<_i2.KeyboardEvent>); + @override + _i4.Stream<_i2.KeyboardEvent> get onKeyPress => (super.noSuchMethod( + Invocation.getter(#onKeyPress), Stream<_i2.KeyboardEvent>.empty()) + as _i4.Stream<_i2.KeyboardEvent>); + @override + _i4.Stream<_i2.KeyboardEvent> get onKeyUp => (super.noSuchMethod( + Invocation.getter(#onKeyUp), Stream<_i2.KeyboardEvent>.empty()) + as _i4.Stream<_i2.KeyboardEvent>); + @override + _i4.Stream<_i2.Event> get onLoad => + (super.noSuchMethod(Invocation.getter(#onLoad), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onLoadedData => (super.noSuchMethod( + Invocation.getter(#onLoadedData), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onLoadedMetadata => (super.noSuchMethod( + Invocation.getter(#onLoadedMetadata), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onLoadStart => (super.noSuchMethod( + Invocation.getter(#onLoadStart), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.MessageEvent> get onMessage => (super.noSuchMethod( + Invocation.getter(#onMessage), Stream<_i2.MessageEvent>.empty()) + as _i4.Stream<_i2.MessageEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseDown => (super.noSuchMethod( + Invocation.getter(#onMouseDown), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseEnter => (super.noSuchMethod( + Invocation.getter(#onMouseEnter), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseLeave => (super.noSuchMethod( + Invocation.getter(#onMouseLeave), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseMove => (super.noSuchMethod( + Invocation.getter(#onMouseMove), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseOut => (super.noSuchMethod( + Invocation.getter(#onMouseOut), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseOver => (super.noSuchMethod( + Invocation.getter(#onMouseOver), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseUp => (super.noSuchMethod( + Invocation.getter(#onMouseUp), Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.WheelEvent> get onMouseWheel => (super.noSuchMethod( + Invocation.getter(#onMouseWheel), Stream<_i2.WheelEvent>.empty()) + as _i4.Stream<_i2.WheelEvent>); + @override + _i4.Stream<_i2.Event> get onOffline => (super.noSuchMethod( + Invocation.getter(#onOffline), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onOnline => (super + .noSuchMethod(Invocation.getter(#onOnline), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onPageHide => (super.noSuchMethod( + Invocation.getter(#onPageHide), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onPageShow => (super.noSuchMethod( + Invocation.getter(#onPageShow), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onPause => (super + .noSuchMethod(Invocation.getter(#onPause), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onPlay => + (super.noSuchMethod(Invocation.getter(#onPlay), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onPlaying => (super.noSuchMethod( + Invocation.getter(#onPlaying), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.PopStateEvent> get onPopState => (super.noSuchMethod( + Invocation.getter(#onPopState), Stream<_i2.PopStateEvent>.empty()) + as _i4.Stream<_i2.PopStateEvent>); + @override + _i4.Stream<_i2.Event> get onProgress => (super.noSuchMethod( + Invocation.getter(#onProgress), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onRateChange => (super.noSuchMethod( + Invocation.getter(#onRateChange), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onReset => (super + .noSuchMethod(Invocation.getter(#onReset), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onResize => (super + .noSuchMethod(Invocation.getter(#onResize), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onScroll => (super + .noSuchMethod(Invocation.getter(#onScroll), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onSearch => (super + .noSuchMethod(Invocation.getter(#onSearch), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onSeeked => (super + .noSuchMethod(Invocation.getter(#onSeeked), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onSeeking => (super.noSuchMethod( + Invocation.getter(#onSeeking), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onSelect => (super + .noSuchMethod(Invocation.getter(#onSelect), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onStalled => (super.noSuchMethod( + Invocation.getter(#onStalled), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.StorageEvent> get onStorage => (super.noSuchMethod( + Invocation.getter(#onStorage), Stream<_i2.StorageEvent>.empty()) + as _i4.Stream<_i2.StorageEvent>); + @override + _i4.Stream<_i2.Event> get onSubmit => (super + .noSuchMethod(Invocation.getter(#onSubmit), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onSuspend => (super.noSuchMethod( + Invocation.getter(#onSuspend), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onTimeUpdate => (super.noSuchMethod( + Invocation.getter(#onTimeUpdate), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.TouchEvent> get onTouchCancel => (super.noSuchMethod( + Invocation.getter(#onTouchCancel), Stream<_i2.TouchEvent>.empty()) + as _i4.Stream<_i2.TouchEvent>); + @override + _i4.Stream<_i2.TouchEvent> get onTouchEnd => (super.noSuchMethod( + Invocation.getter(#onTouchEnd), Stream<_i2.TouchEvent>.empty()) + as _i4.Stream<_i2.TouchEvent>); + @override + _i4.Stream<_i2.TouchEvent> get onTouchMove => (super.noSuchMethod( + Invocation.getter(#onTouchMove), Stream<_i2.TouchEvent>.empty()) + as _i4.Stream<_i2.TouchEvent>); + @override + _i4.Stream<_i2.TouchEvent> get onTouchStart => (super.noSuchMethod( + Invocation.getter(#onTouchStart), Stream<_i2.TouchEvent>.empty()) + as _i4.Stream<_i2.TouchEvent>); + @override + _i4.Stream<_i2.TransitionEvent> get onTransitionEnd => (super.noSuchMethod( + Invocation.getter(#onTransitionEnd), + Stream<_i2.TransitionEvent>.empty()) as _i4.Stream<_i2.TransitionEvent>); + @override + _i4.Stream<_i2.Event> get onUnload => (super + .noSuchMethod(Invocation.getter(#onUnload), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onVolumeChange => (super.noSuchMethod( + Invocation.getter(#onVolumeChange), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onWaiting => (super.noSuchMethod( + Invocation.getter(#onWaiting), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.AnimationEvent> get onAnimationEnd => (super.noSuchMethod( + Invocation.getter(#onAnimationEnd), + Stream<_i2.AnimationEvent>.empty()) as _i4.Stream<_i2.AnimationEvent>); + @override + _i4.Stream<_i2.AnimationEvent> get onAnimationIteration => + (super.noSuchMethod(Invocation.getter(#onAnimationIteration), + Stream<_i2.AnimationEvent>.empty()) + as _i4.Stream<_i2.AnimationEvent>); + @override + _i4.Stream<_i2.AnimationEvent> get onAnimationStart => (super.noSuchMethod( + Invocation.getter(#onAnimationStart), + Stream<_i2.AnimationEvent>.empty()) as _i4.Stream<_i2.AnimationEvent>); + @override + _i4.Stream<_i2.Event> get onBeforeUnload => (super.noSuchMethod( + Invocation.getter(#onBeforeUnload), Stream<_i2.Event>.empty()) + as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.WheelEvent> get onWheel => (super.noSuchMethod( + Invocation.getter(#onWheel), Stream<_i2.WheelEvent>.empty()) + as _i4.Stream<_i2.WheelEvent>); + @override + int get pageXOffset => + (super.noSuchMethod(Invocation.getter(#pageXOffset), 0) as int); + @override + int get pageYOffset => + (super.noSuchMethod(Invocation.getter(#pageYOffset), 0) as int); + @override + int get scrollX => + (super.noSuchMethod(Invocation.getter(#scrollX), 0) as int); + @override + int get scrollY => + (super.noSuchMethod(Invocation.getter(#scrollY), 0) as int); + @override + _i2.Events get on => + (super.noSuchMethod(Invocation.getter(#on), _FakeEvents()) as _i2.Events); + @override + int get hashCode => + (super.noSuchMethod(Invocation.getter(#hashCode), 0) as int); + @override + Type get runtimeType => + (super.noSuchMethod(Invocation.getter(#runtimeType), _FakeType()) + as Type); + @override + _i2.WindowBase open(String? url, String? name, [String? options]) => + (super.noSuchMethod( + Invocation.method(#open, [url, name, options]), _FakeWindowBase()) + as _i2.WindowBase); + @override + int requestAnimationFrame(_i2.FrameRequestCallback? callback) => + (super.noSuchMethod( + Invocation.method(#requestAnimationFrame, [callback]), 0) as int); + @override + void cancelAnimationFrame(int? id) => + super.noSuchMethod(Invocation.method(#cancelAnimationFrame, [id])); + @override + _i4.Future<_i2.FileSystem> requestFileSystem(int? size, {bool? persistent}) => + (super.noSuchMethod( + Invocation.method( + #requestFileSystem, [size], {#persistent: persistent}), + Future.value(_FakeFileSystem())) as _i4.Future<_i2.FileSystem>); + @override + void cancelIdleCallback(int? handle) => + super.noSuchMethod(Invocation.method(#cancelIdleCallback, [handle])); + @override + bool confirm([String? message]) => + (super.noSuchMethod(Invocation.method(#confirm, [message]), false) + as bool); + @override + _i4.Future fetch(dynamic input, [Map? init]) => + (super.noSuchMethod( + Invocation.method(#fetch, [input, init]), Future.value(null)) + as _i4.Future); + @override + bool find(String? string, bool? caseSensitive, bool? backwards, bool? wrap, + bool? wholeWord, bool? searchInFrames, bool? showDialog) => + (super.noSuchMethod( + Invocation.method(#find, [ + string, + caseSensitive, + backwards, + wrap, + wholeWord, + searchInFrames, + showDialog + ]), + false) as bool); + @override + _i2.StylePropertyMapReadonly getComputedStyleMap( + _i2.Element? element, String? pseudoElement) => + (super.noSuchMethod( + Invocation.method(#getComputedStyleMap, [element, pseudoElement]), + _FakeStylePropertyMapReadonly()) as _i2.StylePropertyMapReadonly); + @override + List<_i2.CssRule> getMatchedCssRules( + _i2.Element? element, String? pseudoElement) => + (super.noSuchMethod( + Invocation.method(#getMatchedCssRules, [element, pseudoElement]), + <_i2.CssRule>[]) as List<_i2.CssRule>); + @override + _i2.MediaQueryList matchMedia(String? query) => (super.noSuchMethod( + Invocation.method(#matchMedia, [query]), _FakeMediaQueryList()) + as _i2.MediaQueryList); + @override + void moveBy(int? x, int? y) => + super.noSuchMethod(Invocation.method(#moveBy, [x, y])); + @override + void postMessage(dynamic message, String? targetOrigin, + [List? transfer]) => + super.noSuchMethod( + Invocation.method(#postMessage, [message, targetOrigin, transfer])); + @override + int requestIdleCallback(_i2.IdleRequestCallback? callback, + [Map? options]) => + (super.noSuchMethod( + Invocation.method(#requestIdleCallback, [callback, options]), 0) + as int); + @override + void resizeBy(int? x, int? y) => + super.noSuchMethod(Invocation.method(#resizeBy, [x, y])); + @override + void resizeTo(int? x, int? y) => + super.noSuchMethod(Invocation.method(#resizeTo, [x, y])); + @override + _i4.Future<_i2.Entry> resolveLocalFileSystemUrl(String? url) => + (super.noSuchMethod(Invocation.method(#resolveLocalFileSystemUrl, [url]), + Future.value(_FakeEntry())) as _i4.Future<_i2.Entry>); + @override + String atob(String? atob) => + (super.noSuchMethod(Invocation.method(#atob, [atob]), '') as String); + @override + String btoa(String? btoa) => + (super.noSuchMethod(Invocation.method(#btoa, [btoa]), '') as String); + @override + void moveTo(_i5.Point? p) => + super.noSuchMethod(Invocation.method(#moveTo, [p])); + @override + _i3.SqlDatabase openDatabase(String? name, String? version, + String? displayName, int? estimatedSize, + [_i2.DatabaseCallback? creationCallback]) => + (super.noSuchMethod( + Invocation.method(#openDatabase, + [name, version, displayName, estimatedSize, creationCallback]), + _FakeSqlDatabase()) as _i3.SqlDatabase); + @override + void addEventListener(String? type, _i2.EventListener? listener, + [bool? useCapture]) => + super.noSuchMethod( + Invocation.method(#addEventListener, [type, listener, useCapture])); + @override + void removeEventListener(String? type, _i2.EventListener? listener, + [bool? useCapture]) => + super.noSuchMethod(Invocation.method( + #removeEventListener, [type, listener, useCapture])); + @override + bool dispatchEvent(_i2.Event? event) => + (super.noSuchMethod(Invocation.method(#dispatchEvent, [event]), false) + as bool); + @override + bool operator ==(Object? other) => + (super.noSuchMethod(Invocation.method(#==, [other]), false) as bool); + @override + String toString() => + (super.noSuchMethod(Invocation.method(#toString, []), '') as String); +} + +/// A class which mocks [Navigator]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockNavigator extends _i1.Mock implements _i2.Navigator { + MockNavigator() { + _i1.throwOnMissingStub(this); + } + + @override + String get language => + (super.noSuchMethod(Invocation.getter(#language), '') as String); + @override + _i2.Geolocation get geolocation => + (super.noSuchMethod(Invocation.getter(#geolocation), _FakeGeolocation()) + as _i2.Geolocation); + @override + String get vendor => + (super.noSuchMethod(Invocation.getter(#vendor), '') as String); + @override + String get vendorSub => + (super.noSuchMethod(Invocation.getter(#vendorSub), '') as String); + @override + String get appCodeName => + (super.noSuchMethod(Invocation.getter(#appCodeName), '') as String); + @override + String get appName => + (super.noSuchMethod(Invocation.getter(#appName), '') as String); + @override + String get appVersion => + (super.noSuchMethod(Invocation.getter(#appVersion), '') as String); + @override + String get product => + (super.noSuchMethod(Invocation.getter(#product), '') as String); + @override + String get userAgent => + (super.noSuchMethod(Invocation.getter(#userAgent), '') as String); + @override + int get hashCode => + (super.noSuchMethod(Invocation.getter(#hashCode), 0) as int); + @override + Type get runtimeType => + (super.noSuchMethod(Invocation.getter(#runtimeType), _FakeType()) + as Type); + @override + List<_i2.Gamepad?> getGamepads() => + (super.noSuchMethod(Invocation.method(#getGamepads, []), <_i2.Gamepad?>[]) + as List<_i2.Gamepad?>); + @override + _i4.Future<_i2.MediaStream> getUserMedia({dynamic audio, dynamic video}) => + (super.noSuchMethod( + Invocation.method(#getUserMedia, [], {#audio: audio, #video: video}), + Future.value(_FakeMediaStream())) as _i4.Future<_i2.MediaStream>); + @override + _i4.Future getBattery() => (super + .noSuchMethod(Invocation.method(#getBattery, []), Future.value(null)) + as _i4.Future); + @override + _i4.Future<_i2.RelatedApplication> getInstalledRelatedApps() => + (super.noSuchMethod(Invocation.method(#getInstalledRelatedApps, []), + Future.value(_FakeRelatedApplication())) + as _i4.Future<_i2.RelatedApplication>); + @override + _i4.Future getVRDisplays() => (super.noSuchMethod( + Invocation.method(#getVRDisplays, []), Future.value(null)) + as _i4.Future); + @override + void registerProtocolHandler(String? scheme, String? url, String? title) => + super.noSuchMethod( + Invocation.method(#registerProtocolHandler, [scheme, url, title])); + @override + _i4.Future requestKeyboardLock([List? keyCodes]) => + (super.noSuchMethod(Invocation.method(#requestKeyboardLock, [keyCodes]), + Future.value(null)) as _i4.Future); + @override + _i4.Future requestMidiAccess([Map? options]) => + (super.noSuchMethod(Invocation.method(#requestMidiAccess, [options]), + Future.value(null)) as _i4.Future); + @override + _i4.Future requestMediaKeySystemAccess(String? keySystem, + List>? supportedConfigurations) => + (super.noSuchMethod( + Invocation.method(#requestMediaKeySystemAccess, + [keySystem, supportedConfigurations]), + Future.value(null)) as _i4.Future); + @override + bool sendBeacon(String? url, Object? data) => + (super.noSuchMethod(Invocation.method(#sendBeacon, [url, data]), false) + as bool); + @override + _i4.Future share([Map? data]) => + (super.noSuchMethod(Invocation.method(#share, [data]), Future.value(null)) + as _i4.Future); + @override + bool operator ==(Object? other) => + (super.noSuchMethod(Invocation.method(#==, [other]), false) as bool); + @override + String toString() => + (super.noSuchMethod(Invocation.method(#toString, []), '') as String); +} diff --git a/packages/url_launcher/url_launcher_web/test/lib/main.dart b/packages/url_launcher/url_launcher_web/example/lib/main.dart similarity index 100% rename from packages/url_launcher/url_launcher_web/test/lib/main.dart rename to packages/url_launcher/url_launcher_web/example/lib/main.dart diff --git a/packages/url_launcher/url_launcher_web/test/pubspec.yaml b/packages/url_launcher/url_launcher_web/example/pubspec.yaml similarity index 61% rename from packages/url_launcher/url_launcher_web/test/pubspec.yaml rename to packages/url_launcher/url_launcher_web/example/pubspec.yaml index b8c541f72986..5fc060fe7abe 100644 --- a/packages/url_launcher/url_launcher_web/test/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/example/pubspec.yaml @@ -1,22 +1,22 @@ name: regular_integration_tests publish_to: none -environment: - sdk: ">=2.10.0-56.0.dev <3.0.0" - dependencies: flutter: sdk: flutter dev_dependencies: + build_runner: ^1.10.0 + mockito: ^5.0.0-nullsafety.5 + url_launcher_web: + path: ../ flutter_driver: sdk: flutter flutter_test: sdk: flutter - http: ^0.12.2 - mockito: ^4.1.1 - url_launcher_web: - path: ../ integration_test: - path: ../../../integration_test + sdk: flutter +environment: + sdk: ">=2.12.0-0 <3.0.0" + flutter: ">=1.26.0-0" # For integration_test from sdk diff --git a/packages/url_launcher/url_launcher_web/example/run_test.sh b/packages/url_launcher/url_launcher_web/example/run_test.sh new file mode 100755 index 000000000000..b243f2938b1f --- /dev/null +++ b/packages/url_launcher/url_launcher_web/example/run_test.sh @@ -0,0 +1,23 @@ +#!/usr/bin/bash +if pgrep -lf chromedriver > /dev/null; then + echo "chromedriver is running." + + flutter pub get + + echo "(Re)generating mocks." + flutter pub run build_runner build --delete-conflicting-outputs + + if [ $# -eq 0 ]; then + echo "No target specified, running all tests..." + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test_driver.dart --target='{}' + else + echo "Running test target: $1..." + set -x + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test_driver.dart --target=$1 + fi + + else + echo "chromedriver is not running." + echo "Please, check the README.md for instructions on how to use run_test.sh" +fi + diff --git a/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration_test.dart b/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart similarity index 94% rename from packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration_test.dart rename to packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart index 2d68bb93e9a7..64e2248a4f9b 100644 --- a/packages/url_launcher/url_launcher_web/test/test_driver/url_launcher_web_integration_test.dart +++ b/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 import 'package:integration_test/integration_test_driver.dart'; Future main() async => integrationDriver(); diff --git a/packages/url_launcher/url_launcher_web/test/web/index.html b/packages/url_launcher/url_launcher_web/example/web/index.html similarity index 100% rename from packages/url_launcher/url_launcher_web/test/web/index.html rename to packages/url_launcher/url_launcher_web/example/web/index.html diff --git a/packages/url_launcher/url_launcher_web/lib/src/link.dart b/packages/url_launcher/url_launcher_web/lib/src/link.dart index 8169a9c11b94..42c711b7d818 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/link.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/link.dart @@ -45,16 +45,16 @@ class WebLinkDelegate extends StatefulWidget { /// For external URIs, it lets the browser do its thing. For app route names, it /// pushes the route name to the framework. class WebLinkDelegateState extends State { - LinkViewController _controller; + late LinkViewController _controller; @override void didUpdateWidget(WebLinkDelegate oldWidget) { super.didUpdateWidget(oldWidget); if (widget.link.uri != oldWidget.link.uri) { - _controller?.setUri(widget.link.uri); + _controller.setUri(widget.link.uri); } if (widget.link.target != oldWidget.link.target) { - _controller?.setTarget(widget.link.target); + _controller.setTarget(widget.link.target); } } @@ -126,15 +126,15 @@ class LinkViewController extends PlatformViewController { static Map _instances = {}; static html.Element _viewFactory(int viewId) { - return _instances[viewId]?._element; + return _instances[viewId]!._element; } - static int _hitTestedViewId; + static int? _hitTestedViewId; - static StreamSubscription _clickSubscription; + static late StreamSubscription _clickSubscription; static void _onGlobalClick(html.MouseEvent event) { - final int viewId = getViewIdFromTarget(event); + final int? viewId = getViewIdFromTarget(event); _instances[viewId]?._onDomClick(event); // After the DOM click event has been received, clean up the hit test state // so we can start fresh on the next click. @@ -161,7 +161,7 @@ class LinkViewController extends PlatformViewController { /// The context of the [Link] widget that created this controller. final BuildContext context; - html.Element _element; + late html.Element _element; bool get _isInitialized => _element != null; Future _initialize() async { @@ -193,7 +193,7 @@ class LinkViewController extends PlatformViewController { return; } - if (_uri.hasScheme) { + if (_uri != null && _uri!.hasScheme) { // External links will be handled by the browser, so we don't have to do // anything. return; @@ -207,10 +207,12 @@ class LinkViewController extends PlatformViewController { pushRouteNameToFramework(context, routeName); } - Uri _uri; + Uri? _uri; /// Set the [Uri] value for this link. - void setUri(Uri uri) { + /// + /// When Uri is null, the `href` attribute of the link is removed. + void setUri(Uri? uri) { assert(_isInitialized); _uri = uri; if (uri == null) { @@ -264,8 +266,8 @@ class LinkViewController extends PlatformViewController { } /// Finds the view id of the DOM element targeted by the [event]. -int getViewIdFromTarget(html.Event event) { - final html.Element linkElement = getLinkElementFromTarget(event); +int? getViewIdFromTarget(html.Event event) { + final html.Element? linkElement = getLinkElementFromTarget(event); if (linkElement != null) { return getProperty(linkElement, linkViewIdProperty); } @@ -275,15 +277,17 @@ int getViewIdFromTarget(html.Event event) { /// Finds the targeted DOM element by the [event]. /// /// It handles the case where the target element is inside a shadow DOM too. -html.Element getLinkElementFromTarget(html.Event event) { - final html.Element target = event.target; - if (isLinkElement(target)) { - return target; - } - if (target.shadowRoot != null) { - final html.Element child = target.shadowRoot.lastChild; - if (isLinkElement(child)) { - return child; +html.Element? getLinkElementFromTarget(html.Event event) { + final html.EventTarget? target = event.target; + if (target != null && target is html.Element) { + if (isLinkElement(target)) { + return target; + } + if (target.shadowRoot != null) { + final html.Node? child = target.shadowRoot!.lastChild; + if (child != null && child is html.Element && isLinkElement(child)) { + return child; + } } } return null; @@ -291,6 +295,8 @@ html.Element getLinkElementFromTarget(html.Event event) { /// Checks if the given [element] is a link that was created by /// [LinkViewController]. -bool isLinkElement(html.Element element) { - return element.tagName == 'A' && hasProperty(element, linkViewIdProperty); +bool isLinkElement(html.Element? element) { + return element != null && + element.tagName == 'A' && + hasProperty(element, linkViewIdProperty); } diff --git a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart index 969cfbaa2dfd..e4d2116445cf 100644 --- a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart +++ b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart @@ -19,7 +19,7 @@ const _safariTargetTopSchemes = { 'tel', 'sms', }; -String _getUrlScheme(String url) => Uri.tryParse(url)?.scheme; +String? _getUrlScheme(String url) => Uri.tryParse(url)?.scheme; bool _isSafariTargetTopScheme(String url) => _safariTargetTopSchemes.contains(_getUrlScheme(url)); @@ -38,7 +38,7 @@ class UrlLauncherPlugin extends UrlLauncherPlatform { }.union(_safariTargetTopSchemes); /// A constructor that allows tests to override the window object used by the plugin. - UrlLauncherPlugin({@visibleForTesting html.Window debugWindow}) + UrlLauncherPlugin({@visibleForTesting html.Window? debugWindow}) : _window = debugWindow ?? html.window { _isSafari = navigatorIsSafari(_window.navigator); } @@ -58,7 +58,7 @@ class UrlLauncherPlugin extends UrlLauncherPlatform { /// /// Returns the newly created window. @visibleForTesting - html.WindowBase openNewWindow(String url, {String webOnlyWindowName}) { + html.WindowBase openNewWindow(String url, {String? webOnlyWindowName}) { // We need to open mailto, tel and sms urls on the _top window context on safari browsers. // See https://github.com/flutter/flutter/issues/51461 for reference. final target = webOnlyWindowName ?? @@ -74,13 +74,13 @@ class UrlLauncherPlugin extends UrlLauncherPlatform { @override Future launch( String url, { - @required bool useSafariVC, - @required bool useWebView, - @required bool enableJavaScript, - @required bool enableDomStorage, - @required bool universalLinksOnly, - @required Map headers, - String webOnlyWindowName, + bool useSafariVC = false, + bool useWebView = false, + bool enableJavaScript = false, + bool enableDomStorage = false, + bool universalLinksOnly = false, + Map headers = const {}, + String? webOnlyWindowName, }) { return Future.value( openNewWindow(url, webOnlyWindowName: webOnlyWindowName) != null); diff --git a/packages/url_launcher/url_launcher_web/pubspec.yaml b/packages/url_launcher/url_launcher_web/pubspec.yaml index 77a958677015..b9f957a7ee76 100644 --- a/packages/url_launcher/url_launcher_web/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/pubspec.yaml @@ -1,10 +1,7 @@ name: url_launcher_web description: Web platform implementation of url_launcher homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_web -# 0.1.y+z is compatible with 1.0.0, if you land a breaking change bump -# the version to 2.0.0. -# See more details: https://github.com/flutter/flutter/wiki/Package-migration-to-1.0.0 -version: 0.1.5+3 +version: 2.0.0-nullsafety flutter: plugin: @@ -14,31 +11,18 @@ flutter: fileName: url_launcher_web.dart dependencies: - url_launcher_platform_interface: ^1.0.9 - # TODO(mvanbeusekom): Update to use pub.dev once null safety version is published. - # url_launcher_platform_interface: - # git: - # url: https://github.com/flutter/plugins.git - # ref: nnbd - # path: packages/url_launcher/url_launcher_platform_interface + url_launcher_platform_interface: ^2.0.0-nullsafety + meta: ^1.3.0 # null safe flutter: sdk: flutter flutter_web_plugins: sdk: flutter - meta: ^1.1.7 dev_dependencies: + pedantic: ^1.10.0 # null safe flutter_test: sdk: flutter - url_launcher: ^5.2.5 - # TODO(mvanbeusekom): Update to use pub.dev once null safety version is published. - # url_launcher: - # path: ../url_launcher - pedantic: ^1.8.0 - mockito: ^4.1.1 - integration_test: - path: ../../integration_test environment: - sdk: ">=2.2.0 <3.0.0" - flutter: ">=1.10.0" + sdk: ">=2.12.0-0 <3.0.0" + flutter: ">=1.12.13+hotfix.5" diff --git a/packages/url_launcher/url_launcher_web/test/README.md b/packages/url_launcher/url_launcher_web/test/README.md index 7c48d024ba57..7c5b4ad682ba 100644 --- a/packages/url_launcher/url_launcher_web/test/README.md +++ b/packages/url_launcher/url_launcher_web/test/README.md @@ -1,17 +1,5 @@ -# Running browser_tests +## test -Make sure you have updated to the latest Flutter master. +This package uses integration tests for testing. -1. Check what version of Chrome is running on the machine you're running tests on. - -2. Download and install driver for that version from here: - * - -3. Start the driver using `chromedriver --port=4444` - -4. Change into the `test` directory of your clone. - -5. Run tests: `flutter drive -d web-server --browser-name=chrome --target=test_driver/TEST_NAME_integration.dart`, or (in Linux): - - * Single: `./run_test test_driver/TEST_NAME_integration.dart` - * All: `./run_test` +See `example/README.md` for more info. diff --git a/packages/url_launcher/url_launcher_web/test/run_test b/packages/url_launcher/url_launcher_web/test/run_test deleted file mode 100755 index 74a8526a0fa3..000000000000 --- a/packages/url_launcher/url_launcher_web/test/run_test +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/bash -if pgrep -lf chromedriver > /dev/null; then - echo "chromedriver is running." - - if [ $# -eq 0 ]; then - echo "No target specified, running all tests..." - find test_driver/ -iname *_integration.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --target='{}' - else - echo "Running test target: $1..." - set -x - flutter drive -d web-server --web-port=7357 --browser-name=chrome --target=$1 - fi - - else - echo "chromedriver is not running." -fi - diff --git a/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart b/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart new file mode 100644 index 000000000000..334f52186d9d --- /dev/null +++ b/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart @@ -0,0 +1,10 @@ +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Tell the user where to find the real tests', () { + print('---'); + print('This package uses integration_test for its tests.'); + print('See `example/README.md` for more info.'); + print('---'); + }); +} From 95f856eaea69b19d483a38e8b73856440dab84ec Mon Sep 17 00:00:00 2001 From: Bharat Biradar <62872048+bharat-biradar@users.noreply.github.com> Date: Wed, 17 Feb 2021 04:07:58 +0530 Subject: [PATCH 201/924] [file_selector_web] update documentation #76067 (#3554) Fix documentation typo. This package is file_selector, not file_picker! Co-authored-by: David Iglesias --- .../file_selector/file_selector_web/README.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/file_selector/file_selector_web/README.md b/packages/file_selector/file_selector_web/README.md index 36e0b446ffe8..24d48f48586f 100644 --- a/packages/file_selector/file_selector_web/README.md +++ b/packages/file_selector/file_selector_web/README.md @@ -1,16 +1,16 @@ -# file_picker_web +# file_selector_web -The web implementation of [`file_picker`][1]. +The web implementation of [`file_selector`][1]. ## Usage ### Import the package To use this plugin in your Flutter Web app, simply add it as a dependency in -your pubspec alongside the base `file_picker` plugin. +your pubspec alongside the base `file_selector` plugin. _(This is only temporary: in the future we hope to make this package an -"endorsed" implementation of `file_picker`, so that it is automatically -included in your Flutter Web app when you depend on `package:file_picker`.)_ +"endorsed" implementation of `file_selector`, so that it is automatically +included in your Flutter Web app when you depend on `package:file_selector`.)_ This is what the above means to your `pubspec.yaml`: @@ -18,13 +18,13 @@ This is what the above means to your `pubspec.yaml`: ... dependencies: ... - file_picker: ^0.7.0 - file_picker_web: ^0.7.0 + file_selector: ^0.7.0 + file_selector_web: ^0.7.0 ... ``` ### Use the plugin -Once you have the `file_picker_web` dependency in your pubspec, you should -be able to use `package:file_picker` as normal. +Once you have the `file_selector_web` dependency in your pubspec, you should +be able to use `package:file_selector` as normal. -[1]: ../file_picker/file_picker +[1]: https://pub.dev/packages/file_selector From aaabec0083d7f2a89c1522086b8ae7b5a446b4b9 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 16 Feb 2021 16:01:31 -0800 Subject: [PATCH 202/924] Remove iOS stubs (#3490) Plugins that don't actually support iOS are no longer required to have an iOS stub to prevent build failures. This removes all iOS stubs from plugins that don't support iOS. --- .cirrus.yml | 2 +- .../ios/Flutter/AppFrameworkInfo.plist | 30 - .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../ios/Runner.xcodeproj/project.pbxproj | 490 --------------- .../contents.xcworkspacedata | 7 - .../xcshareddata/xcschemes/Runner.xcscheme | 87 --- .../contents.xcworkspacedata | 10 - .../example/ios/Runner/AppDelegate.h | 6 - .../example/ios/Runner/AppDelegate.m | 13 - .../AppIcon.appiconset/Contents.json | 116 ---- .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 - .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 -- .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../example/ios/Runner/Info.plist | 49 -- .../example/ios/Runner/main.m | 9 - .../android_alarm_manager/ios/Assets/.gitkeep | 0 .../ios/Classes/AndroidAlarmManagerPlugin.h | 8 - .../ios/Classes/AndroidAlarmManagerPlugin.m | 21 - .../ios/android_alarm_manager.podspec | 23 - .../ios/Flutter/AppFrameworkInfo.plist | 30 - .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../ios/Runner.xcodeproj/project.pbxproj | 490 --------------- .../contents.xcworkspacedata | 7 - .../xcshareddata/xcschemes/Runner.xcscheme | 87 --- .../contents.xcworkspacedata | 10 - .../example/ios/Runner/AppDelegate.h | 10 - .../example/ios/Runner/AppDelegate.m | 17 - .../AppIcon.appiconset/Contents.json | 116 ---- .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../Runner/Base.lproj/LaunchScreen.storyboard | 27 - .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../example/ios/Runner/Info.plist | 49 -- .../android_intent/example/ios/Runner/main.m | 13 - packages/android_intent/ios/Assets/.gitkeep | 0 .../ios/Classes/AndroidIntentPlugin.h | 8 - .../ios/Classes/AndroidIntentPlugin.m | 20 - .../android_intent/ios/android_intent.podspec | 24 - .../ios/connectivity_for_web.podspec | 23 - .../ios/Flutter/AppFrameworkInfo.plist | 30 - .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../ios/Runner.xcodeproj/project.pbxproj | 490 --------------- .../contents.xcworkspacedata | 7 - .../xcshareddata/xcschemes/Runner.xcscheme | 87 --- .../contents.xcworkspacedata | 10 - .../example/ios/Runner/AppDelegate.h | 10 - .../example/ios/Runner/AppDelegate.m | 17 - .../AppIcon.appiconset/Contents.json | 116 ---- .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../Runner/Base.lproj/LaunchScreen.storyboard | 27 - .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../example/ios/Runner/Info.plist | 53 -- .../example/ios/Runner/Runner.entitlements | 8 - .../example/ios/Runner/main.m | 13 - .../ios/connectivity_macos.podspec | 21 - packages/espresso/example/ios/.gitignore | 32 - .../ios/Flutter/AppFrameworkInfo.plist | 26 - .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../ios/Runner.xcodeproj/project.pbxproj | 584 ------------------ .../xcshareddata/xcschemes/Runner.xcscheme | 91 --- .../example/ios/Runner/AppDelegate.swift | 13 - .../AppIcon.appiconset/Contents.json | 122 ---- .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 - .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 -- .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../espresso/example/ios/Runner/Info.plist | 45 -- .../ios/Runner/Runner-Bridging-Header.h | 1 - packages/espresso/ios/.gitignore | 37 -- packages/espresso/ios/Assets/.gitkeep | 0 .../espresso/ios/Classes/EspressoPlugin.h | 4 - .../espresso/ios/Classes/EspressoPlugin.m | 15 - packages/espresso/ios/espresso.podspec | 25 - packages/espresso/pubspec.yaml | 2 - .../ios/file_selector_web.podspec | 21 - .../example/ios/.gitignore | 31 - .../ios/Flutter/AppFrameworkInfo.plist | 26 - .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../ios/Runner.xcodeproj/project.pbxproj | 576 ----------------- .../xcshareddata/xcschemes/Runner.xcscheme | 91 --- .../example/ios/Runner/AppDelegate.h | 6 - .../example/ios/Runner/AppDelegate.m | 13 - .../AppIcon.appiconset/Contents.json | 122 ---- .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 - .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 -- .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../example/ios/Runner/Info.plist | 45 -- .../example/ios/Runner/main.m | 9 - .../ios/.gitignore | 37 -- .../ios/Assets/.gitkeep | 0 .../Classes/FlutterAndroidLifecyclePlugin.h | 8 - .../Classes/FlutterAndroidLifecyclePlugin.m | 10 - .../flutter_plugin_android_lifecycle.podspec | 26 - .../ios/google_maps_flutter_web.podspec | 23 - .../ios/google_sign_in_web.podspec | 21 - .../ios/image_picker_for_web.podspec | 20 - .../ios/integration_test_macos.podspec | 21 - .../path_provider_linux/ios/.gitignore | 37 -- .../ios/path_provider_linux.podspec | 19 - .../ios/Flutter/AppFrameworkInfo.plist | 30 - .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../ios/Runner.xcodeproj/project.pbxproj | 490 --------------- .../contents.xcworkspacedata | 10 - .../xcshareddata/xcschemes/Runner.xcscheme | 87 --- .../contents.xcworkspacedata | 10 - .../example/ios/Runner/AppDelegate.h | 10 - .../example/ios/Runner/AppDelegate.m | 16 - .../AppIcon.appiconset/Contents.json | 116 ---- .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../Runner/Base.lproj/LaunchScreen.storyboard | 27 - .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../example/ios/Runner/Info.plist | 49 -- .../example/ios/Runner/main.m | 13 - .../ios/path_provider_macos.podspec | 22 - .../ios/path_provider_windows.podspec | 22 - .../ios/shared_preferences_linux.podspec | 22 - .../ios/shared_preferences_macos.podspec | 21 - .../ios/shared_preferences_web.podspec | 20 - .../ios/shared_preferences_windows.podspec | 22 - .../url_launcher_linux/ios/.gitignore | 37 -- .../ios/url_launcher_linux.podspec | 22 - .../ios/Flutter/AppFrameworkInfo.plist | 30 - .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../ios/Runner.xcodeproj/project.pbxproj | 490 --------------- .../xcshareddata/xcschemes/Runner.xcscheme | 87 --- .../example/ios/Runner/AppDelegate.h | 10 - .../example/ios/Runner/AppDelegate.m | 17 - .../AppIcon.appiconset/Contents.json | 116 ---- .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../Runner/Base.lproj/LaunchScreen.storyboard | 27 - .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../example/ios/Runner/Info.plist | 49 -- .../example/ios/Runner/main.m | 13 - .../ios/url_launcher_macos.podspec | 21 - .../ios/url_launcher_web.podspec | 20 - .../ios/url_launcher_windows.podspec | 22 - .../ios/video_player_web.podspec | 20 - .../tool/lib/src/drive_examples_command.dart | 9 +- 251 files changed, 5 insertions(+), 7227 deletions(-) delete mode 100644 packages/android_alarm_manager/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/android_alarm_manager/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/android_alarm_manager/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/android_alarm_manager/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 packages/android_alarm_manager/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/android_alarm_manager/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/android_alarm_manager/example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/android_alarm_manager/example/ios/Runner/AppDelegate.h delete mode 100644 packages/android_alarm_manager/example/ios/Runner/AppDelegate.m delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/android_alarm_manager/example/ios/Runner/Info.plist delete mode 100644 packages/android_alarm_manager/example/ios/Runner/main.m delete mode 100644 packages/android_alarm_manager/ios/Assets/.gitkeep delete mode 100644 packages/android_alarm_manager/ios/Classes/AndroidAlarmManagerPlugin.h delete mode 100644 packages/android_alarm_manager/ios/Classes/AndroidAlarmManagerPlugin.m delete mode 100644 packages/android_alarm_manager/ios/android_alarm_manager.podspec delete mode 100644 packages/android_intent/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/android_intent/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/android_intent/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/android_intent/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 packages/android_intent/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/android_intent/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/android_intent/example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/android_intent/example/ios/Runner/AppDelegate.h delete mode 100644 packages/android_intent/example/ios/Runner/AppDelegate.m delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/android_intent/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/android_intent/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/android_intent/example/ios/Runner/Info.plist delete mode 100644 packages/android_intent/example/ios/Runner/main.m delete mode 100644 packages/android_intent/ios/Assets/.gitkeep delete mode 100644 packages/android_intent/ios/Classes/AndroidIntentPlugin.h delete mode 100644 packages/android_intent/ios/Classes/AndroidIntentPlugin.m delete mode 100644 packages/android_intent/ios/android_intent.podspec delete mode 100644 packages/connectivity/connectivity_for_web/ios/connectivity_for_web.podspec delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/AppDelegate.h delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/AppDelegate.m delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Info.plist delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/Runner.entitlements delete mode 100644 packages/connectivity/connectivity_macos/example/ios/Runner/main.m delete mode 100644 packages/connectivity/connectivity_macos/ios/connectivity_macos.podspec delete mode 100644 packages/espresso/example/ios/.gitignore delete mode 100644 packages/espresso/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/espresso/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/espresso/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/espresso/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 packages/espresso/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/espresso/example/ios/Runner/AppDelegate.swift delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 packages/espresso/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/espresso/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/espresso/example/ios/Runner/Info.plist delete mode 100644 packages/espresso/example/ios/Runner/Runner-Bridging-Header.h delete mode 100644 packages/espresso/ios/.gitignore delete mode 100644 packages/espresso/ios/Assets/.gitkeep delete mode 100644 packages/espresso/ios/Classes/EspressoPlugin.h delete mode 100644 packages/espresso/ios/Classes/EspressoPlugin.m delete mode 100644 packages/espresso/ios/espresso.podspec delete mode 100644 packages/file_selector/file_selector_web/ios/file_selector_web.podspec delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/.gitignore delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/AppDelegate.h delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/AppDelegate.m delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/Info.plist delete mode 100644 packages/flutter_plugin_android_lifecycle/example/ios/Runner/main.m delete mode 100644 packages/flutter_plugin_android_lifecycle/ios/.gitignore delete mode 100644 packages/flutter_plugin_android_lifecycle/ios/Assets/.gitkeep delete mode 100644 packages/flutter_plugin_android_lifecycle/ios/Classes/FlutterAndroidLifecyclePlugin.h delete mode 100644 packages/flutter_plugin_android_lifecycle/ios/Classes/FlutterAndroidLifecyclePlugin.m delete mode 100644 packages/flutter_plugin_android_lifecycle/ios/flutter_plugin_android_lifecycle.podspec delete mode 100644 packages/google_maps_flutter/google_maps_flutter_web/ios/google_maps_flutter_web.podspec delete mode 100644 packages/google_sign_in/google_sign_in_web/ios/google_sign_in_web.podspec delete mode 100644 packages/image_picker/image_picker_for_web/ios/image_picker_for_web.podspec delete mode 100644 packages/integration_test/integration_test_macos/ios/integration_test_macos.podspec delete mode 100644 packages/path_provider/path_provider_linux/ios/.gitignore delete mode 100644 packages/path_provider/path_provider_linux/ios/path_provider_linux.podspec delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/AppDelegate.h delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/AppDelegate.m delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/Info.plist delete mode 100644 packages/path_provider/path_provider_macos/example/ios/Runner/main.m delete mode 100644 packages/path_provider/path_provider_macos/ios/path_provider_macos.podspec delete mode 100644 packages/path_provider/path_provider_windows/ios/path_provider_windows.podspec delete mode 100644 packages/shared_preferences/shared_preferences_linux/ios/shared_preferences_linux.podspec delete mode 100644 packages/shared_preferences/shared_preferences_macos/ios/shared_preferences_macos.podspec delete mode 100644 packages/shared_preferences/shared_preferences_web/ios/shared_preferences_web.podspec delete mode 100644 packages/shared_preferences/shared_preferences_windows/ios/shared_preferences_windows.podspec delete mode 100644 packages/url_launcher/url_launcher_linux/ios/.gitignore delete mode 100644 packages/url_launcher/url_launcher_linux/ios/url_launcher_linux.podspec delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/AppDelegate.h delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/AppDelegate.m delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/Info.plist delete mode 100644 packages/url_launcher/url_launcher_macos/example/ios/Runner/main.m delete mode 100644 packages/url_launcher/url_launcher_macos/ios/url_launcher_macos.podspec delete mode 100644 packages/url_launcher/url_launcher_web/ios/url_launcher_web.podspec delete mode 100644 packages/url_launcher/url_launcher_windows/ios/url_launcher_windows.podspec delete mode 100644 packages/video_player/video_player_web/ios/video_player_web.podspec diff --git a/.cirrus.yml b/.cirrus.yml index c7323742e6e4..2b6ee2b7f969 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -201,7 +201,7 @@ task: - flutter channel $CHANNEL - flutter upgrade - ./script/incremental_build.sh build-examples --ipa - - ./script/incremental_build.sh drive-examples + - ./script/incremental_build.sh drive-examples --ios - ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=14.3" task: diff --git a/packages/android_alarm_manager/example/ios/Flutter/AppFrameworkInfo.plist b/packages/android_alarm_manager/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6c2de8086bcd..000000000000 --- a/packages/android_alarm_manager/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - UIRequiredDeviceCapabilities - - arm64 - - MinimumOSVersion - 8.0 - - diff --git a/packages/android_alarm_manager/example/ios/Flutter/Debug.xcconfig b/packages/android_alarm_manager/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba114687..000000000000 --- a/packages/android_alarm_manager/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/android_alarm_manager/example/ios/Flutter/Release.xcconfig b/packages/android_alarm_manager/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340e6f6..000000000000 --- a/packages/android_alarm_manager/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/android_alarm_manager/example/ios/Runner.xcodeproj/project.pbxproj b/packages/android_alarm_manager/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 10f77b41d130..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,490 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - C952AD53387AE85A4AAC19D3 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 365DE79D3A08F3F6322AB7B4 /* libPods-Runner.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 192BD17BD81C291EF9467E75 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 365DE79D3A08F3F6322AB7B4 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 842A7CA20B55950D87F2A01A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - C952AD53387AE85A4AAC19D3 /* libPods-Runner.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 1B44A04DB1D7DBDE7E239095 /* Pods */ = { - isa = PBXGroup; - children = ( - 192BD17BD81C291EF9467E75 /* Pods-Runner.debug.xcconfig */, - 842A7CA20B55950D87F2A01A /* Pods-Runner.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 1B44A04DB1D7DBDE7E239095 /* Pods */, - B10ADDD1244B5A67F70F5F08 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 97C146F21CF9000F007C117D /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - B10ADDD1244B5A67F70F5F08 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 365DE79D3A08F3F6322AB7B4 /* libPods-Runner.a */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9AC722C5D70651C49D7ECF80 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - E95CF7E4BD7CAFC3E0F4E1E2 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - 9AC722C5D70651C49D7ECF80 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - E95CF7E4BD7CAFC3E0F4E1E2 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.androidAlarmManagerExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.androidAlarmManagerExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/android_alarm_manager/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/android_alarm_manager/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16ed0f..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/packages/android_alarm_manager/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/android_alarm_manager/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 3bb3697ef41c..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/android_alarm_manager/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/android_alarm_manager/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14c74e..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/packages/android_alarm_manager/example/ios/Runner/AppDelegate.h b/packages/android_alarm_manager/example/ios/Runner/AppDelegate.h deleted file mode 100644 index 36e21bbf9cf4..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,6 +0,0 @@ -#import -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/packages/android_alarm_manager/example/ios/Runner/AppDelegate.m b/packages/android_alarm_manager/example/ios/Runner/AppDelegate.m deleted file mode 100644 index 59a72e90be12..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,13 +0,0 @@ -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d22f10b2ab63..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 28c6bf03016f6c994b70f38d1b7346e5831b531f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 564 zcmV-40?Yl0P)Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 zcmds$`#;kQ7{|XelZftyR5~xW7?MLxS4^|Hw3&P7^y)@A9Fj{Xm1~_CIV^XZ%SLBn zA;!r`GqGHg=7>xrB{?psZQs88ZaedDoagm^KF{a*>G|dJWRSe^I$DNW008I^+;Kjt z>9p3GNR^I;v>5_`+91i(*G;u5|L+Bu6M=(afLjtkya#yZ175|z$pU~>2#^Z_pCZ7o z1c6UNcv2B3?; zX%qdxCXQpdKRz=#b*q0P%b&o)5ZrNZt7$fiETSK_VaY=mb4GK`#~0K#~9^ zcY!`#Af+4h?UMR-gMKOmpuYeN5P*RKF!(tb`)oe0j2BH1l?=>y#S5pMqkx6i{*=V9JF%>N8`ewGhRE(|WohnD59R^$_36{4>S zDFlPC5|k?;SPsDo87!B{6*7eqmMdU|QZ84>6)Kd9wNfh90=y=TFQay-0__>=<4pk& zYDjgIhL-jQ9o>z32K)BgAH+HxamL{ZL~ozu)Qqe@a`FpH=oQRA8=L-m-1dam(Ix2V z?du;LdMO+ooBelr^_y4{|44tmgH^2hSzPFd;U^!1p>6d|o)(-01z{i&Kj@)z-yfWQ)V#3Uo!_U}q3u`(fOs`_f^ueFii1xBNUB z6MecwJN$CqV&vhc+)b(p4NzGGEgwWNs z@*lUV6LaduZH)4_g!cE<2G6#+hJrWd5(|p1Z;YJ7ifVHv+n49btR}dq?HHDjl{m$T z!jLZcGkb&XS2OG~u%&R$(X+Z`CWec%QKt>NGYvd5g20)PU(dOn^7%@6kQb}C(%=vr z{?RP(z~C9DPnL{q^@pVw@|Vx~@3v!9dCaBtbh2EdtoNHm4kGxp>i#ct)7p|$QJs+U z-a3qtcPvhihub?wnJqEt>zC@)2suY?%-96cYCm$Q8R%-8$PZYsx3~QOLMDf(piXMm zB=<63yQk1AdOz#-qsEDX>>c)EES%$owHKue;?B3)8aRd}m~_)>SL3h2(9X;|+2#7X z+#2)NpD%qJvCQ0a-uzZLmz*ms+l*N}w)3LRQ*6>|Ub-fyptY(keUxw+)jfwF5K{L9 z|Cl_w=`!l_o><384d&?)$6Nh(GAm=4p_;{qVn#hI8lqewW7~wUlyBM-4Z|)cZr?Rh z=xZ&Ol>4(CU85ea(CZ^aO@2N18K>ftl8>2MqetAR53_JA>Fal`^)1Y--Am~UDa4th zKfCYpcXky$XSFDWBMIl(q=Mxj$iMBX=|j9P)^fDmF(5(5$|?Cx}DKEJa&XZP%OyE`*GvvYQ4PV&!g2|L^Q z?YG}tx;sY@GzMmsY`7r$P+F_YLz)(e}% zyakqFB<6|x9R#TdoP{R$>o7y(-`$$p0NxJ6?2B8tH)4^yF(WhqGZlM3=9Ibs$%U1w zWzcss*_c0=v_+^bfb`kBFsI`d;ElwiU%frgRB%qBjn@!0U2zZehBn|{%uNIKBA7n= zzE`nnwTP85{g;8AkYxA68>#muXa!G>xH22D1I*SiD~7C?7Za+9y7j1SHiuSkKK*^O zsZ==KO(Ua#?YUpXl{ViynyT#Hzk=}5X$e04O@fsMQjb}EMuPWFO0e&8(2N(29$@Vd zn1h8Yd>6z(*p^E{c(L0Lg=wVdupg!z@WG;E0k|4a%s7Up5C0c)55XVK*|x9RQeZ1J@1v9MX;>n34(i>=YE@Iur`0Vah(inE3VUFZNqf~tSz{1fz3Fsn_x4F>o(Yo;kpqvBe-sbwH(*Y zu$JOl0b83zu$JMvy<#oH^Wl>aWL*?aDwnS0iEAwC?DK@aT)GHRLhnz2WCvf3Ba;o=aY7 z2{Asu5MEjGOY4O#Ggz@@J;q*0`kd2n8I3BeNuMmYZf{}pg=jTdTCrIIYuW~luKecn z+E-pHY%ohj@uS0%^ z&(OxwPFPD$+#~`H?fMvi9geVLci(`K?Kj|w{rZ9JgthFHV+=6vMbK~0)Ea<&WY-NC zy-PnZft_k2tfeQ*SuC=nUj4H%SQ&Y$gbH4#2sT0cU0SdFs=*W*4hKGpuR1{)mV;Qf5pw4? zfiQgy0w3fC*w&Bj#{&=7033qFR*<*61B4f9K%CQvxEn&bsWJ{&winp;FP!KBj=(P6 z4Z_n4L7cS;ao2)ax?Tm|I1pH|uLpDSRVghkA_UtFFuZ0b2#>!8;>-_0ELjQSD-DRd z4im;599VHDZYtnWZGAB25W-e(2VrzEh|etsv2YoP#VbIZ{aFkwPrzJ#JvCvA*mXS& z`}Q^v9(W4GiSs}#s7BaN!WA2bniM$0J(#;MR>uIJ^uvgD3GS^%*ikdW6-!VFUU?JV zZc2)4cMsX@j z5HQ^e3BUzOdm}yC-xA%SY``k$rbfk z;CHqifhU*jfGM@DkYCecD9vl*qr58l6x<8URB=&%{!Cu3RO*MrKZ4VO}V6R0a zZw3Eg^0iKWM1dcTYZ0>N899=r6?+adUiBKPciJw}L$=1f4cs^bio&cr9baLF>6#BM z(F}EXe-`F=f_@`A7+Q&|QaZ??Txp_dB#lg!NH=t3$G8&06MFhwR=Iu*Im0s_b2B@| znW>X}sy~m#EW)&6E&!*0%}8UAS)wjt+A(io#wGI@Z2S+Ms1Cxl%YVE800007ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 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 diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b70f1..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/android_alarm_manager/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/android_alarm_manager/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7c939..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/android_alarm_manager/example/ios/Runner/Base.lproj/Main.storyboard b/packages/android_alarm_manager/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516fb38..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/android_alarm_manager/example/ios/Runner/Info.plist b/packages/android_alarm_manager/example/ios/Runner/Info.plist deleted file mode 100644 index 1d076337d6f4..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner/Info.plist +++ /dev/null @@ -1,49 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - android_alarm_manager_example - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - arm64 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/android_alarm_manager/example/ios/Runner/main.m b/packages/android_alarm_manager/example/ios/Runner/main.m deleted file mode 100644 index dff6597e4513..000000000000 --- a/packages/android_alarm_manager/example/ios/Runner/main.m +++ /dev/null @@ -1,9 +0,0 @@ -#import -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/packages/android_alarm_manager/ios/Assets/.gitkeep b/packages/android_alarm_manager/ios/Assets/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/packages/android_alarm_manager/ios/Classes/AndroidAlarmManagerPlugin.h b/packages/android_alarm_manager/ios/Classes/AndroidAlarmManagerPlugin.h deleted file mode 100644 index 595fcf60fee1..000000000000 --- a/packages/android_alarm_manager/ios/Classes/AndroidAlarmManagerPlugin.h +++ /dev/null @@ -1,8 +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 - -@interface FLTAndroidAlarmManagerPlugin : NSObject -@end diff --git a/packages/android_alarm_manager/ios/Classes/AndroidAlarmManagerPlugin.m b/packages/android_alarm_manager/ios/Classes/AndroidAlarmManagerPlugin.m deleted file mode 100644 index 0aa4f2b2122d..000000000000 --- a/packages/android_alarm_manager/ios/Classes/AndroidAlarmManagerPlugin.m +++ /dev/null @@ -1,21 +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 "AndroidAlarmManagerPlugin.h" - -@implementation FLTAndroidAlarmManagerPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - FlutterMethodChannel* channel = - [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/android_alarm_manager" - binaryMessenger:[registrar messenger] - codec:[FlutterJSONMethodCodec sharedInstance]]; - FLTAndroidAlarmManagerPlugin* instance = [[FLTAndroidAlarmManagerPlugin alloc] init]; - [registrar addMethodCallDelegate:instance channel:channel]; -} - -- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { - result(FlutterMethodNotImplemented); -} - -@end diff --git a/packages/android_alarm_manager/ios/android_alarm_manager.podspec b/packages/android_alarm_manager/ios/android_alarm_manager.podspec deleted file mode 100644 index 2b253878c1ea..000000000000 --- a/packages/android_alarm_manager/ios/android_alarm_manager.podspec +++ /dev/null @@ -1,23 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'android_alarm_manager' - s.version = '0.0.1' - s.summary = 'Flutter Android Alarm Manager' - s.description = <<-DESC -A Flutter plugin for accessing the Android AlarmManager service, and running Dart code in the background when alarms fire. -This plugin a no-op on iOS. -Downloaded by pub (not CocoaPods). - DESC - s.homepage = 'https://github.com/flutter/plugins' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/android_alarm_manager' } - s.documentation_url = 'https://pub.dev/packages/android_alarm_manager' - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - s.platform = :ios, '8.0' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } -end diff --git a/packages/android_intent/example/ios/Flutter/AppFrameworkInfo.plist b/packages/android_intent/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6c2de8086bcd..000000000000 --- a/packages/android_intent/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - UIRequiredDeviceCapabilities - - arm64 - - MinimumOSVersion - 8.0 - - diff --git a/packages/android_intent/example/ios/Flutter/Debug.xcconfig b/packages/android_intent/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba114687..000000000000 --- a/packages/android_intent/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/android_intent/example/ios/Flutter/Release.xcconfig b/packages/android_intent/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340e6f6..000000000000 --- a/packages/android_intent/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/android_intent/example/ios/Runner.xcodeproj/project.pbxproj b/packages/android_intent/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 430cec7ef2b5..000000000000 --- a/packages/android_intent/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,490 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3FC5CBD67A867C34C8CFD7E1 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7ABB9ACA70E30025F77BB759 /* libPods-Runner.a */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 7ABB9ACA70E30025F77BB759 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9B21C620C27B8C2AF08BFA21 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - EFC3461395B2546568135556 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 3FC5CBD67A867C34C8CFD7E1 /* libPods-Runner.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 2C36A917BF8B34817D5A406D /* Pods */ = { - isa = PBXGroup; - children = ( - EFC3461395B2546568135556 /* Pods-Runner.debug.xcconfig */, - 9B21C620C27B8C2AF08BFA21 /* Pods-Runner.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; - 7423FCEB8AD9C632FAF625A3 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 7ABB9ACA70E30025F77BB759 /* libPods-Runner.a */, - ); - name = Frameworks; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 2C36A917BF8B34817D5A406D /* Pods */, - 7423FCEB8AD9C632FAF625A3 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 97C146F21CF9000F007C117D /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - ECD6A6833016AB689F7B8471 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 4B2738B48C3E53795176CD79 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 4B2738B48C3E53795176CD79 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - ECD6A6833016AB689F7B8471 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.androidIntentExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.androidIntentExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/android_intent/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/android_intent/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16ed0f..000000000000 --- a/packages/android_intent/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/packages/android_intent/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/android_intent/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 3bb3697ef41c..000000000000 --- a/packages/android_intent/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/android_intent/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/android_intent/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14c74e..000000000000 --- a/packages/android_intent/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/packages/android_intent/example/ios/Runner/AppDelegate.h b/packages/android_intent/example/ios/Runner/AppDelegate.h deleted file mode 100644 index d9e18e990f2e..000000000000 --- a/packages/android_intent/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,10 +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 -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/packages/android_intent/example/ios/Runner/AppDelegate.m b/packages/android_intent/example/ios/Runner/AppDelegate.m deleted file mode 100644 index f08675707182..000000000000 --- a/packages/android_intent/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,17 +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. - -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d22f10b2ab63..000000000000 --- a/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 28c6bf03016f6c994b70f38d1b7346e5831b531f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 564 zcmV-40?Yl0P)Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 diff --git a/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 zcmVjJBgitF5mAp-i>4+KS_oR{|13AP->1TD4=w)g|)JHOx|a2Wk1Va z!k)vP$UcQ#mdj%wNQoaJ!w>jv_6&JPyutpQps?s5dmDQ>`%?Bvj>o<%kYG!YW6H-z zu`g$@mp`;qDR!51QaS}|ZToSuAGcJ7$2HF0z`ln4t!#Yg46>;vGG9N9{V@9z#}6v* zfP?}r6b{*-C*)(S>NECI_E~{QYzN5SXRmVnP<=gzP+_Sp(Aza_hKlZ{C1D&l*(7IKXxQC1Z9#6wx}YrGcn~g%;icdw>T0Rf^w0{ z$_wn1J+C0@!jCV<%Go5LA45e{5gY9PvZp8uM$=1}XDI+9m7!A95L>q>>oe0$nC->i zeexUIvq%Uk<-$>DiDb?!In)lAmtuMWxvWlk`2>4lNuhSsjAf2*2tjT`y;@d}($o)S zn(+W&hJ1p0xy@oxP%AM15->wPLp{H!k)BdBD$toBpJh+crWdsNV)qsHaqLg2_s|Ih z`8E9z{E3sA!}5aKu?T!#enD(wLw?IT?k-yWVHZ8Akz4k5(TZJN^zZgm&zM28sfTD2BYJ|Fde3Xzh;;S` z=GXTnY4Xc)8nYoz6&vF;P7{xRF-{|2Xs5>a5)@BrnQ}I(_x7Cgpx#5&Td^4Q9_FnQ zX5so*;#8-J8#c$OlA&JyPp$LKUhC~-e~Ij!L%uSMu!-VZG7Hx-L{m2DVR2i=GR(_% zCVD!4N`I)&Q5S`?P&fQZ=4#Dgt_v2-DzkT}K(9gF0L(owe-Id$Rc2qZVLqI_M_DyO z9@LC#U28_LU{;wGZ&))}0R2P4MhajKCd^K#D+JJ&JIXZ_p#@+7J9A&P<0kdRujtQ_ zOy>3=C$kgi6$0pW06KaLz!21oOryKM3ZUOWqppndxfH}QpgjEJ`j7Tzn5bk6K&@RA?vl##y z$?V~1E(!wB5rH`>3nc&@)|#<1dN2cMzzm=PGhQ|Yppne(C-Vlt450IXc`J4R0W@I7 zd1e5uW6juvO%ni(WX7BsKx3MLngO7rHO;^R5I~0^nE^9^E_eYLgiR9&KnJ)pBbfno zSVnW$0R+&6jOOsZ82}nJ126+c|%svPo;TeUku<2G7%?$oft zyaO;tVo}(W)VsTUhq^XmFi#2z%-W9a{7mXn{uzivYQ_d6b7VJG{77naW(vHt-uhnY zVN#d!JTqVh(7r-lhtXVU6o})aZbDt_;&wJVGl2FKYFBFpU-#9U)z#(A%=IVnqytR$SY-sO( z($oNE09{D^@OuYPz&w~?9>Fl5`g9u&ecFGhqX=^#fmR=we0CJw+5xna*@oHnkahk+ z9aWeE3v|An+O5%?4fA&$Fgu~H_YmqR!yIU!bFCk4!#pAj%(lI(A5n)n@Id#M)O9Yx zJU9oKy{sRAIV3=5>(s8n{8ryJ!;ho}%pn6hZKTKbqk=&m=f*UnK$zW3YQP*)pw$O* zIfLA^!-bmBl6%d_n$#tP8Zd_(XdA*z*WH|E_yILwjtI~;jK#v-6jMl^?<%Y%`gvpwv&cFb$||^v4D&V=aNy?NGo620jL3VZnA%s zH~I|qPzB~e(;p;b^gJr7Ure#7?8%F0m4vzzPy^^(q4q1OdthF}Fi*RmVZN1OwTsAP zn9CZP`FazX3^kG(KodIZ=Kty8DLTy--UKfa1$6XugS zk%6v$Kmxt6U!YMx0JQ)0qX*{CXwZZk$vEROidEc7=J-1;peNat!vS<3P-FT5po>iE z!l3R+<`#x|+_hw!HjQGV=8!q|76y8L7N8gP3$%0kfush|u0uU^?dKBaeRSBUpOZ0c z62;D&Mdn2}N}xHRFTRI?zRv=>=AjHgH}`2k4WK=#AHB)UFrR-J87GgX*x5fL^W2#d z=(%K8-oZfMO=i{aWRDg=FX}UubM4eotRDcn;OR#{3q=*?3mE3_oJ-~prjhxh%PgQT zyn)Qozaq0@o&|LEgS{Ind4Swsr;b`u185hZPOBLL<`d2%^Yp1?oL)=jnLi;Zo0ZDliTtQ^b5SmfIMe{T==zZkbvn$KTQGlbG8w}s@M3TZnde;1Am46P3juKb zl9GU&3F=q`>j!`?SyH#r@O59%@aMX^rx}Nxe<>NqpUp5=lX1ojGDIR*-D^SDuvCKF z?3$xG(gVUsBERef_YjPFl^rU9EtD{pt z0CXwpN7BN3!8>hajGaTVk-wl=9rxmfWtIhC{mheHgStLi^+Nz12a?4r(fz)?3A%at zMlvQmL<2-R)-@G1wJ0^zQK%mR=r4d{Y3fHp){nWXUL#|CqXl(+v+qDh>FkF9`eWrW zfr^D%LNfOcTNvtx0JXR35J0~Jpi2#P3Q&80w+nqNfc}&G0A~*)lGHKv=^FE+b(37|)zL;KLF>oiGfb(?&1 zV3XRu!Sw>@quKiab%g6jun#oZ%!>V#A%+lNc?q>6+VvyAn=kf_6z^(TZUa4Eelh{{ zqFX-#dY(EV@7l$NE&kv9u9BR8&Ojd#ZGJ6l8_BW}^r?DIS_rU2(XaGOK z225E@kH5Opf+CgD^{y29jD4gHbGf{1MD6ggQ&%>UG4WyPh5q_tb`{@_34B?xfSO*| zZv8!)q;^o-bz`MuxXk*G^}(6)ACb@=Lfs`Hxoh>`Y0NE8QRQ!*p|SH@{r8=%RKd4p z+#Ty^-0kb=-H-O`nAA3_6>2z(D=~Tbs(n8LHxD0`R0_ATFqp-SdY3(bZ3;VUM?J=O zKCNsxsgt@|&nKMC=*+ZqmLHhX1KHbAJs{nGVMs6~TiF%Q)P@>!koa$%oS zjXa=!5>P`vC-a}ln!uH1ooeI&v?=?v7?1n~P(wZ~0>xWxd_Aw;+}9#eULM7M8&E?Y zC-ZLhi3RoM92SXUb-5i-Lmt5_rfjE{6y^+24`y$1lywLyHO!)Boa7438K4#iLe?rh z2O~YGSgFUBH?og*6=r9rme=peP~ah`(8Zt7V)j5!V0KPFf_mebo3z95U8(up$-+EA^9dTRLq>Yl)YMBuch9%=e5B`Vnb>o zt03=kq;k2TgGe4|lGne&zJa~h(UGutjP_zr?a7~#b)@15XNA>Dj(m=gg2Q5V4-$)D|Q9}R#002ovPDHLkV1o7DH3k3x diff --git a/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/android_intent/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8 - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/android_intent/example/ios/Runner/Base.lproj/Main.storyboard b/packages/android_intent/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516fb38..000000000000 --- a/packages/android_intent/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/android_intent/example/ios/Runner/Info.plist b/packages/android_intent/example/ios/Runner/Info.plist deleted file mode 100644 index 61ad692e0180..000000000000 --- a/packages/android_intent/example/ios/Runner/Info.plist +++ /dev/null @@ -1,49 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - android_intent_example - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - arm64 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/android_intent/example/ios/Runner/main.m b/packages/android_intent/example/ios/Runner/main.m deleted file mode 100644 index bec320c0bee0..000000000000 --- a/packages/android_intent/example/ios/Runner/main.m +++ /dev/null @@ -1,13 +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 -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/packages/android_intent/ios/Assets/.gitkeep b/packages/android_intent/ios/Assets/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/packages/android_intent/ios/Classes/AndroidIntentPlugin.h b/packages/android_intent/ios/Classes/AndroidIntentPlugin.h deleted file mode 100644 index 8810c13f61cf..000000000000 --- a/packages/android_intent/ios/Classes/AndroidIntentPlugin.h +++ /dev/null @@ -1,8 +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 - -@interface FLTAndroidIntentPlugin : NSObject -@end diff --git a/packages/android_intent/ios/Classes/AndroidIntentPlugin.m b/packages/android_intent/ios/Classes/AndroidIntentPlugin.m deleted file mode 100644 index d708adf8c1d0..000000000000 --- a/packages/android_intent/ios/Classes/AndroidIntentPlugin.m +++ /dev/null @@ -1,20 +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 "AndroidIntentPlugin.h" - -@implementation FLTAndroidIntentPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - FlutterMethodChannel* channel = - [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/android_intent" - binaryMessenger:[registrar messenger]]; - FLTAndroidIntentPlugin* instance = [[FLTAndroidIntentPlugin alloc] init]; - [registrar addMethodCallDelegate:instance channel:channel]; -} - -- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { - result(FlutterMethodNotImplemented); -} - -@end diff --git a/packages/android_intent/ios/android_intent.podspec b/packages/android_intent/ios/android_intent.podspec deleted file mode 100644 index b3f9b6eb334f..000000000000 --- a/packages/android_intent/ios/android_intent.podspec +++ /dev/null @@ -1,24 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'android_intent' - s.version = '0.0.1' - s.summary = 'Android Intent Plugin for Flutter' - s.description = <<-DESC -This plugin allows Flutter apps to launch arbitrary intents when the platform is Android. -If the plugin is invoked on iOS, it will crash your app. -Downloaded by pub (not CocoaPods). - DESC - s.homepage = 'https://github.com/flutter/plugins' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/android_intent' } - s.documentation_url = 'https://pub.dev/packages/android_intent' - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - s.platform = :ios, '8.0' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } -end - diff --git a/packages/connectivity/connectivity_for_web/ios/connectivity_for_web.podspec b/packages/connectivity/connectivity_for_web/ios/connectivity_for_web.podspec deleted file mode 100644 index 75b891c56533..000000000000 --- a/packages/connectivity/connectivity_for_web/ios/connectivity_for_web.podspec +++ /dev/null @@ -1,23 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint connectivity_web.podspec' to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'connectivity_for_web' - s.version = '0.1.0' - s.summary = 'No-op implementation of connectivity web plugin to avoid build issues on iOS' - s.description = <<-DESC -temp fake connectivity_web plugin - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_for_web' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.dependency 'Flutter' - s.platform = :ios, '8.0' - - # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } - s.swift_version = '5.0' -end diff --git a/packages/connectivity/connectivity_macos/example/ios/Flutter/AppFrameworkInfo.plist b/packages/connectivity/connectivity_macos/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6c2de8086bcd..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - UIRequiredDeviceCapabilities - - arm64 - - MinimumOSVersion - 8.0 - - diff --git a/packages/connectivity/connectivity_macos/example/ios/Flutter/Debug.xcconfig b/packages/connectivity/connectivity_macos/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba114687..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/connectivity/connectivity_macos/example/ios/Flutter/Release.xcconfig b/packages/connectivity/connectivity_macos/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340e6f6..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/project.pbxproj b/packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index e497d093be56..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,490 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - EB0BA966000B5C35B13186D7 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C80D49AFD183103034E444C2 /* libPods-Runner.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3173C764DD180BE02EB51E47 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 69D903F0A9A7C636EE803AF8 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C80D49AFD183103034E444C2 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - EB0BA966000B5C35B13186D7 /* libPods-Runner.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 89F516DEFCBF79E39D2885C2 /* Frameworks */ = { - isa = PBXGroup; - children = ( - C80D49AFD183103034E444C2 /* libPods-Runner.a */, - ); - name = Frameworks; - sourceTree = ""; - }; - 8ECC1C323F60D5498EEC2315 /* Pods */ = { - isa = PBXGroup; - children = ( - 69D903F0A9A7C636EE803AF8 /* Pods-Runner.debug.xcconfig */, - 3173C764DD180BE02EB51E47 /* Pods-Runner.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 8ECC1C323F60D5498EEC2315 /* Pods */, - 89F516DEFCBF79E39D2885C2 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 97C146F21CF9000F007C117D /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 3BAF367E8BACBC7576CEE653 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 6A2F146AD353BE7A0C3E797E /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 3BAF367E8BACBC7576CEE653 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 6A2F146AD353BE7A0C3E797E /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.connectivityExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.connectivityExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16ed0f..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 3bb3697ef41c..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/connectivity/connectivity_macos/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14c74e..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/AppDelegate.h b/packages/connectivity/connectivity_macos/example/ios/Runner/AppDelegate.h deleted file mode 100644 index d9e18e990f2e..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,10 +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 -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/AppDelegate.m b/packages/connectivity/connectivity_macos/example/ios/Runner/AppDelegate.m deleted file mode 100644 index f08675707182..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,17 +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. - -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d22f10b2ab63..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 28c6bf03016f6c994b70f38d1b7346e5831b531f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 564 zcmV-40?Yl0P)Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 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 diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/connectivity/connectivity_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8 - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Base.lproj/Main.storyboard b/packages/connectivity/connectivity_macos/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516fb38..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Info.plist b/packages/connectivity/connectivity_macos/example/ios/Runner/Info.plist deleted file mode 100644 index babbd80f1619..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner/Info.plist +++ /dev/null @@ -1,53 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - connectivity_example - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSRequiresIPhoneOS - - NSLocationAlwaysAndWhenInUseUsageDescription - This app requires accessing your location information all the time to get wi-fi information. - NSLocationWhenInUseUsageDescription - This app requires accessing your location information when the app is in foreground to get wi-fi information. - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - arm64 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/Runner.entitlements b/packages/connectivity/connectivity_macos/example/ios/Runner/Runner.entitlements deleted file mode 100644 index ba21fbdaf290..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner/Runner.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.developer.networking.wifi-info - - - diff --git a/packages/connectivity/connectivity_macos/example/ios/Runner/main.m b/packages/connectivity/connectivity_macos/example/ios/Runner/main.m deleted file mode 100644 index bec320c0bee0..000000000000 --- a/packages/connectivity/connectivity_macos/example/ios/Runner/main.m +++ /dev/null @@ -1,13 +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 -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/packages/connectivity/connectivity_macos/ios/connectivity_macos.podspec b/packages/connectivity/connectivity_macos/ios/connectivity_macos.podspec deleted file mode 100644 index a941a16327f3..000000000000 --- a/packages/connectivity/connectivity_macos/ios/connectivity_macos.podspec +++ /dev/null @@ -1,21 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'connectivity_macos' - s.version = '0.0.1' - s.summary = 'No-op implementation of the connectivity desktop plugin to avoid build issues on iOS' - s.description = <<-DESC - No-op implementation of connectivity_macos to avoid build issues on iOS. - See https://github.com/flutter/flutter/issues/39659 - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_macos' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' -end \ No newline at end of file diff --git a/packages/espresso/example/ios/.gitignore b/packages/espresso/example/ios/.gitignore deleted file mode 100644 index e96ef602b8d1..000000000000 --- a/packages/espresso/example/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/packages/espresso/example/ios/Flutter/AppFrameworkInfo.plist b/packages/espresso/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6b4c0f78a785..000000000000 --- a/packages/espresso/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/packages/espresso/example/ios/Flutter/Debug.xcconfig b/packages/espresso/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba114687..000000000000 --- a/packages/espresso/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/espresso/example/ios/Flutter/Release.xcconfig b/packages/espresso/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340e6f6..000000000000 --- a/packages/espresso/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/espresso/example/ios/Runner.xcodeproj/project.pbxproj b/packages/espresso/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 2209e01dfcd6..000000000000 --- a/packages/espresso/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,584 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - B4A70C1E3465B7A2E7ECD8F8 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE5F32230E1B4F4C17EDB557 /* Pods_Runner.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 02691CEFCB33C0B1CABE7A23 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 09442C04D3DC0049E7725D93 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 3EF237100A0BFC444DE6BC97 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - AE5F32230E1B4F4C17EDB557 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - B4A70C1E3465B7A2E7ECD8F8 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 301432828879F7BDE0943C41 /* Frameworks */ = { - isa = PBXGroup; - children = ( - AE5F32230E1B4F4C17EDB557 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - E9E5CC94EC52B9D261A44A5E /* Pods */, - 301432828879F7BDE0943C41 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; - E9E5CC94EC52B9D261A44A5E /* Pods */ = { - isa = PBXGroup; - children = ( - 02691CEFCB33C0B1CABE7A23 /* Pods-Runner.debug.xcconfig */, - 3EF237100A0BFC444DE6BC97 /* Pods-Runner.release.xcconfig */, - 09442C04D3DC0049E7725D93 /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 5D7E711796DC6F61E7F1A6AE /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - DC7821945A6EDE472DDF686F /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 5D7E711796DC6F61E7F1A6AE /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - DC7821945A6EDE472DDF686F /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.espressoExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.espressoExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.espressoExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/espresso/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/espresso/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cfdb3f..000000000000 --- a/packages/espresso/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/espresso/example/ios/Runner/AppDelegate.swift b/packages/espresso/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a8c12..000000000000 --- a/packages/espresso/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab2d9d..000000000000 --- a/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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 diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 zcmds$`#;kQ7{|XelZftyR5~xW7?MLxS4^|Hw3&P7^y)@A9Fj{Xm1~_CIV^XZ%SLBn zA;!r`GqGHg=7>xrB{?psZQs88ZaedDoagm^KF{a*>G|dJWRSe^I$DNW008I^+;Kjt z>9p3GNR^I;v>5_`+91i(*G;u5|L+Bu6M=(afLjtkya#yZ175|z$pU~>2#^Z_pCZ7o z1c6UNcv2B3?; zX%qdxCXQpdKRz=#b*q0P%b&o)5ZrNZt7$fiETSK_VaY=mb4GK`#~0K#~9^ zcY!`#Af+4h?UMR-gMKOmpuYeN5P*RKF!(tb`)oe0j2BH1l?=>y#S5pMqkx6i{*=V9JF%>N8`ewGhRE(|WohnD59R^$_36{4>S zDFlPC5|k?;SPsDo87!B{6*7eqmMdU|QZ84>6)Kd9wNfh90=y=TFQay-0__>=<4pk& zYDjgIhL-jQ9o>z32K)BgAH+HxamL{ZL~ozu)Qqe@a`FpH=oQRA8=L-m-1dam(Ix2V z?du;LdMO+ooBelr^_y4{|44tmgH^2hSzPFd;U^!1p>6d|o)(-01z{i&Kj@)z-yfWQ)V#3Uo!_U}q3u`(fOs`_f^ueFii1xBNUB z6MecwJN$CqV&vhc+)b(p4NzGGEgwWNs z@*lUV6LaduZH)4_g!cE<2G6#+hJrWd5(|p1Z;YJ7ifVHv+n49btR}dq?HHDjl{m$T z!jLZcGkb&XS2OG~u%&R$(X+Z`CWec%QKt>NGYvd5g20)PU(dOn^7%@6kQb}C(%=vr z{?RP(z~C9DPnL{q^@pVw@|Vx~@3v!9dCaBtbh2EdtoNHm4kGxp>i#ct)7p|$QJs+U z-a3qtcPvhihub?wnJqEt>zC@)2suY?%-96cYCm$Q8R%-8$PZYsx3~QOLMDf(piXMm zB=<63yQk1AdOz#-qsEDX>>c)EES%$owHKue;?B3)8aRd}m~_)>SL3h2(9X;|+2#7X z+#2)NpD%qJvCQ0a-uzZLmz*ms+l*N}w)3LRQ*6>|Ub-fyptY(keUxw+)jfwF5K{L9 z|Cl_w=`!l_o><384d&?)$6Nh(GAm=4p_;{qVn#hI8lqewW7~wUlyBM-4Z|)cZr?Rh z=xZ&Ol>4(CU85ea(CZ^aO@2N18K>ftl8>2MqetAR53_JA>Fal`^)1Y--Am~UDa4th zKfCYpcXky$XSFDWBMIl(q=Mxj$iMBX=|j9P)^fDmF(5(5$|?Cx}DKEJa&XZP%OyE`*GvvYQ4PV&!g2|L^Q z?YG}tx;sY@GzMmsY`7r$P+F_YLz)(e}% zyakqFB<6|x9R#TdoP{R$>o7y(-`$$p0NxJ6?2B8tH)4^yF(WhqGZlM3=9Ibs$%U1w zWzcss*_c0=v_+^bfb`kBFsI`d;ElwiU%frgRB%qBjn@!0U2zZehBn|{%uNIKBA7n= zzE`nnwTP85{g;8AkYxA68>#muXa!G>xH22D1I*SiD~7C?7Za+9y7j1SHiuSkKK*^O zsZ==KO(Ua#?YUpXl{ViynyT#Hzk=}5X$e04O@fsMQjb}EMuPWFO0e&8(2N(29$@Vd zn1h8Yd>6z(*p^E{c(L0Lg=wVdupg!z@WG;E0k|4a%s7Up5C0c)55XVK*|x9RQeZ1J@1v9MX;>n34(i>=YE@Iur`0Vah(inE3VUFZNqf~tSz{1fz3Fsn_x4F>o(Yo;kpqvBe-sbwH(*Y zu$JOl0b83zu$JMvy<#oH^Wl>aWL*?aDwnS0iEAwC?DK@aT)GHRLhnz2WCvf3Ba;o=aY7 z2{Asu5MEjGOY4O#Ggz@@J;q*0`kd2n8I3BeNuMmYZf{}pg=jTdTCrIIYuW~luKecn z+E-pHY%ohj@uS0%^ z&(OxwPFPD$+#~`H?fMvi9geVLci(`K?Kj|w{rZ9JgthFHV+=6vMbK~0)Ea<&WY-NC zy-PnZft_k2tfeQ*SuC=nUj4H%SQ&Y$gbH4#2sT0cU0SdFs=*W*4hKGpuR1{)mV;Qf5pw4? zfiQgy0w3fC*w&Bj#{&=7033qFR*<*61B4f9K%CQvxEn&bsWJ{&winp;FP!KBj=(P6 z4Z_n4L7cS;ao2)ax?Tm|I1pH|uLpDSRVghkA_UtFFuZ0b2#>!8;>-_0ELjQSD-DRd z4im;599VHDZYtnWZGAB25W-e(2VrzEh|etsv2YoP#VbIZ{aFkwPrzJ#JvCvA*mXS& z`}Q^v9(W4GiSs}#s7BaN!WA2bniM$0J(#;MR>uIJ^uvgD3GS^%*ikdW6-!VFUU?JV zZc2)4cMsX@j z5HQ^e3BUzOdm}yC-xA%SY``k$rbfk z;CHqifhU*jfGM@DkYCecD9vl*qr58l6x<8URB=&%{!Cu3RO*MrKZ4VO}V6R0a zZw3Eg^0iKWM1dcTYZ0>N899=r6?+adUiBKPciJw}L$=1f4cs^bio&cr9baLF>6#BM z(F}EXe-`F=f_@`A7+Q&|QaZ??Txp_dB#lg!NH=t3$G8&06MFhwR=Iu*Im0s_b2B@| znW>X}sy~m#EW)&6E&!*0%}8UAS)wjt+A(io#wGI@Z2S+Ms1Cxl%YVE800007ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 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 diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/espresso/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b70f1..000000000000 --- a/packages/espresso/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/espresso/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/espresso/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7c939..000000000000 --- a/packages/espresso/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/espresso/example/ios/Runner/Base.lproj/Main.storyboard b/packages/espresso/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516fb38..000000000000 --- a/packages/espresso/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/espresso/example/ios/Runner/Info.plist b/packages/espresso/example/ios/Runner/Info.plist deleted file mode 100644 index 96cc992ec974..000000000000 --- a/packages/espresso/example/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - espresso_example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/espresso/example/ios/Runner/Runner-Bridging-Header.h b/packages/espresso/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 7335fdf9000c..000000000000 --- a/packages/espresso/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file diff --git a/packages/espresso/ios/.gitignore b/packages/espresso/ios/.gitignore deleted file mode 100644 index aa479fd3ce8a..000000000000 --- a/packages/espresso/ios/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -.DS_Store -*.swp -profile - -DerivedData/ -build/ -GeneratedPluginRegistrant.h -GeneratedPluginRegistrant.m - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -/Flutter/Generated.xcconfig -/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/packages/espresso/ios/Assets/.gitkeep b/packages/espresso/ios/Assets/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/packages/espresso/ios/Classes/EspressoPlugin.h b/packages/espresso/ios/Classes/EspressoPlugin.h deleted file mode 100644 index 5f9761591f72..000000000000 --- a/packages/espresso/ios/Classes/EspressoPlugin.h +++ /dev/null @@ -1,4 +0,0 @@ -#import - -@interface EspressoPlugin : NSObject -@end diff --git a/packages/espresso/ios/Classes/EspressoPlugin.m b/packages/espresso/ios/Classes/EspressoPlugin.m deleted file mode 100644 index cb4ef8072cae..000000000000 --- a/packages/espresso/ios/Classes/EspressoPlugin.m +++ /dev/null @@ -1,15 +0,0 @@ -#import "EspressoPlugin.h" - -@implementation EspressoPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - FlutterMethodChannel* channel = - [FlutterMethodChannel methodChannelWithName:@"espresso" - binaryMessenger:[registrar messenger]]; - EspressoPlugin* instance = [[EspressoPlugin alloc] init]; - [registrar addMethodCallDelegate:instance channel:channel]; -} - -- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { - result(FlutterMethodNotImplemented); -} -@end diff --git a/packages/espresso/ios/espresso.podspec b/packages/espresso/ios/espresso.podspec deleted file mode 100644 index c9b2d106fd92..000000000000 --- a/packages/espresso/ios/espresso.podspec +++ /dev/null @@ -1,25 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint espresso.podspec' to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'espresso' - s.version = '0.0.1' - s.summary = 'Flutter Espresso' - s.description = <<-DESC -Provides bindings for Espresso tests of Flutter apps. -Downloaded by pub (not CocoaPods). - DESC - s.homepage = 'https://github.com/flutter/plugins' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/espresso' } - s.documentation_url = 'https://pub.dev/packages/espresso' - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - s.platform = :ios, '8.0' - - # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } -end diff --git a/packages/espresso/pubspec.yaml b/packages/espresso/pubspec.yaml index e7e1f6691ed3..e79c46e73e40 100644 --- a/packages/espresso/pubspec.yaml +++ b/packages/espresso/pubspec.yaml @@ -23,5 +23,3 @@ flutter: android: package: com.example.espresso pluginClass: EspressoPlugin - ios: - pluginClass: EspressoPlugin diff --git a/packages/file_selector/file_selector_web/ios/file_selector_web.podspec b/packages/file_selector/file_selector_web/ios/file_selector_web.podspec deleted file mode 100644 index 20656121029d..000000000000 --- a/packages/file_selector/file_selector_web/ios/file_selector_web.podspec +++ /dev/null @@ -1,21 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'file_selector_web' - s.version = '0.0.1' - s.summary = 'No-op implementation of file_selector_web web plugin to avoid build issues on iOS' - s.description = <<-DESC - temp fake file_selector_web plugin - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_web' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' - end - \ No newline at end of file diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/.gitignore b/packages/flutter_plugin_android_lifecycle/example/ios/.gitignore deleted file mode 100644 index f78c1480b6dd..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Flutter/AppFrameworkInfo.plist b/packages/flutter_plugin_android_lifecycle/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6b4c0f78a785..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Flutter/Debug.xcconfig b/packages/flutter_plugin_android_lifecycle/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba114687..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Flutter/Release.xcconfig b/packages/flutter_plugin_android_lifecycle/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340e6f6..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner.xcodeproj/project.pbxproj b/packages/flutter_plugin_android_lifecycle/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index f42fc07b1c19..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,576 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 68BFFC9A2252F6377926CCB6 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D97B2D435F77384E1832544A /* libPods-Runner.a */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 48B2B2D61E102CB7FCA66327 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 8A495AA36DFBF39C3BD5D917 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9E27BB0D8AE008E9718C1EC3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - D97B2D435F77384E1832544A /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 68BFFC9A2252F6377926CCB6 /* libPods-Runner.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 29946A38AEAEDCD95716766D /* Pods */ = { - isa = PBXGroup; - children = ( - 8A495AA36DFBF39C3BD5D917 /* Pods-Runner.debug.xcconfig */, - 9E27BB0D8AE008E9718C1EC3 /* Pods-Runner.release.xcconfig */, - 48B2B2D61E102CB7FCA66327 /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 29946A38AEAEDCD95716766D /* Pods */, - C6B60E52AC0C0C398A9D6E3E /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 97C146F21CF9000F007C117D /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - C6B60E52AC0C0C398A9D6E3E /* Frameworks */ = { - isa = PBXGroup; - children = ( - D97B2D435F77384E1832544A /* libPods-Runner.a */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - B0349D7BFB658C43C3407041 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 2D345E120F865FCD8BCE231E /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 2D345E120F865FCD8BCE231E /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - B0349D7BFB658C43C3407041 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.flutterAndroidLifecycleExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.flutterAndroidLifecycleExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.flutterAndroidLifecycleExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/flutter_plugin_android_lifecycle/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cfdb3f..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/AppDelegate.h b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/AppDelegate.h deleted file mode 100644 index 36e21bbf9cf4..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,6 +0,0 @@ -#import -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/AppDelegate.m b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/AppDelegate.m deleted file mode 100644 index 59a72e90be12..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,13 +0,0 @@ -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab2d9d..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 zcmeHN2~<R zh`|8`A_PQ1nSu(UMFx?8j8PC!!VDphaL#`F42fd#7Vlc`zIE4n%Y~eiz4y1j|NDpi z?<@|pSJ-HM`qifhf@m%MamgwK83`XpBA<+azdF#2QsT{X@z0A9Bq>~TVErigKH1~P zRX-!h-f0NJ4Mh++{D}J+K>~~rq}d%o%+4dogzXp7RxX4C>Km5XEI|PAFDmo;DFm6G zzjVoB`@qW98Yl0Kvc-9w09^PrsobmG*Eju^=3f?0o-t$U)TL1B3;sZ^!++3&bGZ!o-*6w?;oOhf z=A+Qb$scV5!RbG+&2S}BQ6YH!FKb0``VVX~T$dzzeSZ$&9=X$3)_7Z{SspSYJ!lGE z7yig_41zpQ)%5dr4ff0rh$@ky3-JLRk&DK)NEIHecf9c*?Z1bUB4%pZjQ7hD!A0r-@NF(^WKdr(LXj|=UE7?gBYGgGQV zidf2`ZT@pzXf7}!NH4q(0IMcxsUGDih(0{kRSez&z?CFA0RVXsVFw3^u=^KMtt95q z43q$b*6#uQDLoiCAF_{RFc{!H^moH_cmll#Fc^KXi{9GDl{>%+3qyfOE5;Zq|6#Hb zp^#1G+z^AXfRKaa9HK;%b3Ux~U@q?xg<2DXP%6k!3E)PA<#4$ui8eDy5|9hA5&{?v z(-;*1%(1~-NTQ`Is1_MGdQ{+i*ccd96ab$R$T3=% zw_KuNF@vI!A>>Y_2pl9L{9h1-C6H8<)J4gKI6{WzGBi<@u3P6hNsXG=bRq5c+z;Gc3VUCe;LIIFDmQAGy+=mRyF++u=drBWV8-^>0yE9N&*05XHZpPlE zxu@?8(ZNy7rm?|<+UNe0Vs6&o?l`Pt>P&WaL~M&#Eh%`rg@Mbb)J&@DA-wheQ>hRV z<(XhigZAT z>=M;URcdCaiO3d^?H<^EiEMDV+7HsTiOhoaMX%P65E<(5xMPJKxf!0u>U~uVqnPN7T!X!o@_gs3Ct1 zlZ_$5QXP4{Aj645wG_SNT&6m|O6~Tsl$q?nK*)(`{J4b=(yb^nOATtF1_aS978$x3 zx>Q@s4i3~IT*+l{@dx~Hst21fR*+5}S1@cf>&8*uLw-0^zK(+OpW?cS-YG1QBZ5q! zgTAgivzoF#`cSz&HL>Ti!!v#?36I1*l^mkrx7Y|K6L#n!-~5=d3;K<;Zqi|gpNUn_ z_^GaQDEQ*jfzh;`j&KXb66fWEk1K7vxQIMQ_#Wu_%3 z4Oeb7FJ`8I>Px;^S?)}2+4D_83gHEq>8qSQY0PVP?o)zAv3K~;R$fnwTmI-=ZLK`= zTm+0h*e+Yfr(IlH3i7gUclNH^!MU>id$Jw>O?2i0Cila#v|twub21@e{S2v}8Z13( zNDrTXZVgris|qYm<0NU(tAPouG!QF4ZNpZPkX~{tVf8xY690JqY1NVdiTtW+NqyRP zZ&;T0ikb8V{wxmFhlLTQ&?OP7 z;(z*<+?J2~z*6asSe7h`$8~Se(@t(#%?BGLVs$p``;CyvcT?7Y!{tIPva$LxCQ&4W z6v#F*);|RXvI%qnoOY&i4S*EL&h%hP3O zLsrFZhv&Hu5tF$Lx!8(hs&?!Kx5&L(fdu}UI5d*wn~A`nPUhG&Rv z2#ixiJdhSF-K2tpVL=)5UkXRuPAFrEW}7mW=uAmtVQ&pGE-&az6@#-(Te^n*lrH^m@X-ftVcwO_#7{WI)5v(?>uC9GG{lcGXYJ~Q8q zbMFl7;t+kV;|;KkBW2!P_o%Czhw&Q(nXlxK9ak&6r5t_KH8#1Mr-*0}2h8R9XNkr zto5-b7P_auqTJb(TJlmJ9xreA=6d=d)CVbYP-r4$hDn5|TIhB>SReMfh&OVLkMk-T zYf%$taLF0OqYF?V{+6Xkn>iX@TuqQ?&cN6UjC9YF&%q{Ut3zv{U2)~$>-3;Dp)*(? zg*$mu8^i=-e#acaj*T$pNowo{xiGEk$%DusaQiS!KjJH96XZ-hXv+jk%ard#fu=@Q z$AM)YWvE^{%tDfK%nD49=PI|wYu}lYVbB#a7wtN^Nml@CE@{Gv7+jo{_V?I*jkdLD zJE|jfdrmVbkfS>rN*+`#l%ZUi5_bMS<>=MBDNlpiSb_tAF|Zy`K7kcp@|d?yaTmB^ zo?(vg;B$vxS|SszusORgDg-*Uitzdi{dUV+glA~R8V(?`3GZIl^egW{a919!j#>f` znL1o_^-b`}xnU0+~KIFLQ)$Q6#ym%)(GYC`^XM*{g zv3AM5$+TtDRs%`2TyR^$(hqE7Y1b&`Jd6dS6B#hDVbJlUXcG3y*439D8MrK!2D~6gn>UD4Imctb z+IvAt0iaW73Iq$K?4}H`7wq6YkTMm`tcktXgK0lKPmh=>h+l}Y+pDtvHnG>uqBA)l zAH6BV4F}v$(o$8Gfo*PB>IuaY1*^*`OTx4|hM8jZ?B6HY;F6p4{`OcZZ(us-RVwDx zUzJrCQlp@mz1ZFiSZ*$yX3c_#h9J;yBE$2g%xjmGF4ca z&yL`nGVs!Zxsh^j6i%$a*I3ZD2SoNT`{D%mU=LKaEwbN(_J5%i-6Va?@*>=3(dQy` zOv%$_9lcy9+(t>qohkuU4r_P=R^6ME+wFu&LA9tw9RA?azGhjrVJKy&8=*qZT5Dr8g--d+S8zAyJ$1HlW3Olryt`yE zFIph~Z6oF&o64rw{>lgZISC6p^CBer9C5G6yq%?8tC+)7*d+ib^?fU!JRFxynRLEZ zj;?PwtS}Ao#9whV@KEmwQgM0TVP{hs>dg(1*DiMUOKHdQGIqa0`yZnHk9mtbPfoLx zo;^V6pKUJ!5#n`w2D&381#5#_t}AlTGEgDz$^;u;-vxDN?^#5!zN9ngytY@oTv!nc zp1Xn8uR$1Z;7vY`-<*?DfPHB;x|GUi_fI9@I9SVRv1)qETbNU_8{5U|(>Du84qP#7 z*l9Y$SgA&wGbj>R1YeT9vYjZuC@|{rajTL0f%N@>3$DFU=`lSPl=Iv;EjuGjBa$Gw zHD-;%YOE@<-!7-Mn`0WuO3oWuL6tB2cpPw~Nvuj|KM@))ixuDK`9;jGMe2d)7gHin zS<>k@!x;!TJEc#HdL#RF(`|4W+H88d4V%zlh(7#{q2d0OQX9*FW^`^_<3r$kabWAB z$9BONo5}*(%kx zOXi-yM_cmB3>inPpI~)duvZykJ@^^aWzQ=eQ&STUa}2uT@lV&WoRzkUoE`rR0)`=l zFT%f|LA9fCw>`enm$p7W^E@U7RNBtsh{_-7vVz3DtB*y#*~(L9+x9*wn8VjWw|Q~q zKFsj1Yl>;}%MG3=PY`$g$_mnyhuV&~O~u~)968$0b2!Jkd;2MtAP#ZDYw9hmK_+M$ zb3pxyYC&|CuAbtiG8HZjj?MZJBFbt`ryf+c1dXFuC z0*ZQhBzNBd*}s6K_G}(|Z_9NDV162#y%WSNe|FTDDhx)K!c(mMJh@h87@8(^YdK$&d*^WQe8Z53 z(|@MRJ$Lk-&ii74MPIs80WsOFZ(NX23oR-?As+*aq6b?~62@fSVmM-_*cb1RzZ)`5$agEiL`-E9s7{GM2?(KNPgK1(+c*|-FKoy}X(D_b#etO|YR z(BGZ)0Ntfv-7R4GHoXp?l5g#*={S1{u-QzxCGng*oWr~@X-5f~RA14b8~B+pLKvr4 zfgL|7I>jlak9>D4=(i(cqYf7#318!OSR=^`xxvI!bBlS??`xxWeg?+|>MxaIdH1U~#1tHu zB{QMR?EGRmQ_l4p6YXJ{o(hh-7Tdm>TAX380TZZZyVkqHNzjUn*_|cb?T? zt;d2s-?B#Mc>T-gvBmQZx(y_cfkXZO~{N zT6rP7SD6g~n9QJ)8F*8uHxTLCAZ{l1Y&?6v)BOJZ)=R-pY=Y=&1}jE7fQ>USS}xP#exo57uND0i*rEk@$;nLvRB@u~s^dwRf?G?_enN@$t* zbL%JO=rV(3Ju8#GqUpeE3l_Wu1lN9Y{D4uaUe`g>zlj$1ER$6S6@{m1!~V|bYkhZA z%CvrDRTkHuajMU8;&RZ&itnC~iYLW4DVkP<$}>#&(`UO>!n)Po;Mt(SY8Yb`AS9lt znbX^i?Oe9r_o=?})IHKHoQGKXsps_SE{hwrg?6dMI|^+$CeC&z@*LuF+P`7LfZ*yr+KN8B4{Nzv<`A(wyR@!|gw{zB6Ha ziwPAYh)oJ(nlqSknu(8g9N&1hu0$vFK$W#mp%>X~AU1ay+EKWcFdif{% z#4!4aoVVJ;ULmkQf!ke2}3hqxLK>eq|-d7Ly7-J9zMpT`?dxo6HdfJA|t)?qPEVBDv z{y_b?4^|YA4%WW0VZd8C(ZgQzRI5(I^)=Ub`Y#MHc@nv0w-DaJAqsbEHDWG8Ia6ju zo-iyr*sq((gEwCC&^TYBWt4_@|81?=B-?#P6NMff(*^re zYqvDuO`K@`mjm_Jd;mW_tP`3$cS?R$jR1ZN09$YO%_iBqh5ftzSpMQQtxKFU=FYmP zeY^jph+g<4>YO;U^O>-NFLn~-RqlHvnZl2yd2A{Yc1G@Ga$d+Q&(f^tnPf+Z7serIU};17+2DU_f4Z z@GaPFut27d?!YiD+QP@)T=77cR9~MK@bd~pY%X(h%L={{OIb8IQmf-!xmZkm8A0Ga zQSWONI17_ru5wpHg3jI@i9D+_Y|pCqVuHJNdHUauTD=R$JcD2K_liQisqG$(sm=k9;L* z!L?*4B~ql7uioSX$zWJ?;q-SWXRFhz2Jt4%fOHA=Bwf|RzhwqdXGr78y$J)LR7&3T zE1WWz*>GPWKZ0%|@%6=fyx)5rzUpI;bCj>3RKzNG_1w$fIFCZ&UR0(7S?g}`&Pg$M zf`SLsz8wK82Vyj7;RyKmY{a8G{2BHG%w!^T|Njr!h9TO2LaP^_f22Q1=l$QiU84ao zHe_#{S6;qrC6w~7{y(hs-?-j?lbOfgH^E=XcSgnwW*eEz{_Z<_Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 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 diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b70f1..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7c939..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Base.lproj/Main.storyboard b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516fb38..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Info.plist b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Info.plist deleted file mode 100644 index 8526e1f7226c..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - flutter_plugin_android_lifecycle_example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/main.m b/packages/flutter_plugin_android_lifecycle/example/ios/Runner/main.m deleted file mode 100644 index dff6597e4513..000000000000 --- a/packages/flutter_plugin_android_lifecycle/example/ios/Runner/main.m +++ /dev/null @@ -1,9 +0,0 @@ -#import -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/packages/flutter_plugin_android_lifecycle/ios/.gitignore b/packages/flutter_plugin_android_lifecycle/ios/.gitignore deleted file mode 100644 index aa479fd3ce8a..000000000000 --- a/packages/flutter_plugin_android_lifecycle/ios/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -.DS_Store -*.swp -profile - -DerivedData/ -build/ -GeneratedPluginRegistrant.h -GeneratedPluginRegistrant.m - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -/Flutter/Generated.xcconfig -/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/packages/flutter_plugin_android_lifecycle/ios/Assets/.gitkeep b/packages/flutter_plugin_android_lifecycle/ios/Assets/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/packages/flutter_plugin_android_lifecycle/ios/Classes/FlutterAndroidLifecyclePlugin.h b/packages/flutter_plugin_android_lifecycle/ios/Classes/FlutterAndroidLifecyclePlugin.h deleted file mode 100644 index a554ce0500c6..000000000000 --- a/packages/flutter_plugin_android_lifecycle/ios/Classes/FlutterAndroidLifecyclePlugin.h +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2019 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 - -@interface FlutterAndroidLifecyclePlugin : NSObject -@end diff --git a/packages/flutter_plugin_android_lifecycle/ios/Classes/FlutterAndroidLifecyclePlugin.m b/packages/flutter_plugin_android_lifecycle/ios/Classes/FlutterAndroidLifecyclePlugin.m deleted file mode 100644 index 38cffd362da7..000000000000 --- a/packages/flutter_plugin_android_lifecycle/ios/Classes/FlutterAndroidLifecyclePlugin.m +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2019 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 "FlutterAndroidLifecyclePlugin.h" - -@implementation FlutterAndroidLifecyclePlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { -} -@end diff --git a/packages/flutter_plugin_android_lifecycle/ios/flutter_plugin_android_lifecycle.podspec b/packages/flutter_plugin_android_lifecycle/ios/flutter_plugin_android_lifecycle.podspec deleted file mode 100644 index 0c802a3101ba..000000000000 --- a/packages/flutter_plugin_android_lifecycle/ios/flutter_plugin_android_lifecycle.podspec +++ /dev/null @@ -1,26 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint flutter_plugin_android_lifecycle.podspec' to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'flutter_plugin_android_lifecycle' - s.version = '0.0.1' - s.summary = 'Flutter Android Lifecycle Plugin' - s.description = <<-DESC -A Flutter plugin for Android to allow other Flutter plugins to access Android Lifecycle objects in the plugin's binding. -This plugin a no-op on iOS. -Downloaded by pub (not CocoaPods). - DESC - s.homepage = 'https://github.com/flutter/plugins' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/flutter_plugin_android_lifecycle' } - s.documentation_url = 'https://pub.dev/packages/flutter_plugin_android_lifecycle' - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - s.platform = :ios, '8.0' - - # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } -end diff --git a/packages/google_maps_flutter/google_maps_flutter_web/ios/google_maps_flutter_web.podspec b/packages/google_maps_flutter/google_maps_flutter_web/ios/google_maps_flutter_web.podspec deleted file mode 100644 index 18db6ced01b6..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_web/ios/google_maps_flutter_web.podspec +++ /dev/null @@ -1,23 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint google_maps_flutter_web.podspec' to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'google_maps_flutter_web' - s.version = '0.1.0' - s.summary = 'No-op implementation of google maps flutter web plugin to avoid build issues on iOS' - s.description = <<-DESC -temp fake google_maps_flutter_web plugin - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_web' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.dependency 'Flutter' - s.platform = :ios, '8.0' - - # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } - s.swift_version = '5.0' -end diff --git a/packages/google_sign_in/google_sign_in_web/ios/google_sign_in_web.podspec b/packages/google_sign_in/google_sign_in_web/ios/google_sign_in_web.podspec deleted file mode 100644 index 5e192172eb4b..000000000000 --- a/packages/google_sign_in/google_sign_in_web/ios/google_sign_in_web.podspec +++ /dev/null @@ -1,21 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'google_sign_in_web' - s.version = '0.8.1' - s.summary = 'No-op implementation of google_sign_in_web web plugin to avoid build issues on iOS' - s.description = <<-DESC - temp fake google_sign_in_web plugin - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in_web' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' - end - \ No newline at end of file diff --git a/packages/image_picker/image_picker_for_web/ios/image_picker_for_web.podspec b/packages/image_picker/image_picker_for_web/ios/image_picker_for_web.podspec deleted file mode 100644 index 23fb795d1cc2..000000000000 --- a/packages/image_picker/image_picker_for_web/ios/image_picker_for_web.podspec +++ /dev/null @@ -1,20 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'image_picker_for_web' - s.version = '0.0.1' - s.summary = 'No-op implementation of image_picker_for_web plugin to avoid build issues on iOS' - s.description = <<-DESC -temp fake image_picker_for_web plugin - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_for_web' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' -end diff --git a/packages/integration_test/integration_test_macos/ios/integration_test_macos.podspec b/packages/integration_test/integration_test_macos/ios/integration_test_macos.podspec deleted file mode 100644 index 7294590a6479..000000000000 --- a/packages/integration_test/integration_test_macos/ios/integration_test_macos.podspec +++ /dev/null @@ -1,21 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'IntegrationTestMacOS' - s.version = '0.0.1' - s.summary = 'No-op implementation of the integration_test desktop plugin to avoid build issues on iOS' - s.description = <<-DESC - No-op implementation of integration to avoid build issues on iOS. - See https://github.com/flutter/flutter/issues/39659 - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/integration_test/integration_test_macos' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' -end \ No newline at end of file diff --git a/packages/path_provider/path_provider_linux/ios/.gitignore b/packages/path_provider/path_provider_linux/ios/.gitignore deleted file mode 100644 index aa479fd3ce8a..000000000000 --- a/packages/path_provider/path_provider_linux/ios/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -.DS_Store -*.swp -profile - -DerivedData/ -build/ -GeneratedPluginRegistrant.h -GeneratedPluginRegistrant.m - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -/Flutter/Generated.xcconfig -/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/packages/path_provider/path_provider_linux/ios/path_provider_linux.podspec b/packages/path_provider/path_provider_linux/ios/path_provider_linux.podspec deleted file mode 100644 index 3649a30e67ef..000000000000 --- a/packages/path_provider/path_provider_linux/ios/path_provider_linux.podspec +++ /dev/null @@ -1,19 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'path_provider_linux' - s.version = '0.0.1' - s.summary = 'No-op implementation of path_provider linux plugin to avoid build issues on iOS' - s.description = <<-DESC - No-op implementation of path_provider linux plugin - See https://github.com/flutter/flutter/issues/39659 - DESC - s.homepage = 'https://github.com/flutter/plugins' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_linux' } - s.documentation_url = 'https://pub.dev/packages/path_provider' - s.dependency 'Flutter' - s.platform = :ios, '8.0' -end \ No newline at end of file diff --git a/packages/path_provider/path_provider_macos/example/ios/Flutter/AppFrameworkInfo.plist b/packages/path_provider/path_provider_macos/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6c2de8086bcd..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - UIRequiredDeviceCapabilities - - arm64 - - MinimumOSVersion - 8.0 - - diff --git a/packages/path_provider/path_provider_macos/example/ios/Flutter/Debug.xcconfig b/packages/path_provider/path_provider_macos/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 9803018ca79d..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Generated.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" diff --git a/packages/path_provider/path_provider_macos/example/ios/Flutter/Release.xcconfig b/packages/path_provider/path_provider_macos/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index a4a8c604e13d..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Generated.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/project.pbxproj b/packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index eb0222a7c9c5..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,490 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 2D9222481EC32A19007564B0 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D9222471EC32A19007564B0 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 85DDFCF6BBDEE02B9D9F8138 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C0EE60090AA5F3AAAF2175B6 /* libPods-Runner.a */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 2D9222461EC32A19007564B0 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 2D9222471EC32A19007564B0 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 694A199F61914F41AAFD0B7F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C0EE60090AA5F3AAAF2175B6 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - D317CA1E83064E01753D8BB5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 85DDFCF6BBDEE02B9D9F8138 /* libPods-Runner.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { - isa = PBXGroup; - children = ( - 694A199F61914F41AAFD0B7F /* Pods-Runner.debug.xcconfig */, - D317CA1E83064E01753D8BB5 /* Pods-Runner.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 840012C8B5EDBCF56B0E4AC1 /* Pods */, - CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 2D9222461EC32A19007564B0 /* GeneratedPluginRegistrant.h */, - 2D9222471EC32A19007564B0 /* GeneratedPluginRegistrant.m */, - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 97C146F21CF9000F007C117D /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = { - isa = PBXGroup; - children = ( - C0EE60090AA5F3AAAF2175B6 /* libPods-Runner.a */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, - 2D9222481EC32A19007564B0 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.pathProviderExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.pathProviderExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14c74e..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 3bb3697ef41c..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/path_provider/path_provider_macos/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14c74e..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/AppDelegate.h b/packages/path_provider/path_provider_macos/example/ios/Runner/AppDelegate.h deleted file mode 100644 index d9e18e990f2e..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,10 +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 -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/AppDelegate.m b/packages/path_provider/path_provider_macos/example/ios/Runner/AppDelegate.m deleted file mode 100644 index a4b51c88eb60..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,16 +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. - -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d22f10b2ab63..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 28c6bf03016f6c994b70f38d1b7346e5831b531f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 564 zcmV-40?Yl0P)Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 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 diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/path_provider/path_provider_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8 - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Base.lproj/Main.storyboard b/packages/path_provider/path_provider_macos/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516fb38..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/Info.plist b/packages/path_provider/path_provider_macos/example/ios/Runner/Info.plist deleted file mode 100644 index 342db6a5dcaf..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Runner/Info.plist +++ /dev/null @@ -1,49 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - path_provider_example - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - arm64 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/path_provider/path_provider_macos/example/ios/Runner/main.m b/packages/path_provider/path_provider_macos/example/ios/Runner/main.m deleted file mode 100644 index bec320c0bee0..000000000000 --- a/packages/path_provider/path_provider_macos/example/ios/Runner/main.m +++ /dev/null @@ -1,13 +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 -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/packages/path_provider/path_provider_macos/ios/path_provider_macos.podspec b/packages/path_provider/path_provider_macos/ios/path_provider_macos.podspec deleted file mode 100644 index 9f822c58c45c..000000000000 --- a/packages/path_provider/path_provider_macos/ios/path_provider_macos.podspec +++ /dev/null @@ -1,22 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'path_provider_macos' - s.version = '0.0.1' - s.summary = 'No-op implementation of path_provider macOS plugin to avoid build issues on iOS' - s.description = <<-DESC - No-op implementation of path_provider macOS plugin - See https://github.com/flutter/flutter/issues/39659 - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_macos' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' -end - diff --git a/packages/path_provider/path_provider_windows/ios/path_provider_windows.podspec b/packages/path_provider/path_provider_windows/ios/path_provider_windows.podspec deleted file mode 100644 index 941a36c1c794..000000000000 --- a/packages/path_provider/path_provider_windows/ios/path_provider_windows.podspec +++ /dev/null @@ -1,22 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# Run `pod lib lint path_provider_windows.podspec' to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'path_provider_windows' - s.version = '0.0.1' - s.summary = 'path_provider_windows iOS stub' - s.description = <<-DESC - No-op implementation of the windows path_provider plugin to avoid build issues on iOS - DESC - s.homepage = 'https://github.com/flutter/plugins' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_windows' } - s.dependency 'Flutter' - s.platform = :ios, '8.0' - - # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } - s.swift_version = '5.0' -end diff --git a/packages/shared_preferences/shared_preferences_linux/ios/shared_preferences_linux.podspec b/packages/shared_preferences/shared_preferences_linux/ios/shared_preferences_linux.podspec deleted file mode 100644 index 8f4d3cdddcd5..000000000000 --- a/packages/shared_preferences/shared_preferences_linux/ios/shared_preferences_linux.podspec +++ /dev/null @@ -1,22 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint shared_preferences_launcher_linux.podspec' to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'shared_preferences_linux' - s.version = '0.0.1' - s.summary = 'shared_preferences_linux iOS stub' - s.description = <<-DESC - No-op implementation of the Linux shared_preferences plugin to avoid build issues on iOS - DESC - s.homepage = 'https://github.com/flutter/plugins' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux' } - s.dependency 'Flutter' - s.platform = :ios, '8.0' - - # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } - s.swift_version = '5.0' -end diff --git a/packages/shared_preferences/shared_preferences_macos/ios/shared_preferences_macos.podspec b/packages/shared_preferences/shared_preferences_macos/ios/shared_preferences_macos.podspec deleted file mode 100644 index 8e2a2bd30dac..000000000000 --- a/packages/shared_preferences/shared_preferences_macos/ios/shared_preferences_macos.podspec +++ /dev/null @@ -1,21 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'shared_preferences_macos' - s.version = '0.0.1' - s.summary = 'No-op implementation of shared_preferences desktop plugin to avoid build issues on iOS' - s.description = <<-DESC - No-op implementation of shared_preferences to avoid build issues on iOS. - DESC - - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_macos' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' -end diff --git a/packages/shared_preferences/shared_preferences_web/ios/shared_preferences_web.podspec b/packages/shared_preferences/shared_preferences_web/ios/shared_preferences_web.podspec deleted file mode 100644 index 11f8b73e02d8..000000000000 --- a/packages/shared_preferences/shared_preferences_web/ios/shared_preferences_web.podspec +++ /dev/null @@ -1,20 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'shared_preferences_web' - s.version = '0.0.1' - s.summary = 'No-op implementation of shared_preferences web plugin to avoid build issues on iOS' - s.description = <<-DESC -temp fake shared_preferences_web plugin - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_web' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' -end diff --git a/packages/shared_preferences/shared_preferences_windows/ios/shared_preferences_windows.podspec b/packages/shared_preferences/shared_preferences_windows/ios/shared_preferences_windows.podspec deleted file mode 100644 index 2e239e607493..000000000000 --- a/packages/shared_preferences/shared_preferences_windows/ios/shared_preferences_windows.podspec +++ /dev/null @@ -1,22 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# Run `pod lib lint shared_preferences_windows.podspec' to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'shared_preferences_windows' - s.version = '0.0.1' - s.summary = 'shared_preferences_windows iOS stub' - s.description = <<-DESC - No-op implementation of the windows shared_preferences plugin to avoid build issues on iOS - DESC - s.homepage = 'https://github.com/flutter/plugins' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_windows' } - s.dependency 'Flutter' - s.platform = :ios, '8.0' - - # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } - s.swift_version = '5.0' -end diff --git a/packages/url_launcher/url_launcher_linux/ios/.gitignore b/packages/url_launcher/url_launcher_linux/ios/.gitignore deleted file mode 100644 index aa479fd3ce8a..000000000000 --- a/packages/url_launcher/url_launcher_linux/ios/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -.DS_Store -*.swp -profile - -DerivedData/ -build/ -GeneratedPluginRegistrant.h -GeneratedPluginRegistrant.m - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -/Flutter/Generated.xcconfig -/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/packages/url_launcher/url_launcher_linux/ios/url_launcher_linux.podspec b/packages/url_launcher/url_launcher_linux/ios/url_launcher_linux.podspec deleted file mode 100644 index 1359fd403d8d..000000000000 --- a/packages/url_launcher/url_launcher_linux/ios/url_launcher_linux.podspec +++ /dev/null @@ -1,22 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint url_launcher_linux.podspec' to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'url_launcher_linux' - s.version = '0.0.1' - s.summary = 'url_launcher_linux iOS stub' - s.description = <<-DESC - No-op implementation of the Linux url_launcher plugin to avoid build issues on iOS - DESC - s.homepage = 'https://github.com/flutter/plugins' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux' } - s.dependency 'Flutter' - s.platform = :ios, '8.0' - - # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } - s.swift_version = '5.0' -end diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Flutter/AppFrameworkInfo.plist b/packages/url_launcher/url_launcher_macos/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6c2de8086bcd..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - UIRequiredDeviceCapabilities - - arm64 - - MinimumOSVersion - 8.0 - - diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Flutter/Debug.xcconfig b/packages/url_launcher/url_launcher_macos/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 9803018ca79d..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Generated.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Flutter/Release.xcconfig b/packages/url_launcher/url_launcher_macos/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index a4a8c604e13d..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Generated.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner.xcodeproj/project.pbxproj b/packages/url_launcher/url_launcher_macos/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index db72809a6169..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,490 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 2D92223F1EC1DA93007564B0 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D92223E1EC1DA93007564B0 /* GeneratedPluginRegistrant.m */; }; - 2E37D9A274B2EACB147AC51B /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 856D0913184F79C678A42603 /* libPods-Runner.a */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 2D92223D1EC1DA93007564B0 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GeneratedPluginRegistrant.h; path = Runner/GeneratedPluginRegistrant.h; sourceTree = ""; }; - 2D92223E1EC1DA93007564B0 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GeneratedPluginRegistrant.m; path = Runner/GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 836316F9AEA584411312E29F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 856D0913184F79C678A42603 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - A84BFEE343F54B983D1B67EB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 2E37D9A274B2EACB147AC51B /* libPods-Runner.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { - isa = PBXGroup; - children = ( - 836316F9AEA584411312E29F /* Pods-Runner.debug.xcconfig */, - A84BFEE343F54B983D1B67EB /* Pods-Runner.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B80C3931E831B6300D905FE /* App.framework */, - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 2D92223D1EC1DA93007564B0 /* GeneratedPluginRegistrant.h */, - 2D92223E1EC1DA93007564B0 /* GeneratedPluginRegistrant.m */, - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 840012C8B5EDBCF56B0E4AC1 /* Pods */, - CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 97C146F21CF9000F007C117D /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 856D0913184F79C678A42603 /* libPods-Runner.a */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; - }; - 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, - 2D92223F1EC1DA93007564B0 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.urlLauncher; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.urlLauncher; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/url_launcher/url_launcher_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 3bb3697ef41c..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/AppDelegate.h b/packages/url_launcher/url_launcher_macos/example/ios/Runner/AppDelegate.h deleted file mode 100644 index d9e18e990f2e..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,10 +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 -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/AppDelegate.m b/packages/url_launcher/url_launcher_macos/example/ios/Runner/AppDelegate.m deleted file mode 100644 index 9cf1c7796c6a..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,17 +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. - -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - [super application:application didFinishLaunchingWithOptions:launchOptions]; - return YES; -} - -@end diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d22f10b2ab63..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 28c6bf03016f6c994b70f38d1b7346e5831b531f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 564 zcmV-40?Yl0P)Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 zcmVjJBgitF5mAp-i>4+KS_oR{|13AP->1TD4=w)g|)JHOx|a2Wk1Va z!k)vP$UcQ#mdj%wNQoaJ!w>jv_6&JPyutpQps?s5dmDQ>`%?Bvj>o<%kYG!YW6H-z zu`g$@mp`;qDR!51QaS}|ZToSuAGcJ7$2HF0z`ln4t!#Yg46>;vGG9N9{V@9z#}6v* zfP?}r6b{*-C*)(S>NECI_E~{QYzN5SXRmVnP<=gzP+_Sp(Aza_hKlZ{C1D&l*(7IKXxQC1Z9#6wx}YrGcn~g%;icdw>T0Rf^w0{ z$_wn1J+C0@!jCV<%Go5LA45e{5gY9PvZp8uM$=1}XDI+9m7!A95L>q>>oe0$nC->i zeexUIvq%Uk<-$>DiDb?!In)lAmtuMWxvWlk`2>4lNuhSsjAf2*2tjT`y;@d}($o)S zn(+W&hJ1p0xy@oxP%AM15->wPLp{H!k)BdBD$toBpJh+crWdsNV)qsHaqLg2_s|Ih z`8E9z{E3sA!}5aKu?T!#enD(wLw?IT?k-yWVHZ8Akz4k5(TZJN^zZgm&zM28sfTD2BYJ|Fde3Xzh;;S` z=GXTnY4Xc)8nYoz6&vF;P7{xRF-{|2Xs5>a5)@BrnQ}I(_x7Cgpx#5&Td^4Q9_FnQ zX5so*;#8-J8#c$OlA&JyPp$LKUhC~-e~Ij!L%uSMu!-VZG7Hx-L{m2DVR2i=GR(_% zCVD!4N`I)&Q5S`?P&fQZ=4#Dgt_v2-DzkT}K(9gF0L(owe-Id$Rc2qZVLqI_M_DyO z9@LC#U28_LU{;wGZ&))}0R2P4MhajKCd^K#D+JJ&JIXZ_p#@+7J9A&P<0kdRujtQ_ zOy>3=C$kgi6$0pW06KaLz!21oOryKM3ZUOWqppndxfH}QpgjEJ`j7Tzn5bk6K&@RA?vl##y z$?V~1E(!wB5rH`>3nc&@)|#<1dN2cMzzm=PGhQ|Yppne(C-Vlt450IXc`J4R0W@I7 zd1e5uW6juvO%ni(WX7BsKx3MLngO7rHO;^R5I~0^nE^9^E_eYLgiR9&KnJ)pBbfno zSVnW$0R+&6jOOsZ82}nJ126+c|%svPo;TeUku<2G7%?$oft zyaO;tVo}(W)VsTUhq^XmFi#2z%-W9a{7mXn{uzivYQ_d6b7VJG{77naW(vHt-uhnY zVN#d!JTqVh(7r-lhtXVU6o})aZbDt_;&wJVGl2FKYFBFpU-#9U)z#(A%=IVnqytR$SY-sO( z($oNE09{D^@OuYPz&w~?9>Fl5`g9u&ecFGhqX=^#fmR=we0CJw+5xna*@oHnkahk+ z9aWeE3v|An+O5%?4fA&$Fgu~H_YmqR!yIU!bFCk4!#pAj%(lI(A5n)n@Id#M)O9Yx zJU9oKy{sRAIV3=5>(s8n{8ryJ!;ho}%pn6hZKTKbqk=&m=f*UnK$zW3YQP*)pw$O* zIfLA^!-bmBl6%d_n$#tP8Zd_(XdA*z*WH|E_yILwjtI~;jK#v-6jMl^?<%Y%`gvpwv&cFb$||^v4D&V=aNy?NGo620jL3VZnA%s zH~I|qPzB~e(;p;b^gJr7Ure#7?8%F0m4vzzPy^^(q4q1OdthF}Fi*RmVZN1OwTsAP zn9CZP`FazX3^kG(KodIZ=Kty8DLTy--UKfa1$6XugS zk%6v$Kmxt6U!YMx0JQ)0qX*{CXwZZk$vEROidEc7=J-1;peNat!vS<3P-FT5po>iE z!l3R+<`#x|+_hw!HjQGV=8!q|76y8L7N8gP3$%0kfush|u0uU^?dKBaeRSBUpOZ0c z62;D&Mdn2}N}xHRFTRI?zRv=>=AjHgH}`2k4WK=#AHB)UFrR-J87GgX*x5fL^W2#d z=(%K8-oZfMO=i{aWRDg=FX}UubM4eotRDcn;OR#{3q=*?3mE3_oJ-~prjhxh%PgQT zyn)Qozaq0@o&|LEgS{Ind4Swsr;b`u185hZPOBLL<`d2%^Yp1?oL)=jnLi;Zo0ZDliTtQ^b5SmfIMe{T==zZkbvn$KTQGlbG8w}s@M3TZnde;1Am46P3juKb zl9GU&3F=q`>j!`?SyH#r@O59%@aMX^rx}Nxe<>NqpUp5=lX1ojGDIR*-D^SDuvCKF z?3$xG(gVUsBERef_YjPFl^rU9EtD{pt z0CXwpN7BN3!8>hajGaTVk-wl=9rxmfWtIhC{mheHgStLi^+Nz12a?4r(fz)?3A%at zMlvQmL<2-R)-@G1wJ0^zQK%mR=r4d{Y3fHp){nWXUL#|CqXl(+v+qDh>FkF9`eWrW zfr^D%LNfOcTNvtx0JXR35J0~Jpi2#P3Q&80w+nqNfc}&G0A~*)lGHKv=^FE+b(37|)zL;KLF>oiGfb(?&1 zV3XRu!Sw>@quKiab%g6jun#oZ%!>V#A%+lNc?q>6+VvyAn=kf_6z^(TZUa4Eelh{{ zqFX-#dY(EV@7l$NE&kv9u9BR8&Ojd#ZGJ6l8_BW}^r?DIS_rU2(XaGOK z225E@kH5Opf+CgD^{y29jD4gHbGf{1MD6ggQ&%>UG4WyPh5q_tb`{@_34B?xfSO*| zZv8!)q;^o-bz`MuxXk*G^}(6)ACb@=Lfs`Hxoh>`Y0NE8QRQ!*p|SH@{r8=%RKd4p z+#Ty^-0kb=-H-O`nAA3_6>2z(D=~Tbs(n8LHxD0`R0_ATFqp-SdY3(bZ3;VUM?J=O zKCNsxsgt@|&nKMC=*+ZqmLHhX1KHbAJs{nGVMs6~TiF%Q)P@>!koa$%oS zjXa=!5>P`vC-a}ln!uH1ooeI&v?=?v7?1n~P(wZ~0>xWxd_Aw;+}9#eULM7M8&E?Y zC-ZLhi3RoM92SXUb-5i-Lmt5_rfjE{6y^+24`y$1lywLyHO!)Boa7438K4#iLe?rh z2O~YGSgFUBH?og*6=r9rme=peP~ah`(8Zt7V)j5!V0KPFf_mebo3z95U8(up$-+EA^9dTRLq>Yl)YMBuch9%=e5B`Vnb>o zt03=kq;k2TgGe4|lGne&zJa~h(UGutjP_zr?a7~#b)@15XNA>Dj(m=gg2Q5V4-$)D|Q9}R#002ovPDHLkV1o7DH3k3x diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8 - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Base.lproj/Main.storyboard b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516fb38..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Info.plist b/packages/url_launcher/url_launcher_macos/example/ios/Runner/Info.plist deleted file mode 100644 index 80aec052fa79..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Runner/Info.plist +++ /dev/null @@ -1,49 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - url_launcher_example - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - arm64 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/url_launcher/url_launcher_macos/example/ios/Runner/main.m b/packages/url_launcher/url_launcher_macos/example/ios/Runner/main.m deleted file mode 100644 index bec320c0bee0..000000000000 --- a/packages/url_launcher/url_launcher_macos/example/ios/Runner/main.m +++ /dev/null @@ -1,13 +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 -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/packages/url_launcher/url_launcher_macos/ios/url_launcher_macos.podspec b/packages/url_launcher/url_launcher_macos/ios/url_launcher_macos.podspec deleted file mode 100644 index 2bfe79708555..000000000000 --- a/packages/url_launcher/url_launcher_macos/ios/url_launcher_macos.podspec +++ /dev/null @@ -1,21 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'url_launcher_macos' - s.version = '0.0.1' - s.summary = 'No-op implementation of the macos url_launcher plugin to avoid build issues on iOS' - s.description = <<-DESC - No-op implementation of the macos url_launcher plugin to avoid build issues on iOS - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' -end - diff --git a/packages/url_launcher/url_launcher_web/ios/url_launcher_web.podspec b/packages/url_launcher/url_launcher_web/ios/url_launcher_web.podspec deleted file mode 100644 index 161156ef020d..000000000000 --- a/packages/url_launcher/url_launcher_web/ios/url_launcher_web.podspec +++ /dev/null @@ -1,20 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'url_launcher_web' - s.version = '0.0.1' - s.summary = 'No-op implementation of url_launcher_web web plugin to avoid build issues on iOS' - s.description = <<-DESC -temp fake url_launcher_web plugin - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_web' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' -end diff --git a/packages/url_launcher/url_launcher_windows/ios/url_launcher_windows.podspec b/packages/url_launcher/url_launcher_windows/ios/url_launcher_windows.podspec deleted file mode 100644 index 1c700d49f4b5..000000000000 --- a/packages/url_launcher/url_launcher_windows/ios/url_launcher_windows.podspec +++ /dev/null @@ -1,22 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# Run `pod lib lint url_launcher_windows.podspec' to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'url_launcher_windows' - s.version = '0.0.1' - s.summary = 'url_launcher_windows iOS stub' - s.description = <<-DESC - No-op implementation of the windows url_launcher plugin to avoid build issues on iOS - DESC - s.homepage = 'https://github.com/flutter/plugins' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows' } - s.dependency 'Flutter' - s.platform = :ios, '8.0' - - # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } - s.swift_version = '5.0' -end diff --git a/packages/video_player/video_player_web/ios/video_player_web.podspec b/packages/video_player/video_player_web/ios/video_player_web.podspec deleted file mode 100644 index 5129b7c69032..000000000000 --- a/packages/video_player/video_player_web/ios/video_player_web.podspec +++ /dev/null @@ -1,20 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'video_player_web' - s.version = '0.0.1' - s.summary = 'No-op implementation of video_player_web web plugin to avoid build issues on iOS' - s.description = <<-DESC -temp fake video_player_web plugin - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_web' - s.license = { :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - - s.ios.deployment_target = '8.0' -end \ No newline at end of file diff --git a/script/tool/lib/src/drive_examples_command.dart b/script/tool/lib/src/drive_examples_command.dart index 59c642265bae..0bd531a20f8a 100644 --- a/script/tool/lib/src/drive_examples_command.dart +++ b/script/tool/lib/src/drive_examples_command.dart @@ -200,11 +200,10 @@ Tried searching for the following: if (isAndroid) { return (isAndroidPlugin(plugin, fileSystem)); } - // When we are here, no flags are specified. Only return true if the plugin supports mobile for legacy command support. - // TODO(cyanglaz): Make mobile platforms flags also required like other platforms (breaking change). + // When we are here, no flags are specified. Only return true if the plugin + // supports Android for legacy command support. TODO(cyanglaz): Make Android + // flag also required like other platforms (breaking change). // https://github.com/flutter/flutter/issues/58285 - final bool isMobilePlugin = - isIosPlugin(plugin, fileSystem) || isAndroidPlugin(plugin, fileSystem); - return isMobilePlugin; + return isAndroidPlugin(plugin, fileSystem); } } From 6d8ea78c5da1217c60ab9fe6021a896ec90d6a7a Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 16 Feb 2021 17:13:52 -0800 Subject: [PATCH 203/924] [url_launcher] Re-endorse web implementation. (#3557) This change re-endorses url_launcher_web, now that it's been migrated to null-safety. --- packages/url_launcher/url_launcher/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher/pubspec.yaml | 10 ++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 9f2719fd6662..f467ec4d1830 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.0.0-nullsafety.7 + +* Re-endorse `url_launcher_web` in the `nullsafety` prerelease. + ## 6.0.0-nullsafety.6 * Correct statement in description about which platforms url_launcher supports. diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 2fdfd8caf217..d058e2fa1409 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 6.0.0-nullsafety.6 +version: 6.0.0-nullsafety.7 flutter: plugin: @@ -12,9 +12,8 @@ flutter: pluginClass: UrlLauncherPlugin ios: pluginClass: FLTURLLauncherPlugin - # TODO(mvanbeusekom): Temporary disabled until web is migrated to nnbd (advised by @blasten). - #web: - # default_package: url_launcher_web + web: + default_package: url_launcher_web linux: default_package: url_laucher_linux macos: @@ -34,8 +33,7 @@ dependencies: url_launcher_linux: ^0.1.0-nullsafety url_launcher_macos: ^0.1.0-nullsafety url_launcher_windows: ^0.1.0-nullsafety - # TODO(mvanbeusekom): Temporary disabled until web is migrated to nnbd (advised by @blasten). - #url_launcher_web: ^0.1.3 + url_launcher_web: ^2.0.0-nullsafety dev_dependencies: flutter_test: From cbee8561c07495d542ccca6dc8572bd0b4c92cd9 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 16 Feb 2021 20:46:04 -0800 Subject: [PATCH 204/924] Document how to use pigeon and update to the latest version. (#3281) --- .../video_player/video_player/CHANGELOG.md | 4 + .../video_player/video_player/CONTRIBUTING.md | 82 +++++++++++++++++++ .../flutter/plugins/videoplayer/Messages.java | 2 +- .../video_player/ios/Classes/messages.h | 2 +- .../video_player/ios/Classes/messages.m | 2 +- .../video_player/pigeons/messages.dart | 1 + .../video_player/video_player/pubspec.yaml | 15 ++-- .../video_player/test/video_player_test.dart | 1 + script/incremental_build.sh | 2 +- 9 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 packages/video_player/video_player/CONTRIBUTING.md diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 2e8f7396c618..0cabfc48226d 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.10 + +* Updated to video_player_platform_interface 4.0. + ## 2.0.0-nullsafety.9 * Fixed an issue where a crash can occur after a closing a video player view on iOS. diff --git a/packages/video_player/video_player/CONTRIBUTING.md b/packages/video_player/video_player/CONTRIBUTING.md new file mode 100644 index 000000000000..32c9d1b791d1 --- /dev/null +++ b/packages/video_player/video_player/CONTRIBUTING.md @@ -0,0 +1,82 @@ +## Updating pigeon-generated files + +If you update files in the pigeons/ directory, run the following +command in this directory (ignore the errors you get about +dependencies in the examples directory): + +```bash +flutter pub upgrade +flutter pub run pigeon --dart_null_safety --input pigeons/messages.dart +# git commit your changes so that your working environment is clean +(cd ../../../; ./script/incremental_build.sh format --travis --clang-format=clang-format-7) +``` + +If you update pigeon itself and want to test the changes here, +temporarily update the pubspec.yaml by adding the following to the +`dependency_overrides` section, assuming you have checked out the +`flutter/packages` repo in a sibling directory to the `plugins` repo: + +```yaml + pigeon: + path: + ../../../../packages/packages/pigeon/ +``` + +Then, run the commands above. When you run `pub get` it should warn +you that you're using an override. If you do this, you will need to +publish pigeon before you can land the updates to this package, since +the CI tests run the analysis using latest published version of +pigeon, not your version or the version on master. + +In either case, the configuration will be obtained automatically from +the `pigeons/messages.dart` file (see `configurePigeon` at the bottom +of that file). + +While contributing, you may also want to set the following dependency +overrides: + +```yaml +dependency_overrides: + video_player_platform_interface: + path: + ../video_player_platform_interface + video_player_web: + path: + ../video_player_web +``` + +## Publishing plugin updates that span multiple plugin packages + +If your change affects both the interface package and the +implementation packages, then you will need to publish a version of +the plugin in between landing the interface changes and the +implementation changes, since the implementations depend on the +interface via pub. + +To do this, follow these steps: + +1. Create a PR that has all the changes, and update the +`pubspec.yaml`s to have path-based dependency overrides as described +in the "Updating pigeon-generated files" section above. + +2. Upload that PR and get it reviewed and into a state where the only +test failure is the one complaining that you can't publish a package +that has dependency overrides. + +3. Create a PR that's a subset of the one in the previous step that +only includes the interface changes, with no dependency overrides, and +submit that. + +4. Once you have had that reviewed and landed, publish the interface +parts of the plugin to pub. + +5. Now, update the original full PR to not use dependency overrides +but to instead refer to the new version of the plugin, and sync it to +master (so that the interface changes are gone from the PR). Submit +that PR. + +6. Once you have had _that_ PR reviewed and landed, publish the +implementation parts of the plugin to pub. + +You may need to publish each implementation package independently of +the main package also, depending on exactly what your change entails. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java index 98cf6dbaacea..053e3faa9694 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v0.1.12), do not edit directly. +// Autogenerated from Pigeon (v0.1.19), do not edit directly. // See also: https://pub.dev/packages/pigeon package io.flutter.plugins.videoplayer; diff --git a/packages/video_player/video_player/ios/Classes/messages.h b/packages/video_player/video_player/ios/Classes/messages.h index 84e8fc5e5cff..80137c9d61f5 100644 --- a/packages/video_player/video_player/ios/Classes/messages.h +++ b/packages/video_player/video_player/ios/Classes/messages.h @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v0.1.12), do not edit directly. +// Autogenerated from Pigeon (v0.1.19), do not edit directly. // See also: https://pub.dev/packages/pigeon #import @protocol FlutterBinaryMessenger; diff --git a/packages/video_player/video_player/ios/Classes/messages.m b/packages/video_player/video_player/ios/Classes/messages.m index 58ff7292d2b2..3f787fcdf92d 100644 --- a/packages/video_player/video_player/ios/Classes/messages.m +++ b/packages/video_player/video_player/ios/Classes/messages.m @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v0.1.12), do not edit directly. +// Autogenerated from Pigeon (v0.1.19), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "messages.h" #import diff --git a/packages/video_player/video_player/pigeons/messages.dart b/packages/video_player/video_player/pigeons/messages.dart index f1771afecb45..ebef9e526b6a 100644 --- a/packages/video_player/video_player/pigeons/messages.dart +++ b/packages/video_player/video_player/pigeons/messages.dart @@ -54,6 +54,7 @@ abstract class VideoPlayerApi { void configurePigeon(PigeonOptions opts) { opts.dartOut = '../video_player_platform_interface/lib/messages.dart'; + opts.dartTestOut = '../video_player_platform_interface/lib/test.dart'; opts.objcHeaderOut = 'ios/Classes/messages.h'; opts.objcSourceOut = 'ios/Classes/messages.m'; opts.objcOptions.prefix = 'FLT'; diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 47b8f601e711..e21315025005 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -version: 2.0.0-nullsafety.9 +version: 2.0.0-nullsafety.10 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: @@ -17,23 +17,24 @@ flutter: dependencies: meta: ^1.3.0-nullsafety.3 - video_player_platform_interface: ^3.0.0-nullsafety.3 + video_player_platform_interface: ^4.0.0-nullsafety.0 # The design on https://flutter.dev/go/federated-plugins was to leave # this constraint as "any". We cannot do it right now as it fails pub publish - # validation, so we set a ^ constraint. - # TODO(amirh): Revisit this (either update this part in the design or the pub tool). + # validation, so we set a ^ constraint. The exact value doesn't matter since + # the constraints on the interface pins it. + # TODO(amirh): Revisit this (either update this part in the design or the pub tool). # https://github.com/flutter/flutter/issues/46264 video_player_web: ^2.0.0-nullsafety.1 flutter: sdk: flutter - -dev_dependencies: flutter_test: sdk: flutter + +dev_dependencies: pedantic: ^1.10.0-nullsafety.1 - pigeon: 0.1.7 + pigeon: ^0.1.19 environment: sdk: ">=2.12.0-0 <3.0.0" diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart index eb276a8d72e7..582012097b71 100644 --- a/packages/video_player/video_player/test/video_player_test.dart +++ b/packages/video_player/video_player/test/video_player_test.dart @@ -12,6 +12,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:video_player/video_player.dart'; import 'package:video_player_platform_interface/messages.dart'; +import 'package:video_player_platform_interface/test.dart'; import 'package:video_player_platform_interface/video_player_platform_interface.dart'; class FakeController extends ValueNotifier diff --git a/script/incremental_build.sh b/script/incremental_build.sh index d98e7aac6e30..bc41ebd3c70d 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -12,7 +12,7 @@ ALL_EXCLUDED=("") # Exclude nnbd plugins from stable. if [ "$CHANNEL" == "stable" ]; then ALL_EXCLUDED=($EXCLUDED_PLUGINS_FROM_STABLE) - echo "Excluding the following plugins: $ALL_EXCLUDED" + echo "Excluding the following plugins because stable does not yet support NNBD: $ALL_EXCLUDED" fi # Plugins that deliberately use their own analysis_options.yaml. From cb309bca15379d3c09ad56e4564e69b8635d77b3 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Wed, 17 Feb 2021 09:17:44 -0800 Subject: [PATCH 205/924] Publish check (#3556) --- script/check_publish.sh | 26 +----- script/tool/lib/src/main.dart | 2 + .../tool/lib/src/publish_check_command.dart | 92 +++++++++++++++++++ 3 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 script/tool/lib/src/publish_check_command.dart diff --git a/script/check_publish.sh b/script/check_publish.sh index 5584fc601916..c92de4be2e08 100755 --- a/script/check_publish.sh +++ b/script/check_publish.sh @@ -10,33 +10,9 @@ readonly REPO_DIR="$(dirname "$SCRIPT_DIR")" source "$SCRIPT_DIR/common.sh" -function check_publish() { - local failures=() - for dir in $(plugin_tools list --plugins="$1"); do - local package_name=$(basename "$dir") - - echo "Checking that $package_name can be published." - if [[ $(cd "$dir" && cat pubspec.yaml | grep -E "^publish_to: none") ]]; then - echo "Package $package_name is marked as unpublishable. Skipping." - elif (cd "$dir" && flutter pub publish -- --dry-run > /dev/null); then - echo "Package $package_name is able to be published." - else - error "Unable to publish $package_name" - failures=("${failures[@]}" "$package_name") - fi - done - if [[ "${#failures[@]}" != 0 ]]; then - error "FAIL: The following ${#failures[@]} package(s) failed the publishing check:" - for failure in "${failures[@]}"; do - error "$failure" - done - fi - return "${#failures[@]}" -} - # Sets CHANGED_PACKAGE_LIST and CHANGED_PACKAGES check_changed_packages if [[ "${#CHANGED_PACKAGE_LIST[@]}" != 0 ]]; then - check_publish "${CHANGED_PACKAGES}" + plugin_tools publish-check --plugins="${CHANGED_PACKAGES}" fi diff --git a/script/tool/lib/src/main.dart b/script/tool/lib/src/main.dart index bb3f67c0a9e1..fa81597237d7 100644 --- a/script/tool/lib/src/main.dart +++ b/script/tool/lib/src/main.dart @@ -7,6 +7,7 @@ import 'dart:io' as io; import 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:file/local.dart'; +import 'package:flutter_plugin_tools/src/publish_check_command.dart'; import 'package:flutter_plugin_tools/src/publish_plugin_command.dart'; import 'package:path/path.dart' as p; @@ -51,6 +52,7 @@ void main(List args) { ..addCommand(JavaTestCommand(packagesDir, fileSystem)) ..addCommand(LintPodspecsCommand(packagesDir, fileSystem)) ..addCommand(ListCommand(packagesDir, fileSystem)) + ..addCommand(PublishCheckCommand(packagesDir, fileSystem)) ..addCommand(PublishPluginCommand(packagesDir, fileSystem)) ..addCommand(TestCommand(packagesDir, fileSystem)) ..addCommand(VersionCheckCommand(packagesDir, fileSystem)) diff --git a/script/tool/lib/src/publish_check_command.dart b/script/tool/lib/src/publish_check_command.dart new file mode 100644 index 000000000000..8d6f6bb9ab61 --- /dev/null +++ b/script/tool/lib/src/publish_check_command.dart @@ -0,0 +1,92 @@ +// 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:async'; + +import 'package:colorize/colorize.dart'; +import 'package:file/file.dart'; +import 'package:pubspec_parse/pubspec_parse.dart'; + +import 'common.dart'; + +class PublishCheckCommand extends PluginCommand { + PublishCheckCommand( + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + }) : super(packagesDir, fileSystem, processRunner: processRunner); + + @override + final String name = 'publish-check'; + + @override + final String description = + 'Checks to make sure that a plugin *could* be published.'; + + @override + Future run() async { + checkSharding(); + final List failedPackages = []; + + await for (Directory plugin in getPlugins()) { + if (!(await passesPublishCheck(plugin))) failedPackages.add(plugin); + } + + if (failedPackages.isNotEmpty) { + final String error = + 'FAIL: The following ${failedPackages.length} package(s) failed the ' + 'publishing check:'; + final String joinedFailedPackages = failedPackages.join('\n'); + + final Colorize colorizedError = Colorize('$error\n$joinedFailedPackages') + ..red(); + print(colorizedError); + throw ToolExit(1); + } + + final Colorize passedMessage = + Colorize('All packages passed publish check!')..green(); + print(passedMessage); + } + + Pubspec tryParsePubspec(Directory package) { + final File pubspecFile = package.childFile('pubspec.yaml'); + + try { + return Pubspec.parse(pubspecFile.readAsStringSync()); + } on Exception catch (exception) { + print( + 'Failed to parse `pubspec.yaml` at ${pubspecFile.path}: $exception}', + ); + return null; + } + } + + Future passesPublishCheck(Directory package) async { + final String packageName = package.basename; + print('Checking that $packageName can be published.'); + + final Pubspec pubspec = tryParsePubspec(package); + if (pubspec == null) { + return false; + } else if (pubspec.publishTo == 'none') { + print('Package $packageName is marked as unpublishable. Skipping.'); + return true; + } + + final int exitCode = await processRunner.runAndStream( + 'flutter', + ['pub', 'publish', '--', '--dry-run'], + workingDir: package, + ); + + if (exitCode == 0) { + print("Package $packageName is able to be published."); + return true; + } else { + print('Unable to publish $packageName'); + return false; + } + } +} From bf571074fa87baca188a1de6ebc937ed08e7e7d7 Mon Sep 17 00:00:00 2001 From: Jeremiah Parrack Date: Thu, 18 Feb 2021 10:33:13 -0500 Subject: [PATCH 206/924] Update video_player readme to change sample video to https (#3546) --- packages/video_player/video_player/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/video_player/video_player/README.md b/packages/video_player/video_player/README.md index e64ce152f85b..d66dfcdfbd98 100644 --- a/packages/video_player/video_player/README.md +++ b/packages/video_player/video_player/README.md @@ -77,7 +77,7 @@ class _VideoAppState extends State { void initState() { super.initState(); _controller = VideoPlayerController.network( - 'http://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4') + 'https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4') ..initialize().then((_) { // Ensure the first frame is shown after the video is initialized, even before the play button has been pressed. setState(() {}); From 361567b9189c92ccefbc322e88244cfb31bfa00e Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 18 Feb 2021 16:33:41 +0100 Subject: [PATCH 207/924] [camera] Added timeout to Android pre-capture sequence (#3558) * Added timeout for waiting pre-capture state Android * Fix analysis warning and bumped version --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../io/flutter/plugins/camera/Camera.java | 24 +++++++++++++++++++ packages/camera/camera/pubspec.yaml | 2 +- packages/camera/camera/test/camera_test.dart | 2 +- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index aee3774087ba..7391f3090565 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.0-nullsafety.1 + +* Added a timeout to the pre-capture sequence on Android to prevent crashes when the camera cannot get a focus. + ## 0.8.0-nullsafety * Migrated to null safety. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index a5f8647afb0b..5169a3babb74 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -36,6 +36,7 @@ import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.Looper; +import android.os.SystemClock; import android.util.Log; import android.util.Range; import android.util.Rational; @@ -73,6 +74,9 @@ interface ErrorCallback { public class Camera { private static final String TAG = "Camera"; + /** Timeout for the pre-capture sequence. */ + private static final long PRECAPTURE_TIMEOUT_MS = 1000; + private final SurfaceTextureEntry flutterTexture; private final CameraManager cameraManager; private final DeviceOrientationManager deviceOrientationListener; @@ -105,6 +109,7 @@ public class Camera { private boolean useAutoFocus = true; private Range fpsRange; private PlatformChannel.DeviceOrientation lockedCaptureOrientation; + private long preCaptureStartTime; private static final HashMap supportedImageFormats; // Current supported outputs @@ -503,11 +508,16 @@ private void processCapture(CaptureResult result) { || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED || aeState == CaptureRequest.CONTROL_AE_STATE_CONVERGED) { pictureCaptureRequest.setState(State.waitingPreCaptureReady); + setPreCaptureStartTime(); } break; case waitingPreCaptureReady: if (aeState == null || aeState != CaptureRequest.CONTROL_AE_STATE_PRECAPTURE) { runPictureCapture(); + } else { + if (hitPreCaptureTimeout()) { + unlockAutoFocus(); + } } } } @@ -1142,6 +1152,20 @@ public void stopImageStream() throws CameraAccessException { startPreview(); } + /** Sets the time the pre-capture sequence started. */ + private void setPreCaptureStartTime() { + preCaptureStartTime = SystemClock.elapsedRealtime(); + } + + /** + * Check if the timeout for the pre-capture sequence has been reached. + * + * @return true if the timeout is reached; otherwise false is returned. + */ + private boolean hitPreCaptureTimeout() { + return (SystemClock.elapsedRealtime() - preCaptureStartTime) > PRECAPTURE_TIMEOUT_MS; + } + private void closeCaptureSession() { if (cameraCaptureSession != null) { cameraCaptureSession.close(); diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 7ed08d892de8..5b98c39acd99 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.8.0-nullsafety +version: 0.8.0-nullsafety.1 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index b37b7701a14f..40ce29e363b1 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -1268,7 +1268,7 @@ class MockCameraPlatform extends Mock Future createCamera( CameraDescription description, ResolutionPreset? resolutionPreset, { - bool enableAudio = true, + bool enableAudio = false, }) => mockPlatformException ? throw PlatformException(code: 'foo', message: 'bar') From f784207d09b7e695b925bcaf8ba744a26e5b2309 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 18 Feb 2021 09:47:08 -0800 Subject: [PATCH 208/924] Publish check ignores prerelease sdk (#3560) --- .../tool/lib/src/publish_check_command.dart | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/script/tool/lib/src/publish_check_command.dart b/script/tool/lib/src/publish_check_command.dart index 8d6f6bb9ab61..af009952856e 100644 --- a/script/tool/lib/src/publish_check_command.dart +++ b/script/tool/lib/src/publish_check_command.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:io' as io; import 'package:colorize/colorize.dart'; import 'package:file/file.dart'; @@ -63,6 +64,44 @@ class PublishCheckCommand extends PluginCommand { } } + Future hasValidPublishCheckRun(Directory package) async { + final io.Process process = await io.Process.start( + 'flutter', + ['pub', 'publish', '--', '--dry-run'], + workingDirectory: package.path, + ); + + final StringBuffer outputBuffer = StringBuffer(); + + final Completer stdOutCompleter = Completer(); + process.stdout.listen( + (List event) { + io.stdout.add(event); + outputBuffer.write(String.fromCharCodes(event)); + }, + onDone: () => stdOutCompleter.complete(), + ); + + final Completer stdInCompleter = Completer(); + process.stderr.listen( + (List event) { + io.stderr.add(event); + outputBuffer.write(String.fromCharCodes(event)); + }, + onDone: () => stdInCompleter.complete(), + ); + + if (await process.exitCode == 0) return true; + + await stdOutCompleter.future; + await stdInCompleter.future; + + final String output = outputBuffer.toString(); + return output.contains('Package has 1 warning.') && + output.contains( + 'Packages with an SDK constraint on a pre-release of the Dart SDK should themselves be published as a pre-release version.'); + } + Future passesPublishCheck(Directory package) async { final String packageName = package.basename; print('Checking that $packageName can be published.'); @@ -75,13 +114,7 @@ class PublishCheckCommand extends PluginCommand { return true; } - final int exitCode = await processRunner.runAndStream( - 'flutter', - ['pub', 'publish', '--', '--dry-run'], - workingDir: package, - ); - - if (exitCode == 0) { + if (await hasValidPublishCheckRun(package)) { print("Package $packageName is able to be published."); return true; } else { From 73a75b8a73492cea817662d0e496bd1a5d2187b8 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Thu, 18 Feb 2021 13:45:01 -0800 Subject: [PATCH 209/924] Migrate plugin_platform_interface to v2 stable, null-safe (#3543) --- packages/plugin_platform_interface/CHANGELOG.md | 10 +--------- packages/plugin_platform_interface/pubspec.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/plugin_platform_interface/CHANGELOG.md b/packages/plugin_platform_interface/CHANGELOG.md index 96533f01c10f..cea8f2a76266 100644 --- a/packages/plugin_platform_interface/CHANGELOG.md +++ b/packages/plugin_platform_interface/CHANGELOG.md @@ -1,12 +1,4 @@ -## 1.1.0-nullsafety.2 - -* Use Mockito null safe. - -## 1.1.0-nullsafety.1 - -* Bump Dart SDK to support null safety. - -## 1.1.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/plugin_platform_interface/pubspec.yaml b/packages/plugin_platform_interface/pubspec.yaml index 084e577dbf99..12a5b066bc61 100644 --- a/packages/plugin_platform_interface/pubspec.yaml +++ b/packages/plugin_platform_interface/pubspec.yaml @@ -12,7 +12,7 @@ description: Reusable base class for Flutter plugin platform interfaces. # be done when absolutely necessary and after the ecosystem has already migrated to 1.X.Y version # that is forward compatible with 2.0.0 (ideally the ecosystem have migrated to depend on: # `plugin_platform_interface: >=1.X.Y <3.0.0`). -version: 1.1.0-nullsafety.2 +version: 2.0.0 repository: https://github.com/flutter/plugins/tree/master/packages/plugin_platform_interface @@ -20,9 +20,9 @@ environment: sdk: ">=2.12.0-0 <3.0.0" dependencies: - meta: ^1.3.0-nullsafety.3 + meta: ^1.3.0 dev_dependencies: - mockito: ^5.0.0-nullsafety.2 - test: ^1.10.0-nullsafety.1 - pedantic: ^1.10.0-nullsafety.1 + mockito: ^5.0.0-nullsafety.7 + test: ^1.16.0 + pedantic: ^1.10.0 From f1253313425e24ffc2e75814a79e99593d9ad4a4 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 18 Feb 2021 15:01:39 -0800 Subject: [PATCH 210/924] [shared_preferences] fix crash when list type is dynaimc (#3565) --- .../shared_preferences/shared_preferences/CHANGELOG.md | 4 ++++ .../shared_preferences/lib/shared_preferences.dart | 2 +- .../shared_preferences/shared_preferences/pubspec.yaml | 2 +- .../test/shared_preferences_test.dart | 10 ++++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 1f003ef5b133..a14ebf547659 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.1 + +* Fix crash when list string's type is dynamic. + ## 2.0.0-nullsafety * Migrate to null-safety. diff --git a/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart b/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart index 03619fd14b4f..2f4ebe730351 100644 --- a/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart +++ b/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart @@ -107,7 +107,7 @@ class SharedPreferences { /// Reads a set of string values from persistent storage, throwing an /// exception if it's not a string set. List? getStringList(String key) { - List? list = _preferenceCache[key] as List?; + List? list = _preferenceCache[key] as List?; if (list != null && list is! List) { list = list.cast().toList(); _preferenceCache[key] = list; diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 1bf314cadcfa..fc556972a847 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences description: Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences -version: 2.0.0-nullsafety +version: 2.0.0-nullsafety.1 flutter: plugin: diff --git a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart index 9f6e7203fa85..7866b2e38fac 100755 --- a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart @@ -39,6 +39,7 @@ void main() { tearDown(() async { await preferences.clear(); + await store.clear(); }); test('reading', () async { @@ -156,6 +157,15 @@ void main() { expect(await first, await second); }); + test('string list type is dynamic (usually from method channel)', () async { + SharedPreferences.setMockInitialValues({ + 'dynamic_list': ['1', '2'] + }); + final SharedPreferences prefs = await SharedPreferences.getInstance(); + final List? value = prefs.getStringList('dynamic_list'); + expect(value, ['1', '2']); + }); + group('mocking', () { const String _key = 'dummy'; const String _prefixedKey = 'flutter.' + _key; From 4290d18f0e43288087b3754c41d4739872d9a152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Vincke?= Date: Fri, 19 Feb 2021 00:48:21 +0100 Subject: [PATCH 211/924] [webview_flutter] Support for loading progress tracking (#2151) --- packages/webview_flutter/CHANGELOG.md | 4 ++ .../webviewflutter/FlutterWebView.java | 8 +++ .../webviewflutter/FlutterWebViewClient.java | 9 +++ .../webview_flutter/example/lib/main.dart | 3 + .../ios/Classes/FLTWKProgressionDelegate.h | 19 ++++++ .../ios/Classes/FLTWKProgressionDelegate.m | 42 ++++++++++++ .../ios/Classes/FlutterWebView.m | 15 ++++ .../lib/platform_interface.dart | 11 ++- .../lib/src/webview_method_channel.dart | 4 ++ .../webview_flutter/lib/webview_flutter.dart | 20 ++++++ .../test/webview_flutter_test.dart | 68 +++++++++++++++++++ 11 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h create mode 100644 packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index b3218e296d98..0a060ef0cf2d 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.6 + +* Added support for progress tracking. + ## 2.0.0-nullsafety.5 * Add section to the wiki explaining how to use Material components. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java index ef9f006f6e5b..4578c7e0d1fe 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java @@ -72,6 +72,11 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { return true; } + + @Override + public void onProgressChanged(WebView view, int progress) { + flutterWebViewClient.onLoadingProgress(progress); + } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) @@ -367,6 +372,9 @@ private void applySettings(Map settings) { webView.setWebContentsDebuggingEnabled(debuggingEnabled); } break; + case "hasProgressTracking": + flutterWebViewClient.hasProgressTracking = (boolean) settings.get(key); + break; case "gestureNavigationEnabled": break; case "userAgent": diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java index 24926bfc4117..3590d67eb334 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java @@ -30,6 +30,7 @@ class FlutterWebViewClient { private static final String TAG = "FlutterWebViewClient"; private final MethodChannel methodChannel; private boolean hasNavigationDelegate; + boolean hasProgressTracking; FlutterWebViewClient(MethodChannel methodChannel) { this.methodChannel = methodChannel; @@ -125,6 +126,14 @@ private void onPageFinished(WebView view, String url) { methodChannel.invokeMethod("onPageFinished", args); } + void onLoadingProgress(int progress) { + if (hasProgressTracking) { + Map args = new HashMap<>(); + args.put("progress", progress); + methodChannel.invokeMethod("onProgress", args); + } + } + private void onWebResourceError( final int errorCode, final String description, final String failingUrl) { final Map args = new HashMap<>(); diff --git a/packages/webview_flutter/example/lib/main.dart b/packages/webview_flutter/example/lib/main.dart index c7f42ac2bf66..e7e7981150ca 100644 --- a/packages/webview_flutter/example/lib/main.dart +++ b/packages/webview_flutter/example/lib/main.dart @@ -62,6 +62,9 @@ class _WebViewExampleState extends State { onWebViewCreated: (WebViewController webViewController) { _controller.complete(webViewController); }, + onProgress: (int progress) { + print("WebView is loading (progress : $progress%)"); + }, javascriptChannels: { _toasterJavascriptChannel(context), }, diff --git a/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h new file mode 100644 index 000000000000..40139ead262c --- /dev/null +++ b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h @@ -0,0 +1,19 @@ +// Copyright 2019 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 +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTWKProgressionDelegate : NSObject + +- (instancetype)initWithWebView:(WKWebView *)webView channel:(FlutterMethodChannel *)channel; + +- (void)stopObservingProgress:(WKWebView *)webView; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m new file mode 100644 index 000000000000..ad864e6e1fd1 --- /dev/null +++ b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m @@ -0,0 +1,42 @@ +// Copyright 2019 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 "FLTWKProgressionDelegate.h" + +NSString *const FLTWKEstimatedProgressKeyPath = @"estimatedProgress"; + +@implementation FLTWKProgressionDelegate { + FlutterMethodChannel *_methodChannel; +} + +- (instancetype)initWithWebView:(WKWebView *)webView channel:(FlutterMethodChannel *)channel { + self = [super init]; + if (self) { + _methodChannel = channel; + [webView addObserver:self + forKeyPath:FLTWKEstimatedProgressKeyPath + options:NSKeyValueObservingOptionNew + context:nil]; + } + return self; +} + +- (void)stopObservingProgress:(WKWebView *)webView { + [webView removeObserver:self forKeyPath:FLTWKEstimatedProgressKeyPath]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if ([keyPath isEqualToString:FLTWKEstimatedProgressKeyPath]) { + NSNumber *newValue = + change[NSKeyValueChangeNewKey] ?: 0; // newValue is anywhere between 0.0 and 1.0 + int newValueAsInt = [newValue floatValue] * 100; // Anywhere between 0 and 100 + [_methodChannel invokeMethod:@"onProgress" + arguments:@{@"progress" : [NSNumber numberWithInt:newValueAsInt]}]; + } +} + +@end diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index ed3cf44424e8..5f2af3b8aae0 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -4,6 +4,7 @@ #import "FlutterWebView.h" #import "FLTWKNavigationDelegate.h" +#import "FLTWKProgressionDelegate.h" #import "JavaScriptChannelHandler.h" @implementation FLTWebViewFactory { @@ -64,6 +65,7 @@ @implementation FLTWebViewController { // The set of registered JavaScript channel names. NSMutableSet* _javaScriptChannelNames; FLTWKNavigationDelegate* _navigationDelegate; + FLTWKProgressionDelegate* _progressionDelegate; } - (instancetype)initWithFrame:(CGRect)frame @@ -119,6 +121,12 @@ - (instancetype)initWithFrame:(CGRect)frame return self; } +- (void)dealloc { + if (_progressionDelegate != nil) { + [_progressionDelegate stopObservingProgress:_webView]; + } +} + - (UIView*)view { return _webView; } @@ -323,6 +331,13 @@ - (NSString*)applySettings:(NSDictionary*)settings { } else if ([key isEqualToString:@"hasNavigationDelegate"]) { NSNumber* hasDartNavigationDelegate = settings[key]; _navigationDelegate.hasDartNavigationDelegate = [hasDartNavigationDelegate boolValue]; + } else if ([key isEqualToString:@"hasProgressTracking"]) { + NSNumber* hasProgressTrackingValue = settings[key]; + bool hasProgressTracking = [hasProgressTrackingValue boolValue]; + if (hasProgressTracking) { + _progressionDelegate = [[FLTWKProgressionDelegate alloc] initWithWebView:_webView + channel:_channel]; + } } else if ([key isEqualToString:@"debuggingEnabled"]) { // no-op debugging is always enabled on iOS. } else if ([key isEqualToString:@"gestureNavigationEnabled"]) { diff --git a/packages/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/lib/platform_interface.dart index a840c0036fb3..16b529d7090e 100644 --- a/packages/webview_flutter/lib/platform_interface.dart +++ b/packages/webview_flutter/lib/platform_interface.dart @@ -30,6 +30,10 @@ abstract class WebViewPlatformCallbacksHandler { /// Invoked by [WebViewPlatformController] when a page has finished loading. void onPageFinished(String url); + /// Invoked by [WebViewPlatformController] when a page is loading. + /// /// Only works when [WebSettings.hasProgressTracking] is set to `true`. + void onProgress(int progress); + /// Report web resource loading error to the host application. void onWebResourceError(WebResourceError error); } @@ -388,6 +392,7 @@ class WebSettings { WebSettings({ this.javascriptMode, this.hasNavigationDelegate, + this.hasProgressTracking, this.debuggingEnabled, this.gestureNavigationEnabled, this.allowsInlineMediaPlayback, @@ -400,6 +405,10 @@ class WebSettings { /// Whether the [WebView] has a [NavigationDelegate] set. final bool? hasNavigationDelegate; + /// Whether the [WebView] should track page loading progress. + /// See also: [WebViewPlatformCallbacksHandler.onProgress] to get the progress. + final bool? hasProgressTracking; + /// Whether to enable the platform's webview content debugging tools. /// /// See also: [WebView.debuggingEnabled]. @@ -427,7 +436,7 @@ class WebSettings { @override String toString() { - return 'WebSettings(javascriptMode: $javascriptMode, hasNavigationDelegate: $hasNavigationDelegate, debuggingEnabled: $debuggingEnabled, gestureNavigationEnabled: $gestureNavigationEnabled, userAgent: $userAgent, allowsInlineMediaPlayback: $allowsInlineMediaPlayback)'; + return 'WebSettings(javascriptMode: $javascriptMode, hasNavigationDelegate: $hasNavigationDelegate, hasProgressTracking: $hasProgressTracking, debuggingEnabled: $debuggingEnabled, gestureNavigationEnabled: $gestureNavigationEnabled, userAgent: $userAgent, allowsInlineMediaPlayback: $allowsInlineMediaPlayback)'; } } diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart index 54ab647cdc04..ef1ed51835b8 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -40,6 +40,9 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { case 'onPageFinished': _platformCallbacksHandler.onPageFinished(call.arguments['url']!); return null; + case 'onProgress': + _platformCallbacksHandler.onProgress(call.arguments['progress']); + return null; case 'onPageStarted': _platformCallbacksHandler.onPageStarted(call.arguments['url']!); return null; @@ -183,6 +186,7 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { _addIfNonNull('jsMode', settings!.javascriptMode?.index); _addIfNonNull('hasNavigationDelegate', settings.hasNavigationDelegate); + _addIfNonNull('hasProgressTracking', settings.hasProgressTracking); _addIfNonNull('debuggingEnabled', settings.debuggingEnabled); _addIfNonNull( 'gestureNavigationEnabled', settings.gestureNavigationEnabled); diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 6853d39555c3..7e4f3d6ac079 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -142,6 +142,9 @@ typedef void PageStartedCallback(String url); /// Signature for when a [WebView] has finished loading a page. typedef void PageFinishedCallback(String url); +/// Signature for when a [WebView] is loading a page. +typedef void PageLoadingCallback(int progress); + /// Signature for when a [WebView] has failed to load a resource. typedef void WebResourceErrorCallback(WebResourceError error); @@ -217,6 +220,7 @@ class WebView extends StatefulWidget { this.gestureRecognizers, this.onPageStarted, this.onPageFinished, + this.onProgress, this.onWebResourceError, this.debuggingEnabled = false, this.gestureNavigationEnabled = false, @@ -357,6 +361,9 @@ class WebView extends StatefulWidget { /// [WebViewController.evaluateJavascript] can assume this. final PageFinishedCallback? onPageFinished; + /// Invoked when a page is loading. + final PageLoadingCallback? onProgress; + /// Invoked when a web resource has failed to load. /// /// This can be called for any resource (iframe, image, etc.), not just for @@ -476,6 +483,7 @@ WebSettings _webSettingsFromWidget(WebView widget) { return WebSettings( javascriptMode: widget.javascriptMode, hasNavigationDelegate: widget.navigationDelegate != null, + hasProgressTracking: widget.onProgress != null, debuggingEnabled: widget.debuggingEnabled, gestureNavigationEnabled: widget.gestureNavigationEnabled, allowsInlineMediaPlayback: widget.allowsInlineMediaPlayback, @@ -488,6 +496,7 @@ WebSettings _clearUnchangedWebSettings( WebSettings currentValue, WebSettings newValue) { assert(currentValue.javascriptMode != null); assert(currentValue.hasNavigationDelegate != null); + assert(currentValue.hasProgressTracking != null); assert(currentValue.debuggingEnabled != null); assert(currentValue.userAgent != null); assert(newValue.javascriptMode != null); @@ -497,6 +506,7 @@ WebSettings _clearUnchangedWebSettings( JavascriptMode? javascriptMode; bool? hasNavigationDelegate; + bool? hasProgressTracking; bool? debuggingEnabled; WebSetting userAgent = WebSetting.absent(); if (currentValue.javascriptMode != newValue.javascriptMode) { @@ -505,6 +515,9 @@ WebSettings _clearUnchangedWebSettings( if (currentValue.hasNavigationDelegate != newValue.hasNavigationDelegate) { hasNavigationDelegate = newValue.hasNavigationDelegate; } + if (currentValue.hasProgressTracking != newValue.hasProgressTracking) { + hasProgressTracking = newValue.hasProgressTracking; + } if (currentValue.debuggingEnabled != newValue.debuggingEnabled) { debuggingEnabled = newValue.debuggingEnabled; } @@ -515,6 +528,7 @@ WebSettings _clearUnchangedWebSettings( return WebSettings( javascriptMode: javascriptMode, hasNavigationDelegate: hasNavigationDelegate, + hasProgressTracking: hasProgressTracking, debuggingEnabled: debuggingEnabled, userAgent: userAgent, ); @@ -571,6 +585,12 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler { } @override + void onProgress(int progress) { + if (_widget.onProgress != null) { + _widget.onProgress!(progress); + } + } + void onWebResourceError(WebResourceError error) { if (_widget.onWebResourceError != null) { _widget.onWebResourceError!(error); diff --git a/packages/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/test/webview_flutter_test.dart index 162b1932e49d..8ae6e625431d 100644 --- a/packages/webview_flutter/test/webview_flutter_test.dart +++ b/packages/webview_flutter/test/webview_flutter_test.dart @@ -692,6 +692,62 @@ void main() { }); }); + group('$PageLoadingCallback', () { + testWidgets('onLoadingProgress is not null', (WidgetTester tester) async { + int? loadingProgress; + + await tester.pumpWidget(WebView( + initialUrl: 'https://youtube.com', + onProgress: (int progress) { + loadingProgress = progress; + }, + )); + + final FakePlatformWebView? platformWebView = + fakePlatformViewsController.lastCreatedView; + + platformWebView?.fakeOnProgressCallback(50); + + expect(loadingProgress, 50); + }); + + testWidgets('onLoadingProgress is null', (WidgetTester tester) async { + await tester.pumpWidget(const WebView( + initialUrl: 'https://youtube.com', + onProgress: null, + )); + + final FakePlatformWebView platformWebView = + fakePlatformViewsController.lastCreatedView!; + + // This is to test that it does not crash on a null callback. + platformWebView.fakeOnProgressCallback(50); + }); + + testWidgets('onLoadingProgress changed', (WidgetTester tester) async { + int? loadingProgress; + + await tester.pumpWidget(WebView( + initialUrl: 'https://youtube.com', + onProgress: (int progress) {}, + )); + + await tester.pumpWidget(WebView( + initialUrl: 'https://youtube.com', + onProgress: (int progress) { + loadingProgress = progress; + }, + )); + + final FakePlatformWebView platformWebView = + fakePlatformViewsController.lastCreatedView!; + + platformWebView.fakeOnProgressCallback(50); + + expect(loadingProgress, 50); + }); + }); + group('navigationDelegate', () { testWidgets('hasNavigationDelegate', (WidgetTester tester) async { await tester.pumpWidget(const WebView( @@ -1021,6 +1077,18 @@ class FakePlatformWebView { ); } + void fakeOnProgressCallback(int progress) { + final StandardMethodCodec codec = const StandardMethodCodec(); + + final ByteData data = codec.encodeMethodCall(MethodCall( + 'onProgress', + {'progress': progress}, + )); + + ServicesBinding.instance!.defaultBinaryMessenger + .handlePlatformMessage(channel.name, data, (ByteData? data) {}); + } + void _loadUrl(String? url) { history = history.sublist(0, currentPosition + 1); history.add(url); From d2c011f80a0bbb2b40752c934566e5b8ad6c148f Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 18 Feb 2021 18:34:24 -0800 Subject: [PATCH 212/924] [shared_preferences] Migrate examples to NNBD (#3564) Migrate all examples to NNBD so that the example apps will run in strong mode. Converts macOS example to use the platform interface to remove circular dependencies (code is based on the Linux and Windows versions which already use essentially that approach). --- .../shared_preferences_test.dart | 6 + .../shared_preferences/example/lib/main.dart | 4 +- .../shared_preferences/example/pubspec.yaml | 3 +- .../example/test_driver/integration_test.dart | 2 + .../shared_preferences_test.dart | 6 + .../example/lib/main.dart | 10 +- .../example/pubspec.yaml | 2 +- .../example/test_driver/integration_test.dart | 2 + .../shared_preferences_test.dart | 110 +++++++++++------- .../example/lib/main.dart | 24 ++-- .../macos/Runner.xcodeproj/project.pbxproj | 21 +--- .../contents.xcworkspacedata | 3 + .../example/pubspec.yaml | 4 +- .../example/test_driver/integration_test.dart | 2 + .../shared_preferences_macos/pubspec.yaml | 1 + .../shared_preferences_test.dart | 6 +- .../example/lib/main.dart | 10 +- .../example/pubspec.yaml | 6 +- .../example/test_driver/integration_test.dart | 8 +- 19 files changed, 138 insertions(+), 92 deletions(-) diff --git a/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart index e43d4e3ae0c2..1caf695d9365 100644 --- a/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart @@ -1,3 +1,9 @@ +// 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. + +// @dart=2.9 + import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; diff --git a/packages/shared_preferences/shared_preferences/example/lib/main.dart b/packages/shared_preferences/shared_preferences/example/lib/main.dart index 46daeff6706f..26e6c8eb42f8 100644 --- a/packages/shared_preferences/shared_preferences/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences/example/lib/main.dart @@ -24,7 +24,7 @@ class MyApp extends StatelessWidget { } class SharedPreferencesDemo extends StatefulWidget { - SharedPreferencesDemo({Key key}) : super(key: key); + SharedPreferencesDemo({Key? key}) : super(key: key); @override SharedPreferencesDemoState createState() => SharedPreferencesDemoState(); @@ -32,7 +32,7 @@ class SharedPreferencesDemo extends StatefulWidget { class SharedPreferencesDemoState extends State { Future _prefs = SharedPreferences.getInstance(); - Future _counter; + late Future _counter; Future _incrementCounter() async { final SharedPreferences prefs = await _prefs; diff --git a/packages/shared_preferences/shared_preferences/example/pubspec.yaml b/packages/shared_preferences/shared_preferences/example/pubspec.yaml index 05f2528af2af..ab6c8fe11f7f 100644 --- a/packages/shared_preferences/shared_preferences/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/example/pubspec.yaml @@ -23,6 +23,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.0.0-dev.28.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.9.1+hotfix.2" - diff --git a/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart index 7a2c21338786..ac106b63b339 100644 --- a/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart index 3aedccd0feba..019dc248a918 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart @@ -1,3 +1,9 @@ +// 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. + +// @dart=2.9 + import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart b/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart index ceacf2f95f28..ab664cd652ff 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart @@ -24,7 +24,7 @@ class MyApp extends StatelessWidget { } class SharedPreferencesDemo extends StatefulWidget { - SharedPreferencesDemo({Key key}) : super(key: key); + SharedPreferencesDemo({Key? key}) : super(key: key); @override SharedPreferencesDemoState createState() => SharedPreferencesDemoState(); @@ -32,14 +32,14 @@ class SharedPreferencesDemo extends StatefulWidget { class SharedPreferencesDemoState extends State { final prefs = SharedPreferencesLinux.instance; - Future _counter; + late Future _counter; Future _incrementCounter() async { final values = await prefs.getAll(); - final int counter = (values['counter'] as int ?? 0) + 1; + final int counter = (values['counter'] as int? ?? 0) + 1; setState(() { - _counter = prefs.setValue(null, "counter", counter).then((bool success) { + _counter = prefs.setValue('Int', 'counter', counter).then((bool success) { return counter; }); }); @@ -49,7 +49,7 @@ class SharedPreferencesDemoState extends State { void initState() { super.initState(); _counter = prefs.getAll().then((Map values) { - return (values['counter'] ?? 0); + return (values['counter'] as int? ?? 0); }); } diff --git a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml index 5fc8ae039812..12b78c37ea9c 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml @@ -23,5 +23,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.8" diff --git a/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart index 7a2c21338786..ac106b63b339 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart index 0d49ed95dd2d..58b59463b352 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart @@ -1,12 +1,18 @@ +// Copyright 2017, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// @dart=2.9 + import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; -import 'package:shared_preferences/shared_preferences.dart'; +import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:integration_test/integration_test.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - group('$SharedPreferences', () { + group('SharedPreferencesMacOS', () { const Map kTestValues = { 'flutter.String': 'hello world', 'flutter.bool': true, @@ -23,67 +29,81 @@ void main() { 'flutter.List': ['baz', 'quox'], }; - SharedPreferences preferences; + SharedPreferencesStorePlatform preferences; setUp(() async { - preferences = await SharedPreferences.getInstance(); + preferences = SharedPreferencesStorePlatform.instance; }); tearDown(() { preferences.clear(); }); - test('reading', () async { - expect(preferences.get('String'), isNull); - expect(preferences.get('bool'), isNull); - expect(preferences.get('int'), isNull); - expect(preferences.get('double'), isNull); - expect(preferences.get('List'), isNull); - expect(preferences.getString('String'), isNull); - expect(preferences.getBool('bool'), isNull); - expect(preferences.getInt('int'), isNull); - expect(preferences.getDouble('double'), isNull); - expect(preferences.getStringList('List'), isNull); + // Normally the app-facing package adds the prefix, but since this test + // bypasses the app-facing package it needs to be manually added. + String _prefixedKey(String key) { + return 'flutter.$key'; + } + + testWidgets('reading', (WidgetTester _) async { + final Map values = await preferences.getAll(); + expect(values[_prefixedKey('String')], isNull); + expect(values[_prefixedKey('bool')], isNull); + expect(values[_prefixedKey('int')], isNull); + expect(values[_prefixedKey('double')], isNull); + expect(values[_prefixedKey('List')], isNull); }); - test('writing', () async { + testWidgets('writing', (WidgetTester _) async { await Future.wait(>[ - preferences.setString('String', kTestValues2['flutter.String']), - preferences.setBool('bool', kTestValues2['flutter.bool']), - preferences.setInt('int', kTestValues2['flutter.int']), - preferences.setDouble('double', kTestValues2['flutter.double']), - preferences.setStringList('List', kTestValues2['flutter.List']) + preferences.setValue( + 'String', _prefixedKey('String'), kTestValues2['flutter.String']), + preferences.setValue( + 'Bool', _prefixedKey('bool'), kTestValues2['flutter.bool']), + preferences.setValue( + 'Int', _prefixedKey('int'), kTestValues2['flutter.int']), + preferences.setValue( + 'Double', _prefixedKey('double'), kTestValues2['flutter.double']), + preferences.setValue( + 'StringList', _prefixedKey('List'), kTestValues2['flutter.List']) ]); - expect(preferences.getString('String'), kTestValues2['flutter.String']); - expect(preferences.getBool('bool'), kTestValues2['flutter.bool']); - expect(preferences.getInt('int'), kTestValues2['flutter.int']); - expect(preferences.getDouble('double'), kTestValues2['flutter.double']); - expect(preferences.getStringList('List'), kTestValues2['flutter.List']); + final Map values = await preferences.getAll(); + expect(values[_prefixedKey('String')], kTestValues2['flutter.String']); + expect(values[_prefixedKey('bool')], kTestValues2['flutter.bool']); + expect(values[_prefixedKey('int')], kTestValues2['flutter.int']); + expect(values[_prefixedKey('double')], kTestValues2['flutter.double']); + expect(values[_prefixedKey('List')], kTestValues2['flutter.List']); }); - test('removing', () async { - const String key = 'testKey'; - await preferences.setString(key, kTestValues['flutter.String']); - await preferences.setBool(key, kTestValues['flutter.bool']); - await preferences.setInt(key, kTestValues['flutter.int']); - await preferences.setDouble(key, kTestValues['flutter.double']); - await preferences.setStringList(key, kTestValues['flutter.List']); + testWidgets('removing', (WidgetTester _) async { + final String key = _prefixedKey('testKey'); + await preferences.setValue('String', key, kTestValues['flutter.String']); + await preferences.setValue('Bool', key, kTestValues['flutter.bool']); + await preferences.setValue('Int', key, kTestValues['flutter.int']); + await preferences.setValue('Double', key, kTestValues['flutter.double']); + await preferences.setValue( + 'StringList', key, kTestValues['flutter.List']); await preferences.remove(key); - expect(preferences.get('testKey'), isNull); + final Map values = await preferences.getAll(); + expect(values[key], isNull); }); - test('clearing', () async { - await preferences.setString('String', kTestValues['flutter.String']); - await preferences.setBool('bool', kTestValues['flutter.bool']); - await preferences.setInt('int', kTestValues['flutter.int']); - await preferences.setDouble('double', kTestValues['flutter.double']); - await preferences.setStringList('List', kTestValues['flutter.List']); + testWidgets('clearing', (WidgetTester _) async { + await preferences.setValue( + 'String', 'String', kTestValues['flutter.String']); + await preferences.setValue('Bool', 'bool', kTestValues['flutter.bool']); + await preferences.setValue('Int', 'int', kTestValues['flutter.int']); + await preferences.setValue( + 'Double', 'double', kTestValues['flutter.double']); + await preferences.setValue( + 'StringList', 'List', kTestValues['flutter.List']); await preferences.clear(); - expect(preferences.getString('String'), null); - expect(preferences.getBool('bool'), null); - expect(preferences.getInt('int'), null); - expect(preferences.getDouble('double'), null); - expect(preferences.getStringList('List'), null); + final Map values = await preferences.getAll(); + expect(values['String'], null); + expect(values['bool'], null); + expect(values['int'], null); + expect(values['double'], null); + expect(values['List'], null); }); }); } diff --git a/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart b/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart index 46daeff6706f..f1058cddd63b 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart @@ -7,7 +7,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:shared_preferences/shared_preferences.dart'; +import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; void main() { runApp(MyApp()); @@ -24,22 +24,28 @@ class MyApp extends StatelessWidget { } class SharedPreferencesDemo extends StatefulWidget { - SharedPreferencesDemo({Key key}) : super(key: key); + SharedPreferencesDemo({Key? key}) : super(key: key); @override SharedPreferencesDemoState createState() => SharedPreferencesDemoState(); } class SharedPreferencesDemoState extends State { - Future _prefs = SharedPreferences.getInstance(); - Future _counter; + SharedPreferencesStorePlatform _prefs = + SharedPreferencesStorePlatform.instance; + late Future _counter; + + // Includes the prefix because this is using the platform interface directly, + // but the prefix (which the native code assumes is present) is added by the + // app-facing package. + static const String _prefKey = 'flutter.counter'; Future _incrementCounter() async { - final SharedPreferences prefs = await _prefs; - final int counter = (prefs.getInt('counter') ?? 0) + 1; + final Map values = await _prefs.getAll(); + final int counter = ((values[_prefKey] as int?) ?? 0) + 1; setState(() { - _counter = prefs.setInt("counter", counter).then((bool success) { + _counter = _prefs.setValue('Int', _prefKey, counter).then((bool success) { return counter; }); }); @@ -48,8 +54,8 @@ class SharedPreferencesDemoState extends State { @override void initState() { super.initState(); - _counter = _prefs.then((SharedPreferences prefs) { - return (prefs.getInt('counter') ?? 0); + _counter = _prefs.getAll().then((Map values) { + return (values[_prefKey] as int?) ?? 0; }); } diff --git a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner.xcodeproj/project.pbxproj b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner.xcodeproj/project.pbxproj index a95e62daada1..20c47b4f601f 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner.xcodeproj/project.pbxproj @@ -26,10 +26,6 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; }; - 33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - D73912F022F37F9E000D13A0 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; }; - D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; DD4A1B9DEDBB72C87CD7AE27 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5067D74CB28D28AE3B3DD05B /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ @@ -50,8 +46,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */, - 33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */, ); name = "Bundle Framework"; runOnlyForDeploymentPostprocessing = 0; @@ -70,7 +64,6 @@ 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FlutterMacOS.framework; path = Flutter/ephemeral/FlutterMacOS.framework; sourceTree = SOURCE_ROOT; }; 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; @@ -80,7 +73,6 @@ 899489AD6AA35AECA4E2BEA6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; B36FDC1D769C9045B8821207 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - D73912EF22F37F9E000D13A0 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/ephemeral/App.framework; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -88,8 +80,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D73912F022F37F9E000D13A0 /* App.framework in Frameworks */, - 33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */, DD4A1B9DEDBB72C87CD7AE27 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -145,8 +135,6 @@ 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - D73912EF22F37F9E000D13A0 /* App.framework */, - 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */, ); path = Flutter; sourceTree = ""; @@ -281,7 +269,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename\n"; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; }; 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -308,10 +296,13 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/shared_preferences_macos/shared_preferences_macos.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_macos.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16ed0f..21a3cc14c74e 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml index 5543b4a3b8c2..6a8e7e4b470a 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml @@ -4,7 +4,7 @@ description: Demonstrates how to use the shared_preferences plugin. dependencies: flutter: sdk: flutter - shared_preferences: any + shared_preferences_platform_interface: ^2.0.0-nullsafety shared_preferences_macos: # When depending on this package from a real application you should use: # shared_preferences_macos: ^x.y.z @@ -24,5 +24,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.8" diff --git a/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart index 7a2c21338786..ac106b63b339 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml index 754cf14f18f0..4f014ecb8929 100644 --- a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml @@ -17,5 +17,6 @@ dependencies: shared_preferences_platform_interface: ^2.0.0-nullsafety flutter: sdk: flutter + dev_dependencies: pedantic: ^1.8.0 diff --git a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart index 016a21f70fe3..027daa6eaeb1 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart @@ -2,13 +2,15 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences_windows/shared_preferences_windows.dart'; -import 'package:e2e/e2e.dart'; +import 'package:integration_test/integration_test.dart'; void main() { - E2EWidgetsFlutterBinding.ensureInitialized(); + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('SharedPreferencesWindows', () { const Map kTestValues = { diff --git a/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart b/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart index 140851c90504..f0dc155aee4a 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart @@ -24,7 +24,7 @@ class MyApp extends StatelessWidget { } class SharedPreferencesDemo extends StatefulWidget { - SharedPreferencesDemo({Key key}) : super(key: key); + SharedPreferencesDemo({Key? key}) : super(key: key); @override SharedPreferencesDemoState createState() => SharedPreferencesDemoState(); @@ -32,14 +32,14 @@ class SharedPreferencesDemo extends StatefulWidget { class SharedPreferencesDemoState extends State { final prefs = SharedPreferencesWindows.instance; - Future _counter; + late Future _counter; Future _incrementCounter() async { final values = await prefs.getAll(); - final int counter = (values['counter'] as int ?? 0) + 1; + final int counter = (values['counter'] as int? ?? 0) + 1; setState(() { - _counter = prefs.setValue(null, "counter", counter).then((bool success) { + _counter = prefs.setValue('Int', 'counter', counter).then((bool success) { return counter; }); }); @@ -49,7 +49,7 @@ class SharedPreferencesDemoState extends State { void initState() { super.initState(); _counter = prefs.getAll().then((Map values) { - return (values['counter'] ?? 0); + return (values['counter'] as int? ?? 0); }); } diff --git a/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml index 1af679b4ede3..575e3f8409c6 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml @@ -2,7 +2,8 @@ name: shared_preferences_windows_example description: Demonstrates how to use the shared_preferences_windows plugin. environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" + flutter: ">=1.12.8" dependencies: flutter: @@ -21,7 +22,8 @@ dependency_overrides: dev_dependencies: flutter_driver: sdk: flutter - e2e: ^0.2.0 + integration_test: + path: ../../../integration_test pedantic: ^1.8.0 flutter: diff --git a/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart index 102dfdfef708..353548ee0e8c 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart @@ -2,14 +2,18 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; Future main() async { final FlutterDriver driver = await FlutterDriver.connect(); - final String result = + final String data = await driver.requestData(null, timeout: const Duration(minutes: 1)); await driver.close(); - exit(result == 'pass' ? 0 : 1); + final Map result = jsonDecode(data); + exit(result['result'] == 'true' ? 0 : 1); } From fa95cde0781289ef6918ecc287bfa63d4736bf1f Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Fri, 19 Feb 2021 09:13:19 +0100 Subject: [PATCH 213/924] [video_player_web] Ignore mixWithOthers option (#3561) The documentation is updated to note this option will be silently ignored in web. Signed-off-by: Leandro Lucarella --- packages/video_player/video_player/CHANGELOG.md | 4 ++++ packages/video_player/video_player/README.md | 2 ++ packages/video_player/video_player/pubspec.yaml | 2 +- .../video_player_platform_interface/CHANGELOG.md | 4 ++++ .../lib/video_player_platform_interface.dart | 3 +++ .../video_player_platform_interface/pubspec.yaml | 2 +- packages/video_player/video_player_web/CHANGELOG.md | 4 ++++ packages/video_player/video_player_web/README.md | 4 ++++ .../video_player/video_player_web/lib/video_player_web.dart | 4 ++++ packages/video_player/video_player_web/pubspec.yaml | 2 +- .../video_player_web/test/video_player_web_test.dart | 5 +++++ 11 files changed, 33 insertions(+), 3 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 0cabfc48226d..f79a05f0e036 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.11 + +* Setting the `mixWithOthers` `VideoPlayerOptions` in web now is silently ignored instead of throwing an exception. + ## 2.0.0-nullsafety.10 * Updated to video_player_platform_interface 4.0. diff --git a/packages/video_player/video_player/README.md b/packages/video_player/video_player/README.md index d66dfcdfbd98..7e36008cbbc3 100644 --- a/packages/video_player/video_player/README.md +++ b/packages/video_player/video_player/README.md @@ -48,6 +48,8 @@ This plugin compiles for the web platform since version `0.10.5`, in recent enou Different web browsers may have different video-playback capabilities (supported formats, autoplay...). Check [package:video_player_web](https://pub.dev/packages/video_player_web) for more web-specific information. +The `VideoPlayerOptions.mixWithOthers` option can't be implemented in web, at least at the moment. If you use this option in web it will be silently ignored. + ## Supported Formats - On iOS, the backing player is [AVPlayer](https://developer.apple.com/documentation/avfoundation/avplayer). diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index e21315025005..39289d159195 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -version: 2.0.0-nullsafety.10 +version: 2.0.0-nullsafety.11 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: diff --git a/packages/video_player/video_player_platform_interface/CHANGELOG.md b/packages/video_player/video_player_platform_interface/CHANGELOG.md index 34df33664c68..7b223f4d958c 100644 --- a/packages/video_player/video_player_platform_interface/CHANGELOG.md +++ b/packages/video_player/video_player_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.0.0-nullsafety.1 + +* Add note about the `mixWithOthers` option being ignored on the web. + ## 4.0.0-nullsafety.0 * Update to latest Pigeon. diff --git a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart index f2bc00205acc..77b34f46bc10 100644 --- a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart +++ b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart @@ -346,6 +346,9 @@ class DurationRange { class VideoPlayerOptions { /// Set this to true to mix the video players audio with other audio sources. /// The default value is false + /// + /// Note: This option will be silently ignored in the web platform (there is + /// currently no way to implement this feature in this platform). final bool mixWithOthers; /// set additional optional player settings diff --git a/packages/video_player/video_player_platform_interface/pubspec.yaml b/packages/video_player/video_player_platform_interface/pubspec.yaml index e493eebd800e..ed16ea1033fa 100644 --- a/packages/video_player/video_player_platform_interface/pubspec.yaml +++ b/packages/video_player/video_player_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the video_player plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_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: 4.0.0-nullsafety.0 +version: 4.0.0-nullsafety.1 dependencies: flutter: diff --git a/packages/video_player/video_player_web/CHANGELOG.md b/packages/video_player/video_player_web/CHANGELOG.md index 7b3fc7871628..4c58311508a2 100644 --- a/packages/video_player/video_player_web/CHANGELOG.md +++ b/packages/video_player/video_player_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.4 + +* Calling `setMixWithOthers()` now is silently ignored instead of throwing an exception. + ## 2.0.0-nullsafety.3 * Updated to video_player_platform_interface 4.0. diff --git a/packages/video_player/video_player_web/README.md b/packages/video_player/video_player_web/README.md index 4f222be914eb..d44f738aeb66 100644 --- a/packages/video_player/video_player_web/README.md +++ b/packages/video_player/video_player_web/README.md @@ -28,6 +28,10 @@ The Web platform does **not** suppport `dart:io`, so attempts to create a `Video Playing videos without prior interaction with the site might be prohibited by the browser and lead to runtime errors. See also: https://goo.gl/xX8pDD. +## Mixing audio with other audio sources + +The `VideoPlayerOptions.mixWithOthers` option can't be implemented in web, at least at the moment. If you use this option it will be silently ignored. + ## Supported Formats **Different web browsers support different sets of video codecs.** diff --git a/packages/video_player/video_player_web/lib/video_player_web.dart b/packages/video_player/video_player_web/lib/video_player_web.dart index 9132a08437da..18f9e5e58cd6 100644 --- a/packages/video_player/video_player_web/lib/video_player_web.dart +++ b/packages/video_player/video_player_web/lib/video_player_web.dart @@ -144,6 +144,10 @@ class VideoPlayerPlugin extends VideoPlayerPlatform { Widget buildView(int textureId) { return HtmlElementView(viewType: 'videoPlayer-$textureId'); } + + /// Sets the audio mode to mix with other sources (ignored) + @override + Future setMixWithOthers(bool mixWithOthers) => Future.value(); } class _VideoPlayer { diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml index df5f4564bf4a..d9628535e353 100644 --- a/packages/video_player/video_player_web/pubspec.yaml +++ b/packages/video_player/video_player_web/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player_web description: Web platform implementation of video_player. homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_web -version: 2.0.0-nullsafety.3 +version: 2.0.0-nullsafety.4 flutter: plugin: diff --git a/packages/video_player/video_player_web/test/video_player_web_test.dart b/packages/video_player/video_player_web/test/video_player_web_test.dart index 94b788872b03..604bebf4e17a 100644 --- a/packages/video_player/video_player_web/test/video_player_web_test.dart +++ b/packages/video_player/video_player_web/test/video_player_web_test.dart @@ -136,5 +136,10 @@ void main() { expect(VideoPlayerPlatform.instance.buildView(textureId), isInstanceOf()); }); + + test('ignores setting mixWithOthers', () { + expect(VideoPlayerPlatform.instance.setMixWithOthers(true), completes); + expect(VideoPlayerPlatform.instance.setMixWithOthers(false), completes); + }); }); } From 982e1ca54bac31572b9c43897eec39e24f818dc5 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Feb 2021 07:29:09 -0800 Subject: [PATCH 214/924] [path_provider] Migrate examples to null-safety (#3559) Allows running the examples in strong mode, even though the integration tests can't yet be. Converts the macOS example to use the platform interface, rather than the app-facing package, to eliminate the circular dependency. Also does some cleanup and simplification of the desktop example pubspecs. Does not update versions/changelogs since this won't be explicitly published, given that it's example-only. --- .../integration_test/path_provider_test.dart | 2 + .../path_provider/example/lib/main.dart | 38 ++-- .../path_provider/example/pubspec.yaml | 2 +- .../example/test_driver/integration_test.dart | 2 + .../integration_test/path_provider_test.dart | 2 + .../path_provider_linux/example/lib/main.dart | 18 +- .../path_provider_linux/example/pubspec.yaml | 44 +---- .../example/test/widget_test.dart | 8 +- .../example/test_driver/integration_test.dart | 2 + .../integration_test/path_provider_test.dart | 36 ++-- .../path_provider_macos/example/lib/main.dart | 170 ++++++------------ .../macos/Runner.xcodeproj/project.pbxproj | 21 +-- .../macos/Runner/DebugProfile.entitlements | 2 + .../example/macos/Runner/Release.entitlements | 2 + .../path_provider_macos/example/pubspec.yaml | 8 +- .../example/test_driver/integration_test.dart | 2 + .../integration_test/path_provider_test.dart | 6 +- .../example/lib/main.dart | 18 +- .../example/pubspec.yaml | 8 +- .../example/test_driver/integration_test.dart | 8 +- .../path_provider_windows/pubspec.yaml | 2 +- 21 files changed, 162 insertions(+), 239 deletions(-) diff --git a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart index 8eb8520b5b4b..2b12c82f959b 100644 --- a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; import 'dart:io'; diff --git a/packages/path_provider/path_provider/example/lib/main.dart b/packages/path_provider/path_provider/example/lib/main.dart index 8e929a6882fe..ddc1f8a6e2d5 100644 --- a/packages/path_provider/path_provider/example/lib/main.dart +++ b/packages/path_provider/path_provider/example/lib/main.dart @@ -28,7 +28,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override @@ -36,13 +36,13 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - Future _tempDirectory; - Future _appSupportDirectory; - Future _appLibraryDirectory; - Future _appDocumentsDirectory; - Future _externalDocumentsDirectory; - Future> _externalStorageDirectories; - Future> _externalCacheDirectories; + Future? _tempDirectory; + Future? _appSupportDirectory; + Future? _appLibraryDirectory; + Future? _appDocumentsDirectory; + Future? _externalDocumentsDirectory; + Future?>? _externalStorageDirectories; + Future?>? _externalCacheDirectories; void _requestTempDirectory() { setState(() { @@ -51,13 +51,13 @@ class _MyHomePageState extends State { } Widget _buildDirectory( - BuildContext context, AsyncSnapshot snapshot) { + BuildContext context, AsyncSnapshot snapshot) { Text text = const Text(''); if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasError) { text = Text('Error: ${snapshot.error}'); } else if (snapshot.hasData) { - text = Text('path: ${snapshot.data.path}'); + text = Text('path: ${snapshot.data!.path}'); } else { text = const Text('path unavailable'); } @@ -66,14 +66,14 @@ class _MyHomePageState extends State { } Widget _buildDirectories( - BuildContext context, AsyncSnapshot> snapshot) { + BuildContext context, AsyncSnapshot?> snapshot) { Text text = const Text(''); if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasError) { text = Text('Error: ${snapshot.error}'); } else if (snapshot.hasData) { final String combined = - snapshot.data.map((Directory d) => d.path).join(', '); + snapshot.data!.map((Directory d) => d.path).join(', '); text = Text('paths: $combined'); } else { text = const Text('path unavailable'); @@ -134,7 +134,7 @@ class _MyHomePageState extends State { onPressed: _requestTempDirectory, ), ), - FutureBuilder( + FutureBuilder( future: _tempDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), @@ -143,7 +143,7 @@ class _MyHomePageState extends State { onPressed: _requestAppDocumentsDirectory, ), ), - FutureBuilder( + FutureBuilder( future: _appDocumentsDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), @@ -152,7 +152,7 @@ class _MyHomePageState extends State { onPressed: _requestAppSupportDirectory, ), ), - FutureBuilder( + FutureBuilder( future: _appSupportDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), @@ -161,7 +161,7 @@ class _MyHomePageState extends State { onPressed: _requestAppLibraryDirectory, ), ), - FutureBuilder( + FutureBuilder( future: _appLibraryDirectory, builder: _buildDirectory), Padding( padding: const EdgeInsets.all(16.0), @@ -172,7 +172,7 @@ class _MyHomePageState extends State { Platform.isIOS ? null : _requestExternalStorageDirectory, ), ), - FutureBuilder( + FutureBuilder( future: _externalDocumentsDirectory, builder: _buildDirectory), Column(children: [ Padding( @@ -190,7 +190,7 @@ class _MyHomePageState extends State { ), ), ]), - FutureBuilder>( + FutureBuilder?>( future: _externalStorageDirectories, builder: _buildDirectories), Column(children: [ @@ -204,7 +204,7 @@ class _MyHomePageState extends State { ), ), ]), - FutureBuilder>( + FutureBuilder?>( future: _externalCacheDirectories, builder: _buildDirectories), ], ), diff --git a/packages/path_provider/path_provider/example/pubspec.yaml b/packages/path_provider/path_provider/example/pubspec.yaml index bbb140e8f4bf..cef0449ca01a 100644 --- a/packages/path_provider/path_provider/example/pubspec.yaml +++ b/packages/path_provider/path_provider/example/pubspec.yaml @@ -23,5 +23,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/path_provider/path_provider/example/test_driver/integration_test.dart b/packages/path_provider/path_provider/example/test_driver/integration_test.dart index 7a2c21338786..ac106b63b339 100644 --- a/packages/path_provider/path_provider/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart index febd52172759..d08b3878a4d5 100644 --- a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:path_provider_linux/path_provider_linux.dart'; diff --git a/packages/path_provider/path_provider_linux/example/lib/main.dart b/packages/path_provider/path_provider_linux/example/lib/main.dart index 069308233acb..6958ed10cb23 100644 --- a/packages/path_provider/path_provider_linux/example/lib/main.dart +++ b/packages/path_provider/path_provider_linux/example/lib/main.dart @@ -4,7 +4,7 @@ import 'dart:async'; import 'package:flutter/services.dart'; import 'package:path_provider_linux/path_provider_linux.dart'; -void main() async { +void main() { runApp(MyApp()); } @@ -15,10 +15,10 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - String _tempDirectory = 'Unknown'; - String _downloadsDirectory = 'Unknown'; - String _appSupportDirectory = 'Unknown'; - String _documentsDirectory = 'Unknown'; + String? _tempDirectory = 'Unknown'; + String? _downloadsDirectory = 'Unknown'; + String? _appSupportDirectory = 'Unknown'; + String? _documentsDirectory = 'Unknown'; final PathProviderLinux _provider = PathProviderLinux(); @override @@ -29,10 +29,10 @@ class _MyAppState extends State { // Platform messages are asynchronous, so we initialize in an async method. Future initDirectories() async { - String tempDirectory; - String downloadsDirectory; - String appSupportDirectory; - String documentsDirectory; + String? tempDirectory; + String? downloadsDirectory; + String? appSupportDirectory; + String? documentsDirectory; // Platform messages may fail, so we use a try/catch PlatformException. try { tempDirectory = await _provider.getTemporaryPath(); diff --git a/packages/path_provider/path_provider_linux/example/pubspec.yaml b/packages/path_provider/path_provider_linux/example/pubspec.yaml index a1a9dde163cf..1fd55712ee44 100644 --- a/packages/path_provider/path_provider_linux/example/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/example/pubspec.yaml @@ -3,19 +3,13 @@ description: Demonstrates how to use the path_provider_linux plugin. publish_to: "none" environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" + flutter: ">=1.10.0" dependencies: flutter: sdk: flutter - path_provider_linux: any - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.3 - -dependency_overrides: path_provider_linux: # When depending on this package from a real application you should use: # path_provider_linux: ^x.y.z @@ -32,39 +26,5 @@ dev_dependencies: integration_test: path: ../../../integration_test -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/path_provider/path_provider_linux/example/test/widget_test.dart b/packages/path_provider/path_provider_linux/example/test/widget_test.dart index 8ebda3b77176..086b6d614e13 100644 --- a/packages/path_provider/path_provider_linux/example/test/widget_test.dart +++ b/packages/path_provider/path_provider_linux/example/test/widget_test.dart @@ -30,7 +30,7 @@ void main() { find.byWidgetPredicate( (Widget widget) => widget is Text && - widget.data.startsWith('Temp Directory: /tmp'), + widget.data!.startsWith('Temp Directory: /tmp'), ), findsOneWidget, ); @@ -48,7 +48,7 @@ void main() { find.byWidgetPredicate( (Widget widget) => widget is Text && - widget.data.startsWith('Documents Directory: /'), + widget.data!.startsWith('Documents Directory: /'), ), findsOneWidget, ); @@ -66,7 +66,7 @@ void main() { find.byWidgetPredicate( (Widget widget) => widget is Text && - widget.data.startsWith('Downloads Directory: /'), + widget.data!.startsWith('Downloads Directory: /'), ), findsOneWidget, ); @@ -85,7 +85,7 @@ void main() { find.byWidgetPredicate( (Widget widget) => widget is Text && - widget.data.startsWith('Application Support Directory: /'), + widget.data!.startsWith('Application Support Directory: /'), ), findsOneWidget, ); diff --git a/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart index 7a2c21338786..ac106b63b339 100644 --- a/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart index 58a4d1805cb0..1bb079051cfc 100644 --- a/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart @@ -2,42 +2,56 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; -import 'package:path_provider/path_provider.dart'; +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; import 'package:integration_test/integration_test.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('getTemporaryDirectory', (WidgetTester tester) async { - final Directory result = await getTemporaryDirectory(); + final PathProviderPlatform provider = PathProviderPlatform.instance; + final String result = await provider.getTemporaryPath(); _verifySampleFile(result, 'temporaryDirectory'); }); testWidgets('getApplicationDocumentsDirectory', (WidgetTester tester) async { - final Directory result = await getApplicationDocumentsDirectory(); + final PathProviderPlatform provider = PathProviderPlatform.instance; + final String result = await provider.getApplicationDocumentsPath(); _verifySampleFile(result, 'applicationDocuments'); }); testWidgets('getApplicationSupportDirectory', (WidgetTester tester) async { - final Directory result = await getApplicationSupportDirectory(); + final PathProviderPlatform provider = PathProviderPlatform.instance; + final String result = await provider.getApplicationSupportPath(); _verifySampleFile(result, 'applicationSupport'); }); testWidgets('getLibraryDirectory', (WidgetTester tester) async { - if (!Platform.isMacOS) { - return; - } - final Directory result = await getLibraryDirectory(); + final PathProviderPlatform provider = PathProviderPlatform.instance; + final String result = await provider.getLibraryPath(); _verifySampleFile(result, 'library'); }); + + testWidgets('getDownloadsDirectory', (WidgetTester tester) async { + final PathProviderPlatform provider = PathProviderPlatform.instance; + final String result = await provider.getDownloadsPath(); + // _verifySampleFile causes hangs in driver for some reason, so just + // validate that a non-empty path was returned. + expect(result, isNotEmpty); + }); } -/// Verify a file called [name] in [directory] by recreating it with test +/// Verify a file called [name] in [directoryPath] by recreating it with test /// contents when necessary. -void _verifySampleFile(Directory directory, String name) { - final File file = File('${directory.path}/$name'); +/// +/// If [createDirectory] is true, the directory will be created if missing. +void _verifySampleFile(String directoryPath, String name) { + final Directory directory = Directory(directoryPath); + final File file = File('${directory.path}${Platform.pathSeparator}$name'); if (file.existsSync()) { file.deleteSync(); diff --git a/packages/path_provider/path_provider_macos/example/lib/main.dart b/packages/path_provider/path_provider_macos/example/lib/main.dart index 1c1c90b983c3..f19807f1c273 100644 --- a/packages/path_provider/path_provider_macos/example/lib/main.dart +++ b/packages/path_provider/path_provider_macos/example/lib/main.dart @@ -5,143 +5,87 @@ // ignore_for_file: public_member_api_docs import 'dart:async'; -import 'dart:io' show Directory; import 'package:flutter/material.dart'; -import 'package:path_provider/path_provider.dart'; +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; void main() { runApp(MyApp()); } -class MyApp extends StatelessWidget { +/// Sample app +class MyApp extends StatefulWidget { @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Path Provider', - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: MyHomePage(title: 'Path Provider'), - ); - } + _MyAppState createState() => _MyAppState(); } -class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); - final String title; +class _MyAppState extends State { + String? _tempDirectory = 'Unknown'; + String? _downloadsDirectory = 'Unknown'; + String? _appSupportDirectory = 'Unknown'; + String? _documentsDirectory = 'Unknown'; @override - _MyHomePageState createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - Future _tempDirectory; - Future _appSupportDirectory; - Future _appDocumentsDirectory; - Future _appLibraryDirectory; - Future _downloadsDirectory; - - void _requestTempDirectory() { - setState(() { - _tempDirectory = getTemporaryDirectory(); - }); + void initState() { + super.initState(); + initDirectories(); } - Widget _buildDirectory( - BuildContext context, AsyncSnapshot snapshot) { - Text text = const Text(''); - if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.hasError) { - text = Text('Error: ${snapshot.error}'); - } else if (snapshot.hasData) { - text = Text('path: ${snapshot.data.path}'); - } else { - text = const Text('path unavailable'); - } - } - return Padding(padding: const EdgeInsets.all(16.0), child: text); - } + // Platform messages are asynchronous, so we initialize in an async method. + Future initDirectories() async { + String? tempDirectory; + String? downloadsDirectory; + String? appSupportDirectory; + String? documentsDirectory; + final PathProviderPlatform provider = PathProviderPlatform.instance; - void _requestAppDocumentsDirectory() { - setState(() { - _appDocumentsDirectory = getApplicationDocumentsDirectory(); - }); - } + try { + tempDirectory = await provider.getTemporaryPath(); + } catch (exception) { + tempDirectory = 'Failed to get temp directory: $exception'; + } + try { + downloadsDirectory = await provider.getDownloadsPath(); + } catch (exception) { + downloadsDirectory = 'Failed to get downloads directory: $exception'; + } - void _requestAppSupportDirectory() { - setState(() { - _appSupportDirectory = getApplicationSupportDirectory(); - }); - } + try { + documentsDirectory = await provider.getApplicationDocumentsPath(); + } catch (exception) { + documentsDirectory = 'Failed to get documents directory: $exception'; + } - void _requestAppLibraryDirectory() { - setState(() { - _appLibraryDirectory = getLibraryDirectory(); - }); - } + try { + appSupportDirectory = await provider.getApplicationSupportPath(); + } catch (exception) { + appSupportDirectory = 'Failed to get app support directory: $exception'; + } - void _requestDownloadsDirectory() { setState(() { - _downloadsDirectory = getDownloadsDirectory(); + _tempDirectory = tempDirectory; + _downloadsDirectory = downloadsDirectory; + _appSupportDirectory = appSupportDirectory; + _documentsDirectory = documentsDirectory; }); } @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: ListView( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: ElevatedButton( - child: const Text('Get Temporary Directory'), - onPressed: _requestTempDirectory, - ), - ), - FutureBuilder( - future: _tempDirectory, builder: _buildDirectory), - Padding( - padding: const EdgeInsets.all(16.0), - child: ElevatedButton( - child: const Text('Get Application Documents Directory'), - onPressed: _requestAppDocumentsDirectory, - ), - ), - FutureBuilder( - future: _appDocumentsDirectory, builder: _buildDirectory), - Padding( - padding: const EdgeInsets.all(16.0), - child: ElevatedButton( - child: const Text('Get Application Support Directory'), - onPressed: _requestAppSupportDirectory, - ), - ), - FutureBuilder( - future: _appSupportDirectory, builder: _buildDirectory), - Padding( - padding: const EdgeInsets.all(16.0), - child: ElevatedButton( - child: const Text('Get Application Library Directory'), - onPressed: _requestAppLibraryDirectory, - ), - ), - FutureBuilder( - future: _appLibraryDirectory, builder: _buildDirectory), - Padding( - padding: const EdgeInsets.all(16.0), - child: ElevatedButton( - child: const Text('Get Downlads Directory'), - onPressed: _requestDownloadsDirectory, - ), - ), - FutureBuilder( - future: _downloadsDirectory, builder: _buildDirectory), - ], + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Path Provider example app'), + ), + body: Center( + child: Column( + children: [ + Text('Temp Directory: $_tempDirectory\n'), + Text('Documents Directory: $_documentsDirectory\n'), + Text('Downloads Directory: $_downloadsDirectory\n'), + Text('Application Support Directory: $_appSupportDirectory\n'), + ], + ), ), ), ); diff --git a/packages/path_provider/path_provider_macos/example/macos/Runner.xcodeproj/project.pbxproj b/packages/path_provider/path_provider_macos/example/macos/Runner.xcodeproj/project.pbxproj index 1e39683e1446..51bfc333fa23 100644 --- a/packages/path_provider/path_provider_macos/example/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/path_provider/path_provider_macos/example/macos/Runner.xcodeproj/project.pbxproj @@ -27,10 +27,6 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; }; - 33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - D73912F022F37F9E000D13A0 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; }; - D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -50,8 +46,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */, - 33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */, ); name = "Bundle Framework"; runOnlyForDeploymentPostprocessing = 0; @@ -72,14 +66,12 @@ 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FlutterMacOS.framework; path = Flutter/ephemeral/FlutterMacOS.framework; sourceTree = SOURCE_ROOT; }; 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 46139048DB9F59D473B61B5E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - D73912EF22F37F9E000D13A0 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/ephemeral/App.framework; sourceTree = SOURCE_ROOT; }; F4586DA69948E3A954A2FC9C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -88,8 +80,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D73912F022F37F9E000D13A0 /* App.framework in Frameworks */, - 33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */, 23F6FAA3AF82DFCF2B7DD79A /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -156,8 +146,6 @@ 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - D73912EF22F37F9E000D13A0 /* App.framework */, - 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */, ); path = Flutter; sourceTree = ""; @@ -281,7 +269,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename\n"; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; }; 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -308,10 +296,13 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/path_provider_macos/path_provider_macos.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_macos.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/packages/path_provider/path_provider_macos/example/macos/Runner/DebugProfile.entitlements b/packages/path_provider/path_provider_macos/example/macos/Runner/DebugProfile.entitlements index dddb8a30c851..8139952b3e55 100644 --- a/packages/path_provider/path_provider_macos/example/macos/Runner/DebugProfile.entitlements +++ b/packages/path_provider/path_provider_macos/example/macos/Runner/DebugProfile.entitlements @@ -8,5 +8,7 @@ com.apple.security.network.server + com.apple.security.files.downloads.read-write + diff --git a/packages/path_provider/path_provider_macos/example/macos/Runner/Release.entitlements b/packages/path_provider/path_provider_macos/example/macos/Runner/Release.entitlements index 852fa1a4728a..2f9659c917fb 100644 --- a/packages/path_provider/path_provider_macos/example/macos/Runner/Release.entitlements +++ b/packages/path_provider/path_provider_macos/example/macos/Runner/Release.entitlements @@ -4,5 +4,7 @@ com.apple.security.app-sandbox + com.apple.security.files.downloads.read-write + diff --git a/packages/path_provider/path_provider_macos/example/pubspec.yaml b/packages/path_provider/path_provider_macos/example/pubspec.yaml index cb904fa5ea98..495459319ca4 100644 --- a/packages/path_provider/path_provider_macos/example/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/example/pubspec.yaml @@ -4,11 +4,6 @@ description: Demonstrates how to use the path_provider plugin. dependencies: flutter: sdk: flutter - path_provider: ^1.6.14 - -# path_provider_macos is endorsed, so we need to add it to dependency_overrides -# to depend on it from path: -dependency_overrides: path_provider_macos: # When depending on this package from a real application you should use: # path_provider_macos: ^x.y.z @@ -16,6 +11,7 @@ dependency_overrides: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ + path_provider_platform_interface: 2.0.0-nullsafety dev_dependencies: integration_test: @@ -28,5 +24,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.10.0" diff --git a/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart index 7a2c21338786..ac106b63b339 100644 --- a/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart index ee9427686026..0953fc100950 100644 --- a/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart @@ -2,13 +2,15 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:path_provider_windows/path_provider_windows.dart'; -import 'package:e2e/e2e.dart'; +import 'package:integration_test/integration_test.dart'; void main() { - E2EWidgetsFlutterBinding.ensureInitialized(); + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('getTemporaryDirectory', (WidgetTester tester) async { final PathProviderWindows provider = PathProviderWindows(); diff --git a/packages/path_provider/path_provider_windows/example/lib/main.dart b/packages/path_provider/path_provider_windows/example/lib/main.dart index 4fbb1decf2f4..964ef3d04db1 100644 --- a/packages/path_provider/path_provider_windows/example/lib/main.dart +++ b/packages/path_provider/path_provider_windows/example/lib/main.dart @@ -9,7 +9,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:path_provider_windows/path_provider_windows.dart'; -void main() async { +void main() { runApp(MyApp()); } @@ -20,10 +20,10 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - String _tempDirectory = 'Unknown'; - String _downloadsDirectory = 'Unknown'; - String _appSupportDirectory = 'Unknown'; - String _documentsDirectory = 'Unknown'; + String? _tempDirectory = 'Unknown'; + String? _downloadsDirectory = 'Unknown'; + String? _appSupportDirectory = 'Unknown'; + String? _documentsDirectory = 'Unknown'; @override void initState() { @@ -33,10 +33,10 @@ class _MyAppState extends State { // Platform messages are asynchronous, so we initialize in an async method. Future initDirectories() async { - String tempDirectory; - String downloadsDirectory; - String appSupportDirectory; - String documentsDirectory; + String? tempDirectory; + String? downloadsDirectory; + String? appSupportDirectory; + String? documentsDirectory; final PathProviderWindows provider = PathProviderWindows(); try { diff --git a/packages/path_provider/path_provider_windows/example/pubspec.yaml b/packages/path_provider/path_provider_windows/example/pubspec.yaml index 7a34d90c0f6c..5704502528f7 100644 --- a/packages/path_provider/path_provider_windows/example/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/example/pubspec.yaml @@ -4,9 +4,6 @@ description: Demonstrates how to use the path_provider plugin. dependencies: flutter: sdk: flutter - path_provider_windows: any - -dependency_overrides: path_provider_windows: # When depending on this package from a real application you should use: # path_provider_windows: ^x.y.z @@ -16,7 +13,8 @@ dependency_overrides: path: ../ dev_dependencies: - e2e: ^0.2.1 + integration_test: + path: ../../../integration_test flutter_driver: sdk: flutter pedantic: ^1.8.0 @@ -25,5 +23,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.4" diff --git a/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart index f3aa9e218d82..ac106b63b339 100644 --- a/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart @@ -2,14 +2,18 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; Future main() async { final FlutterDriver driver = await FlutterDriver.connect(); - final String result = + final String data = await driver.requestData(null, timeout: const Duration(minutes: 1)); await driver.close(); - exit(result == 'pass' ? 0 : 1); + final Map result = jsonDecode(data); + exit(result['result'] == 'true' ? 0 : 1); } diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index 384eae94f5e5..eb7d1087d5f5 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -25,5 +25,5 @@ dev_dependencies: pedantic: ^1.10.0-nullsafety.3 environment: - sdk: '>=2.12.0-259.8.beta <3.0.0' + sdk: ">=2.12.0-0 <3.0.0" flutter: ">=1.12.13+hotfix.4" From e8b38f6e03d1fea2746669c6e654714eca582b6e Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Fri, 19 Feb 2021 11:13:29 -0800 Subject: [PATCH 215/924] [image_picker_for_web] Add doc comments to point out that some arguments aren't supported on the web (#3566) Re-landing a PR that @ditman messed up! https://github.com/flutter/plugins/pull/3566 Co-authored-by: Jens Becker Co-authored-by: Chris Yang --- .../image_picker_for_web/CHANGELOG.md | 4 ++++ .../image_picker_for_web/README.md | 8 ++++++- .../lib/image_picker_for_web.dart | 24 +++++++++++++++++++ .../image_picker_for_web/pubspec.yaml | 2 +- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md index 37b17b3eef26..fcc6c9980c29 100644 --- a/packages/image_picker/image_picker_for_web/CHANGELOG.md +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 2.0.0-nullsafety.1 + +* Add doc comments to point out that some arguments aren't supported on the web. + # 2.0.0-nullsafety * Migrate to null safety. diff --git a/packages/image_picker/image_picker_for_web/README.md b/packages/image_picker/image_picker_for_web/README.md index 81452e290984..074053c9b956 100644 --- a/packages/image_picker/image_picker_for_web/README.md +++ b/packages/image_picker/image_picker_for_web/README.md @@ -2,7 +2,7 @@ A web implementation of [`image_picker`][1]. -## Browser Support +## Limitations on the web platform Since Web Browsers don't offer direct access to their users' file system, this plugin provides a `PickedFile` abstraction to make access access uniform @@ -42,6 +42,12 @@ In order to "take a photo", some mobile browsers offer a [`capture` attribute](h Each browser may implement `capture` any way they please, so it may (or may not) make a difference in your users' experience. +### pickImage() +The arguments `maxWidth`, `maxHeight` and `imageQuality` are not supported on the web. + +### pickVideo() +The argument `maxDuration` is not supported on the web. + ## Usage ### Import the package diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index 0c05980172aa..05afd2e54a4c 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -30,6 +30,18 @@ class ImagePickerPlugin extends ImagePickerPlatform { ImagePickerPlatform.instance = ImagePickerPlugin(); } + /// Returns a [PickedFile] with the image that was picked. + /// + /// The `source` argument controls where the image comes from. This can + /// be either [ImageSource.camera] or [ImageSource.gallery]. + /// + /// Note that the `maxWidth`, `maxHeight` and `imageQuality` arguments are not supported on the web. If any of these arguments is supplied, it'll be silently ignored by the web version of the plugin. + /// + /// 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]. + /// + /// If no images were picked, the return value is null. @override Future pickImage({ required ImageSource source, @@ -42,6 +54,18 @@ class ImagePickerPlugin extends ImagePickerPlatform { return pickFile(accept: _kAcceptImageMimeType, capture: capture); } + /// Returns a [PickedFile] containing the video that was picked. + /// + /// The [source] argument controls where the video comes from. This can + /// be either [ImageSource.camera] or [ImageSource.gallery]. + /// + /// Note that the `maxDuration` argument is not supported on the web. If the argument is supplied, it'll be silently ignored by the web version of the plugin. + /// + /// 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]. + /// + /// If no images were picked, the return value is null. @override Future pickVideo({ required ImageSource source, diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index c270cd597c87..adc636192c69 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_for_web description: Web platform implementation of image_picker homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_for_web -version: 2.0.0-nullsafety +version: 2.0.0-nullsafety.1 flutter: plugin: From 849f25818d67e4a2f43682e9d747f9e94f8ae584 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Feb 2021 11:18:32 -0800 Subject: [PATCH 216/924] [google_maps_flutter] Migrate to NNBD (#3548) Migrates the full plugin to null safety. --- .../google_maps_flutter/CHANGELOG.md | 8 + .../google_map_inspector.dart | 1 + .../integration_test/google_maps_test.dart | 7 +- .../example/lib/animate_camera.dart | 22 +- .../example/lib/map_click.dart | 6 +- .../example/lib/map_coordinates.dart | 4 +- .../example/lib/map_ui.dart | 7 +- .../example/lib/marker_icons.dart | 26 +- .../example/lib/move_camera.dart | 22 +- .../example/lib/padding.dart | 10 +- .../example/lib/place_circle.dart | 60 ++-- .../example/lib/place_marker.dart | 130 ++++---- .../example/lib/place_polygon.dart | 96 +++--- .../example/lib/place_polyline.dart | 103 ++++--- .../example/lib/scrolling_map.dart | 50 ++-- .../example/lib/snapshot.dart | 6 +- .../example/lib/tile_overlay.dart | 16 +- .../google_maps_flutter/example/pubspec.yaml | 4 +- .../example/test_driver/integration_test.dart | 1 + .../lib/src/controller.dart | 111 +++---- .../lib/src/google_map.dart | 277 +++++++++-------- .../google_maps_flutter/pubspec.yaml | 16 +- .../test/android_google_map_test.dart | 2 +- .../test/circle_updates_test.dart | 68 ++--- .../test/fake_maps_controllers.dart | 196 +++++------- .../test/google_map_test.dart | 38 +-- .../test/map_creation_test.dart | 278 ++++++++++++++---- .../test/marker_updates_test.dart | 68 ++--- .../test/polygon_updates_test.dart | 118 ++++---- .../test/polyline_updates_test.dart | 78 ++--- .../test/tile_overlay_updates_test.dart | 62 ++-- script/nnbd_plugins.sh | 2 +- 32 files changed, 1003 insertions(+), 890 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index fd73ad6ca0eb..549aa4e06f3c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.0.0-nullsafety + +* Migrate to null-safety +* BREAKING CHANGE: Passing an unknown map object ID (e.g., MarkerId) to a + method, it will throw an `UnknownMapObjectIDError`. Previously it would + either silently do nothing, or throw an error trying to call a function on + `null`, depneding on the method. + ## 1.2.0 * Support custom tiles. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart index 0f2dafb80f70..a5025590d72a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart @@ -1,6 +1,7 @@ // Copyright 2019, the Chromium project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 import 'dart:typed_data'; import 'package:flutter/services.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart index 557337f0c025..01b0c9b03e68 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart @@ -1,6 +1,7 @@ // Copyright 2019, the Chromium project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 import 'dart:async'; import 'dart:io'; @@ -954,10 +955,8 @@ void main() { final BitmapDescriptor scaled = await BitmapDescriptor.fromAssetImage( imageConfiguration, 'red_square.png', mipmaps: false); - // ignore: invalid_use_of_visible_for_testing_member - expect(mip.toJson()[2], 1); - // ignore: invalid_use_of_visible_for_testing_member - expect(scaled.toJson()[2], 2); + expect((mip.toJson() as List)[2], 1); + expect((scaled.toJson() as List)[2], 2); }); testWidgets('testTakeSnapshot', (WidgetTester tester) async { diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart index ae5e9f6cee3a..f6a2fecf5b0d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart @@ -26,7 +26,7 @@ class AnimateCamera extends StatefulWidget { } class AnimateCameraState extends State { - GoogleMapController mapController; + GoogleMapController? mapController; void _onMapCreated(GoogleMapController controller) { mapController = controller; @@ -56,7 +56,7 @@ class AnimateCameraState extends State { children: [ TextButton( onPressed: () { - mapController.animateCamera( + mapController?.animateCamera( CameraUpdate.newCameraPosition( const CameraPosition( bearing: 270.0, @@ -71,7 +71,7 @@ class AnimateCameraState extends State { ), TextButton( onPressed: () { - mapController.animateCamera( + mapController?.animateCamera( CameraUpdate.newLatLng( const LatLng(56.1725505, 10.1850512), ), @@ -81,7 +81,7 @@ class AnimateCameraState extends State { ), TextButton( onPressed: () { - mapController.animateCamera( + mapController?.animateCamera( CameraUpdate.newLatLngBounds( LatLngBounds( southwest: const LatLng(-38.483935, 113.248673), @@ -95,7 +95,7 @@ class AnimateCameraState extends State { ), TextButton( onPressed: () { - mapController.animateCamera( + mapController?.animateCamera( CameraUpdate.newLatLngZoom( const LatLng(37.4231613, -122.087159), 11.0, @@ -106,7 +106,7 @@ class AnimateCameraState extends State { ), TextButton( onPressed: () { - mapController.animateCamera( + mapController?.animateCamera( CameraUpdate.scrollBy(150.0, -225.0), ); }, @@ -118,7 +118,7 @@ class AnimateCameraState extends State { children: [ TextButton( onPressed: () { - mapController.animateCamera( + mapController?.animateCamera( CameraUpdate.zoomBy( -0.5, const Offset(30.0, 20.0), @@ -129,7 +129,7 @@ class AnimateCameraState extends State { ), TextButton( onPressed: () { - mapController.animateCamera( + mapController?.animateCamera( CameraUpdate.zoomBy(-0.5), ); }, @@ -137,7 +137,7 @@ class AnimateCameraState extends State { ), TextButton( onPressed: () { - mapController.animateCamera( + mapController?.animateCamera( CameraUpdate.zoomIn(), ); }, @@ -145,7 +145,7 @@ class AnimateCameraState extends State { ), TextButton( onPressed: () { - mapController.animateCamera( + mapController?.animateCamera( CameraUpdate.zoomOut(), ); }, @@ -153,7 +153,7 @@ class AnimateCameraState extends State { ), TextButton( onPressed: () { - mapController.animateCamera( + mapController?.animateCamera( CameraUpdate.zoomTo(16.0), ); }, diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart index 029d3a1f187e..eaeb463e1b33 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart @@ -31,9 +31,9 @@ class _MapClickBody extends StatefulWidget { class _MapClickBodyState extends State<_MapClickBody> { _MapClickBodyState(); - GoogleMapController mapController; - LatLng _lastTap; - LatLng _lastLongPress; + GoogleMapController? mapController; + LatLng? _lastTap; + LatLng? _lastLongPress; @override Widget build(BuildContext context) { diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart index f194f8cb3f3b..20cccd6b61fd 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart @@ -31,7 +31,7 @@ class _MapCoordinatesBody extends StatefulWidget { class _MapCoordinatesBodyState extends State<_MapCoordinatesBody> { _MapCoordinatesBodyState(); - GoogleMapController mapController; + GoogleMapController? mapController; LatLngBounds _visibleRegion = LatLngBounds( southwest: const LatLng(0, 0), northeast: const LatLng(0, 0), @@ -87,7 +87,7 @@ class _MapCoordinatesBodyState extends State<_MapCoordinatesBody> { child: const Text('Get Visible Region Bounds'), onPressed: () async { final LatLngBounds visibleRegion = - await mapController.getVisibleRegion(); + await mapController!.getVisibleRegion(); setState(() { _visibleRegion = visibleRegion; }); diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart index 61a62ac0cf6d..edae82e4074c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart @@ -56,7 +56,7 @@ class MapUiBodyState extends State { bool _myLocationEnabled = true; bool _myTrafficEnabled = false; bool _myLocationButtonEnabled = true; - GoogleMapController _controller; + late GoogleMapController _controller; bool _nightMode = false; @override @@ -249,10 +249,9 @@ class MapUiBodyState extends State { }); } + // Should only be called if _isMapCreated is true. Widget _nightModeToggler() { - if (!_isMapCreated) { - return null; - } + assert(_isMapCreated); return TextButton( child: Text('${_nightMode ? 'disable' : 'enable'} night mode'), onPressed: () { diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart index b62d898c3a3b..90404c347dd8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart @@ -29,8 +29,8 @@ class MarkerIconsBody extends StatefulWidget { const LatLng _kMapCenter = LatLng(52.4478, -3.5402); class MarkerIconsBodyState extends State { - GoogleMapController controller; - BitmapDescriptor _markerIcon; + GoogleMapController? controller; + BitmapDescriptor? _markerIcon; @override Widget build(BuildContext context) { @@ -48,7 +48,7 @@ class MarkerIconsBodyState extends State { target: _kMapCenter, zoom: 7.0, ), - markers: _createMarker(), + markers: {_createMarker()}, onMapCreated: _onMapCreated, ), ), @@ -57,17 +57,19 @@ class MarkerIconsBodyState extends State { ); } - Set _createMarker() { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return [ - Marker( + Marker _createMarker() { + if (_markerIcon != null) { + return Marker( markerId: MarkerId("marker_1"), position: _kMapCenter, - icon: _markerIcon, - ), - ].toSet(); + icon: _markerIcon!, + ); + } else { + return Marker( + markerId: MarkerId("marker_1"), + position: _kMapCenter, + ); + } } Future _createMarkerImageFromAsset(BuildContext context) async { diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart index 262d362d8c3e..860b19e7925c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart @@ -25,7 +25,7 @@ class MoveCamera extends StatefulWidget { } class MoveCameraState extends State { - GoogleMapController mapController; + GoogleMapController? mapController; void _onMapCreated(GoogleMapController controller) { mapController = controller; @@ -55,7 +55,7 @@ class MoveCameraState extends State { children: [ TextButton( onPressed: () { - mapController.moveCamera( + mapController?.moveCamera( CameraUpdate.newCameraPosition( const CameraPosition( bearing: 270.0, @@ -70,7 +70,7 @@ class MoveCameraState extends State { ), TextButton( onPressed: () { - mapController.moveCamera( + mapController?.moveCamera( CameraUpdate.newLatLng( const LatLng(56.1725505, 10.1850512), ), @@ -80,7 +80,7 @@ class MoveCameraState extends State { ), TextButton( onPressed: () { - mapController.moveCamera( + mapController?.moveCamera( CameraUpdate.newLatLngBounds( LatLngBounds( southwest: const LatLng(-38.483935, 113.248673), @@ -94,7 +94,7 @@ class MoveCameraState extends State { ), TextButton( onPressed: () { - mapController.moveCamera( + mapController?.moveCamera( CameraUpdate.newLatLngZoom( const LatLng(37.4231613, -122.087159), 11.0, @@ -105,7 +105,7 @@ class MoveCameraState extends State { ), TextButton( onPressed: () { - mapController.moveCamera( + mapController?.moveCamera( CameraUpdate.scrollBy(150.0, -225.0), ); }, @@ -117,7 +117,7 @@ class MoveCameraState extends State { children: [ TextButton( onPressed: () { - mapController.moveCamera( + mapController?.moveCamera( CameraUpdate.zoomBy( -0.5, const Offset(30.0, 20.0), @@ -128,7 +128,7 @@ class MoveCameraState extends State { ), TextButton( onPressed: () { - mapController.moveCamera( + mapController?.moveCamera( CameraUpdate.zoomBy(-0.5), ); }, @@ -136,7 +136,7 @@ class MoveCameraState extends State { ), TextButton( onPressed: () { - mapController.moveCamera( + mapController?.moveCamera( CameraUpdate.zoomIn(), ); }, @@ -144,7 +144,7 @@ class MoveCameraState extends State { ), TextButton( onPressed: () { - mapController.moveCamera( + mapController?.moveCamera( CameraUpdate.zoomOut(), ); }, @@ -152,7 +152,7 @@ class MoveCameraState extends State { ), TextButton( onPressed: () { - mapController.moveCamera( + mapController?.moveCamera( CameraUpdate.zoomTo(16.0), ); }, diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart index 934d4c647aa4..45b4a9e09e5c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart @@ -27,7 +27,7 @@ class MarkerIconsBody extends StatefulWidget { const LatLng _kMapCenter = LatLng(52.4478, -3.5402); class MarkerIconsBodyState extends State { - GoogleMapController controller; + GoogleMapController? controller; EdgeInsets _padding = const EdgeInsets.all(0); @@ -152,10 +152,10 @@ class MarkerIconsBodyState extends State { onPressed: () { setState(() { _padding = EdgeInsets.fromLTRB( - double.tryParse(_leftController.value?.text) ?? 0, - double.tryParse(_topController.value?.text) ?? 0, - double.tryParse(_rightController.value?.text) ?? 0, - double.tryParse(_bottomController.value?.text) ?? 0); + double.tryParse(_leftController.value.text) ?? 0, + double.tryParse(_topController.value.text) ?? 0, + double.tryParse(_rightController.value.text) ?? 0, + double.tryParse(_bottomController.value.text) ?? 0); }); }, ), diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart index 7f0447e9a279..59d30e51ce8b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart @@ -28,10 +28,10 @@ class PlaceCircleBody extends StatefulWidget { class PlaceCircleBodyState extends State { PlaceCircleBodyState(); - GoogleMapController controller; + GoogleMapController? controller; Map circles = {}; int _circleIdCounter = 1; - CircleId selectedCircle; + CircleId? selectedCircle; // Values when toggling circle color int fillColorsIndex = 0; @@ -62,12 +62,14 @@ class PlaceCircleBodyState extends State { }); } - void _remove() { + void _remove(CircleId circleId) { setState(() { - if (circles.containsKey(selectedCircle)) { - circles.remove(selectedCircle); + if (circles.containsKey(circleId)) { + circles.remove(circleId); + } + if (circleId == selectedCircle) { + selectedCircle = null; } - selectedCircle = null; }); } @@ -100,37 +102,37 @@ class PlaceCircleBodyState extends State { }); } - void _toggleVisible() { - final Circle circle = circles[selectedCircle]; + void _toggleVisible(CircleId circleId) { + final Circle circle = circles[circleId]!; setState(() { - circles[selectedCircle] = circle.copyWith( + circles[circleId] = circle.copyWith( visibleParam: !circle.visible, ); }); } - void _changeFillColor() { - final Circle circle = circles[selectedCircle]; + void _changeFillColor(CircleId circleId) { + final Circle circle = circles[circleId]!; setState(() { - circles[selectedCircle] = circle.copyWith( + circles[circleId] = circle.copyWith( fillColorParam: colors[++fillColorsIndex % colors.length], ); }); } - void _changeStrokeColor() { - final Circle circle = circles[selectedCircle]; + void _changeStrokeColor(CircleId circleId) { + final Circle circle = circles[circleId]!; setState(() { - circles[selectedCircle] = circle.copyWith( + circles[circleId] = circle.copyWith( strokeColorParam: colors[++strokeColorsIndex % colors.length], ); }); } - void _changeStrokeWidth() { - final Circle circle = circles[selectedCircle]; + void _changeStrokeWidth(CircleId circleId) { + final Circle circle = circles[circleId]!; setState(() { - circles[selectedCircle] = circle.copyWith( + circles[circleId] = circle.copyWith( strokeWidthParam: widths[++widthsIndex % widths.length], ); }); @@ -138,6 +140,7 @@ class PlaceCircleBodyState extends State { @override Widget build(BuildContext context) { + final CircleId? selectedId = selectedCircle; return Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -171,12 +174,15 @@ class PlaceCircleBodyState extends State { ), TextButton( child: const Text('remove'), - onPressed: (selectedCircle == null) ? null : _remove, + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), ), TextButton( child: const Text('toggle visible'), - onPressed: - (selectedCircle == null) ? null : _toggleVisible, + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), ), ], ), @@ -184,21 +190,21 @@ class PlaceCircleBodyState extends State { children: [ TextButton( child: const Text('change stroke width'), - onPressed: (selectedCircle == null) + onPressed: (selectedId == null) ? null - : _changeStrokeWidth, + : () => _changeStrokeWidth(selectedId), ), TextButton( child: const Text('change stroke color'), - onPressed: (selectedCircle == null) + onPressed: (selectedId == null) ? null - : _changeStrokeColor, + : () => _changeStrokeColor(selectedId), ), TextButton( child: const Text('change fill color'), - onPressed: (selectedCircle == null) + onPressed: (selectedId == null) ? null - : _changeFillColor, + : () => _changeFillColor(selectedId), ), ], ) diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart index 2c5439590443..576808c38a5e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart @@ -35,9 +35,9 @@ class PlaceMarkerBodyState extends State { PlaceMarkerBodyState(); static final LatLng center = const LatLng(-33.86711, 151.1947171); - GoogleMapController controller; + GoogleMapController? controller; Map markers = {}; - MarkerId selectedMarker; + MarkerId? selectedMarker; int _markerIdCounter = 1; void _onMapCreated(GoogleMapController controller) { @@ -50,13 +50,13 @@ class PlaceMarkerBodyState extends State { } void _onMarkerTapped(MarkerId markerId) { - final Marker tappedMarker = markers[markerId]; + final Marker? tappedMarker = markers[markerId]; if (tappedMarker != null) { setState(() { - if (markers.containsKey(selectedMarker)) { - final Marker resetOld = markers[selectedMarker] + if (markers.containsKey(markerId)) { + final Marker resetOld = markers[markerId]! .copyWith(iconParam: BitmapDescriptor.defaultMarker); - markers[selectedMarker] = resetOld; + markers[markerId] = resetOld; } selectedMarker = markerId; final Marker newMarker = tappedMarker.copyWith( @@ -70,7 +70,7 @@ class PlaceMarkerBodyState extends State { } void _onMarkerDragEnd(MarkerId markerId, LatLng newPosition) async { - final Marker tappedMarker = markers[markerId]; + final Marker? tappedMarker = markers[markerId]; if (tappedMarker != null) { await showDialog( context: context, @@ -126,23 +126,23 @@ class PlaceMarkerBodyState extends State { }); } - void _remove() { + void _remove(MarkerId markerId) { setState(() { - if (markers.containsKey(selectedMarker)) { - markers.remove(selectedMarker); + if (markers.containsKey(markerId)) { + markers.remove(markerId); } }); } - void _changePosition() { - final Marker marker = markers[selectedMarker]; + void _changePosition(MarkerId markerId) { + final Marker marker = markers[markerId]!; final LatLng current = marker.position; final Offset offset = Offset( center.latitude - current.latitude, center.longitude - current.longitude, ); setState(() { - markers[selectedMarker] = marker.copyWith( + markers[markerId] = marker.copyWith( positionParam: LatLng( center.latitude + offset.dy, center.longitude + offset.dx, @@ -151,23 +151,23 @@ class PlaceMarkerBodyState extends State { }); } - void _changeAnchor() { - final Marker marker = markers[selectedMarker]; + void _changeAnchor(MarkerId markerId) { + final Marker marker = markers[markerId]!; final Offset currentAnchor = marker.anchor; final Offset newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); setState(() { - markers[selectedMarker] = marker.copyWith( + markers[markerId] = marker.copyWith( anchorParam: newAnchor, ); }); } - Future _changeInfoAnchor() async { - final Marker marker = markers[selectedMarker]; + Future _changeInfoAnchor(MarkerId markerId) async { + final Marker marker = markers[markerId]!; final Offset currentAnchor = marker.infoWindow.anchor; final Offset newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); setState(() { - markers[selectedMarker] = marker.copyWith( + markers[markerId] = marker.copyWith( infoWindowParam: marker.infoWindow.copyWith( anchorParam: newAnchor, ), @@ -175,29 +175,29 @@ class PlaceMarkerBodyState extends State { }); } - Future _toggleDraggable() async { - final Marker marker = markers[selectedMarker]; + Future _toggleDraggable(MarkerId markerId) async { + final Marker marker = markers[markerId]!; setState(() { - markers[selectedMarker] = marker.copyWith( + markers[markerId] = marker.copyWith( draggableParam: !marker.draggable, ); }); } - Future _toggleFlat() async { - final Marker marker = markers[selectedMarker]; + Future _toggleFlat(MarkerId markerId) async { + final Marker marker = markers[markerId]!; setState(() { - markers[selectedMarker] = marker.copyWith( + markers[markerId] = marker.copyWith( flatParam: !marker.flat, ); }); } - Future _changeInfo() async { - final Marker marker = markers[selectedMarker]; - final String newSnippet = marker.infoWindow.snippet + '*'; + Future _changeInfo(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final String newSnippet = marker.infoWindow.snippet! + '*'; setState(() { - markers[selectedMarker] = marker.copyWith( + markers[markerId] = marker.copyWith( infoWindowParam: marker.infoWindow.copyWith( snippetParam: newSnippet, ), @@ -205,40 +205,40 @@ class PlaceMarkerBodyState extends State { }); } - Future _changeAlpha() async { - final Marker marker = markers[selectedMarker]; + Future _changeAlpha(MarkerId markerId) async { + final Marker marker = markers[markerId]!; final double current = marker.alpha; setState(() { - markers[selectedMarker] = marker.copyWith( + markers[markerId] = marker.copyWith( alphaParam: current < 0.1 ? 1.0 : current * 0.75, ); }); } - Future _changeRotation() async { - final Marker marker = markers[selectedMarker]; + Future _changeRotation(MarkerId markerId) async { + final Marker marker = markers[markerId]!; final double current = marker.rotation; setState(() { - markers[selectedMarker] = marker.copyWith( + markers[markerId] = marker.copyWith( rotationParam: current == 330.0 ? 0.0 : current + 30.0, ); }); } - Future _toggleVisible() async { - final Marker marker = markers[selectedMarker]; + Future _toggleVisible(MarkerId markerId) async { + final Marker marker = markers[markerId]!; setState(() { - markers[selectedMarker] = marker.copyWith( + markers[markerId] = marker.copyWith( visibleParam: !marker.visible, ); }); } - Future _changeZIndex() async { - final Marker marker = markers[selectedMarker]; + Future _changeZIndex(MarkerId markerId) async { + final Marker marker = markers[markerId]!; final double current = marker.zIndex; setState(() { - markers[selectedMarker] = marker.copyWith( + markers[markerId] = marker.copyWith( zIndexParam: current == 12.0 ? 0.0 : current + 1.0, ); }); @@ -283,6 +283,7 @@ class PlaceMarkerBodyState extends State { @override Widget build(BuildContext context) { + final MarkerId? selectedId = selectedMarker; return Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -297,9 +298,6 @@ class PlaceMarkerBodyState extends State { target: LatLng(-33.852, 151.211), zoom: 11.0, ), - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals markers: Set.of(markers.values), ), ), @@ -319,15 +317,21 @@ class PlaceMarkerBodyState extends State { ), TextButton( child: const Text('remove'), - onPressed: _remove, + onPressed: selectedId == null + ? null + : () => _remove(selectedId), ), TextButton( child: const Text('change info'), - onPressed: _changeInfo, + onPressed: selectedId == null + ? null + : () => _changeInfo(selectedId), ), TextButton( child: const Text('change info anchor'), - onPressed: _changeInfoAnchor, + onPressed: selectedId == null + ? null + : () => _changeInfoAnchor(selectedId), ), ], ), @@ -335,35 +339,51 @@ class PlaceMarkerBodyState extends State { children: [ TextButton( child: const Text('change alpha'), - onPressed: _changeAlpha, + onPressed: selectedId == null + ? null + : () => _changeAlpha(selectedId), ), TextButton( child: const Text('change anchor'), - onPressed: _changeAnchor, + onPressed: selectedId == null + ? null + : () => _changeAnchor(selectedId), ), TextButton( child: const Text('toggle draggable'), - onPressed: _toggleDraggable, + onPressed: selectedId == null + ? null + : () => _toggleDraggable(selectedId), ), TextButton( child: const Text('toggle flat'), - onPressed: _toggleFlat, + onPressed: selectedId == null + ? null + : () => _toggleFlat(selectedId), ), TextButton( child: const Text('change position'), - onPressed: _changePosition, + onPressed: selectedId == null + ? null + : () => _changePosition(selectedId), ), TextButton( child: const Text('change rotation'), - onPressed: _changeRotation, + onPressed: selectedId == null + ? null + : () => _changeRotation(selectedId), ), TextButton( child: const Text('toggle visible'), - onPressed: _toggleVisible, + onPressed: selectedId == null + ? null + : () => _toggleVisible(selectedId), ), TextButton( child: const Text('change zIndex'), - onPressed: _changeZIndex, + onPressed: selectedId == null + ? null + : () => _changeZIndex(selectedId), ), // A breaking change to the ImageStreamListener API affects this sample. // I've updates the sample to use the new API, but as we cannot use the new diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart index 5f2a0985b1b9..8ee58420f508 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart @@ -28,11 +28,11 @@ class PlacePolygonBody extends StatefulWidget { class PlacePolygonBodyState extends State { PlacePolygonBodyState(); - GoogleMapController controller; + GoogleMapController? controller; Map polygons = {}; Map polygonOffsets = {}; int _polygonIdCounter = 0; - PolygonId selectedPolygon; + PolygonId? selectedPolygon; // Values when toggling polygon color int strokeColorsIndex = 0; @@ -63,10 +63,10 @@ class PlacePolygonBodyState extends State { }); } - void _remove() { + void _remove(PolygonId polygonId) { setState(() { - if (polygons.containsKey(selectedPolygon)) { - polygons.remove(selectedPolygon); + if (polygons.containsKey(polygonId)) { + polygons.remove(polygonId); } selectedPolygon = null; }); @@ -102,62 +102,63 @@ class PlacePolygonBodyState extends State { }); } - void _toggleGeodesic() { - final Polygon polygon = polygons[selectedPolygon]; + void _toggleGeodesic(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; setState(() { - polygons[selectedPolygon] = polygon.copyWith( + polygons[polygonId] = polygon.copyWith( geodesicParam: !polygon.geodesic, ); }); } - void _toggleVisible() { - final Polygon polygon = polygons[selectedPolygon]; + void _toggleVisible(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; setState(() { - polygons[selectedPolygon] = polygon.copyWith( + polygons[polygonId] = polygon.copyWith( visibleParam: !polygon.visible, ); }); } - void _changeStrokeColor() { - final Polygon polygon = polygons[selectedPolygon]; + void _changeStrokeColor(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; setState(() { - polygons[selectedPolygon] = polygon.copyWith( + polygons[polygonId] = polygon.copyWith( strokeColorParam: colors[++strokeColorsIndex % colors.length], ); }); } - void _changeFillColor() { - final Polygon polygon = polygons[selectedPolygon]; + void _changeFillColor(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; setState(() { - polygons[selectedPolygon] = polygon.copyWith( + polygons[polygonId] = polygon.copyWith( fillColorParam: colors[++fillColorsIndex % colors.length], ); }); } - void _changeWidth() { - final Polygon polygon = polygons[selectedPolygon]; + void _changeWidth(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; setState(() { - polygons[selectedPolygon] = polygon.copyWith( + polygons[polygonId] = polygon.copyWith( strokeWidthParam: widths[++widthsIndex % widths.length], ); }); } - void _addHoles() { - final Polygon polygon = polygons[selectedPolygon]; + void _addHoles(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; setState(() { - polygons[selectedPolygon] = polygon.copyWith(holesParam: _createHoles()); + polygons[polygonId] = + polygon.copyWith(holesParam: _createHoles(polygonId)); }); } - void _removeHoles() { - final Polygon polygon = polygons[selectedPolygon]; + void _removeHoles(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; setState(() { - polygons[selectedPolygon] = polygon.copyWith( + polygons[polygonId] = polygon.copyWith( holesParam: >[], ); }); @@ -165,6 +166,7 @@ class PlacePolygonBodyState extends State { @override Widget build(BuildContext context) { + final PolygonId? selectedId = selectedPolygon; return Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -198,18 +200,21 @@ class PlacePolygonBodyState extends State { ), TextButton( child: const Text('remove'), - onPressed: (selectedPolygon == null) ? null : _remove, + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), ), TextButton( child: const Text('toggle visible'), - onPressed: - (selectedPolygon == null) ? null : _toggleVisible, + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), ), TextButton( child: const Text('toggle geodesic'), - onPressed: (selectedPolygon == null) + onPressed: (selectedId == null) ? null - : _toggleGeodesic, + : () => _toggleGeodesic(selectedId), ), ], ), @@ -217,36 +222,37 @@ class PlacePolygonBodyState extends State { children: [ TextButton( child: const Text('add holes'), - onPressed: (selectedPolygon == null) + onPressed: (selectedId == null) ? null - : ((polygons[selectedPolygon].holes.isNotEmpty) + : ((polygons[selectedId]!.holes.isNotEmpty) ? null - : _addHoles), + : () => _addHoles(selectedId)), ), TextButton( child: const Text('remove holes'), - onPressed: (selectedPolygon == null) + onPressed: (selectedId == null) ? null - : ((polygons[selectedPolygon].holes.isEmpty) + : ((polygons[selectedId]!.holes.isEmpty) ? null - : _removeHoles), + : () => _removeHoles(selectedId)), ), TextButton( child: const Text('change stroke width'), - onPressed: - (selectedPolygon == null) ? null : _changeWidth, + onPressed: (selectedId == null) + ? null + : () => _changeWidth(selectedId), ), TextButton( child: const Text('change stroke color'), - onPressed: (selectedPolygon == null) + onPressed: (selectedId == null) ? null - : _changeStrokeColor, + : () => _changeStrokeColor(selectedId), ), TextButton( child: const Text('change fill color'), - onPressed: (selectedPolygon == null) + onPressed: (selectedId == null) ? null - : _changeFillColor, + : () => _changeFillColor(selectedId), ), ], ) @@ -270,9 +276,9 @@ class PlacePolygonBodyState extends State { return points; } - List> _createHoles() { + List> _createHoles(PolygonId polygonId) { final List> holes = >[]; - final double offset = polygonOffsets[selectedPolygon]; + final double offset = polygonOffsets[polygonId]!; final List hole1 = []; hole1.add(_createLatLng(51.8395 + offset, -3.8814)); diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart index fe22603853bc..c66343d78f00 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart @@ -29,10 +29,10 @@ class PlacePolylineBody extends StatefulWidget { class PlacePolylineBodyState extends State { PlacePolylineBodyState(); - GoogleMapController controller; + GoogleMapController? controller; Map polylines = {}; int _polylineIdCounter = 0; - PolylineId selectedPolyline; + PolylineId? selectedPolyline; // Values when toggling polyline color int colorsIndex = 0; @@ -91,10 +91,10 @@ class PlacePolylineBodyState extends State { }); } - void _remove() { + void _remove(PolylineId polylineId) { setState(() { - if (polylines.containsKey(selectedPolyline)) { - polylines.remove(selectedPolyline); + if (polylines.containsKey(polylineId)) { + polylines.remove(polylineId); } selectedPolyline = null; }); @@ -127,73 +127,73 @@ class PlacePolylineBodyState extends State { }); } - void _toggleGeodesic() { - final Polyline polyline = polylines[selectedPolyline]; + void _toggleGeodesic(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; setState(() { - polylines[selectedPolyline] = polyline.copyWith( + polylines[polylineId] = polyline.copyWith( geodesicParam: !polyline.geodesic, ); }); } - void _toggleVisible() { - final Polyline polyline = polylines[selectedPolyline]; + void _toggleVisible(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; setState(() { - polylines[selectedPolyline] = polyline.copyWith( + polylines[polylineId] = polyline.copyWith( visibleParam: !polyline.visible, ); }); } - void _changeColor() { - final Polyline polyline = polylines[selectedPolyline]; + void _changeColor(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; setState(() { - polylines[selectedPolyline] = polyline.copyWith( + polylines[polylineId] = polyline.copyWith( colorParam: colors[++colorsIndex % colors.length], ); }); } - void _changeWidth() { - final Polyline polyline = polylines[selectedPolyline]; + void _changeWidth(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; setState(() { - polylines[selectedPolyline] = polyline.copyWith( + polylines[polylineId] = polyline.copyWith( widthParam: widths[++widthsIndex % widths.length], ); }); } - void _changeJointType() { - final Polyline polyline = polylines[selectedPolyline]; + void _changeJointType(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; setState(() { - polylines[selectedPolyline] = polyline.copyWith( + polylines[polylineId] = polyline.copyWith( jointTypeParam: jointTypes[++jointTypesIndex % jointTypes.length], ); }); } - void _changeEndCap() { - final Polyline polyline = polylines[selectedPolyline]; + void _changeEndCap(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; setState(() { - polylines[selectedPolyline] = polyline.copyWith( + polylines[polylineId] = polyline.copyWith( endCapParam: endCaps[++endCapsIndex % endCaps.length], ); }); } - void _changeStartCap() { - final Polyline polyline = polylines[selectedPolyline]; + void _changeStartCap(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; setState(() { - polylines[selectedPolyline] = polyline.copyWith( + polylines[polylineId] = polyline.copyWith( startCapParam: startCaps[++startCapsIndex % startCaps.length], ); }); } - void _changePattern() { - final Polyline polyline = polylines[selectedPolyline]; + void _changePattern(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; setState(() { - polylines[selectedPolyline] = polyline.copyWith( + polylines[polylineId] = polyline.copyWith( patternsParam: patterns[++patternsIndex % patterns.length], ); }); @@ -201,9 +201,9 @@ class PlacePolylineBodyState extends State { @override Widget build(BuildContext context) { - final bool iOSorNotSelected = - (!kIsWeb && defaultTargetPlatform == TargetPlatform.iOS) || - (selectedPolyline == null); + final bool isIOS = !kIsWeb && defaultTargetPlatform == TargetPlatform.iOS; + + final PolylineId? selectedId = selectedPolyline; return Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -238,20 +238,21 @@ class PlacePolylineBodyState extends State { ), TextButton( child: const Text('remove'), - onPressed: - (selectedPolyline == null) ? null : _remove, + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), ), TextButton( child: const Text('toggle visible'), - onPressed: (selectedPolyline == null) + onPressed: (selectedId == null) ? null - : _toggleVisible, + : () => _toggleVisible(selectedId), ), TextButton( child: const Text('toggle geodesic'), - onPressed: (selectedPolyline == null) + onPressed: (selectedId == null) ? null - : _toggleGeodesic, + : () => _toggleGeodesic(selectedId), ), ], ), @@ -259,29 +260,39 @@ class PlacePolylineBodyState extends State { children: [ TextButton( child: const Text('change width'), - onPressed: - (selectedPolyline == null) ? null : _changeWidth, + onPressed: (selectedId == null) + ? null + : () => _changeWidth(selectedId), ), TextButton( child: const Text('change color'), - onPressed: - (selectedPolyline == null) ? null : _changeColor, + onPressed: (selectedId == null) + ? null + : () => _changeColor(selectedId), ), TextButton( child: const Text('change start cap [Android only]'), - onPressed: iOSorNotSelected ? null : _changeStartCap, + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeStartCap(selectedId), ), TextButton( child: const Text('change end cap [Android only]'), - onPressed: iOSorNotSelected ? null : _changeEndCap, + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeEndCap(selectedId), ), TextButton( child: const Text('change joint type [Android only]'), - onPressed: iOSorNotSelected ? null : _changeJointType, + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeJointType(selectedId), ), TextButton( child: const Text('change pattern [Android only]'), - onPressed: iOSorNotSelected ? null : _changePattern, + onPressed: isIOS || (selectedId == null) + ? null + : () => _changePattern(selectedId), ), ], ) diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart index 2aa1243fd27c..b7d88bc46a58 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart @@ -48,15 +48,12 @@ class ScrollingMapBody extends StatelessWidget { target: center, zoom: 11.0, ), - gestureRecognizers: - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - >[ + gestureRecognizers: // + >{ Factory( () => EagerGestureRecognizer(), ), - ].toSet(), + }, ), ), ), @@ -84,34 +81,25 @@ class ScrollingMapBody extends StatelessWidget { target: center, zoom: 11.0, ), - markers: - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - Set.of( - [ - Marker( - markerId: MarkerId("test_marker_id"), - position: LatLng( - center.latitude, - center.longitude, - ), - infoWindow: const InfoWindow( - title: 'An interesting location', - snippet: '*', - ), - ) - ], - ), - gestureRecognizers: - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - >[ + markers: { + Marker( + markerId: MarkerId("test_marker_id"), + position: LatLng( + center.latitude, + center.longitude, + ), + infoWindow: const InfoWindow( + title: 'An interesting location', + snippet: '*', + ), + ), + }, + gestureRecognizers: < + Factory>{ Factory( () => ScaleGestureRecognizer(), ), - ].toSet(), + }, ), ), ), diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart index f470a4f9783e..3ba12bfac3f2 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart @@ -30,8 +30,8 @@ class _SnapshotBody extends StatefulWidget { } class _SnapshotBodyState extends State<_SnapshotBody> { - GoogleMapController _mapController; - Uint8List _imageBytes; + GoogleMapController? _mapController; + Uint8List? _imageBytes; @override Widget build(BuildContext context) { @@ -59,7 +59,7 @@ class _SnapshotBodyState extends State<_SnapshotBody> { Container( decoration: BoxDecoration(color: Colors.blueGrey[50]), height: 180, - child: _imageBytes != null ? Image.memory(_imageBytes) : null, + child: _imageBytes != null ? Image.memory(_imageBytes!) : null, ), ], ), diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart index 354fa06a7ab7..8ae3b3bca979 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart @@ -31,8 +31,8 @@ class TileOverlayBody extends StatefulWidget { class TileOverlayBodyState extends State { TileOverlayBodyState(); - GoogleMapController controller; - TileOverlay _tileOverlay; + GoogleMapController? controller; + TileOverlay? _tileOverlay; void _onMapCreated(GoogleMapController controller) { this.controller = controller; @@ -61,12 +61,15 @@ class TileOverlayBodyState extends State { void _clearTileCache() { if (_tileOverlay != null && controller != null) { - controller.clearTileCache(_tileOverlay.tileOverlayId); + controller!.clearTileCache(_tileOverlay!.tileOverlayId); } } @override Widget build(BuildContext context) { + Set overlays = { + if (_tileOverlay != null) _tileOverlay, + }; return Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.spaceEvenly, @@ -81,8 +84,7 @@ class TileOverlayBodyState extends State { target: LatLng(59.935460, 30.325177), zoom: 7.0, ), - tileOverlays: - _tileOverlay != null ? {_tileOverlay} : null, + tileOverlays: overlays as Set, onMapCreated: _onMapCreated, ), ), @@ -121,7 +123,7 @@ class _DebugTileProvider implements TileProvider { ); @override - Future getTile(int x, int y, int zoom) async { + Future getTile(int x, int y, int? zoom) async { final ui.PictureRecorder recorder = ui.PictureRecorder(); final Canvas canvas = Canvas(recorder); final TextSpan textSpan = TextSpan( @@ -145,7 +147,7 @@ class _DebugTileProvider implements TileProvider { .toImage(width, height) .then((ui.Image image) => image.toByteData(format: ui.ImageByteFormat.png)) - .then((ByteData byteData) => byteData.buffer.asUint8List()); + .then((ByteData? byteData) => byteData!.buffer.asUint8List()); return Tile(width, height, byteData); } } diff --git a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml index b3a0ae75daad..181550d32877 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_example description: Demonstrates how to use the google_maps_flutter plugin. environment: - sdk: ">=2.2.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.22.0" dependencies: @@ -19,7 +19,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - flutter_plugin_android_lifecycle: ^1.0.0 + flutter_plugin_android_lifecycle: ^2.0.0-nullsafety.2 dev_dependencies: flutter_driver: diff --git a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart index 7a2c21338786..ceb6c4d6a3a0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart @@ -1,6 +1,7 @@ // Copyright 2019, the Chromium project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 import 'dart:async'; import 'dart:convert'; diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart index 3967179b0e50..9b61ec002ff9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart @@ -4,9 +4,6 @@ part of google_maps_flutter; -final GoogleMapsFlutterPlatform _googleMapsFlutterPlatform = - GoogleMapsFlutterPlatform.instance; - /// Controller for a single GoogleMap instance running on the host platform. class GoogleMapController { /// The mapId for this controller @@ -15,8 +12,8 @@ class GoogleMapController { GoogleMapController._( CameraPosition initialCameraPosition, this._googleMapState, { - @required this.mapId, - }) : assert(_googleMapsFlutterPlatform != null) { + required this.mapId, + }) { _connectStreams(mapId); } @@ -30,7 +27,7 @@ class GoogleMapController { _GoogleMapState googleMapState, ) async { assert(id != null); - await _googleMapsFlutterPlatform.init(id); + await GoogleMapsFlutterPlatform.instance.init(id); return GoogleMapController._( initialCameraPosition, googleMapState, @@ -43,9 +40,10 @@ class GoogleMapController { /// Accessible only for testing. // TODO(dit) https://github.com/flutter/flutter/issues/55504 Remove this getter. @visibleForTesting - MethodChannel get channel { - if (_googleMapsFlutterPlatform is MethodChannelGoogleMapsFlutter) { - return (_googleMapsFlutterPlatform as MethodChannelGoogleMapsFlutter) + MethodChannel? get channel { + if (GoogleMapsFlutterPlatform.instance is MethodChannelGoogleMapsFlutter) { + return (GoogleMapsFlutterPlatform.instance + as MethodChannelGoogleMapsFlutter) .channel(mapId); } return null; @@ -55,40 +53,40 @@ class GoogleMapController { void _connectStreams(int mapId) { if (_googleMapState.widget.onCameraMoveStarted != null) { - _googleMapsFlutterPlatform + GoogleMapsFlutterPlatform.instance .onCameraMoveStarted(mapId: mapId) - .listen((_) => _googleMapState.widget.onCameraMoveStarted()); + .listen((_) => _googleMapState.widget.onCameraMoveStarted!()); } if (_googleMapState.widget.onCameraMove != null) { - _googleMapsFlutterPlatform.onCameraMove(mapId: mapId).listen( - (CameraMoveEvent e) => _googleMapState.widget.onCameraMove(e.value)); + GoogleMapsFlutterPlatform.instance.onCameraMove(mapId: mapId).listen( + (CameraMoveEvent e) => _googleMapState.widget.onCameraMove!(e.value)); } if (_googleMapState.widget.onCameraIdle != null) { - _googleMapsFlutterPlatform + GoogleMapsFlutterPlatform.instance .onCameraIdle(mapId: mapId) - .listen((_) => _googleMapState.widget.onCameraIdle()); + .listen((_) => _googleMapState.widget.onCameraIdle!()); } - _googleMapsFlutterPlatform + GoogleMapsFlutterPlatform.instance .onMarkerTap(mapId: mapId) .listen((MarkerTapEvent e) => _googleMapState.onMarkerTap(e.value)); - _googleMapsFlutterPlatform.onMarkerDragEnd(mapId: mapId).listen( + GoogleMapsFlutterPlatform.instance.onMarkerDragEnd(mapId: mapId).listen( (MarkerDragEndEvent e) => _googleMapState.onMarkerDragEnd(e.value, e.position)); - _googleMapsFlutterPlatform.onInfoWindowTap(mapId: mapId).listen( + GoogleMapsFlutterPlatform.instance.onInfoWindowTap(mapId: mapId).listen( (InfoWindowTapEvent e) => _googleMapState.onInfoWindowTap(e.value)); - _googleMapsFlutterPlatform + GoogleMapsFlutterPlatform.instance .onPolylineTap(mapId: mapId) .listen((PolylineTapEvent e) => _googleMapState.onPolylineTap(e.value)); - _googleMapsFlutterPlatform + GoogleMapsFlutterPlatform.instance .onPolygonTap(mapId: mapId) .listen((PolygonTapEvent e) => _googleMapState.onPolygonTap(e.value)); - _googleMapsFlutterPlatform + GoogleMapsFlutterPlatform.instance .onCircleTap(mapId: mapId) .listen((CircleTapEvent e) => _googleMapState.onCircleTap(e.value)); - _googleMapsFlutterPlatform + GoogleMapsFlutterPlatform.instance .onTap(mapId: mapId) .listen((MapTapEvent e) => _googleMapState.onTap(e.position)); - _googleMapsFlutterPlatform.onLongPress(mapId: mapId).listen( + GoogleMapsFlutterPlatform.instance.onLongPress(mapId: mapId).listen( (MapLongPressEvent e) => _googleMapState.onLongPress(e.position)); } @@ -100,8 +98,8 @@ class GoogleMapController { /// The returned [Future] completes after listeners have been notified. Future _updateMapOptions(Map optionsUpdate) { assert(optionsUpdate != null); - return _googleMapsFlutterPlatform.updateMapOptions(optionsUpdate, - mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .updateMapOptions(optionsUpdate, mapId: mapId); } /// Updates marker configuration. @@ -112,8 +110,8 @@ class GoogleMapController { /// The returned [Future] completes after listeners have been notified. Future _updateMarkers(MarkerUpdates markerUpdates) { assert(markerUpdates != null); - return _googleMapsFlutterPlatform.updateMarkers(markerUpdates, - mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .updateMarkers(markerUpdates, mapId: mapId); } /// Updates polygon configuration. @@ -124,8 +122,8 @@ class GoogleMapController { /// The returned [Future] completes after listeners have been notified. Future _updatePolygons(PolygonUpdates polygonUpdates) { assert(polygonUpdates != null); - return _googleMapsFlutterPlatform.updatePolygons(polygonUpdates, - mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .updatePolygons(polygonUpdates, mapId: mapId); } /// Updates polyline configuration. @@ -136,8 +134,8 @@ class GoogleMapController { /// The returned [Future] completes after listeners have been notified. Future _updatePolylines(PolylineUpdates polylineUpdates) { assert(polylineUpdates != null); - return _googleMapsFlutterPlatform.updatePolylines(polylineUpdates, - mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .updatePolylines(polylineUpdates, mapId: mapId); } /// Updates circle configuration. @@ -148,8 +146,8 @@ class GoogleMapController { /// The returned [Future] completes after listeners have been notified. Future _updateCircles(CircleUpdates circleUpdates) { assert(circleUpdates != null); - return _googleMapsFlutterPlatform.updateCircles(circleUpdates, - mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .updateCircles(circleUpdates, mapId: mapId); } /// Updates tile overlays configuration. @@ -159,8 +157,8 @@ class GoogleMapController { /// /// The returned [Future] completes after listeners have been notified. Future _updateTileOverlays(Set newTileOverlays) { - return _googleMapsFlutterPlatform.updateTileOverlays( - newTileOverlays: newTileOverlays, mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .updateTileOverlays(newTileOverlays: newTileOverlays, mapId: mapId); } /// Clears the tile cache so that all tiles will be requested again from the @@ -172,8 +170,8 @@ class GoogleMapController { /// should implement an on-disk cache. Future clearTileCache(TileOverlayId tileOverlayId) async { assert(tileOverlayId != null); - return _googleMapsFlutterPlatform.clearTileCache(tileOverlayId, - mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .clearTileCache(tileOverlayId, mapId: mapId); } /// Starts an animated change of the map camera position. @@ -181,7 +179,8 @@ class GoogleMapController { /// The returned [Future] completes after the change has been started on the /// platform side. Future animateCamera(CameraUpdate cameraUpdate) { - return _googleMapsFlutterPlatform.animateCamera(cameraUpdate, mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .animateCamera(cameraUpdate, mapId: mapId); } /// Changes the map camera position. @@ -189,7 +188,8 @@ class GoogleMapController { /// The returned [Future] completes after the change has been made on the /// platform side. Future moveCamera(CameraUpdate cameraUpdate) { - return _googleMapsFlutterPlatform.moveCamera(cameraUpdate, mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .moveCamera(cameraUpdate, mapId: mapId); } /// Sets the styling of the base map. @@ -205,13 +205,14 @@ class GoogleMapController { /// Also, refer [iOS](https://developers.google.com/maps/documentation/ios-sdk/style-reference) /// and [Android](https://developers.google.com/maps/documentation/android-sdk/style-reference) /// style reference for more information regarding the supported styles. - Future setMapStyle(String mapStyle) { - return _googleMapsFlutterPlatform.setMapStyle(mapStyle, mapId: mapId); + Future setMapStyle(String? mapStyle) { + return GoogleMapsFlutterPlatform.instance + .setMapStyle(mapStyle, mapId: mapId); } /// Return [LatLngBounds] defining the region that is visible in a map. Future getVisibleRegion() { - return _googleMapsFlutterPlatform.getVisibleRegion(mapId: mapId); + return GoogleMapsFlutterPlatform.instance.getVisibleRegion(mapId: mapId); } /// Return [ScreenCoordinate] of the [LatLng] in the current map view. @@ -220,7 +221,8 @@ class GoogleMapController { /// Screen location is in screen pixels (not display pixels) with respect to the top left corner /// of the map, not necessarily of the whole screen. Future getScreenCoordinate(LatLng latLng) { - return _googleMapsFlutterPlatform.getScreenCoordinate(latLng, mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .getScreenCoordinate(latLng, mapId: mapId); } /// Returns [LatLng] corresponding to the [ScreenCoordinate] in the current map view. @@ -228,7 +230,8 @@ class GoogleMapController { /// Returned [LatLng] corresponds to a screen location. The screen location is specified in screen /// pixels (not display pixels) relative to the top left of the map, not top left of the whole screen. Future getLatLng(ScreenCoordinate screenCoordinate) { - return _googleMapsFlutterPlatform.getLatLng(screenCoordinate, mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .getLatLng(screenCoordinate, mapId: mapId); } /// Programmatically show the Info Window for a [Marker]. @@ -241,8 +244,8 @@ class GoogleMapController { /// * [isMarkerInfoWindowShown] to check if the Info Window is showing. Future showMarkerInfoWindow(MarkerId markerId) { assert(markerId != null); - return _googleMapsFlutterPlatform.showMarkerInfoWindow(markerId, - mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .showMarkerInfoWindow(markerId, mapId: mapId); } /// Programmatically hide the Info Window for a [Marker]. @@ -255,8 +258,8 @@ class GoogleMapController { /// * [isMarkerInfoWindowShown] to check if the Info Window is showing. Future hideMarkerInfoWindow(MarkerId markerId) { assert(markerId != null); - return _googleMapsFlutterPlatform.hideMarkerInfoWindow(markerId, - mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .hideMarkerInfoWindow(markerId, mapId: mapId); } /// Returns `true` when the [InfoWindow] is showing, `false` otherwise. @@ -269,22 +272,22 @@ class GoogleMapController { /// * [hideMarkerInfoWindow] to hide the Info Window. Future isMarkerInfoWindowShown(MarkerId markerId) { assert(markerId != null); - return _googleMapsFlutterPlatform.isMarkerInfoWindowShown(markerId, - mapId: mapId); + return GoogleMapsFlutterPlatform.instance + .isMarkerInfoWindowShown(markerId, mapId: mapId); } /// Returns the current zoom level of the map Future getZoomLevel() { - return _googleMapsFlutterPlatform.getZoomLevel(mapId: mapId); + return GoogleMapsFlutterPlatform.instance.getZoomLevel(mapId: mapId); } /// Returns the image bytes of the map - Future takeSnapshot() { - return _googleMapsFlutterPlatform.takeSnapshot(mapId: mapId); + Future takeSnapshot() { + return GoogleMapsFlutterPlatform.instance.takeSnapshot(mapId: mapId); } /// Disposes of the platform resources void dispose() { - _googleMapsFlutterPlatform.dispose(mapId: mapId); + GoogleMapsFlutterPlatform.instance.dispose(mapId: mapId); } } diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart index e7f5e32d61b9..deac00658d6b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart @@ -14,7 +14,29 @@ typedef void MapCreatedCallback(GoogleMapController controller); // to the buildView function, so the web implementation can use it as a // cache key. This needs to be provided from the outside, because web // views seem to re-render much more often that mobile platform views. -int _webOnlyMapId = 0; +int _nextMapCreationId = 0; + +/// Error thrown when an unknown map object ID is provided to a method. +class UnknownMapObjectIdError extends Error { + /// Creates an assertion error with the provided [message]. + UnknownMapObjectIdError(this.objectType, this.objectId, [this.context]); + + /// The name of the map object whose ID is unknown. + final String objectType; + + /// The unknown maps object ID. + final MapsObjectId objectId; + + /// The context where the error occurred. + final String? context; + + String toString() { + if (context != null) { + return 'Unknown $objectType ID "${objectId.value}" in $context'; + } + return 'Unknown $objectType ID "${objectId.value}"'; + } +} /// A widget which displays a map with data obtained from the Google Maps service. class GoogleMap extends StatefulWidget { @@ -22,10 +44,10 @@ class GoogleMap extends StatefulWidget { /// /// [AssertionError] will be thrown if [initialCameraPosition] is null; const GoogleMap({ - Key key, - @required this.initialCameraPosition, + Key? key, + required this.initialCameraPosition, this.onMapCreated, - this.gestureRecognizers, + this.gestureRecognizers = const >{}, this.compassEnabled = true, this.mapToolbarEnabled = true, this.cameraTargetBounds = CameraTargetBounds.unbounded, @@ -45,12 +67,12 @@ class GoogleMap extends StatefulWidget { this.indoorViewEnabled = false, this.trafficEnabled = false, this.buildingsEnabled = true, - this.markers, - this.polygons, - this.polylines, - this.circles, + this.markers = const {}, + this.polygons = const {}, + this.polylines = const {}, + this.circles = const {}, this.onCameraMoveStarted, - this.tileOverlays, + this.tileOverlays = const {}, this.onCameraMove, this.onCameraIdle, this.onTap, @@ -61,7 +83,7 @@ class GoogleMap extends StatefulWidget { /// Callback method for when the map is ready to be used. /// /// Used to receive a [GoogleMapController] for this [GoogleMap]. - final MapCreatedCallback onMapCreated; + final MapCreatedCallback? onMapCreated; /// The initial position of the map's camera. final CameraPosition initialCameraPosition; @@ -132,24 +154,24 @@ class GoogleMap extends StatefulWidget { /// 2. Programmatically initiated animation. /// 3. Camera motion initiated in response to user gestures on the map. /// For example: pan, tilt, pinch to zoom, or rotate. - final VoidCallback onCameraMoveStarted; + final VoidCallback? onCameraMoveStarted; /// Called repeatedly as the camera continues to move after an /// onCameraMoveStarted call. /// /// This may be called as often as once every frame and should /// not perform expensive operations. - final CameraPositionCallback onCameraMove; + final CameraPositionCallback? onCameraMove; /// Called when camera movement has ended, there are no pending /// animations and the user has stopped interacting with the map. - final VoidCallback onCameraIdle; + final VoidCallback? onCameraIdle; /// Called every time a [GoogleMap] is tapped. - final ArgumentCallback onTap; + final ArgumentCallback? onTap; /// Called every time a [GoogleMap] is long pressed. - final ArgumentCallback onLongPress; + final ArgumentCallback? onLongPress; /// True if a "My Location" layer should be shown on the map. /// @@ -205,7 +227,7 @@ class GoogleMap extends StatefulWidget { /// vertical drags. The map will claim gestures that are recognized by any of the /// recognizers on this list. /// - /// When this set is empty or null, the map will only handle pointer events for gestures that + /// When this set is empty, the map will only handle pointer events for gestures that /// were not claimed by any other gesture recognizer. final Set> gestureRecognizers; @@ -215,7 +237,7 @@ class GoogleMap extends StatefulWidget { } class _GoogleMapState extends State { - final _webOnlyMapCreationId = _webOnlyMapId++; + final _mapId = _nextMapCreationId++; final Completer _controller = Completer(); @@ -224,25 +246,20 @@ class _GoogleMapState extends State { Map _polygons = {}; Map _polylines = {}; Map _circles = {}; - _GoogleMapOptions _googleMapOptions; + late _GoogleMapOptions _googleMapOptions; @override Widget build(BuildContext context) { - final Map creationParams = { - 'initialCameraPosition': widget.initialCameraPosition?.toMap(), - 'options': _googleMapOptions.toMap(), - 'markersToAdd': serializeMarkerSet(widget.markers), - 'polygonsToAdd': serializePolygonSet(widget.polygons), - 'polylinesToAdd': serializePolylineSet(widget.polylines), - 'circlesToAdd': serializeCircleSet(widget.circles), - '_webOnlyMapCreationId': _webOnlyMapCreationId, - 'tileOverlaysToAdd': serializeTileOverlaySet(widget.tileOverlays), - }; - - return _googleMapsFlutterPlatform.buildView( - creationParams, - widget.gestureRecognizers, + return GoogleMapsFlutterPlatform.instance.buildView( + _mapId, onPlatformViewCreated, + initialCameraPosition: widget.initialCameraPosition, + markers: widget.markers, + polygons: widget.polygons, + polylines: widget.polylines, + circles: widget.circles, + gestureRecognizers: widget.gestureRecognizers, + mapOptions: _googleMapOptions.toMap(), ); } @@ -333,116 +350,123 @@ class _GoogleMapState extends State { ); _controller.complete(controller); _updateTileOverlays(); - if (widget.onMapCreated != null) { - widget.onMapCreated(controller); + final MapCreatedCallback? onMapCreated = widget.onMapCreated; + if (onMapCreated != null) { + onMapCreated(controller); } } void onMarkerTap(MarkerId markerId) { assert(markerId != null); - if (_markers[markerId]?.onTap != null) { - _markers[markerId].onTap(); + final Marker? marker = _markers[markerId]; + if (marker == null) { + throw UnknownMapObjectIdError('marker', markerId, 'onTap'); + } + final VoidCallback? onTap = marker.onTap; + if (onTap != null) { + onTap(); } } void onMarkerDragEnd(MarkerId markerId, LatLng position) { assert(markerId != null); - if (_markers[markerId]?.onDragEnd != null) { - _markers[markerId].onDragEnd(position); + final Marker? marker = _markers[markerId]; + if (marker == null) { + throw UnknownMapObjectIdError('marker', markerId, 'onDragEnd'); + } + final ValueChanged? onDragEnd = marker.onDragEnd; + if (onDragEnd != null) { + onDragEnd(position); } } void onPolygonTap(PolygonId polygonId) { assert(polygonId != null); - _polygons[polygonId].onTap(); + final Polygon? polygon = _polygons[polygonId]; + if (polygon == null) { + throw UnknownMapObjectIdError('polygon', polygonId, 'onTap'); + } + final VoidCallback? onTap = polygon.onTap; + if (onTap != null) { + onTap(); + } } void onPolylineTap(PolylineId polylineId) { assert(polylineId != null); - if (_polylines[polylineId]?.onTap != null) { - _polylines[polylineId].onTap(); + final Polyline? polyline = _polylines[polylineId]; + if (polyline == null) { + throw UnknownMapObjectIdError('polyline', polylineId, 'onTap'); + } + final VoidCallback? onTap = polyline.onTap; + if (onTap != null) { + onTap(); } } void onCircleTap(CircleId circleId) { assert(circleId != null); - _circles[circleId].onTap(); + final Circle? circle = _circles[circleId]; + if (circle == null) { + throw UnknownMapObjectIdError('marker', circleId, 'onTap'); + } + final VoidCallback? onTap = circle.onTap; + if (onTap != null) { + onTap(); + } } void onInfoWindowTap(MarkerId markerId) { assert(markerId != null); - if (_markers[markerId]?.infoWindow?.onTap != null) { - _markers[markerId].infoWindow.onTap(); + final Marker? marker = _markers[markerId]; + if (marker == null) { + throw UnknownMapObjectIdError('marker', markerId, 'InfoWindow onTap'); + } + final VoidCallback? onTap = marker.infoWindow.onTap; + if (onTap != null) { + onTap(); } } void onTap(LatLng position) { assert(position != null); - if (widget.onTap != null) { - widget.onTap(position); + final ArgumentCallback? onTap = widget.onTap; + if (onTap != null) { + onTap(position); } } void onLongPress(LatLng position) { assert(position != null); - if (widget.onLongPress != null) { - widget.onLongPress(position); + final ArgumentCallback? onLongPress = widget.onLongPress; + if (onLongPress != null) { + onLongPress(position); } } } /// Configuration options for the GoogleMaps user interface. -/// -/// When used to change configuration, null values will be interpreted as -/// "do not change this configuration option". class _GoogleMapOptions { - _GoogleMapOptions({ - this.compassEnabled, - this.mapToolbarEnabled, - this.cameraTargetBounds, - this.mapType, - this.minMaxZoomPreference, - this.rotateGesturesEnabled, - this.scrollGesturesEnabled, - this.tiltGesturesEnabled, - this.trackCameraPosition, - this.zoomControlsEnabled, - this.zoomGesturesEnabled, - this.liteModeEnabled, - this.myLocationEnabled, - this.myLocationButtonEnabled, - this.padding, - this.indoorViewEnabled, - this.trafficEnabled, - this.buildingsEnabled, - }) { - assert(liteModeEnabled == null || - !liteModeEnabled || - (liteModeEnabled && Platform.isAndroid)); - } - - static _GoogleMapOptions fromWidget(GoogleMap map) { - return _GoogleMapOptions( - compassEnabled: map.compassEnabled, - mapToolbarEnabled: map.mapToolbarEnabled, - cameraTargetBounds: map.cameraTargetBounds, - mapType: map.mapType, - minMaxZoomPreference: map.minMaxZoomPreference, - rotateGesturesEnabled: map.rotateGesturesEnabled, - scrollGesturesEnabled: map.scrollGesturesEnabled, - tiltGesturesEnabled: map.tiltGesturesEnabled, - trackCameraPosition: map.onCameraMove != null, - zoomControlsEnabled: map.zoomControlsEnabled, - zoomGesturesEnabled: map.zoomGesturesEnabled, - liteModeEnabled: map.liteModeEnabled, - myLocationEnabled: map.myLocationEnabled, - myLocationButtonEnabled: map.myLocationButtonEnabled, - padding: map.padding, - indoorViewEnabled: map.indoorViewEnabled, - trafficEnabled: map.trafficEnabled, - buildingsEnabled: map.buildingsEnabled, - ); - } + _GoogleMapOptions.fromWidget(GoogleMap map) + : compassEnabled = map.compassEnabled, + mapToolbarEnabled = map.mapToolbarEnabled, + cameraTargetBounds = map.cameraTargetBounds, + mapType = map.mapType, + minMaxZoomPreference = map.minMaxZoomPreference, + rotateGesturesEnabled = map.rotateGesturesEnabled, + scrollGesturesEnabled = map.scrollGesturesEnabled, + tiltGesturesEnabled = map.tiltGesturesEnabled, + trackCameraPosition = map.onCameraMove != null, + zoomControlsEnabled = map.zoomControlsEnabled, + zoomGesturesEnabled = map.zoomGesturesEnabled, + liteModeEnabled = map.liteModeEnabled, + myLocationEnabled = map.myLocationEnabled, + myLocationButtonEnabled = map.myLocationButtonEnabled, + padding = map.padding, + indoorViewEnabled = map.indoorViewEnabled, + trafficEnabled = map.trafficEnabled, + buildingsEnabled = map.buildingsEnabled, + assert(!map.liteModeEnabled || Platform.isAndroid); final bool compassEnabled; @@ -481,38 +505,31 @@ class _GoogleMapOptions { final bool buildingsEnabled; Map toMap() { - final Map optionsMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - optionsMap[fieldName] = value; - } - } - - addIfNonNull('compassEnabled', compassEnabled); - addIfNonNull('mapToolbarEnabled', mapToolbarEnabled); - addIfNonNull('cameraTargetBounds', cameraTargetBounds?.toJson()); - addIfNonNull('mapType', mapType?.index); - addIfNonNull('minMaxZoomPreference', minMaxZoomPreference?.toJson()); - addIfNonNull('rotateGesturesEnabled', rotateGesturesEnabled); - addIfNonNull('scrollGesturesEnabled', scrollGesturesEnabled); - addIfNonNull('tiltGesturesEnabled', tiltGesturesEnabled); - addIfNonNull('zoomControlsEnabled', zoomControlsEnabled); - addIfNonNull('zoomGesturesEnabled', zoomGesturesEnabled); - addIfNonNull('liteModeEnabled', liteModeEnabled); - addIfNonNull('trackCameraPosition', trackCameraPosition); - addIfNonNull('myLocationEnabled', myLocationEnabled); - addIfNonNull('myLocationButtonEnabled', myLocationButtonEnabled); - addIfNonNull('padding', [ - padding?.top, - padding?.left, - padding?.bottom, - padding?.right, - ]); - addIfNonNull('indoorEnabled', indoorViewEnabled); - addIfNonNull('trafficEnabled', trafficEnabled); - addIfNonNull('buildingsEnabled', buildingsEnabled); - return optionsMap; + return { + 'compassEnabled': compassEnabled, + 'mapToolbarEnabled': mapToolbarEnabled, + 'cameraTargetBounds': cameraTargetBounds.toJson(), + 'mapType': mapType.index, + 'minMaxZoomPreference': minMaxZoomPreference.toJson(), + 'rotateGesturesEnabled': rotateGesturesEnabled, + 'scrollGesturesEnabled': scrollGesturesEnabled, + 'tiltGesturesEnabled': tiltGesturesEnabled, + 'zoomControlsEnabled': zoomControlsEnabled, + 'zoomGesturesEnabled': zoomGesturesEnabled, + 'liteModeEnabled': liteModeEnabled, + 'trackCameraPosition': trackCameraPosition, + 'myLocationEnabled': myLocationEnabled, + 'myLocationButtonEnabled': myLocationButtonEnabled, + 'padding': [ + padding.top, + padding.left, + padding.bottom, + padding.right, + ], + 'indoorEnabled': indoorViewEnabled, + 'trafficEnabled': trafficEnabled, + 'buildingsEnabled': buildingsEnabled, + }; } Map updatesMap(_GoogleMapOptions newOptions) { diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 20bd56ab57da..8e9ab62d5f38 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,13 +1,13 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 1.2.0 +version: 2.0.0-nullsafety dependencies: flutter: sdk: flutter - flutter_plugin_android_lifecycle: ^1.0.0 - google_maps_flutter_platform_interface: ^1.2.0 + flutter_plugin_android_lifecycle: ^2.0.0-nullsafety.2 + google_maps_flutter_platform_interface: ^2.0.0-nullsafety.1 dev_dependencies: flutter_test: @@ -17,10 +17,10 @@ dev_dependencies: # https://github.com/dart-lang/pub/issues/2101 is resolved. flutter_driver: sdk: flutter - test: ^1.6.0 - pedantic: ^1.8.0 - plugin_platform_interface: ^1.0.2 - mockito: ^4.1.1 + test: ^1.16.0-nullsafety.17 + pedantic: ^1.10.0-nullsafety.3 + plugin_platform_interface: ^1.1.0-nullsafety.2 + stream_transform: ^2.0.0-nullsafety.0 flutter: plugin: @@ -32,5 +32,5 @@ flutter: pluginClass: FLTGoogleMapsPlugin environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.22.0" diff --git a/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart index 194efe9a66f0..2399b7b15eff 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart @@ -37,7 +37,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.liteModeEnabled, false); diff --git a/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart index 3533ceb229e3..d61526b2bbeb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart @@ -9,20 +9,6 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'fake_maps_controllers.dart'; -Set _toSet({Circle c1, Circle c2, Circle c3}) { - final Set res = Set.identity(); - if (c1 != null) { - res.add(c1); - } - if (c2 != null) { - res.add(c2); - } - if (c3 != null) { - res.add(c3); - } - return res; -} - Widget _mapWithCircles(Set circles) { return Directionality( textDirection: TextDirection.ltr, @@ -50,10 +36,10 @@ void main() { testWidgets('Initializing a circle', (WidgetTester tester) async { final Circle c1 = Circle(circleId: CircleId("circle_1")); - await tester.pumpWidget(_mapWithCircles(_toSet(c1: c1))); + await tester.pumpWidget(_mapWithCircles({c1})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.circlesToAdd.length, 1); final Circle initializedCircle = platformGoogleMap.circlesToAdd.first; @@ -66,11 +52,11 @@ void main() { final Circle c1 = Circle(circleId: CircleId("circle_1")); final Circle c2 = Circle(circleId: CircleId("circle_2")); - await tester.pumpWidget(_mapWithCircles(_toSet(c1: c1))); - await tester.pumpWidget(_mapWithCircles(_toSet(c1: c1, c2: c2))); + await tester.pumpWidget(_mapWithCircles({c1})); + await tester.pumpWidget(_mapWithCircles({c1, c2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.circlesToAdd.length, 1); final Circle addedCircle = platformGoogleMap.circlesToAdd.first; @@ -84,11 +70,11 @@ void main() { testWidgets("Removing a circle", (WidgetTester tester) async { final Circle c1 = Circle(circleId: CircleId("circle_1")); - await tester.pumpWidget(_mapWithCircles(_toSet(c1: c1))); - await tester.pumpWidget(_mapWithCircles(null)); + await tester.pumpWidget(_mapWithCircles({c1})); + await tester.pumpWidget(_mapWithCircles({})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.circleIdsToRemove.length, 1); expect(platformGoogleMap.circleIdsToRemove.first, equals(c1.circleId)); @@ -100,11 +86,11 @@ void main() { final Circle c1 = Circle(circleId: CircleId("circle_1")); final Circle c2 = Circle(circleId: CircleId("circle_1"), radius: 10); - await tester.pumpWidget(_mapWithCircles(_toSet(c1: c1))); - await tester.pumpWidget(_mapWithCircles(_toSet(c1: c2))); + await tester.pumpWidget(_mapWithCircles({c1})); + await tester.pumpWidget(_mapWithCircles({c2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.circlesToChange.length, 1); expect(platformGoogleMap.circlesToChange.first, equals(c2)); @@ -116,11 +102,11 @@ void main() { final Circle c1 = Circle(circleId: CircleId("circle_1")); final Circle c2 = Circle(circleId: CircleId("circle_1"), radius: 10); - await tester.pumpWidget(_mapWithCircles(_toSet(c1: c1))); - await tester.pumpWidget(_mapWithCircles(_toSet(c1: c2))); + await tester.pumpWidget(_mapWithCircles({c1})); + await tester.pumpWidget(_mapWithCircles({c2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.circlesToChange.length, 1); final Circle update = platformGoogleMap.circlesToChange.first; @@ -131,16 +117,16 @@ void main() { testWidgets("Multi Update", (WidgetTester tester) async { Circle c1 = Circle(circleId: CircleId("circle_1")); Circle c2 = Circle(circleId: CircleId("circle_2")); - final Set prev = _toSet(c1: c1, c2: c2); + final Set prev = {c1, c2}; c1 = Circle(circleId: CircleId("circle_1"), visible: false); c2 = Circle(circleId: CircleId("circle_2"), radius: 10); - final Set cur = _toSet(c1: c1, c2: c2); + final Set cur = {c1, c2}; await tester.pumpWidget(_mapWithCircles(prev)); await tester.pumpWidget(_mapWithCircles(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.circlesToChange, cur); expect(platformGoogleMap.circleIdsToRemove.isEmpty, true); @@ -150,18 +136,18 @@ void main() { testWidgets("Multi Update", (WidgetTester tester) async { Circle c2 = Circle(circleId: CircleId("circle_2")); final Circle c3 = Circle(circleId: CircleId("circle_3")); - final Set prev = _toSet(c2: c2, c3: c3); + final Set prev = {c2, c3}; // c1 is added, c2 is updated, c3 is removed. final Circle c1 = Circle(circleId: CircleId("circle_1")); c2 = Circle(circleId: CircleId("circle_2"), radius: 10); - final Set cur = _toSet(c1: c1, c2: c2); + final Set cur = {c1, c2}; await tester.pumpWidget(_mapWithCircles(prev)); await tester.pumpWidget(_mapWithCircles(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.circlesToChange.length, 1); expect(platformGoogleMap.circlesToAdd.length, 1); @@ -176,32 +162,32 @@ void main() { final Circle c1 = Circle(circleId: CircleId("circle_1")); final Circle c2 = Circle(circleId: CircleId("circle_2")); Circle c3 = Circle(circleId: CircleId("circle_3")); - final Set prev = _toSet(c1: c1, c2: c2, c3: c3); + final Set prev = {c1, c2, c3}; c3 = Circle(circleId: CircleId("circle_3"), radius: 10); - final Set cur = _toSet(c1: c1, c2: c2, c3: c3); + final Set cur = {c1, c2, c3}; await tester.pumpWidget(_mapWithCircles(prev)); await tester.pumpWidget(_mapWithCircles(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; - expect(platformGoogleMap.circlesToChange, _toSet(c3: c3)); + expect(platformGoogleMap.circlesToChange, {c3}); expect(platformGoogleMap.circleIdsToRemove.isEmpty, true); expect(platformGoogleMap.circlesToAdd.isEmpty, true); }); testWidgets("Update non platform related attr", (WidgetTester tester) async { Circle c1 = Circle(circleId: CircleId("circle_1")); - final Set prev = _toSet(c1: c1); + final Set prev = {c1}; c1 = Circle(circleId: CircleId("circle_1"), onTap: () => print("hello")); - final Set cur = _toSet(c1: c1); + final Set cur = {c1}; await tester.pumpWidget(_mapWithCircles(prev)); await tester.pumpWidget(_mapWithCircles(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.circlesToChange.isEmpty, true); expect(platformGoogleMap.circleIdsToRemove.isEmpty, true); diff --git a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart index d72ac2ebe656..8bc0fbb1d86e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart @@ -9,10 +9,11 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; class FakePlatformGoogleMap { - FakePlatformGoogleMap(int id, Map params) { - cameraPosition = CameraPosition.fromMap(params['initialCameraPosition']); - channel = MethodChannel( - 'plugins.flutter.io/google_maps_$id', const StandardMethodCodec()); + FakePlatformGoogleMap(int id, Map params) + : cameraPosition = + CameraPosition.fromMap(params['initialCameraPosition']), + channel = MethodChannel( + 'plugins.flutter.io/google_maps_$id', const StandardMethodCodec()) { channel.setMockMethodCallHandler(onMethodCall); updateOptions(params['options']); updateMarkers(params); @@ -24,71 +25,71 @@ class FakePlatformGoogleMap { MethodChannel channel; - CameraPosition cameraPosition; + CameraPosition? cameraPosition; - bool compassEnabled; + bool? compassEnabled; - bool mapToolbarEnabled; + bool? mapToolbarEnabled; - CameraTargetBounds cameraTargetBounds; + CameraTargetBounds? cameraTargetBounds; - MapType mapType; + MapType? mapType; - MinMaxZoomPreference minMaxZoomPreference; + MinMaxZoomPreference? minMaxZoomPreference; - bool rotateGesturesEnabled; + bool? rotateGesturesEnabled; - bool scrollGesturesEnabled; + bool? scrollGesturesEnabled; - bool tiltGesturesEnabled; + bool? tiltGesturesEnabled; - bool zoomGesturesEnabled; + bool? zoomGesturesEnabled; - bool zoomControlsEnabled; + bool? zoomControlsEnabled; - bool liteModeEnabled; + bool? liteModeEnabled; - bool trackCameraPosition; + bool? trackCameraPosition; - bool myLocationEnabled; + bool? myLocationEnabled; - bool trafficEnabled; + bool? trafficEnabled; - bool buildingsEnabled; + bool? buildingsEnabled; - bool myLocationButtonEnabled; + bool? myLocationButtonEnabled; - List padding; + List? padding; - Set markerIdsToRemove; + Set markerIdsToRemove = {}; - Set markersToAdd; + Set markersToAdd = {}; - Set markersToChange; + Set markersToChange = {}; - Set polygonIdsToRemove; + Set polygonIdsToRemove = {}; - Set polygonsToAdd; + Set polygonsToAdd = {}; - Set polygonsToChange; + Set polygonsToChange = {}; - Set polylineIdsToRemove; + Set polylineIdsToRemove = {}; - Set polylinesToAdd; + Set polylinesToAdd = {}; - Set polylinesToChange; + Set polylinesToChange = {}; - Set circleIdsToRemove; + Set circleIdsToRemove = {}; - Set circlesToAdd; + Set circlesToAdd = {}; - Set circlesToChange; + Set circlesToChange = {}; - Set tileOverlayIdsToRemove; + Set tileOverlayIdsToRemove = {}; - Set tileOverlaysToAdd; + Set tileOverlaysToAdd = {}; - Set tileOverlaysToChange; + Set tileOverlaysToChange = {}; Future onMethodCall(MethodCall call) { switch (call.method) { @@ -116,7 +117,7 @@ class FakePlatformGoogleMap { } } - void updateMarkers(Map markerUpdates) { + void updateMarkers(Map? markerUpdates) { if (markerUpdates == null) { return; } @@ -126,29 +127,21 @@ class FakePlatformGoogleMap { markersToChange = _deserializeMarkers(markerUpdates['markersToChange']); } - Set _deserializeMarkerIds(List markerIds) { + Set _deserializeMarkerIds(List? markerIds) { if (markerIds == null) { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return Set(); + return {}; } return markerIds.map((dynamic markerId) => MarkerId(markerId)).toSet(); } Set _deserializeMarkers(dynamic markers) { if (markers == null) { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return Set(); + return {}; } final List markersData = markers; - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - final Set result = Set(); - for (Map markerData in markersData) { + final Set result = {}; + for (Map markerData + in markersData.cast>()) { final String markerId = markerData['markerId']; final double alpha = markerData['alpha']; final bool draggable = markerData['draggable']; @@ -176,7 +169,7 @@ class FakePlatformGoogleMap { return result; } - void updatePolygons(Map polygonUpdates) { + void updatePolygons(Map? polygonUpdates) { if (polygonUpdates == null) { return; } @@ -186,29 +179,21 @@ class FakePlatformGoogleMap { polygonsToChange = _deserializePolygons(polygonUpdates['polygonsToChange']); } - Set _deserializePolygonIds(List polygonIds) { + Set _deserializePolygonIds(List? polygonIds) { if (polygonIds == null) { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return Set(); + return {}; } return polygonIds.map((dynamic polygonId) => PolygonId(polygonId)).toSet(); } Set _deserializePolygons(dynamic polygons) { if (polygons == null) { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return Set(); + return {}; } final List polygonsData = polygons; - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - final Set result = Set(); - for (Map polygonData in polygonsData) { + final Set result = {}; + for (Map polygonData + in polygonsData.cast>()) { final String polygonId = polygonData['polygonId']; final bool visible = polygonData['visible']; final bool geodesic = polygonData['geodesic']; @@ -241,7 +226,7 @@ class FakePlatformGoogleMap { }).toList(); } - void updatePolylines(Map polylineUpdates) { + void updatePolylines(Map? polylineUpdates) { if (polylineUpdates == null) { return; } @@ -252,12 +237,9 @@ class FakePlatformGoogleMap { _deserializePolylines(polylineUpdates['polylinesToChange']); } - Set _deserializePolylineIds(List polylineIds) { + Set _deserializePolylineIds(List? polylineIds) { if (polylineIds == null) { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return Set(); + return {}; } return polylineIds .map((dynamic polylineId) => PolylineId(polylineId)) @@ -266,17 +248,12 @@ class FakePlatformGoogleMap { Set _deserializePolylines(dynamic polylines) { if (polylines == null) { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return Set(); + return {}; } final List polylinesData = polylines; - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - final Set result = Set(); - for (Map polylineData in polylinesData) { + final Set result = {}; + for (Map polylineData + in polylinesData.cast>()) { final String polylineId = polylineData['polylineId']; final bool visible = polylineData['visible']; final bool geodesic = polylineData['geodesic']; @@ -293,7 +270,7 @@ class FakePlatformGoogleMap { return result; } - void updateCircles(Map circleUpdates) { + void updateCircles(Map? circleUpdates) { if (circleUpdates == null) { return; } @@ -307,17 +284,17 @@ class FakePlatformGoogleMap { if (updateTileOverlayUpdates == null) { return; } - final List> tileOverlaysToAddList = + final List>? tileOverlaysToAddList = updateTileOverlayUpdates['tileOverlaysToAdd'] != null ? List.castFrom>( updateTileOverlayUpdates['tileOverlaysToAdd']) : null; - final List tileOverlayIdsToRemoveList = + final List? tileOverlayIdsToRemoveList = updateTileOverlayUpdates['tileOverlayIdsToRemove'] != null ? List.castFrom( updateTileOverlayUpdates['tileOverlayIdsToRemove']) : null; - final List> tileOverlaysToChangeList = + final List>? tileOverlaysToChangeList = updateTileOverlayUpdates['tileOverlaysToChange'] != null ? List.castFrom>( updateTileOverlayUpdates['tileOverlaysToChange']) @@ -328,29 +305,21 @@ class FakePlatformGoogleMap { tileOverlaysToChange = _deserializeTileOverlays(tileOverlaysToChangeList); } - Set _deserializeCircleIds(List circleIds) { + Set _deserializeCircleIds(List? circleIds) { if (circleIds == null) { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return Set(); + return {}; } return circleIds.map((dynamic circleId) => CircleId(circleId)).toSet(); } Set _deserializeCircles(dynamic circles) { if (circles == null) { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return Set(); + return {}; } final List circlesData = circles; - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - final Set result = Set(); - for (Map circleData in circlesData) { + final Set result = {}; + for (Map circleData + in circlesData.cast>()) { final String circleId = circleData['circleId']; final bool visible = circleData['visible']; final double radius = circleData['radius']; @@ -365,12 +334,9 @@ class FakePlatformGoogleMap { return result; } - Set _deserializeTileOverlayIds(List tileOverlayIds) { + Set _deserializeTileOverlayIds(List? tileOverlayIds) { if (tileOverlayIds == null || tileOverlayIds.isEmpty) { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return Set(); + return {}; } return tileOverlayIds .map((String tileOverlayId) => TileOverlayId(tileOverlayId)) @@ -378,17 +344,11 @@ class FakePlatformGoogleMap { } Set _deserializeTileOverlays( - List> tileOverlays) { + List>? tileOverlays) { if (tileOverlays == null || tileOverlays.isEmpty) { - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - return Set(); - } - // TODO(iskakaushik): Remove this when collection literals makes it to stable. - // https://github.com/flutter/flutter/issues/28312 - // ignore: prefer_collection_literals - final Set result = Set(); + return {}; + } + final Set result = {}; for (Map tileOverlayData in tileOverlays) { final String tileOverlayId = tileOverlayData['tileOverlayId']; final bool fadeIn = tileOverlayData['fadeIn']; @@ -469,13 +429,13 @@ class FakePlatformGoogleMap { } class FakePlatformViewsController { - FakePlatformGoogleMap lastCreatedView; + FakePlatformGoogleMap? lastCreatedView; Future fakePlatformViewsMethodHandler(MethodCall call) { switch (call.method) { case 'create': final Map args = call.arguments; - final Map params = _decodeParams(args['params']); + final Map params = _decodeParams(args['params'])!; lastCreatedView = FakePlatformGoogleMap( args['id'], params, @@ -491,7 +451,7 @@ class FakePlatformViewsController { } } -Map _decodeParams(Uint8List paramsMessage) { +Map? _decodeParams(Uint8List paramsMessage) { final ByteBuffer buffer = paramsMessage.buffer; final ByteData messageBytes = buffer.asByteData( paramsMessage.offsetInBytes, diff --git a/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart index 3c1eadb8d2a4..857344f5ac5e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart @@ -35,7 +35,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.cameraPosition, const CameraPosition(target: LatLng(10.0, 15.0))); @@ -62,7 +62,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.cameraPosition, const CameraPosition(target: LatLng(10.0, 15.0))); @@ -80,7 +80,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.compassEnabled, false); @@ -109,7 +109,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.mapToolbarEnabled, false); @@ -144,7 +144,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect( platformGoogleMap.cameraTargetBounds, @@ -193,7 +193,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.mapType, MapType.hybrid); @@ -222,7 +222,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.minMaxZoomPreference, const MinMaxZoomPreference(1.0, 3.0)); @@ -253,7 +253,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.rotateGesturesEnabled, false); @@ -282,7 +282,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.scrollGesturesEnabled, false); @@ -311,7 +311,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.tiltGesturesEnabled, false); @@ -339,7 +339,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.trackCameraPosition, false); @@ -369,7 +369,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.zoomGesturesEnabled, false); @@ -398,7 +398,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.zoomControlsEnabled, false); @@ -427,7 +427,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.myLocationEnabled, false); @@ -457,7 +457,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.myLocationButtonEnabled, true); @@ -485,7 +485,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.padding, [0, 0, 0, 0]); }); @@ -501,7 +501,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.padding, [0, 0, 0, 0]); @@ -542,7 +542,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.trafficEnabled, false); @@ -571,7 +571,7 @@ void main() { ); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.buildingsEnabled, false); diff --git a/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart index 5ea9a679a1be..684e8659c4b5 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart @@ -2,26 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'package:mockito/mockito.dart'; - -class MockGoogleMapsFlutterPlatform extends Mock - with MockPlatformInterfaceMixin - implements GoogleMapsFlutterPlatform {} +import 'package:stream_transform/stream_transform.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - final platform = MockGoogleMapsFlutterPlatform(); + late TestGoogleMapsFlutterPlatform platform; setUp(() { // Use a mock platform so we never need to hit the MethodChannel code. + platform = TestGoogleMapsFlutterPlatform(); GoogleMapsFlutterPlatform.instance = platform; - resetMockitoState(); - _setupMock(platform); }); testWidgets('_webOnlyMapCreationId increments with each GoogleMap widget', ( @@ -49,18 +49,9 @@ void main() { ); // Verify that each one was created with a different _webOnlyMapCreationId. - verifyInOrder([ - platform.buildView( - argThat(containsPair('_webOnlyMapCreationId', 0)), - any, - any, - ), - platform.buildView( - argThat(containsPair('_webOnlyMapCreationId', 1)), - any, - any, - ), - ]); + expect(platform.createdIds.length, 2); + expect(platform.createdIds[0], 0); + expect(platform.createdIds[1], 1); }); testWidgets('Calls platform.dispose when GoogleMap is disposed of', ( @@ -75,47 +66,220 @@ void main() { // Now dispose of the map... await tester.pumpWidget(Container()); - verify(platform.dispose(mapId: anyNamed('mapId'))); + expect(platform.disposed, true); }); } -// Some test setup classes below... +// A dummy implementation of the platform interface for tests. +class TestGoogleMapsFlutterPlatform extends GoogleMapsFlutterPlatform { + TestGoogleMapsFlutterPlatform(); + + // The IDs passed to each call to buildView, in call order. + List createdIds = []; + + // Whether `dispose` has been called. + bool disposed = false; + + // Stream controller to inject events for testing. + final StreamController mapEventStreamController = + StreamController.broadcast(); + + @override + Future init(int mapId) async {} + + @override + Future updateMapOptions( + Map optionsUpdate, { + required int mapId, + }) async {} + + @override + Future updateMarkers( + MarkerUpdates markerUpdates, { + required int mapId, + }) async {} + + @override + Future updatePolygons( + PolygonUpdates polygonUpdates, { + required int mapId, + }) async {} + + @override + Future updatePolylines( + PolylineUpdates polylineUpdates, { + required int mapId, + }) async {} + + @override + Future updateCircles( + CircleUpdates circleUpdates, { + required int mapId, + }) async {} + + @override + Future updateTileOverlays({ + required Set newTileOverlays, + required int mapId, + }) async {} + + @override + Future clearTileCache( + TileOverlayId tileOverlayId, { + required int mapId, + }) async {} + + @override + Future animateCamera( + CameraUpdate cameraUpdate, { + required int mapId, + }) async {} + + @override + Future moveCamera( + CameraUpdate cameraUpdate, { + required int mapId, + }) async {} + + @override + Future setMapStyle( + String? mapStyle, { + required int mapId, + }) async {} + + @override + Future getVisibleRegion({ + required int mapId, + }) async { + return LatLngBounds(southwest: LatLng(0, 0), northeast: LatLng(0, 0)); + } -class _MockStream extends Mock implements Stream {} + @override + Future getScreenCoordinate( + LatLng latLng, { + required int mapId, + }) async { + return ScreenCoordinate(x: 0, y: 0); + } -typedef _CreationCallback = void Function(int); + @override + Future getLatLng( + ScreenCoordinate screenCoordinate, { + required int mapId, + }) async { + return LatLng(0, 0); + } -// Installs test mocks on the platform -void _setupMock(MockGoogleMapsFlutterPlatform platform) { - // Used to create the view of the map... - when(platform.buildView(any, any, any)).thenAnswer((realInvocation) { - // Call the onPlatformViewCreated callback so the controller gets created. - _CreationCallback onPlatformViewCreatedCb = - realInvocation.positionalArguments[2]; - onPlatformViewCreatedCb.call(0); + @override + Future showMarkerInfoWindow( + MarkerId markerId, { + required int mapId, + }) async {} + + @override + Future hideMarkerInfoWindow( + MarkerId markerId, { + required int mapId, + }) async {} + + @override + Future isMarkerInfoWindowShown( + MarkerId markerId, { + required int mapId, + }) async { + return false; + } + + @override + Future getZoomLevel({ + required int mapId, + }) async { + return 0.0; + } + + @override + Future takeSnapshot({ + required int mapId, + }) async { + return null; + } + + @override + Stream onCameraMoveStarted({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCameraMove({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCameraIdle({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onInfoWindowTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerDragEnd({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onPolylineTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onPolygonTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCircleTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onLongPress({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + void dispose({required int mapId}) { + disposed = true; + } + + @override + Widget buildView( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required CameraPosition initialCameraPosition, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set>? gestureRecognizers = + const >{}, + Map mapOptions = const {}, + }) { + onPlatformViewCreated(0); + createdIds.add(creationId); return Container(); - }); - // Used to create the Controller - when(platform.onCameraIdle(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); - when(platform.onCameraMove(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); - when(platform.onCameraMoveStarted(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); - when(platform.onCircleTap(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); - when(platform.onInfoWindowTap(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); - when(platform.onLongPress(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); - when(platform.onMarkerDragEnd(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); - when(platform.onMarkerTap(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); - when(platform.onPolygonTap(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); - when(platform.onPolylineTap(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); - when(platform.onTap(mapId: anyNamed('mapId'))) - .thenAnswer((_) => _MockStream()); + } } diff --git a/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart index 620e1ef4bfea..ce0da4235c9c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart @@ -9,20 +9,6 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'fake_maps_controllers.dart'; -Set _toSet({Marker m1, Marker m2, Marker m3}) { - final Set res = Set.identity(); - if (m1 != null) { - res.add(m1); - } - if (m2 != null) { - res.add(m2); - } - if (m3 != null) { - res.add(m3); - } - return res; -} - Widget _mapWithMarkers(Set markers) { return Directionality( textDirection: TextDirection.ltr, @@ -50,10 +36,10 @@ void main() { testWidgets('Initializing a marker', (WidgetTester tester) async { final Marker m1 = Marker(markerId: MarkerId("marker_1")); - await tester.pumpWidget(_mapWithMarkers(_toSet(m1: m1))); + await tester.pumpWidget(_mapWithMarkers({m1})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.markersToAdd.length, 1); final Marker initializedMarker = platformGoogleMap.markersToAdd.first; @@ -66,11 +52,11 @@ void main() { final Marker m1 = Marker(markerId: MarkerId("marker_1")); final Marker m2 = Marker(markerId: MarkerId("marker_2")); - await tester.pumpWidget(_mapWithMarkers(_toSet(m1: m1))); - await tester.pumpWidget(_mapWithMarkers(_toSet(m1: m1, m2: m2))); + await tester.pumpWidget(_mapWithMarkers({m1})); + await tester.pumpWidget(_mapWithMarkers({m1, m2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.markersToAdd.length, 1); final Marker addedMarker = platformGoogleMap.markersToAdd.first; @@ -84,11 +70,11 @@ void main() { testWidgets("Removing a marker", (WidgetTester tester) async { final Marker m1 = Marker(markerId: MarkerId("marker_1")); - await tester.pumpWidget(_mapWithMarkers(_toSet(m1: m1))); - await tester.pumpWidget(_mapWithMarkers(null)); + await tester.pumpWidget(_mapWithMarkers({m1})); + await tester.pumpWidget(_mapWithMarkers({})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.markerIdsToRemove.length, 1); expect(platformGoogleMap.markerIdsToRemove.first, equals(m1.markerId)); @@ -100,11 +86,11 @@ void main() { final Marker m1 = Marker(markerId: MarkerId("marker_1")); final Marker m2 = Marker(markerId: MarkerId("marker_1"), alpha: 0.5); - await tester.pumpWidget(_mapWithMarkers(_toSet(m1: m1))); - await tester.pumpWidget(_mapWithMarkers(_toSet(m1: m2))); + await tester.pumpWidget(_mapWithMarkers({m1})); + await tester.pumpWidget(_mapWithMarkers({m2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.markersToChange.length, 1); expect(platformGoogleMap.markersToChange.first, equals(m2)); @@ -119,11 +105,11 @@ void main() { infoWindow: const InfoWindow(snippet: 'changed'), ); - await tester.pumpWidget(_mapWithMarkers(_toSet(m1: m1))); - await tester.pumpWidget(_mapWithMarkers(_toSet(m1: m2))); + await tester.pumpWidget(_mapWithMarkers({m1})); + await tester.pumpWidget(_mapWithMarkers({m2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.markersToChange.length, 1); final Marker update = platformGoogleMap.markersToChange.first; @@ -134,16 +120,16 @@ void main() { testWidgets("Multi Update", (WidgetTester tester) async { Marker m1 = Marker(markerId: MarkerId("marker_1")); Marker m2 = Marker(markerId: MarkerId("marker_2")); - final Set prev = _toSet(m1: m1, m2: m2); + final Set prev = {m1, m2}; m1 = Marker(markerId: MarkerId("marker_1"), visible: false); m2 = Marker(markerId: MarkerId("marker_2"), draggable: true); - final Set cur = _toSet(m1: m1, m2: m2); + final Set cur = {m1, m2}; await tester.pumpWidget(_mapWithMarkers(prev)); await tester.pumpWidget(_mapWithMarkers(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.markersToChange, cur); expect(platformGoogleMap.markerIdsToRemove.isEmpty, true); @@ -153,18 +139,18 @@ void main() { testWidgets("Multi Update", (WidgetTester tester) async { Marker m2 = Marker(markerId: MarkerId("marker_2")); final Marker m3 = Marker(markerId: MarkerId("marker_3")); - final Set prev = _toSet(m2: m2, m3: m3); + final Set prev = {m2, m3}; // m1 is added, m2 is updated, m3 is removed. final Marker m1 = Marker(markerId: MarkerId("marker_1")); m2 = Marker(markerId: MarkerId("marker_2"), draggable: true); - final Set cur = _toSet(m1: m1, m2: m2); + final Set cur = {m1, m2}; await tester.pumpWidget(_mapWithMarkers(prev)); await tester.pumpWidget(_mapWithMarkers(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.markersToChange.length, 1); expect(platformGoogleMap.markersToAdd.length, 1); @@ -179,35 +165,35 @@ void main() { final Marker m1 = Marker(markerId: MarkerId("marker_1")); final Marker m2 = Marker(markerId: MarkerId("marker_2")); Marker m3 = Marker(markerId: MarkerId("marker_3")); - final Set prev = _toSet(m1: m1, m2: m2, m3: m3); + final Set prev = {m1, m2, m3}; m3 = Marker(markerId: MarkerId("marker_3"), draggable: true); - final Set cur = _toSet(m1: m1, m2: m2, m3: m3); + final Set cur = {m1, m2, m3}; await tester.pumpWidget(_mapWithMarkers(prev)); await tester.pumpWidget(_mapWithMarkers(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; - expect(platformGoogleMap.markersToChange, _toSet(m3: m3)); + expect(platformGoogleMap.markersToChange, {m3}); expect(platformGoogleMap.markerIdsToRemove.isEmpty, true); expect(platformGoogleMap.markersToAdd.isEmpty, true); }); testWidgets("Update non platform related attr", (WidgetTester tester) async { Marker m1 = Marker(markerId: MarkerId("marker_1")); - final Set prev = _toSet(m1: m1); + final Set prev = {m1}; m1 = Marker( markerId: MarkerId("marker_1"), onTap: () => print("hello"), onDragEnd: (LatLng latLng) => print(latLng)); - final Set cur = _toSet(m1: m1); + final Set cur = {m1}; await tester.pumpWidget(_mapWithMarkers(prev)); await tester.pumpWidget(_mapWithMarkers(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.markersToChange.isEmpty, true); expect(platformGoogleMap.markerIdsToRemove.isEmpty, true); diff --git a/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart index 667c7d83644e..e187426bf7f6 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart @@ -9,20 +9,6 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'fake_maps_controllers.dart'; -Set _toSet({Polygon p1, Polygon p2, Polygon p3}) { - final Set res = Set.identity(); - if (p1 != null) { - res.add(p1); - } - if (p2 != null) { - res.add(p2); - } - if (p3 != null) { - res.add(p3); - } - return res; -} - Widget _mapWithPolygons(Set polygons) { return Directionality( textDirection: TextDirection.ltr, @@ -34,7 +20,7 @@ Widget _mapWithPolygons(Set polygons) { } List _rectPoints({ - @required double size, + required double size, LatLng center = const LatLng(0, 0), }) { final halfSize = size / 2; @@ -73,10 +59,10 @@ void main() { testWidgets('Initializing a polygon', (WidgetTester tester) async { final Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolygons({p1})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToAdd.length, 1); final Polygon initializedPolygon = platformGoogleMap.polygonsToAdd.first; @@ -89,11 +75,11 @@ void main() { final Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); final Polygon p2 = Polygon(polygonId: PolygonId("polygon_2")); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1, p2: p2))); + await tester.pumpWidget(_mapWithPolygons({p1})); + await tester.pumpWidget(_mapWithPolygons({p1, p2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToAdd.length, 1); final Polygon addedPolygon = platformGoogleMap.polygonsToAdd.first; @@ -107,11 +93,11 @@ void main() { testWidgets("Removing a polygon", (WidgetTester tester) async { final Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolygons(null)); + await tester.pumpWidget(_mapWithPolygons({p1})); + await tester.pumpWidget(_mapWithPolygons({})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonIdsToRemove.length, 1); expect(platformGoogleMap.polygonIdsToRemove.first, equals(p1.polygonId)); @@ -124,11 +110,11 @@ void main() { final Polygon p2 = Polygon(polygonId: PolygonId("polygon_1"), geodesic: true); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p2))); + await tester.pumpWidget(_mapWithPolygons({p1})); + await tester.pumpWidget(_mapWithPolygons({p2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToChange.length, 1); expect(platformGoogleMap.polygonsToChange.first, equals(p2)); @@ -141,13 +127,13 @@ void main() { polygonId: PolygonId("polygon_1"), points: [const LatLng(0.0, 0.0)], ); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolygons({p1})); p1.points.add(const LatLng(1.0, 1.0)); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolygons({p1})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToChange.length, 1); expect(platformGoogleMap.polygonsToChange.first, equals(p1)); @@ -158,16 +144,16 @@ void main() { testWidgets("Multi Update", (WidgetTester tester) async { Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); Polygon p2 = Polygon(polygonId: PolygonId("polygon_2")); - final Set prev = _toSet(p1: p1, p2: p2); + final Set prev = {p1, p2}; p1 = Polygon(polygonId: PolygonId("polygon_1"), visible: false); p2 = Polygon(polygonId: PolygonId("polygon_2"), geodesic: true); - final Set cur = _toSet(p1: p1, p2: p2); + final Set cur = {p1, p2}; await tester.pumpWidget(_mapWithPolygons(prev)); await tester.pumpWidget(_mapWithPolygons(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToChange, cur); expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); @@ -177,18 +163,18 @@ void main() { testWidgets("Multi Update", (WidgetTester tester) async { Polygon p2 = Polygon(polygonId: PolygonId("polygon_2")); final Polygon p3 = Polygon(polygonId: PolygonId("polygon_3")); - final Set prev = _toSet(p2: p2, p3: p3); + final Set prev = {p2, p3}; // p1 is added, p2 is updated, p3 is removed. final Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); p2 = Polygon(polygonId: PolygonId("polygon_2"), geodesic: true); - final Set cur = _toSet(p1: p1, p2: p2); + final Set cur = {p1, p2}; await tester.pumpWidget(_mapWithPolygons(prev)); await tester.pumpWidget(_mapWithPolygons(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToChange.length, 1); expect(platformGoogleMap.polygonsToAdd.length, 1); @@ -203,32 +189,32 @@ void main() { final Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); final Polygon p2 = Polygon(polygonId: PolygonId("polygon_2")); Polygon p3 = Polygon(polygonId: PolygonId("polygon_3")); - final Set prev = _toSet(p1: p1, p2: p2, p3: p3); + final Set prev = {p1, p2, p3}; p3 = Polygon(polygonId: PolygonId("polygon_3"), geodesic: true); - final Set cur = _toSet(p1: p1, p2: p2, p3: p3); + final Set cur = {p1, p2, p3}; await tester.pumpWidget(_mapWithPolygons(prev)); await tester.pumpWidget(_mapWithPolygons(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; - expect(platformGoogleMap.polygonsToChange, _toSet(p3: p3)); + expect(platformGoogleMap.polygonsToChange, {p3}); expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); expect(platformGoogleMap.polygonsToAdd.isEmpty, true); }); testWidgets("Update non platform related attr", (WidgetTester tester) async { Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); - final Set prev = _toSet(p1: p1); + final Set prev = {p1}; p1 = Polygon(polygonId: PolygonId("polygon_1"), onTap: () => print(2 + 2)); - final Set cur = _toSet(p1: p1); + final Set cur = {p1}; await tester.pumpWidget(_mapWithPolygons(prev)); await tester.pumpWidget(_mapWithPolygons(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToChange.isEmpty, true); expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); @@ -238,10 +224,10 @@ void main() { testWidgets('Initializing a polygon with points and hole', (WidgetTester tester) async { final Polygon p1 = _polygonWithPointsAndHole(PolygonId("polygon_1")); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolygons({p1})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToAdd.length, 1); final Polygon initializedPolygon = platformGoogleMap.polygonsToAdd.first; @@ -255,11 +241,11 @@ void main() { final Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); final Polygon p2 = _polygonWithPointsAndHole(PolygonId("polygon_2")); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1, p2: p2))); + await tester.pumpWidget(_mapWithPolygons({p1})); + await tester.pumpWidget(_mapWithPolygons({p1, p2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToAdd.length, 1); final Polygon addedPolygon = platformGoogleMap.polygonsToAdd.first; @@ -274,11 +260,11 @@ void main() { (WidgetTester tester) async { final Polygon p1 = _polygonWithPointsAndHole(PolygonId("polygon_1")); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolygons(null)); + await tester.pumpWidget(_mapWithPolygons({p1})); + await tester.pumpWidget(_mapWithPolygons({})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonIdsToRemove.length, 1); expect(platformGoogleMap.polygonIdsToRemove.first, equals(p1.polygonId)); @@ -291,11 +277,11 @@ void main() { final Polygon p1 = Polygon(polygonId: PolygonId("polygon_1")); final Polygon p2 = _polygonWithPointsAndHole(PolygonId("polygon_1")); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p2))); + await tester.pumpWidget(_mapWithPolygons({p1})); + await tester.pumpWidget(_mapWithPolygons({p2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToChange.length, 1); expect(platformGoogleMap.polygonsToChange.first, equals(p2)); @@ -310,7 +296,7 @@ void main() { points: _rectPoints(size: 1), holes: [_rectPoints(size: 0.5)], ); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolygons({p1})); p1.points ..clear() @@ -318,10 +304,10 @@ void main() { p1.holes ..clear() ..addAll([_rectPoints(size: 1)]); - await tester.pumpWidget(_mapWithPolygons(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolygons({p1})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToChange.length, 1); expect(platformGoogleMap.polygonsToChange.first, equals(p1)); @@ -337,19 +323,19 @@ void main() { points: _rectPoints(size: 2), holes: [_rectPoints(size: 1)], ); - final Set prev = _toSet(p1: p1, p2: p2); + final Set prev = {p1, p2}; p1 = Polygon(polygonId: PolygonId("polygon_1"), visible: false); p2 = p2.copyWith( pointsParam: _rectPoints(size: 5), holesParam: [_rectPoints(size: 2)], ); - final Set cur = _toSet(p1: p1, p2: p2); + final Set cur = {p1, p2}; await tester.pumpWidget(_mapWithPolygons(prev)); await tester.pumpWidget(_mapWithPolygons(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToChange, cur); expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); @@ -364,7 +350,7 @@ void main() { holes: [_rectPoints(size: 1)], ); final Polygon p3 = Polygon(polygonId: PolygonId("polygon_3")); - final Set prev = _toSet(p2: p2, p3: p3); + final Set prev = {p2, p3}; // p1 is added, p2 is updated, p3 is removed. final Polygon p1 = _polygonWithPointsAndHole(PolygonId("polygon_1")); @@ -372,13 +358,13 @@ void main() { pointsParam: _rectPoints(size: 5), holesParam: [_rectPoints(size: 3)], ); - final Set cur = _toSet(p1: p1, p2: p2); + final Set cur = {p1, p2}; await tester.pumpWidget(_mapWithPolygons(prev)); await tester.pumpWidget(_mapWithPolygons(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polygonsToChange.length, 1); expect(platformGoogleMap.polygonsToAdd.length, 1); @@ -398,20 +384,20 @@ void main() { points: _rectPoints(size: 2), holes: [_rectPoints(size: 1)], ); - final Set prev = _toSet(p1: p1, p2: p2, p3: p3); + final Set prev = {p1, p2, p3}; p3 = p3.copyWith( pointsParam: _rectPoints(size: 5), holesParam: [_rectPoints(size: 3)], ); - final Set cur = _toSet(p1: p1, p2: p2, p3: p3); + final Set cur = {p1, p2, p3}; await tester.pumpWidget(_mapWithPolygons(prev)); await tester.pumpWidget(_mapWithPolygons(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; - expect(platformGoogleMap.polygonsToChange, _toSet(p3: p3)); + expect(platformGoogleMap.polygonsToChange, {p3}); expect(platformGoogleMap.polygonIdsToRemove.isEmpty, true); expect(platformGoogleMap.polygonsToAdd.isEmpty, true); }); diff --git a/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart index 269e8f1313f5..3644f83a1adc 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart @@ -9,20 +9,6 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'fake_maps_controllers.dart'; -Set _toSet({Polyline p1, Polyline p2, Polyline p3}) { - final Set res = Set.identity(); - if (p1 != null) { - res.add(p1); - } - if (p2 != null) { - res.add(p2); - } - if (p3 != null) { - res.add(p3); - } - return res; -} - Widget _mapWithPolylines(Set polylines) { return Directionality( textDirection: TextDirection.ltr, @@ -50,10 +36,10 @@ void main() { testWidgets('Initializing a polyline', (WidgetTester tester) async { final Polyline p1 = Polyline(polylineId: PolylineId("polyline_1")); - await tester.pumpWidget(_mapWithPolylines(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolylines({p1})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polylinesToAdd.length, 1); final Polyline initializedPolyline = platformGoogleMap.polylinesToAdd.first; @@ -66,11 +52,11 @@ void main() { final Polyline p1 = Polyline(polylineId: PolylineId("polyline_1")); final Polyline p2 = Polyline(polylineId: PolylineId("polyline_2")); - await tester.pumpWidget(_mapWithPolylines(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolylines(_toSet(p1: p1, p2: p2))); + await tester.pumpWidget(_mapWithPolylines({p1})); + await tester.pumpWidget(_mapWithPolylines({p1, p2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polylinesToAdd.length, 1); final Polyline addedPolyline = platformGoogleMap.polylinesToAdd.first; @@ -84,11 +70,11 @@ void main() { testWidgets("Removing a polyline", (WidgetTester tester) async { final Polyline p1 = Polyline(polylineId: PolylineId("polyline_1")); - await tester.pumpWidget(_mapWithPolylines(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolylines(null)); + await tester.pumpWidget(_mapWithPolylines({p1})); + await tester.pumpWidget(_mapWithPolylines({})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polylineIdsToRemove.length, 1); expect(platformGoogleMap.polylineIdsToRemove.first, equals(p1.polylineId)); @@ -101,11 +87,11 @@ void main() { final Polyline p2 = Polyline(polylineId: PolylineId("polyline_1"), geodesic: true); - await tester.pumpWidget(_mapWithPolylines(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolylines(_toSet(p1: p2))); + await tester.pumpWidget(_mapWithPolylines({p1})); + await tester.pumpWidget(_mapWithPolylines({p2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polylinesToChange.length, 1); expect(platformGoogleMap.polylinesToChange.first, equals(p2)); @@ -118,11 +104,11 @@ void main() { final Polyline p2 = Polyline(polylineId: PolylineId("polyline_1"), geodesic: true); - await tester.pumpWidget(_mapWithPolylines(_toSet(p1: p1))); - await tester.pumpWidget(_mapWithPolylines(_toSet(p1: p2))); + await tester.pumpWidget(_mapWithPolylines({p1})); + await tester.pumpWidget(_mapWithPolylines({p2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polylinesToChange.length, 1); final Polyline update = platformGoogleMap.polylinesToChange.first; @@ -135,13 +121,13 @@ void main() { polylineId: PolylineId("polyline_1"), points: [const LatLng(0.0, 0.0)], ); - await tester.pumpWidget(_mapWithPolylines(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolylines({p1})); p1.points.add(const LatLng(1.0, 1.0)); - await tester.pumpWidget(_mapWithPolylines(_toSet(p1: p1))); + await tester.pumpWidget(_mapWithPolylines({p1})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polylinesToChange.length, 1); expect(platformGoogleMap.polylinesToChange.first, equals(p1)); @@ -152,16 +138,16 @@ void main() { testWidgets("Multi Update", (WidgetTester tester) async { Polyline p1 = Polyline(polylineId: PolylineId("polyline_1")); Polyline p2 = Polyline(polylineId: PolylineId("polyline_2")); - final Set prev = _toSet(p1: p1, p2: p2); + final Set prev = {p1, p2}; p1 = Polyline(polylineId: PolylineId("polyline_1"), visible: false); p2 = Polyline(polylineId: PolylineId("polyline_2"), geodesic: true); - final Set cur = _toSet(p1: p1, p2: p2); + final Set cur = {p1, p2}; await tester.pumpWidget(_mapWithPolylines(prev)); await tester.pumpWidget(_mapWithPolylines(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polylinesToChange, cur); expect(platformGoogleMap.polylineIdsToRemove.isEmpty, true); @@ -171,18 +157,18 @@ void main() { testWidgets("Multi Update", (WidgetTester tester) async { Polyline p2 = Polyline(polylineId: PolylineId("polyline_2")); final Polyline p3 = Polyline(polylineId: PolylineId("polyline_3")); - final Set prev = _toSet(p2: p2, p3: p3); + final Set prev = {p2, p3}; // p1 is added, p2 is updated, p3 is removed. final Polyline p1 = Polyline(polylineId: PolylineId("polyline_1")); p2 = Polyline(polylineId: PolylineId("polyline_2"), geodesic: true); - final Set cur = _toSet(p1: p1, p2: p2); + final Set cur = {p1, p2}; await tester.pumpWidget(_mapWithPolylines(prev)); await tester.pumpWidget(_mapWithPolylines(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polylinesToChange.length, 1); expect(platformGoogleMap.polylinesToAdd.length, 1); @@ -197,37 +183,33 @@ void main() { final Polyline p1 = Polyline(polylineId: PolylineId("polyline_1")); final Polyline p2 = Polyline(polylineId: PolylineId("polyline_2")); Polyline p3 = Polyline(polylineId: PolylineId("polyline_3")); - final Set prev = _toSet(p1: p1, p2: p2, p3: p3); + final Set prev = {p1, p2, p3}; p3 = Polyline(polylineId: PolylineId("polyline_3"), geodesic: true); - final Set cur = _toSet(p1: p1, p2: p2, p3: p3); + final Set cur = {p1, p2, p3}; await tester.pumpWidget(_mapWithPolylines(prev)); await tester.pumpWidget(_mapWithPolylines(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; - expect(platformGoogleMap.polylinesToChange, _toSet(p3: p3)); + expect(platformGoogleMap.polylinesToChange, {p3}); expect(platformGoogleMap.polylineIdsToRemove.isEmpty, true); expect(platformGoogleMap.polylinesToAdd.isEmpty, true); }); testWidgets("Update non platform related attr", (WidgetTester tester) async { Polyline p1 = Polyline(polylineId: PolylineId("polyline_1"), onTap: null); - final Set prev = _toSet( - p1: p1, - ); + final Set prev = {p1}; p1 = Polyline( polylineId: PolylineId("polyline_1"), onTap: () => print(2 + 2)); - final Set cur = _toSet( - p1: p1, - ); + final Set cur = {p1}; await tester.pumpWidget(_mapWithPolylines(prev)); await tester.pumpWidget(_mapWithPolylines(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.polylinesToChange.isEmpty, true); expect(platformGoogleMap.polylineIdsToRemove.isEmpty, true); diff --git a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart index b94d4906dec7..d2b6efb69e66 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart @@ -5,20 +5,6 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'fake_maps_controllers.dart'; -Set _toSet({TileOverlay t1, TileOverlay t2, TileOverlay t3}) { - final Set res = Set.identity(); - if (t1 != null) { - res.add(t1); - } - if (t2 != null) { - res.add(t2); - } - if (t3 != null) { - res.add(t3); - } - return res; -} - Widget _mapWithTileOverlays(Set tileOverlays) { return Directionality( textDirection: TextDirection.ltr, @@ -45,10 +31,10 @@ void main() { testWidgets('Initializing a tile overlay', (WidgetTester tester) async { final TileOverlay t1 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); - await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); + await tester.pumpWidget(_mapWithTileOverlays({t1})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.tileOverlaysToAdd.length, 1); final TileOverlay initializedTileOverlay = @@ -64,11 +50,11 @@ void main() { final TileOverlay t2 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); - await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); - await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1, t2: t2))); + await tester.pumpWidget(_mapWithTileOverlays({t1})); + await tester.pumpWidget(_mapWithTileOverlays({t1, t2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.tileOverlaysToAdd.length, 1); final TileOverlay addedTileOverlay = @@ -83,11 +69,11 @@ void main() { final TileOverlay t1 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); - await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); - await tester.pumpWidget(_mapWithTileOverlays(null)); + await tester.pumpWidget(_mapWithTileOverlays({t1})); + await tester.pumpWidget(_mapWithTileOverlays({})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.tileOverlayIdsToRemove.length, 1); expect(platformGoogleMap.tileOverlayIdsToRemove.first, equals(t1.tileOverlayId)); @@ -102,11 +88,11 @@ void main() { final TileOverlay t2 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1"), zIndex: 10); - await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); - await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t2))); + await tester.pumpWidget(_mapWithTileOverlays({t1})); + await tester.pumpWidget(_mapWithTileOverlays({t2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.tileOverlaysToChange.length, 1); expect(platformGoogleMap.tileOverlaysToChange.first, equals(t2)); @@ -120,11 +106,11 @@ void main() { final TileOverlay t2 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1"), zIndex: 10); - await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t1))); - await tester.pumpWidget(_mapWithTileOverlays(_toSet(t1: t2))); + await tester.pumpWidget(_mapWithTileOverlays({t1})); + await tester.pumpWidget(_mapWithTileOverlays({t2})); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.tileOverlaysToChange.length, 1); final TileOverlay update = platformGoogleMap.tileOverlaysToChange.first; @@ -137,18 +123,18 @@ void main() { TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); TileOverlay t2 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); - final Set prev = _toSet(t1: t1, t2: t2); + final Set prev = {t1, t2}; t1 = TileOverlay( tileOverlayId: TileOverlayId("tile_overlay_1"), visible: false); t2 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2"), zIndex: 10); - final Set cur = _toSet(t1: t1, t2: t2); + final Set cur = {t1, t2}; await tester.pumpWidget(_mapWithTileOverlays(prev)); await tester.pumpWidget(_mapWithTileOverlays(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.tileOverlaysToChange, cur); expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); @@ -160,20 +146,20 @@ void main() { TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); final TileOverlay t3 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3")); - final Set prev = _toSet(t2: t2, t3: t3); + final Set prev = {t2, t3}; // t1 is added, t2 is updated, t3 is removed. final TileOverlay t1 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_1")); t2 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2"), zIndex: 10); - final Set cur = _toSet(t1: t1, t2: t2); + final Set cur = {t1, t2}; await tester.pumpWidget(_mapWithTileOverlays(prev)); await tester.pumpWidget(_mapWithTileOverlays(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; expect(platformGoogleMap.tileOverlaysToChange.length, 1); expect(platformGoogleMap.tileOverlaysToAdd.length, 1); @@ -192,18 +178,18 @@ void main() { TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_2")); TileOverlay t3 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3")); - final Set prev = _toSet(t1: t1, t2: t2, t3: t3); + final Set prev = {t1, t2, t3}; t3 = TileOverlay(tileOverlayId: TileOverlayId("tile_overlay_3"), zIndex: 10); - final Set cur = _toSet(t1: t1, t2: t2, t3: t3); + final Set cur = {t1, t2, t3}; await tester.pumpWidget(_mapWithTileOverlays(prev)); await tester.pumpWidget(_mapWithTileOverlays(cur)); final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView; + fakePlatformViewsController.lastCreatedView!; - expect(platformGoogleMap.tileOverlaysToChange, _toSet(t3: t3)); + expect(platformGoogleMap.tileOverlaysToChange, {t3}); expect(platformGoogleMap.tileOverlayIdsToRemove.isEmpty, true); expect(platformGoogleMap.tileOverlaysToAdd.isEmpty, true); }); diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 112dccfcbba8..3e9e50ebd0f4 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -40,7 +40,7 @@ readonly NNBD_PLUGINS_LIST=( readonly NON_NNBD_PLUGINS_LIST=( "extension_google_sign_in_as_googleapis_auth" - "google_maps_flutter" # partially migrated + "google_maps_flutter_web" # Not yet migrated. ) export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}") From 23155313346866ee7ba8503bfb26201526208be3 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Feb 2021 11:19:23 -0800 Subject: [PATCH 217/924] [url_launcher] Bump platform interface package to stable NNBD (#3570) Also enables null safety for the unit tests, which had been opted out. --- .../url_launcher_platform_interface/CHANGELOG.md | 6 +----- .../url_launcher_platform_interface/pubspec.yaml | 10 +++++----- .../test/link_test.dart | 15 +++++++-------- .../test/method_channel_url_launcher_test.dart | 4 +--- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md index 5bbbe9d28cd1..5cd56432ece4 100644 --- a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md @@ -1,8 +1,4 @@ -## 2.0.0-nullsafety.1 - -* Bump Dart SDK to support null safety. - -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml index e576e967ec46..a8761c3594ea 100644 --- a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml +++ b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml @@ -3,19 +3,19 @@ description: A common platform interface for the url_launcher plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_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: 2.0.0-nullsafety.1 +version: 2.0.0 dependencies: flutter: sdk: flutter - plugin_platform_interface: ^1.1.0-nullsafety.1 + plugin_platform_interface: ">=1.0.0 <3.0.0" dev_dependencies: flutter_test: sdk: flutter - mockito: ^4.1.1 - pedantic: ^1.10.0-nullsafety.1 + mockito: ^5.0.0-nullsafety.7 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-2.12.0-259.9.beta <3.0.0" flutter: ">=1.22.0" diff --git a/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart b/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart index 58cdd22dca02..a01637e2f378 100644 --- a/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart +++ b/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(egarciad): Remove once Mockito has been migrated to null safety. -// @dart = 2.9 - import 'dart:ui'; import 'package:mockito/mockito.dart'; @@ -19,18 +16,20 @@ final MethodCodec _codec = const JSONMethodCodec(); void main() { TestWidgetsFlutterBinding.ensureInitialized(); - PlatformMessageCallback oldHandler; - MethodCall lastCall; + PlatformMessageCallback? oldHandler; + MethodCall? lastCall; setUp(() { oldHandler = window.onPlatformMessage; window.onPlatformMessage = ( String name, - ByteData data, - PlatformMessageResponseCallback callback, + ByteData? data, + PlatformMessageResponseCallback? callback, ) { lastCall = _codec.decodeMethodCall(data); - callback(_codec.encodeSuccessEnvelope(true)); + if (callback != null) { + callback(_codec.encodeSuccessEnvelope(true)); + } }; }); diff --git a/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart b/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart index dfd4b7380c3e..b5a96b18c91a 100644 --- a/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(mvanbeusekom): Remove once Mockito is migrated to null safety. -// @dart = 2.9 import 'package:mockito/mockito.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -315,5 +313,5 @@ class ImplementsUrlLauncherPlatform extends Mock class ExtendsUrlLauncherPlatform extends UrlLauncherPlatform { @override - final LinkDelegate linkDelegate = null; + final LinkDelegate? linkDelegate = null; } From 0638189d6a8e61e38a6412845f50340a641ba3a2 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 19 Feb 2021 11:56:26 -0800 Subject: [PATCH 218/924] [in_app_purchase] Migrate to NNBD (#3555) --- packages/in_app_purchase/CHANGELOG.md | 7 + packages/in_app_purchase/build.yaml | 1 - .../in_app_purchase/example/lib/main.dart | 19 ++- packages/in_app_purchase/example/pubspec.yaml | 8 +- .../test_driver/test/integration_test.dart | 1 + .../in_app_purchase_test.dart | 1 + .../ios/Classes/FIAPReceiptManager.m | 7 - .../ios/Classes/InAppPurchasePlugin.m | 4 +- .../billing_client_wrapper.dart | 112 ++++++++-------- .../enum_converters.dart | 49 ++++--- .../enum_converters.g.dart | 35 ++--- .../purchase_wrapper.dart | 81 +++++++----- .../purchase_wrapper.g.dart | 61 +++++---- .../sku_details_wrapper.dart | 74 +++++++---- .../sku_details_wrapper.g.dart | 49 +++---- packages/in_app_purchase/lib/src/channel.dart | 9 +- .../in_app_purchase/app_store_connection.dart | 82 +++++++----- .../google_play_connection.dart | 61 +++++---- .../in_app_purchase_connection.dart | 44 ++++--- .../src/in_app_purchase/product_details.dart | 23 ++-- .../src/in_app_purchase/purchase_details.dart | 77 ++++++----- .../store_kit_wrappers/enum_converters.dart | 75 +++++++++-- .../store_kit_wrappers/enum_converters.g.dart | 58 ++++++--- .../sk_payment_queue_wrapper.dart | 87 ++++++++----- .../sk_payment_queue_wrapper.g.dart | 22 ++-- .../sk_payment_transaction_wrappers.dart | 58 +++++---- .../sk_payment_transaction_wrappers.g.dart | 18 +-- .../sk_product_wrapper.dart | 110 +++++++++------- .../sk_product_wrapper.g.dart | 123 +++++++----------- .../sk_receipt_manager.dart | 7 +- .../store_kit_wrappers/sk_request_maker.dart | 5 +- packages/in_app_purchase/pubspec.yaml | 22 ++-- .../billing_client_wrapper_test.dart | 115 ++++++++++++++-- .../purchase_wrapper_test.dart | 24 ++++ .../sku_details_wrapper_test.dart | 27 ++++ .../app_store_connection_test.dart | 85 ++++++------ .../google_play_connection_test.dart | 50 +++---- .../sk_methodchannel_apis_test.dart | 51 +++++--- .../store_kit_wrappers/sk_product_test.dart | 66 +++++++--- .../sk_test_stub_objects.dart | 20 +-- .../test/stub_in_app_purchase_platform.dart | 12 +- script/nnbd_plugins.sh | 1 + .../tool/lib/src/publish_check_command.dart | 2 +- 43 files changed, 1134 insertions(+), 709 deletions(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index abafaf506f3a..79f64d5bda53 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.4.0 + +* Migrate to nullsafety. +* Deprecate `sandboxTesting`, introduce `simulatesAskToBuyInSandbox`. +* **Breaking Change:** + * Removed `callbackChannel` in `channels.dart`, see https://github.com/flutter/flutter/issues/69225. + ## 0.3.5+2 * Migrate deprecated references. diff --git a/packages/in_app_purchase/build.yaml b/packages/in_app_purchase/build.yaml index d7b59734f27e..e15cf14b85fd 100644 --- a/packages/in_app_purchase/build.yaml +++ b/packages/in_app_purchase/build.yaml @@ -5,4 +5,3 @@ targets: options: any_map: true create_to_json: true - nullable: false \ No newline at end of file diff --git a/packages/in_app_purchase/example/lib/main.dart b/packages/in_app_purchase/example/lib/main.dart index 911edae98cfb..82cd509b30be 100644 --- a/packages/in_app_purchase/example/lib/main.dart +++ b/packages/in_app_purchase/example/lib/main.dart @@ -32,7 +32,7 @@ class _MyApp extends StatefulWidget { class _MyAppState extends State<_MyApp> { final InAppPurchaseConnection _connection = InAppPurchaseConnection.instance; - StreamSubscription> _subscription; + late StreamSubscription> _subscription; List _notFoundIds = []; List _products = []; List _purchases = []; @@ -40,11 +40,11 @@ class _MyAppState extends State<_MyApp> { bool _isAvailable = false; bool _purchasePending = false; bool _loading = true; - String _queryProductError; + String? _queryProductError; @override void initState() { - Stream purchaseUpdated = + final Stream> purchaseUpdated = InAppPurchaseConnection.instance.purchaseUpdatedStream; _subscription = purchaseUpdated.listen((purchaseDetailsList) { _listenToPurchaseUpdated(purchaseDetailsList); @@ -76,7 +76,7 @@ class _MyAppState extends State<_MyApp> { await _connection.queryProductDetails(_kProductIds.toSet()); if (productDetailResponse.error != null) { setState(() { - _queryProductError = productDetailResponse.error.message; + _queryProductError = productDetailResponse.error!.message; _isAvailable = isAvailable; _products = productDetailResponse.productDetails; _purchases = []; @@ -146,7 +146,7 @@ class _MyAppState extends State<_MyApp> { ); } else { stack.add(Center( - child: Text(_queryProductError), + child: Text(_queryProductError!), )); } if (_purchasePending) { @@ -235,7 +235,7 @@ class _MyAppState extends State<_MyApp> { })); productList.addAll(_products.map( (ProductDetails productDetails) { - PurchaseDetails previousPurchase = purchases[productDetails.id]; + PurchaseDetails? previousPurchase = purchases[productDetails.id]; return ListTile( title: Text( productDetails.title, @@ -254,8 +254,7 @@ class _MyAppState extends State<_MyApp> { onPressed: () { PurchaseParam purchaseParam = PurchaseParam( productDetails: productDetails, - applicationUserName: null, - sandboxTesting: true); + applicationUserName: null); if (productDetails.id == _kConsumableId) { _connection.buyConsumable( purchaseParam: purchaseParam, @@ -329,7 +328,7 @@ class _MyAppState extends State<_MyApp> { void deliverProduct(PurchaseDetails purchaseDetails) async { // IMPORTANT!! Always verify a purchase purchase details before delivering the product. if (purchaseDetails.productID == _kConsumableId) { - await ConsumableStore.save(purchaseDetails.purchaseID); + await ConsumableStore.save(purchaseDetails.purchaseID!); List consumables = await ConsumableStore.load(); setState(() { _purchasePending = false; @@ -365,7 +364,7 @@ class _MyAppState extends State<_MyApp> { showPendingUI(); } else { if (purchaseDetails.status == PurchaseStatus.error) { - handleError(purchaseDetails.error); + handleError(purchaseDetails.error!); } else if (purchaseDetails.status == PurchaseStatus.purchased) { bool valid = await _verifyPurchase(purchaseDetails); if (valid) { diff --git a/packages/in_app_purchase/example/pubspec.yaml b/packages/in_app_purchase/example/pubspec.yaml index 9b623a15795a..8c9296dc98c8 100644 --- a/packages/in_app_purchase/example/pubspec.yaml +++ b/packages/in_app_purchase/example/pubspec.yaml @@ -5,11 +5,9 @@ author: Flutter Team dependencies: flutter: sdk: flutter - cupertino_icons: ^0.1.2 - shared_preferences: ^0.5.2 + shared_preferences: ^2.0.0-nullsafety.1 dev_dependencies: - test: ^1.5.2 flutter_driver: sdk: flutter in_app_purchase: @@ -21,11 +19,11 @@ dev_dependencies: path: ../ integration_test: path: ../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.3.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.9.1+hotfix.2" diff --git a/packages/in_app_purchase/example/test_driver/test/integration_test.dart b/packages/in_app_purchase/example/test_driver/test/integration_test.dart index 7a2c21338786..0352d4aaeb2d 100644 --- a/packages/in_app_purchase/example/test_driver/test/integration_test.dart +++ b/packages/in_app_purchase/example/test_driver/test/integration_test.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/in_app_purchase/integration_test/in_app_purchase_test.dart b/packages/in_app_purchase/integration_test/in_app_purchase_test.dart index a5bfdb0eb409..aa3430fbc7d2 100644 --- a/packages/in_app_purchase/integration_test/in_app_purchase_test.dart +++ b/packages/in_app_purchase/integration_test/in_app_purchase_test.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 import 'package:flutter_test/flutter_test.dart'; import 'package:in_app_purchase/in_app_purchase.dart'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m index 92872d91234e..f6bdf0c4f249 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m @@ -2,13 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// -// FIAPReceiptManager.m -// in_app_purchase -// -// Created by Chris Yang on 3/2/19. -// - #import "FIAPReceiptManager.h" #import diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m index 872a34a94954..9b44ad766a98 100644 --- a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m +++ b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m @@ -75,7 +75,7 @@ - (instancetype)initWithRegistrar:(NSObject *)registrar }]; [_paymentQueueHandler startObservingPaymentQueue]; _callbackChannel = - [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/in_app_purchase_callback" + [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/in_app_purchase" binaryMessenger:[registrar messenger]]; return self; } @@ -290,7 +290,7 @@ - (void)refreshReceipt:(FlutterMethodCall *)call result:(FlutterResult)result { }]; } -#pragma mark - delegates +#pragma mark - delegates: - (void)handleTransactionsUpdated:(NSArray *)transactions { NSMutableArray *maps = [NSMutableArray new]; diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart index 2aa91d9f9225..9f96c05e15f9 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart @@ -53,10 +53,7 @@ class BillingClient { bool _enablePendingPurchases = false; /// Creates a billing client. - /// - /// The `onPurchasesUpdated` parameter must not be null. BillingClient(PurchasesUpdatedListener onPurchasesUpdated) { - assert(onPurchasesUpdated != null); channel.setMethodCallHandler(callHandler); _callbacks[kOnPurchasesUpdated] = [onPurchasesUpdated]; } @@ -74,8 +71,11 @@ class BillingClient { /// Calls /// [`BillingClient#isReady()`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#isReady()) /// to get the ready status of the BillingClient instance. - Future isReady() async => - await channel.invokeMethod('BillingClient#isReady()'); + Future isReady() async { + final bool? ready = + await channel.invokeMethod('BillingClient#isReady()'); + return ready ?? false; + } /// Enable the [BillingClientWrapper] to handle pending purchases. /// @@ -100,20 +100,21 @@ class BillingClient { /// This triggers the creation of a new `BillingClient` instance in Java if /// one doesn't already exist. Future startConnection( - {@required - OnBillingServiceDisconnected onBillingServiceDisconnected}) async { + {required OnBillingServiceDisconnected + onBillingServiceDisconnected}) async { assert(_enablePendingPurchases, 'enablePendingPurchases() must be called before calling startConnection'); List disconnectCallbacks = _callbacks[_kOnBillingServiceDisconnected] ??= []; disconnectCallbacks.add(onBillingServiceDisconnected); - return BillingResultWrapper.fromJson(await channel - .invokeMapMethod( - "BillingClient#startConnection(BillingClientStateListener)", - { - 'handle': disconnectCallbacks.length - 1, - 'enablePendingPurchases': _enablePendingPurchases - })); + return BillingResultWrapper.fromJson((await channel + .invokeMapMethod( + "BillingClient#startConnection(BillingClientStateListener)", + { + 'handle': disconnectCallbacks.length - 1, + 'enablePendingPurchases': _enablePendingPurchases + })) ?? + {}); } /// Calls @@ -137,15 +138,16 @@ class BillingClient { /// `SkuDetailsParams` as direct arguments instead of requiring it constructed /// and passed in as a class. Future querySkuDetails( - {@required SkuType skuType, @required List skusList}) async { + {required SkuType skuType, required List skusList}) async { final Map arguments = { 'skuType': SkuTypeConverter().toJson(skuType), 'skusList': skusList }; - return SkuDetailsResponseWrapper.fromJson(await channel.invokeMapMethod< - String, dynamic>( - 'BillingClient#querySkuDetailsAsync(SkuDetailsParams, SkuDetailsResponseListener)', - arguments)); + return SkuDetailsResponseWrapper.fromJson((await channel.invokeMapMethod< + String, dynamic>( + 'BillingClient#querySkuDetailsAsync(SkuDetailsParams, SkuDetailsResponseListener)', + arguments)) ?? + {}); } /// Attempt to launch the Play Billing Flow for a given [skuDetails]. @@ -172,16 +174,17 @@ class BillingClient { /// and [the given /// accountId](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder.html#setAccountId(java.lang.String)). Future launchBillingFlow( - {@required String sku, String accountId}) async { + {required String sku, String? accountId}) async { assert(sku != null); final Map arguments = { 'sku': sku, 'accountId': accountId, }; return BillingResultWrapper.fromJson( - await channel.invokeMapMethod( - 'BillingClient#launchBillingFlow(Activity, BillingFlowParams)', - arguments)); + (await channel.invokeMapMethod( + 'BillingClient#launchBillingFlow(Activity, BillingFlowParams)', + arguments)) ?? + {}); } /// Fetches recent purchases for the given [SkuType]. @@ -197,10 +200,12 @@ class BillingClient { /// skutype)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases). Future queryPurchases(SkuType skuType) async { assert(skuType != null); - return PurchasesResultWrapper.fromJson(await channel - .invokeMapMethod( - 'BillingClient#queryPurchases(String)', - {'skuType': SkuTypeConverter().toJson(skuType)})); + return PurchasesResultWrapper.fromJson((await channel + .invokeMapMethod( + 'BillingClient#queryPurchases(String)', { + 'skuType': SkuTypeConverter().toJson(skuType) + })) ?? + {}); } /// Fetches purchase history for the given [SkuType]. @@ -218,10 +223,13 @@ class BillingClient { /// listener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchasehistoryasync). Future queryPurchaseHistory(SkuType skuType) async { assert(skuType != null); - return PurchasesHistoryResult.fromJson(await channel.invokeMapMethod( - 'BillingClient#queryPurchaseHistoryAsync(String, PurchaseHistoryResponseListener)', - {'skuType': SkuTypeConverter().toJson(skuType)})); + return PurchasesHistoryResult.fromJson((await channel.invokeMapMethod< + String, dynamic>( + 'BillingClient#queryPurchaseHistoryAsync(String, PurchaseHistoryResponseListener)', + { + 'skuType': SkuTypeConverter().toJson(skuType) + })) ?? + {}); } /// Consumes a given in-app product. @@ -229,20 +237,20 @@ class BillingClient { /// Consuming can only be done on an item that's owned, and as a result of consumption, the user will no longer own it. /// Consumption is done asynchronously. The method returns a Future containing a [BillingResultWrapper]. /// - /// The `purchaseToken` must not be null. /// The `developerPayload` is the developer data associated with the purchase to be consumed, it defaults to null. /// /// This wraps [`BillingClient#consumeAsync(String, ConsumeResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#consumeAsync(java.lang.String,%20com.android.billingclient.api.ConsumeResponseListener)) Future consumeAsync(String purchaseToken, - {String developerPayload}) async { + {String? developerPayload}) async { assert(purchaseToken != null); - return BillingResultWrapper.fromJson(await channel - .invokeMapMethod( - 'BillingClient#consumeAsync(String, ConsumeResponseListener)', - { - 'purchaseToken': purchaseToken, - 'developerPayload': developerPayload, - })); + return BillingResultWrapper.fromJson((await channel + .invokeMapMethod( + 'BillingClient#consumeAsync(String, ConsumeResponseListener)', + { + 'purchaseToken': purchaseToken, + 'developerPayload': developerPayload, + })) ?? + {}); } /// Acknowledge an in-app purchase. @@ -261,20 +269,20 @@ class BillingClient { /// Please refer to [acknowledge](https://developer.android.com/google/play/billing/billing_library_overview#acknowledge) for more /// details. /// - /// The `purchaseToken` must not be null. /// The `developerPayload` is the developer data associated with the purchase to be consumed, it defaults to null. /// /// This wraps [`BillingClient#acknowledgePurchase(String, AcknowledgePurchaseResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#acknowledgePurchase(com.android.billingclient.api.AcknowledgePurchaseParams,%20com.android.billingclient.api.AcknowledgePurchaseResponseListener)) Future acknowledgePurchase(String purchaseToken, - {String developerPayload}) async { + {String? developerPayload}) async { assert(purchaseToken != null); - return BillingResultWrapper.fromJson(await channel.invokeMapMethod( - 'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)', - { - 'purchaseToken': purchaseToken, - 'developerPayload': developerPayload, - })); + return BillingResultWrapper.fromJson((await channel.invokeMapMethod( + 'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)', + { + 'purchaseToken': purchaseToken, + 'developerPayload': developerPayload, + })) ?? + {}); } /// The method call handler for [channel]. @@ -283,15 +291,15 @@ class BillingClient { switch (call.method) { case kOnPurchasesUpdated: // The purchases updated listener is a singleton. - assert(_callbacks[kOnPurchasesUpdated].length == 1); + assert(_callbacks[kOnPurchasesUpdated]!.length == 1); final PurchasesUpdatedListener listener = - _callbacks[kOnPurchasesUpdated].first; + _callbacks[kOnPurchasesUpdated]!.first as PurchasesUpdatedListener; listener(PurchasesResultWrapper.fromJson( call.arguments.cast())); break; case _kOnBillingServiceDisconnected: final int handle = call.arguments['handle']; - await _callbacks[_kOnBillingServiceDisconnected][handle](); + await _callbacks[_kOnBillingServiceDisconnected]![handle](); break; } } diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart index 966c89176b1e..30828d8882a7 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart @@ -12,40 +12,50 @@ part 'enum_converters.g.dart'; /// /// Use these in `@JsonSerializable()` classes by annotating them with /// `@BillingResponseConverter()`. -class BillingResponseConverter implements JsonConverter { +class BillingResponseConverter implements JsonConverter { /// Default const constructor. const BillingResponseConverter(); @override - BillingResponse fromJson(int json) => _$enumDecode( - _$BillingResponseEnumMap.cast(), json); + BillingResponse fromJson(int? json) { + if (json == null) { + return BillingResponse.error; + } + return _$enumDecode( + _$BillingResponseEnumMap.cast(), json); + } @override - int toJson(BillingResponse object) => _$BillingResponseEnumMap[object]; + int toJson(BillingResponse object) => _$BillingResponseEnumMap[object]!; } /// Serializer for [SkuType]. /// /// Use these in `@JsonSerializable()` classes by annotating them with /// `@SkuTypeConverter()`. -class SkuTypeConverter implements JsonConverter { +class SkuTypeConverter implements JsonConverter { /// Default const constructor. const SkuTypeConverter(); @override - SkuType fromJson(String json) => - _$enumDecode(_$SkuTypeEnumMap.cast(), json); + SkuType fromJson(String? json) { + if (json == null) { + return SkuType.inapp; + } + return _$enumDecode( + _$SkuTypeEnumMap.cast(), json); + } @override - String toJson(SkuType object) => _$SkuTypeEnumMap[object]; + String toJson(SkuType object) => _$SkuTypeEnumMap[object]!; } // Define a class so we generate serializer helper methods for the enums @JsonSerializable() class _SerializedEnums { - BillingResponse response; - SkuType type; - PurchaseStateWrapper purchaseState; + late BillingResponse response; + late SkuType type; + late PurchaseStateWrapper purchaseState; } /// Serializer for [PurchaseStateWrapper]. @@ -53,18 +63,23 @@ class _SerializedEnums { /// Use these in `@JsonSerializable()` classes by annotating them with /// `@PurchaseStateConverter()`. class PurchaseStateConverter - implements JsonConverter { + implements JsonConverter { /// Default const constructor. const PurchaseStateConverter(); @override - PurchaseStateWrapper fromJson(int json) => _$enumDecode( - _$PurchaseStateWrapperEnumMap.cast(), - json); + PurchaseStateWrapper fromJson(int? json) { + if (json == null) { + return PurchaseStateWrapper.unspecified_state; + } + return _$enumDecode( + _$PurchaseStateWrapperEnumMap.cast(), + json); + } @override int toJson(PurchaseStateWrapper object) => - _$PurchaseStateWrapperEnumMap[object]; + _$PurchaseStateWrapperEnumMap[object]!; /// Converts the purchase state stored in `object` to a [PurchaseStatus]. /// @@ -78,7 +93,5 @@ class PurchaseStateConverter case PurchaseStateWrapper.unspecified_state: return PurchaseStatus.error; } - - throw ArgumentError('$object isn\'t mapped to PurchaseStatus'); } } diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart index 947700df64df..5d59dd8888b7 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart @@ -21,25 +21,30 @@ Map _$_SerializedEnumsToJson(_SerializedEnums instance) => 'purchaseState': _$PurchaseStateWrapperEnumMap[instance.purchaseState], }; -T _$enumDecode( - Map enumValues, - dynamic source, { - T unknownValue, +K _$enumDecode( + Map enumValues, + Object? source, { + K? unknownValue, }) { if (source == null) { - throw ArgumentError('A value must be provided. Supported values: ' - '${enumValues.values.join(', ')}'); + throw ArgumentError( + 'A value must be provided. Supported values: ' + '${enumValues.values.join(', ')}', + ); } - final value = enumValues.entries - .singleWhere((e) => e.value == source, orElse: () => null) - ?.key; - - if (value == null && unknownValue == null) { - throw ArgumentError('`$source` is not one of the supported values: ' - '${enumValues.values.join(', ')}'); - } - return value ?? unknownValue; + return enumValues.entries.singleWhere( + (e) => e.value == source, + orElse: () { + if (unknownValue == null) { + throw ArgumentError( + '`$source` is not one of the supported values: ' + '${enumValues.values.join(', ')}', + ); + } + return MapEntry(unknownValue, enumValues.values.first); + }, + ).key; } const _$BillingResponseEnumMap = { diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart index 8bdd738e7ed3..05472278968a 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -27,26 +27,27 @@ class PurchaseWrapper { /// Creates a purchase wrapper with the given purchase details. @visibleForTesting PurchaseWrapper( - {@required this.orderId, - @required this.packageName, - @required this.purchaseTime, - @required this.purchaseToken, - @required this.signature, - @required this.sku, - @required this.isAutoRenewing, - @required this.originalJson, - @required this.developerPayload, - @required this.isAcknowledged, - @required this.purchaseState}); + {required this.orderId, + required this.packageName, + required this.purchaseTime, + required this.purchaseToken, + required this.signature, + required this.sku, + required this.isAutoRenewing, + required this.originalJson, + this.developerPayload, + required this.isAcknowledged, + required this.purchaseState}); /// Factory for creating a [PurchaseWrapper] from a [Map] with the purchase details. - factory PurchaseWrapper.fromJson(Map map) => _$PurchaseWrapperFromJson(map); + factory PurchaseWrapper.fromJson(Map map) => + _$PurchaseWrapperFromJson(map); @override bool operator ==(Object other) { if (identical(other, this)) return true; if (other.runtimeType != runtimeType) return false; - final PurchaseWrapper typedOther = other; + final PurchaseWrapper typedOther = other as PurchaseWrapper; return typedOther.orderId == orderId && typedOther.packageName == packageName && typedOther.purchaseTime == purchaseTime && @@ -74,22 +75,28 @@ class PurchaseWrapper { /// The unique ID for this purchase. Corresponds to the Google Payments order /// ID. + @JsonKey(defaultValue: '') final String orderId; /// The package name the purchase was made from. + @JsonKey(defaultValue: '') final String packageName; /// When the purchase was made, as an epoch timestamp. + @JsonKey(defaultValue: 0) final int purchaseTime; /// A unique ID for a given [SkuDetailsWrapper], user, and purchase. + @JsonKey(defaultValue: '') final String purchaseToken; /// Signature of purchase data, signed with the developer's private key. Uses /// RSASSA-PKCS1-v1_5. + @JsonKey(defaultValue: '') final String signature; /// The product ID of this purchase. + @JsonKey(defaultValue: '') final String sku; /// True for subscriptions that renew automatically. Does not apply to @@ -97,6 +104,8 @@ class PurchaseWrapper { /// /// For [SkuType.subs] this means that the subscription is canceled when it is /// false. + /// + /// The value is `false` for [SkuType.inapp] products. final bool isAutoRenewing; /// Details about this purchase, in JSON. @@ -105,15 +114,19 @@ class PurchaseWrapper { /// device"](https://developer.android.com/google/play/billing/billing_library_overview#Verify-purchase-device). /// Note though that verifying a purchase locally is inherently insecure (see /// the article for more details). + @JsonKey(defaultValue: '') final String originalJson; /// The payload specified by the developer when the purchase was acknowledged or consumed. - final String developerPayload; + /// + /// The value is `null` if it wasn't specified when the purchase was acknowledged or consumed. + final String? developerPayload; /// Whether the purchase has been acknowledged. /// /// A successful purchase has to be acknowledged within 3 days after the purchase via [BillingClient.acknowledgePurchase]. /// * See also [BillingClient.acknowledgePurchase] for more details on acknowledging purchases. + @JsonKey(defaultValue: false) final bool isAcknowledged; /// Determines the current state of the purchase. @@ -137,29 +150,33 @@ class PurchaseHistoryRecordWrapper { /// Creates a [PurchaseHistoryRecordWrapper] with the given record details. @visibleForTesting PurchaseHistoryRecordWrapper({ - @required this.purchaseTime, - @required this.purchaseToken, - @required this.signature, - @required this.sku, - @required this.originalJson, - @required this.developerPayload, + required this.purchaseTime, + required this.purchaseToken, + required this.signature, + required this.sku, + required this.originalJson, + required this.developerPayload, }); /// Factory for creating a [PurchaseHistoryRecordWrapper] from a [Map] with the record details. - factory PurchaseHistoryRecordWrapper.fromJson(Map map) => + factory PurchaseHistoryRecordWrapper.fromJson(Map map) => _$PurchaseHistoryRecordWrapperFromJson(map); /// When the purchase was made, as an epoch timestamp. + @JsonKey(defaultValue: 0) final int purchaseTime; /// A unique ID for a given [SkuDetailsWrapper], user, and purchase. + @JsonKey(defaultValue: '') final String purchaseToken; /// Signature of purchase data, signed with the developer's private key. Uses /// RSASSA-PKCS1-v1_5. + @JsonKey(defaultValue: '') final String signature; /// The product ID of this purchase. + @JsonKey(defaultValue: '') final String sku; /// Details about this purchase, in JSON. @@ -168,16 +185,20 @@ class PurchaseHistoryRecordWrapper { /// device"](https://developer.android.com/google/play/billing/billing_library_overview#Verify-purchase-device). /// Note though that verifying a purchase locally is inherently insecure (see /// the article for more details). + @JsonKey(defaultValue: '') final String originalJson; /// The payload specified by the developer when the purchase was acknowledged or consumed. - final String developerPayload; + /// + /// The value is `null` if it wasn't specified when the purchase was acknowledged or consumed. + final String? developerPayload; @override bool operator ==(Object other) { if (identical(other, this)) return true; if (other.runtimeType != runtimeType) return false; - final PurchaseHistoryRecordWrapper typedOther = other; + final PurchaseHistoryRecordWrapper typedOther = + other as PurchaseHistoryRecordWrapper; return typedOther.purchaseTime == purchaseTime && typedOther.purchaseToken == purchaseToken && typedOther.signature == signature && @@ -203,9 +224,9 @@ class PurchaseHistoryRecordWrapper { class PurchasesResultWrapper { /// Creates a [PurchasesResultWrapper] with the given purchase result details. PurchasesResultWrapper( - {@required this.responseCode, - @required this.billingResult, - @required this.purchasesList}); + {required this.responseCode, + required this.billingResult, + required this.purchasesList}); /// Factory for creating a [PurchaseResultWrapper] from a [Map] with the result details. factory PurchasesResultWrapper.fromJson(Map map) => @@ -215,7 +236,7 @@ class PurchasesResultWrapper { bool operator ==(Object other) { if (identical(other, this)) return true; if (other.runtimeType != runtimeType) return false; - final PurchasesResultWrapper typedOther = other; + final PurchasesResultWrapper typedOther = other as PurchasesResultWrapper; return typedOther.responseCode == responseCode && typedOther.purchasesList == purchasesList && typedOther.billingResult == billingResult; @@ -236,6 +257,7 @@ class PurchasesResultWrapper { /// The list of successful purchases made in this transaction. /// /// May be empty, especially if [responseCode] is not [BillingResponse.ok]. + @JsonKey(defaultValue: []) final List purchasesList; } @@ -248,7 +270,7 @@ class PurchasesResultWrapper { class PurchasesHistoryResult { /// Creates a [PurchasesHistoryResult] with the provided history. PurchasesHistoryResult( - {@required this.billingResult, @required this.purchaseHistoryRecordList}); + {required this.billingResult, required this.purchaseHistoryRecordList}); /// Factory for creating a [PurchasesHistoryResult] from a [Map] with the history result details. factory PurchasesHistoryResult.fromJson(Map map) => @@ -258,7 +280,7 @@ class PurchasesHistoryResult { bool operator ==(Object other) { if (identical(other, this)) return true; if (other.runtimeType != runtimeType) return false; - final PurchasesHistoryResult typedOther = other; + final PurchasesHistoryResult typedOther = other as PurchasesHistoryResult; return typedOther.purchaseHistoryRecordList == purchaseHistoryRecordList && typedOther.billingResult == billingResult; } @@ -272,6 +294,7 @@ class PurchasesHistoryResult { /// The list of queried purchase history records. /// /// May be empty, especially if [billingResult.responseCode] is not [BillingResponse.ok]. + @JsonKey(defaultValue: []) final List purchaseHistoryRecordList; } diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart index 3d555890b31e..5f0d936e09c2 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart @@ -8,18 +8,18 @@ part of 'purchase_wrapper.dart'; PurchaseWrapper _$PurchaseWrapperFromJson(Map json) { return PurchaseWrapper( - orderId: json['orderId'] as String, - packageName: json['packageName'] as String, - purchaseTime: json['purchaseTime'] as int, - purchaseToken: json['purchaseToken'] as String, - signature: json['signature'] as String, - sku: json['sku'] as String, + orderId: json['orderId'] as String? ?? '', + packageName: json['packageName'] as String? ?? '', + purchaseTime: json['purchaseTime'] as int? ?? 0, + purchaseToken: json['purchaseToken'] as String? ?? '', + signature: json['signature'] as String? ?? '', + sku: json['sku'] as String? ?? '', isAutoRenewing: json['isAutoRenewing'] as bool, - originalJson: json['originalJson'] as String, - developerPayload: json['developerPayload'] as String, - isAcknowledged: json['isAcknowledged'] as bool, + originalJson: json['originalJson'] as String? ?? '', + developerPayload: json['developerPayload'] as String?, + isAcknowledged: json['isAcknowledged'] as bool? ?? false, purchaseState: - const PurchaseStateConverter().fromJson(json['purchaseState'] as int), + const PurchaseStateConverter().fromJson(json['purchaseState'] as int?), ); } @@ -41,12 +41,12 @@ Map _$PurchaseWrapperToJson(PurchaseWrapper instance) => PurchaseHistoryRecordWrapper _$PurchaseHistoryRecordWrapperFromJson(Map json) { return PurchaseHistoryRecordWrapper( - purchaseTime: json['purchaseTime'] as int, - purchaseToken: json['purchaseToken'] as String, - signature: json['signature'] as String, - sku: json['sku'] as String, - originalJson: json['originalJson'] as String, - developerPayload: json['developerPayload'] as String, + purchaseTime: json['purchaseTime'] as int? ?? 0, + purchaseToken: json['purchaseToken'] as String? ?? '', + signature: json['signature'] as String? ?? '', + sku: json['sku'] as String? ?? '', + originalJson: json['originalJson'] as String? ?? '', + developerPayload: json['developerPayload'] as String?, ); } @@ -64,11 +64,16 @@ Map _$PurchaseHistoryRecordWrapperToJson( PurchasesResultWrapper _$PurchasesResultWrapperFromJson(Map json) { return PurchasesResultWrapper( responseCode: - const BillingResponseConverter().fromJson(json['responseCode'] as int), - billingResult: BillingResultWrapper.fromJson(json['billingResult'] as Map), - purchasesList: (json['purchasesList'] as List) - .map((e) => PurchaseWrapper.fromJson(e as Map)) - .toList(), + const BillingResponseConverter().fromJson(json['responseCode'] as int?), + billingResult: + BillingResultWrapper.fromJson((json['billingResult'] as Map?)?.map( + (k, e) => MapEntry(k as String, e), + )), + purchasesList: (json['purchasesList'] as List?) + ?.map((e) => + PurchaseWrapper.fromJson(Map.from(e as Map))) + .toList() ?? + [], ); } @@ -83,10 +88,16 @@ Map _$PurchasesResultWrapperToJson( PurchasesHistoryResult _$PurchasesHistoryResultFromJson(Map json) { return PurchasesHistoryResult( - billingResult: BillingResultWrapper.fromJson(json['billingResult'] as Map), - purchaseHistoryRecordList: (json['purchaseHistoryRecordList'] as List) - .map((e) => PurchaseHistoryRecordWrapper.fromJson(e as Map)) - .toList(), + billingResult: + BillingResultWrapper.fromJson((json['billingResult'] as Map?)?.map( + (k, e) => MapEntry(k as String, e), + )), + purchaseHistoryRecordList: + (json['purchaseHistoryRecordList'] as List?) + ?.map((e) => PurchaseHistoryRecordWrapper.fromJson( + Map.from(e as Map))) + .toList() ?? + [], ); } diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart index db65e2064a14..b3872958e5b9 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart @@ -13,6 +13,13 @@ import 'enum_converters.dart'; // rebuild and watch for further changes. part 'sku_details_wrapper.g.dart'; +/// The error message shown when the map represents billing result is invalid from method channel. +/// +/// This usually indicates a series underlining code issue in the plugin. +@visibleForTesting +const kInvalidBillingResultErrorMessage = + 'Invalid billing result map from method channel.'; + /// Dart wrapper around [`com.android.billingclient.api.SkuDetails`](https://developer.android.com/reference/com/android/billingclient/api/SkuDetails). /// /// Contains the details of an available product in Google Play Billing. @@ -22,22 +29,22 @@ class SkuDetailsWrapper { /// Creates a [SkuDetailsWrapper] with the given purchase details. @visibleForTesting SkuDetailsWrapper({ - @required this.description, - @required this.freeTrialPeriod, - @required this.introductoryPrice, - @required this.introductoryPriceMicros, - @required this.introductoryPriceCycles, - @required this.introductoryPricePeriod, - @required this.price, - @required this.priceAmountMicros, - @required this.priceCurrencyCode, - @required this.sku, - @required this.subscriptionPeriod, - @required this.title, - @required this.type, - @required this.isRewarded, - @required this.originalPrice, - @required this.originalPriceAmountMicros, + required this.description, + required this.freeTrialPeriod, + required this.introductoryPrice, + required this.introductoryPriceMicros, + required this.introductoryPriceCycles, + required this.introductoryPricePeriod, + required this.price, + required this.priceAmountMicros, + required this.priceCurrencyCode, + required this.sku, + required this.subscriptionPeriod, + required this.title, + required this.type, + required this.isRewarded, + required this.originalPrice, + required this.originalPriceAmountMicros, }); /// Constructs an instance of this from a key value map of data. @@ -45,55 +52,70 @@ class SkuDetailsWrapper { /// The map needs to have named string keys with values matching the names and /// types of all of the members on this class. @visibleForTesting - factory SkuDetailsWrapper.fromJson(Map map) => + factory SkuDetailsWrapper.fromJson(Map map) => _$SkuDetailsWrapperFromJson(map); /// Textual description of the product. + @JsonKey(defaultValue: '') final String description; /// Trial period in ISO 8601 format. + @JsonKey(defaultValue: '') final String freeTrialPeriod; /// Introductory price, only applies to [SkuType.subs]. Formatted ("$0.99"). + @JsonKey(defaultValue: '') final String introductoryPrice; /// [introductoryPrice] in micro-units 990000 + @JsonKey(defaultValue: '') final String introductoryPriceMicros; /// The number of billing perios that [introductoryPrice] is valid for ("2"). + @JsonKey(defaultValue: '') final String introductoryPriceCycles; /// The billing period of [introductoryPrice], in ISO 8601 format. + @JsonKey(defaultValue: '') final String introductoryPricePeriod; /// Formatted with currency symbol ("$0.99"). + @JsonKey(defaultValue: '') final String price; /// [price] in micro-units ("990000"). + @JsonKey(defaultValue: 0) final int priceAmountMicros; /// [price] ISO 4217 currency code. + @JsonKey(defaultValue: '') final String priceCurrencyCode; /// The product ID in Google Play Console. + @JsonKey(defaultValue: '') final String sku; /// Applies to [SkuType.subs], formatted in ISO 8601. + @JsonKey(defaultValue: '') final String subscriptionPeriod; /// The product's title. + @JsonKey(defaultValue: '') final String title; /// The [SkuType] of the product. final SkuType type; /// False if the product is paid. + @JsonKey(defaultValue: false) final bool isRewarded; /// The original price that the user purchased this product for. + @JsonKey(defaultValue: '') final String originalPrice; /// [originalPrice] in micro-units ("990000"). + @JsonKey(defaultValue: 0) final int originalPriceAmountMicros; @override @@ -150,7 +172,7 @@ class SkuDetailsResponseWrapper { /// Creates a [SkuDetailsResponseWrapper] with the given purchase details. @visibleForTesting SkuDetailsResponseWrapper( - {@required this.billingResult, this.skuDetailsList}); + {required this.billingResult, required this.skuDetailsList}); /// Constructs an instance of this from a key value map of data. /// @@ -163,6 +185,7 @@ class SkuDetailsResponseWrapper { final BillingResultWrapper billingResult; /// A list of [SkuDetailsWrapper] matching the query to [BillingClient.querySkuDetails]. + @JsonKey(defaultValue: []) final List skuDetailsList; @override @@ -186,22 +209,29 @@ class SkuDetailsResponseWrapper { @BillingResponseConverter() class BillingResultWrapper { /// Constructs the object with [responseCode] and [debugMessage]. - BillingResultWrapper({@required this.responseCode, this.debugMessage}); + BillingResultWrapper({required this.responseCode, this.debugMessage}); /// Constructs an instance of this from a key value map of data. /// /// The map needs to have named string keys with values matching the names and /// types of all of the members on this class. - factory BillingResultWrapper.fromJson(Map map) => - _$BillingResultWrapperFromJson(map); + factory BillingResultWrapper.fromJson(Map? map) { + if (map == null || map.isEmpty) { + return BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage); + } + return _$BillingResultWrapperFromJson(map); + } /// Response code returned in the Play Billing API calls. final BillingResponse responseCode; /// Debug message returned in the Play Billing API calls. /// + /// Defaults to `null`. /// This message uses an en-US locale and should not be shown to users. - final String debugMessage; + final String? debugMessage; @override bool operator ==(dynamic other) { diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart index 70bde9318f03..247dbd54b666 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart @@ -8,22 +8,22 @@ part of 'sku_details_wrapper.dart'; SkuDetailsWrapper _$SkuDetailsWrapperFromJson(Map json) { return SkuDetailsWrapper( - description: json['description'] as String, - freeTrialPeriod: json['freeTrialPeriod'] as String, - introductoryPrice: json['introductoryPrice'] as String, - introductoryPriceMicros: json['introductoryPriceMicros'] as String, - introductoryPriceCycles: json['introductoryPriceCycles'] as String, - introductoryPricePeriod: json['introductoryPricePeriod'] as String, - price: json['price'] as String, - priceAmountMicros: json['priceAmountMicros'] as int, - priceCurrencyCode: json['priceCurrencyCode'] as String, - sku: json['sku'] as String, - subscriptionPeriod: json['subscriptionPeriod'] as String, - title: json['title'] as String, - type: const SkuTypeConverter().fromJson(json['type'] as String), - isRewarded: json['isRewarded'] as bool, - originalPrice: json['originalPrice'] as String, - originalPriceAmountMicros: json['originalPriceAmountMicros'] as int, + description: json['description'] as String? ?? '', + freeTrialPeriod: json['freeTrialPeriod'] as String? ?? '', + introductoryPrice: json['introductoryPrice'] as String? ?? '', + introductoryPriceMicros: json['introductoryPriceMicros'] as String? ?? '', + introductoryPriceCycles: json['introductoryPriceCycles'] as String? ?? '', + introductoryPricePeriod: json['introductoryPricePeriod'] as String? ?? '', + price: json['price'] as String? ?? '', + priceAmountMicros: json['priceAmountMicros'] as int? ?? 0, + priceCurrencyCode: json['priceCurrencyCode'] as String? ?? '', + sku: json['sku'] as String? ?? '', + subscriptionPeriod: json['subscriptionPeriod'] as String? ?? '', + title: json['title'] as String? ?? '', + type: const SkuTypeConverter().fromJson(json['type'] as String?), + isRewarded: json['isRewarded'] as bool? ?? false, + originalPrice: json['originalPrice'] as String? ?? '', + originalPriceAmountMicros: json['originalPriceAmountMicros'] as int? ?? 0, ); } @@ -49,10 +49,15 @@ Map _$SkuDetailsWrapperToJson(SkuDetailsWrapper instance) => SkuDetailsResponseWrapper _$SkuDetailsResponseWrapperFromJson(Map json) { return SkuDetailsResponseWrapper( - billingResult: BillingResultWrapper.fromJson(json['billingResult'] as Map), - skuDetailsList: (json['skuDetailsList'] as List) - .map((e) => SkuDetailsWrapper.fromJson(e as Map)) - .toList(), + billingResult: + BillingResultWrapper.fromJson((json['billingResult'] as Map?)?.map( + (k, e) => MapEntry(k as String, e), + )), + skuDetailsList: (json['skuDetailsList'] as List?) + ?.map((e) => + SkuDetailsWrapper.fromJson(Map.from(e as Map))) + .toList() ?? + [], ); } @@ -66,8 +71,8 @@ Map _$SkuDetailsResponseWrapperToJson( BillingResultWrapper _$BillingResultWrapperFromJson(Map json) { return BillingResultWrapper( responseCode: - const BillingResponseConverter().fromJson(json['responseCode'] as int), - debugMessage: json['debugMessage'] as String, + const BillingResponseConverter().fromJson(json['responseCode'] as int?), + debugMessage: json['debugMessage'] as String?, ); } diff --git a/packages/in_app_purchase/lib/src/channel.dart b/packages/in_app_purchase/lib/src/channel.dart index a0b92b5d5f1e..5d140e281e7b 100644 --- a/packages/in_app_purchase/lib/src/channel.dart +++ b/packages/in_app_purchase/lib/src/channel.dart @@ -4,13 +4,6 @@ import 'package:flutter/services.dart'; -/// Method channel for the plugin's platform<-->Dart calls (all but the -/// ios->Dart calls which are carried over the [callbackChannel]). +/// Method channel for the plugin's platform<-->Dart calls. const MethodChannel channel = MethodChannel('plugins.flutter.io/in_app_purchase'); - -/// Method channel for the plugin's ios->Dart calls. -// This is in a separate channel due to historic reasons only. -// TODO(cyanglaz): Remove this. https://github.com/flutter/flutter/issues/69225 -const MethodChannel callbackChannel = - MethodChannel('plugins.flutter.io/in_app_purchase_callback'); diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index a244ab13fc28..50560a666a40 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -21,9 +21,9 @@ class AppStoreConnection implements InAppPurchaseConnection { /// Returns the singleton instance of the [AppStoreConnection] that should be /// used across the app. static AppStoreConnection get instance => _getOrCreateInstance(); - static AppStoreConnection _instance; - static SKPaymentQueueWrapper _skPaymentQueueWrapper; - static _TransactionObserver _observer; + static AppStoreConnection? _instance; + static late SKPaymentQueueWrapper _skPaymentQueueWrapper; + static late _TransactionObserver _observer; /// Creates an [AppStoreConnection] object. /// @@ -41,55 +41,61 @@ class AppStoreConnection implements InAppPurchaseConnection { static AppStoreConnection _getOrCreateInstance() { if (_instance != null) { - return _instance; + return _instance!; } _instance = AppStoreConnection(); _skPaymentQueueWrapper = SKPaymentQueueWrapper(); _observer = _TransactionObserver(StreamController.broadcast()); _skPaymentQueueWrapper.setTransactionObserver(observer); - return _instance; + return _instance!; } @override Future isAvailable() => SKPaymentQueueWrapper.canMakePayments(); @override - Future buyNonConsumable({@required PurchaseParam purchaseParam}) async { + Future buyNonConsumable({required PurchaseParam purchaseParam}) async { await _skPaymentQueueWrapper.addPayment(SKPaymentWrapper( productIdentifier: purchaseParam.productDetails.id, quantity: 1, applicationUsername: purchaseParam.applicationUserName, - simulatesAskToBuyInSandbox: purchaseParam.sandboxTesting, + simulatesAskToBuyInSandbox: purchaseParam.simulatesAskToBuyInSandbox || + // ignore: deprecated_member_use_from_same_package + purchaseParam.sandboxTesting, requestData: null)); return true; // There's no error feedback from iOS here to return. } @override Future buyConsumable( - {@required PurchaseParam purchaseParam, bool autoConsume = true}) { + {required PurchaseParam purchaseParam, bool autoConsume = true}) { assert(autoConsume == true, 'On iOS, we should always auto consume'); return buyNonConsumable(purchaseParam: purchaseParam); } @override Future completePurchase(PurchaseDetails purchase, - {String developerPayload}) async { + {String? developerPayload}) async { + if (purchase.skPaymentTransaction == null) { + throw ArgumentError( + 'completePurchase unsuccessful. The `purchase.skPaymentTransaction` is not valid'); + } await _skPaymentQueueWrapper - .finishTransaction(purchase.skPaymentTransaction); + .finishTransaction(purchase.skPaymentTransaction!); return BillingResultWrapper(responseCode: BillingResponse.ok); } @override Future consumePurchase(PurchaseDetails purchase, - {String developerPayload}) { + {String? developerPayload}) { throw UnsupportedError('consume purchase is not available on Android'); } @override Future queryPastPurchases( - {String applicationUserName}) async { - IAPError error; + {String? applicationUserName}) async { + IAPError? error; List pastPurchases = []; try { @@ -98,7 +104,6 @@ class AppStoreConnection implements InAppPurchaseConnection { await _observer.getRestoredTransactions( queue: _skPaymentQueueWrapper, applicationUserName: applicationUserName); - _observer.cleanUpRestoredTransactions(); pastPurchases = restoredTransactions.map((SKPaymentTransactionWrapper transaction) { assert(transaction.transactionState == @@ -110,16 +115,17 @@ class AppStoreConnection implements InAppPurchaseConnection { ? IAPError( source: IAPSource.AppStore, code: kPurchaseErrorCode, - message: transaction.error.domain, - details: transaction.error.userInfo, + message: transaction.error?.domain ?? '', + details: transaction.error?.userInfo, ) : null; }).toList(); + _observer.cleanUpRestoredTransactions(); } on PlatformException catch (e) { error = IAPError( source: IAPSource.AppStore, code: e.code, - message: e.message, + message: e.message ?? '', details: e.details); } on SKError catch (e) { error = IAPError( @@ -133,9 +139,12 @@ class AppStoreConnection implements InAppPurchaseConnection { } @override - Future refreshPurchaseVerificationData() async { + Future refreshPurchaseVerificationData() async { await SKRequestMaker().startRefreshReceiptRequest(); - String receipt = await SKReceiptManager.retrieveReceiptData(); + final String? receipt = await SKReceiptManager.retrieveReceiptData(); + if (receipt == null) { + return null; + } return PurchaseVerificationData( localVerificationData: receipt, serverVerificationData: receipt, @@ -152,7 +161,7 @@ class AppStoreConnection implements InAppPurchaseConnection { Set identifiers) async { final SKRequestMaker requestMaker = SKRequestMaker(); SkProductResponseWrapper response; - PlatformException exception; + PlatformException? exception; try { response = await requestMaker.startProductRequest(identifiers.toList()); } on PlatformException catch (e) { @@ -167,7 +176,7 @@ class AppStoreConnection implements InAppPurchaseConnection { ProductDetails.fromSKProduct(productWrapper)) .toList(); } - List invalidIdentifiers = response.invalidProductIdentifiers ?? []; + List invalidIdentifiers = response.invalidProductIdentifiers; if (productDetails.isEmpty) { invalidIdentifiers = identifiers.toList(); } @@ -179,7 +188,7 @@ class AppStoreConnection implements InAppPurchaseConnection { : IAPError( source: IAPSource.AppStore, code: exception.code, - message: exception.message, + message: exception.message ?? '', details: exception.details), ); return productDetailsResponse; @@ -189,27 +198,27 @@ class AppStoreConnection implements InAppPurchaseConnection { class _TransactionObserver implements SKTransactionObserverWrapper { final StreamController> purchaseUpdatedController; - Completer> _restoreCompleter; - List _restoredTransactions; - String _receiptData; + Completer>? _restoreCompleter; + List _restoredTransactions = + []; + late String _receiptData; _TransactionObserver(this.purchaseUpdatedController); Future> getRestoredTransactions( - {@required SKPaymentQueueWrapper queue, String applicationUserName}) { - assert(queue != null); + {required SKPaymentQueueWrapper queue, String? applicationUserName}) { _restoreCompleter = Completer(); queue.restoreTransactions(applicationUserName: applicationUserName); - return _restoreCompleter.future; + return _restoreCompleter!.future; } void cleanUpRestoredTransactions() { - _restoredTransactions = null; + _restoredTransactions.clear(); _restoreCompleter = null; } void updatedTransactions( - {List transactions}) async { + {required List transactions}) async { if (_restoreCompleter != null) { if (_restoredTransactions == null) { _restoredTransactions = []; @@ -233,19 +242,20 @@ class _TransactionObserver implements SKTransactionObserverWrapper { }).toList()); } - void removedTransactions({List transactions}) {} + void removedTransactions( + {required List transactions}) {} /// Triggered when there is an error while restoring transactions. - void restoreCompletedTransactionsFailed({SKError error}) { - _restoreCompleter.completeError(error); + void restoreCompletedTransactionsFailed({required SKError error}) { + _restoreCompleter!.completeError(error); } void paymentQueueRestoreCompletedTransactionsFinished() { - _restoreCompleter.complete(_restoredTransactions ?? []); + _restoreCompleter!.complete(_restoredTransactions); } bool shouldAddStorePayment( - {SKPaymentWrapper payment, SKProductWrapper product}) { + {required SKPaymentWrapper payment, required SKProductWrapper product}) { // In this unified API, we always return true to keep it consistent with the behavior on Google Play. return true; } @@ -254,7 +264,7 @@ class _TransactionObserver implements SKTransactionObserverWrapper { try { _receiptData = await SKReceiptManager.retrieveReceiptData(); } catch (e) { - _receiptData = null; + _receiptData = ''; } return _receiptData; } diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart index b980bbd77d85..ef0b7d2efa59 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart @@ -8,6 +8,7 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart'; import '../../billing_client_wrappers.dart'; +import '../../in_app_purchase.dart'; import 'in_app_purchase_connection.dart'; import 'product_details.dart'; @@ -28,26 +29,27 @@ class GooglePlayConnection billingClient.enablePendingPurchases(); } _readyFuture = _connect(); - WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance!.addObserver(this); _purchaseUpdatedController = StreamController.broadcast(); ; } /// Returns the singleton instance of the [GooglePlayConnection]. static GooglePlayConnection get instance => _getOrCreateInstance(); - static GooglePlayConnection _instance; + static GooglePlayConnection? _instance; Stream> get purchaseUpdatedStream => _purchaseUpdatedController.stream; - static StreamController> _purchaseUpdatedController; + static late StreamController> + _purchaseUpdatedController; /// The [BillingClient] that's abstracted by [GooglePlayConnection]. /// /// This field should not be used out of test code. @visibleForTesting - final BillingClient billingClient; + late final BillingClient billingClient; - Future _readyFuture; + late Future _readyFuture; static Set _productIdsToConsume = Set(); @override @@ -57,7 +59,7 @@ class GooglePlayConnection } @override - Future buyNonConsumable({@required PurchaseParam purchaseParam}) async { + Future buyNonConsumable({required PurchaseParam purchaseParam}) async { BillingResultWrapper billingResultWrapper = await billingClient.launchBillingFlow( sku: purchaseParam.productDetails.id, @@ -67,7 +69,7 @@ class GooglePlayConnection @override Future buyConsumable( - {@required PurchaseParam purchaseParam, bool autoConsume = true}) { + {required PurchaseParam purchaseParam, bool autoConsume = true}) { if (autoConsume) { _productIdsToConsume.add(purchaseParam.productDetails.id); } @@ -76,10 +78,14 @@ class GooglePlayConnection @override Future completePurchase(PurchaseDetails purchase, - {String developerPayload}) async { - if (purchase.billingClientPurchase.isAcknowledged) { + {String? developerPayload}) async { + if (purchase.billingClientPurchase!.isAcknowledged) { return BillingResultWrapper(responseCode: BillingResponse.ok); } + if (purchase.verificationData == null) { + throw ArgumentError( + 'completePurchase unsuccessful. The `purchase.verificationData` is not valid'); + } return await billingClient.acknowledgePurchase( purchase.verificationData.serverVerificationData, developerPayload: developerPayload); @@ -87,7 +93,11 @@ class GooglePlayConnection @override Future consumePurchase(PurchaseDetails purchase, - {String developerPayload}) { + {String? developerPayload}) { + if (purchase.verificationData == null) { + throw ArgumentError( + 'consumePurchase unsuccessful. The `purchase.verificationData` is not valid'); + } return billingClient.consumeAsync( purchase.verificationData.serverVerificationData, developerPayload: developerPayload); @@ -95,9 +105,9 @@ class GooglePlayConnection @override Future queryPastPurchases( - {String applicationUserName}) async { + {String? applicationUserName}) async { List responses; - PlatformException exception; + PlatformException? exception; try { responses = await Future.wait([ billingClient.queryPurchases(SkuType.inapp), @@ -133,7 +143,7 @@ class GooglePlayConnection .toSet(); String errorMessage = - errorCodeSet.isNotEmpty ? errorCodeSet.join(', ') : null; + errorCodeSet.isNotEmpty ? errorCodeSet.join(', ') : ''; List pastPurchases = responses.expand((PurchasesResultWrapper response) { @@ -142,14 +152,14 @@ class GooglePlayConnection return PurchaseDetails.fromPurchase(purchaseWrapper); }).toList(); - IAPError error; + IAPError? error; if (exception != null) { error = IAPError( source: IAPSource.GooglePlay, code: exception.code, - message: exception.message, + message: exception.message ?? '', details: exception.details); - } else if (errorMessage != null) { + } else if (errorMessage.isNotEmpty) { error = IAPError( source: IAPSource.GooglePlay, code: kRestoredPurchaseErrorCode, @@ -175,11 +185,11 @@ class GooglePlayConnection static GooglePlayConnection _getOrCreateInstance() { if (_instance != null) { - return _instance; + return _instance!; } _instance = GooglePlayConnection._(); - return _instance; + return _instance!; } Future _connect() => @@ -193,7 +203,7 @@ class GooglePlayConnection Future queryProductDetails( Set identifiers) async { List responses; - PlatformException exception; + PlatformException? exception; try { responses = await Future.wait([ billingClient.querySkuDetails( @@ -235,13 +245,13 @@ class GooglePlayConnection : IAPError( source: IAPSource.GooglePlay, code: exception.code, - message: exception.message, + message: exception.message ?? '', details: exception.details)); } static Future> _getPurchaseDetailsFromResult( PurchasesResultWrapper resultWrapper) async { - IAPError error; + IAPError? error; if (resultWrapper.responseCode != BillingResponse.ok) { error = IAPError( source: IAPSource.GooglePlay, @@ -260,10 +270,13 @@ class GooglePlayConnection } else { return [ PurchaseDetails( - purchaseID: null, - productID: null, + purchaseID: '', + productID: '', transactionDate: null, - verificationData: null) + verificationData: PurchaseVerificationData( + localVerificationData: '', + serverVerificationData: '', + source: IAPSource.GooglePlay)) ..status = PurchaseStatus.error ..error = error ]; diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart index f07ff96d4403..81a0e92cc591 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart @@ -7,7 +7,6 @@ import 'dart:io'; import 'app_store_connection.dart'; import 'google_play_connection.dart'; import 'product_details.dart'; -import 'package:flutter/foundation.dart'; import 'package:in_app_purchase/billing_client_wrappers.dart'; import './purchase_details.dart'; @@ -40,11 +39,11 @@ abstract class InAppPurchaseConnection { /// events after they start to listen. Stream> get purchaseUpdatedStream => _getStream(); - Stream> _purchaseUpdatedStream; + Stream>? _purchaseUpdatedStream; Stream> _getStream() { if (_purchaseUpdatedStream != null) { - return _purchaseUpdatedStream; + return _purchaseUpdatedStream!; } if (Platform.isAndroid) { @@ -57,7 +56,7 @@ abstract class InAppPurchaseConnection { throw UnsupportedError( 'InAppPurchase plugin only works on Android and iOS.'); } - return _purchaseUpdatedStream; + return _purchaseUpdatedStream!; } /// Whether pending purchase is enabled. @@ -133,7 +132,7 @@ abstract class InAppPurchaseConnection { /// * [queryPastPurchases], for restoring non consumable products. /// /// Calling this method for consumable items will cause unwanted behaviors! - Future buyNonConsumable({@required PurchaseParam purchaseParam}); + Future buyNonConsumable({required PurchaseParam purchaseParam}); /// Buy a consumable product. /// @@ -186,7 +185,7 @@ abstract class InAppPurchaseConnection { /// Calling this method for non consumable items will cause unwanted /// behaviors! Future buyConsumable( - {@required PurchaseParam purchaseParam, bool autoConsume = true}); + {required PurchaseParam purchaseParam, bool autoConsume = true}); /// Mark that purchased content has been delivered to the /// user. @@ -206,9 +205,9 @@ abstract class InAppPurchaseConnection { /// Warning! Failure to call this method and get a successful response within 3 days of the purchase will result a refund on Android. /// The [consumePurchase] acts as an implicit [completePurchase] on Android. /// - /// The optional parameter `developerPayload` only works on Android. + /// The optional parameter `developerPayload` (defaults to `null`) only works on Android. Future completePurchase(PurchaseDetails purchase, - {String developerPayload}); + {String? developerPayload}); /// (Play only) Mark that the user has consumed a product. /// @@ -216,16 +215,17 @@ abstract class InAppPurchaseConnection { /// delivered. The user won't be able to buy the same product again until the /// purchase of the product is consumed. /// - /// The `developerPayload` can be specified to be associated with this consumption. + /// The `developerPayload` (defaults to `null`) can be specified to be associated with this consumption. /// /// This throws an [UnsupportedError] on iOS. Future consumePurchase(PurchaseDetails purchase, - {String developerPayload}); + {String? developerPayload}); /// Query all previous purchases. /// /// The `applicationUserName` should match whatever was sent in the initial - /// `PurchaseParam`, if anything. + /// `PurchaseParam`, if anything. If no `applicationUserName` was specified in the initial + /// `PurchaseParam`, use `null`. /// /// This does not return consumed products. If you want to restore unused /// consumable products, you need to persist consumable product information @@ -236,23 +236,25 @@ abstract class InAppPurchaseConnection { /// * [refreshPurchaseVerificationData], for reloading failed /// [PurchaseDetails.verificationData]. Future queryPastPurchases( - {String applicationUserName}); + {String? applicationUserName}); /// (App Store only) retry loading purchase data after an initial failure. /// + /// If no results, a `null` value is returned. + /// /// Throws an [UnsupportedError] on Android. - Future refreshPurchaseVerificationData(); + Future refreshPurchaseVerificationData(); /// The [InAppPurchaseConnection] implemented for this platform. /// /// Throws an [UnsupportedError] when accessed on a platform other than /// Android or iOS. static InAppPurchaseConnection get instance => _getOrCreateInstance(); - static InAppPurchaseConnection _instance; + static InAppPurchaseConnection? _instance; static InAppPurchaseConnection _getOrCreateInstance() { if (_instance != null) { - return _instance; + return _instance!; } if (Platform.isAndroid) { @@ -264,7 +266,7 @@ abstract class InAppPurchaseConnection { 'InAppPurchase plugin only works on Android and iOS.'); } - return _instance; + return _instance!; } } @@ -287,9 +289,9 @@ enum IAPSource { class IAPError { /// Creates a new IAP error object with the given error details. IAPError( - {@required this.source, - @required this.code, - @required this.message, + {required this.source, + required this.code, + required this.message, this.details}); /// Which source is the error on. @@ -298,9 +300,9 @@ class IAPError { /// The error code. final String code; - /// A human-readable error message, possibly null. + /// A human-readable error message. final String message; /// Error details, possibly null. - final dynamic details; + final dynamic? details; } diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart b/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart index bb9e2682b9b7..a3eb79d9a450 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/foundation.dart'; import 'package:in_app_purchase/store_kit_wrappers.dart'; import 'package:in_app_purchase/billing_client_wrappers.dart'; import 'in_app_purchase_connection.dart'; @@ -14,10 +13,10 @@ import 'in_app_purchase_connection.dart'; class ProductDetails { /// Creates a new product details object with the provided details. ProductDetails( - {@required this.id, - @required this.title, - @required this.description, - @required this.price, + {required this.id, + required this.title, + required this.description, + required this.price, this.skProduct, this.skuDetail}); @@ -36,13 +35,13 @@ class ProductDetails { /// Points back to the `StoreKits`'s [SKProductWrapper] object that generated this [ProductDetails] object. /// - /// This is null on Android. - final SKProductWrapper skProduct; + /// This is `null` on Android. + final SKProductWrapper? skProduct; /// Points back to the `BillingClient1`'s [SkuDetailsWrapper] object that generated this [ProductDetails] object. /// - /// This is null on iOS. - final SkuDetailsWrapper skuDetail; + /// This is `null` on iOS. + final SkuDetailsWrapper? skuDetail; /// Generate a [ProductDetails] object based on an iOS [SKProductWrapper] object. ProductDetails.fromSKProduct(SKProductWrapper product) @@ -69,7 +68,7 @@ class ProductDetails { class ProductDetailsResponse { /// Creates a new [ProductDetailsResponse] with the provided response details. ProductDetailsResponse( - {@required this.productDetails, @required this.notFoundIDs, this.error}); + {required this.productDetails, required this.notFoundIDs, this.error}); /// Each [ProductDetails] uniquely matches one valid identifier in [identifiers] of [InAppPurchaseConnection.queryProductDetails]. final List productDetails; @@ -82,7 +81,9 @@ class ProductDetailsResponse { /// A caught platform exception thrown while querying the purchases. /// + /// The value is `null` if there is no error. + /// /// It's possible for this to be null but for there still to be notFoundIds in cases where the request itself was a success but the /// requested IDs could not be found. - final IAPError error; + final IAPError? error; } diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart b/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart index 708b42c01623..c211d2a4cdb8 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/foundation.dart'; import 'package:in_app_purchase/src/billing_client_wrappers/enum_converters.dart'; import 'package:in_app_purchase/src/billing_client_wrappers/purchase_wrapper.dart'; import 'package:in_app_purchase/src/store_kit_wrappers/enum_converters.dart'; @@ -59,9 +58,9 @@ class PurchaseVerificationData { /// Creates a [PurchaseVerificationData] object with the provided information. PurchaseVerificationData( - {@required this.localVerificationData, - @required this.serverVerificationData, - @required this.source}); + {required this.localVerificationData, + required this.serverVerificationData, + required this.source}); } /// Status for a [PurchaseDetails]. @@ -88,9 +87,10 @@ enum PurchaseStatus { class PurchaseParam { /// Creates a new purchase parameter object with the given data. PurchaseParam( - {@required this.productDetails, + {required this.productDetails, this.applicationUserName, - this.sandboxTesting}); + this.sandboxTesting = false, + this.simulatesAskToBuyInSandbox = false}); /// The product to create payment for. /// @@ -103,10 +103,20 @@ class PurchaseParam { /// Do not pass in a clear text, your developer ID, the user’s Apple ID, or the /// user's Google ID for this field. /// For example, you can use a one-way hash of the user’s account name on your server. - final String applicationUserName; + final String? applicationUserName; - /// The 'sandboxTesting' is only available on iOS, set it to `true` for testing in AppStore's sandbox environment. The default value is `false`. + /// @deprecated Use [simulatesAskToBuyInSandbox] instead. + /// + /// Only available on iOS, set it to `true` to produce an "ask to buy" flow for this payment in the sandbox. + /// + /// See also [SKPaymentWrapper.simulatesAskToBuyInSandbox]. + @deprecated final bool sandboxTesting; + + /// Only available on iOS, set it to `true` to produce an "ask to buy" flow for this payment in the sandbox. + /// + /// See also [SKPaymentWrapper.simulatesAskToBuyInSandbox]. + final bool simulatesAskToBuyInSandbox; } /// Represents the transaction details of a purchase. @@ -115,7 +125,9 @@ class PurchaseParam { /// This class for simple operations. If you would like to see the detailed representation of the product, instead, use [PurchaseWrapper] on Android and [SKPaymentTransactionWrapper] on iOS. class PurchaseDetails { /// A unique identifier of the purchase. - final String purchaseID; + /// + /// The `value` is null on iOS if it is not a successful purchase. + final String? purchaseID; /// The product identifier of the purchase. final String productID; @@ -126,15 +138,16 @@ class PurchaseDetails { /// details on how to verify purchase use this data. You should never use any /// purchase data until verified. /// - /// On iOS, this may be null. Call - /// [InAppPurchaseConnection.refreshPurchaseVerificationData] to get a new + /// On iOS, [InAppPurchaseConnection.refreshPurchaseVerificationData] can be used to get a new /// [PurchaseVerificationData] object for further validation. final PurchaseVerificationData verificationData; /// The timestamp of the transaction. /// /// Milliseconds since epoch. - final String transactionDate; + /// + /// The value is `null` if [status] is not [PurchaseStatus.purchased]. + final String? transactionDate; /// The status that this [PurchaseDetails] is currently on. PurchaseStatus get status => _status; @@ -153,20 +166,22 @@ class PurchaseDetails { _status = status; } - PurchaseStatus _status; + late PurchaseStatus _status; - /// The error is only available when [status] is [PurchaseStatus.error]. - IAPError error; + /// The error details when the [status] is [PurchaseStatus.error]. + /// + /// The value is `null` if [status] is not [PurchaseStatus.error]. + IAPError? error; /// Points back to the `StoreKits`'s [SKPaymentTransactionWrapper] object that generated this [PurchaseDetails] object. /// - /// This is null on Android. - final SKPaymentTransactionWrapper skPaymentTransaction; + /// This is `null` on Android. + final SKPaymentTransactionWrapper? skPaymentTransaction; /// Points back to the `BillingClient`'s [PurchaseWrapper] object that generated this [PurchaseDetails] object. /// - /// This is null on iOS. - final PurchaseWrapper billingClientPurchase; + /// This is `null` on iOS. + final PurchaseWrapper? billingClientPurchase; /// The developer has to call [InAppPurchaseConnection.completePurchase] if the value is `true` /// and the product has been delivered to the user. @@ -179,14 +194,14 @@ class PurchaseDetails { // The platform that the object is created on. // // The value is either '_kPlatformIOS' or '_kPlatformAndroid'. - String _platform; + String? _platform; /// Creates a new PurchaseDetails object with the provided data. PurchaseDetails({ - @required this.purchaseID, - @required this.productID, - @required this.verificationData, - @required this.transactionDate, + this.purchaseID, + required this.productID, + required this.verificationData, + required this.transactionDate, this.skPaymentTransaction, this.billingClientPurchase, }); @@ -201,7 +216,7 @@ class PurchaseDetails { serverVerificationData: base64EncodedReceipt, source: IAPSource.AppStore), this.transactionDate = transaction.transactionTimeStamp != null - ? (transaction.transactionTimeStamp * 1000).toInt().toString() + ? (transaction.transactionTimeStamp! * 1000).toInt().toString() : null, this.skPaymentTransaction = transaction, this.billingClientPurchase = null, @@ -212,8 +227,8 @@ class PurchaseDetails { error = IAPError( source: IAPSource.AppStore, code: kPurchaseErrorCode, - message: transaction.error.domain, - details: transaction.error.userInfo, + message: transaction.error?.domain ?? '', + details: transaction.error?.userInfo, ); } } @@ -235,7 +250,7 @@ class PurchaseDetails { error = IAPError( source: IAPSource.GooglePlay, code: kPurchaseErrorCode, - message: null, + message: '', ); } } @@ -246,7 +261,7 @@ class PurchaseDetails { /// An instance of this class is returned in [InAppPurchaseConnection.queryPastPurchases]. class QueryPurchaseDetailsResponse { /// Creates a new [QueryPurchaseDetailsResponse] object with the provider information. - QueryPurchaseDetailsResponse({@required this.pastPurchases, this.error}); + QueryPurchaseDetailsResponse({required this.pastPurchases, this.error}); /// A list of successfully fetched past purchases. /// @@ -257,6 +272,6 @@ class QueryPurchaseDetailsResponse { /// The error when fetching past purchases. /// - /// If the fetch is successful, the value is null. - final IAPError error; + /// If the fetch is successful, the value is `null`. + final IAPError? error; } diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart index 62188705035a..ce2c1fad406f 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart @@ -13,16 +13,20 @@ part 'enum_converters.g.dart'; /// Use these in `@JsonSerializable()` classes by annotating them with /// `@SKTransactionStatusConverter()`. class SKTransactionStatusConverter - implements JsonConverter { + implements JsonConverter { /// Default const constructor. const SKTransactionStatusConverter(); @override - SKPaymentTransactionStateWrapper fromJson(int json) => - _$enumDecode( - _$SKPaymentTransactionStateWrapperEnumMap - .cast(), - json); + SKPaymentTransactionStateWrapper fromJson(int? json) { + if (json == null) { + return SKPaymentTransactionStateWrapper.unspecified; + } + return _$enumDecode( + _$SKPaymentTransactionStateWrapperEnumMap + .cast(), + json); + } /// Converts an [SKPaymentTransactionStateWrapper] to a [PurchaseStatus]. PurchaseStatus toPurchaseStatus(SKPaymentTransactionStateWrapper object) { @@ -34,19 +38,70 @@ class SKTransactionStatusConverter case SKPaymentTransactionStateWrapper.restored: return PurchaseStatus.purchased; case SKPaymentTransactionStateWrapper.failed: + case SKPaymentTransactionStateWrapper.unspecified: return PurchaseStatus.error; } - - throw ArgumentError('$object isn\'t mapped to PurchaseStatus'); } @override int toJson(SKPaymentTransactionStateWrapper object) => - _$SKPaymentTransactionStateWrapperEnumMap[object]; + _$SKPaymentTransactionStateWrapperEnumMap[object]!; +} + +/// Serializer for [SKSubscriptionPeriodUnit]. +/// +/// Use these in `@JsonSerializable()` classes by annotating them with +/// `@SKSubscriptionPeriodUnitConverter()`. +class SKSubscriptionPeriodUnitConverter + implements JsonConverter { + /// Default const constructor. + const SKSubscriptionPeriodUnitConverter(); + + @override + SKSubscriptionPeriodUnit fromJson(int? json) { + if (json == null) { + return SKSubscriptionPeriodUnit.day; + } + return _$enumDecode( + _$SKSubscriptionPeriodUnitEnumMap + .cast(), + json); + } + + @override + int toJson(SKSubscriptionPeriodUnit object) => + _$SKSubscriptionPeriodUnitEnumMap[object]!; +} + +/// Serializer for [SKProductDiscountPaymentMode]. +/// +/// Use these in `@JsonSerializable()` classes by annotating them with +/// `@SKProductDiscountPaymentModeConverter()`. +class SKProductDiscountPaymentModeConverter + implements JsonConverter { + /// Default const constructor. + const SKProductDiscountPaymentModeConverter(); + + @override + SKProductDiscountPaymentMode fromJson(int? json) { + if (json == null) { + return SKProductDiscountPaymentMode.payAsYouGo; + } + return _$enumDecode( + _$SKProductDiscountPaymentModeEnumMap + .cast(), + json); + } + + @override + int toJson(SKProductDiscountPaymentMode object) => + _$SKProductDiscountPaymentModeEnumMap[object]!; } // Define a class so we generate serializer helper methods for the enums @JsonSerializable() class _SerializedEnums { - SKPaymentTransactionStateWrapper response; + late SKPaymentTransactionStateWrapper response; + late SKSubscriptionPeriodUnit unit; + late SKProductDiscountPaymentMode discountPaymentMode; } diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart index f4f17df846a7..b003f435a800 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart @@ -9,33 +9,44 @@ part of 'enum_converters.dart'; _SerializedEnums _$_SerializedEnumsFromJson(Map json) { return _SerializedEnums() ..response = _$enumDecode( - _$SKPaymentTransactionStateWrapperEnumMap, json['response']); + _$SKPaymentTransactionStateWrapperEnumMap, json['response']) + ..unit = _$enumDecode(_$SKSubscriptionPeriodUnitEnumMap, json['unit']) + ..discountPaymentMode = _$enumDecode( + _$SKProductDiscountPaymentModeEnumMap, json['discountPaymentMode']); } Map _$_SerializedEnumsToJson(_SerializedEnums instance) => { 'response': _$SKPaymentTransactionStateWrapperEnumMap[instance.response], + 'unit': _$SKSubscriptionPeriodUnitEnumMap[instance.unit], + 'discountPaymentMode': + _$SKProductDiscountPaymentModeEnumMap[instance.discountPaymentMode], }; -T _$enumDecode( - Map enumValues, - dynamic source, { - T unknownValue, +K _$enumDecode( + Map enumValues, + Object? source, { + K? unknownValue, }) { if (source == null) { - throw ArgumentError('A value must be provided. Supported values: ' - '${enumValues.values.join(', ')}'); + throw ArgumentError( + 'A value must be provided. Supported values: ' + '${enumValues.values.join(', ')}', + ); } - final value = enumValues.entries - .singleWhere((e) => e.value == source, orElse: () => null) - ?.key; - - if (value == null && unknownValue == null) { - throw ArgumentError('`$source` is not one of the supported values: ' - '${enumValues.values.join(', ')}'); - } - return value ?? unknownValue; + return enumValues.entries.singleWhere( + (e) => e.value == source, + orElse: () { + if (unknownValue == null) { + throw ArgumentError( + '`$source` is not one of the supported values: ' + '${enumValues.values.join(', ')}', + ); + } + return MapEntry(unknownValue, enumValues.values.first); + }, + ).key; } const _$SKPaymentTransactionStateWrapperEnumMap = { @@ -44,4 +55,19 @@ const _$SKPaymentTransactionStateWrapperEnumMap = { SKPaymentTransactionStateWrapper.failed: 2, SKPaymentTransactionStateWrapper.restored: 3, SKPaymentTransactionStateWrapper.deferred: 4, + SKPaymentTransactionStateWrapper.unspecified: -1, +}; + +const _$SKSubscriptionPeriodUnitEnumMap = { + SKSubscriptionPeriodUnit.day: 0, + SKSubscriptionPeriodUnit.week: 1, + SKSubscriptionPeriodUnit.month: 2, + SKSubscriptionPeriodUnit.year: 3, +}; + +const _$SKProductDiscountPaymentModeEnumMap = { + SKProductDiscountPaymentMode.payAsYouGo: 0, + SKProductDiscountPaymentMode.payUpFront: 1, + SKProductDiscountPaymentMode.freeTrail: 2, + SKProductDiscountPaymentMode.unspecified: -1, }; diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart index ce38759c74ec..d56fbd00c6fe 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart @@ -5,7 +5,6 @@ import 'dart:ui' show hashValues; import 'dart:async'; import 'package:collection/collection.dart'; -import 'package:flutter/foundation.dart'; import 'package:in_app_purchase/src/channel.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:flutter/services.dart'; @@ -25,7 +24,7 @@ part 'sk_payment_queue_wrapper.g.dart'; /// available at the [In-App Purchase Programming /// Guide](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction.html#//apple_ref/doc/uid/TP40008267). class SKPaymentQueueWrapper { - SKTransactionObserverWrapper _observer; + SKTransactionObserverWrapper? _observer; /// Returns the default payment queue. /// @@ -41,13 +40,15 @@ class SKPaymentQueueWrapper { /// Calls [`-[SKPaymentQueue transactions]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506026-transactions?language=objc) Future> transactions() async { - return _getTransactionList( - await channel.invokeListMethod('-[SKPaymentQueue transactions]')); + return _getTransactionList((await channel + .invokeListMethod('-[SKPaymentQueue transactions]'))!); } /// Calls [`-[SKPaymentQueue canMakePayments:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506139-canmakepayments?language=objc). static Future canMakePayments() async => - await channel.invokeMethod('-[SKPaymentQueue canMakePayments:]'); + (await channel + .invokeMethod('-[SKPaymentQueue canMakePayments:]')) ?? + false; /// Sets an observer to listen to all incoming transaction events. /// @@ -57,7 +58,7 @@ class SKPaymentQueueWrapper { /// addTransactionObserver:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506042-addtransactionobserver?language=objc). void setTransactionObserver(SKTransactionObserverWrapper observer) { _observer = observer; - callbackChannel.setMethodCallHandler(_handleObserverCallbacks); + channel.setMethodCallHandler(_handleObserverCallbacks); } /// Posts a payment to the queue. @@ -83,7 +84,7 @@ class SKPaymentQueueWrapper { Future addPayment(SKPaymentWrapper payment) async { assert(_observer != null, '[in_app_purchase]: Trying to add a payment without an observer. One must be set using `SkPaymentQueueWrapper.setTransactionObserver` before the app launches.'); - Map requestMap = payment.toMap(); + final Map requestMap = payment.toMap(); await channel.invokeMethod( '-[InAppPurchasePlugin addPayment:result:]', requestMap, @@ -103,7 +104,7 @@ class SKPaymentQueueWrapper { /// finishTransaction:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506003-finishtransaction?language=objc). Future finishTransaction( SKPaymentTransactionWrapper transaction) async { - Map requestMap = transaction.toFinishMap(); + Map requestMap = transaction.toFinishMap(); await channel.invokeMethod( '-[InAppPurchasePlugin finishTransaction:result:]', requestMap, @@ -124,28 +125,30 @@ class SKPaymentQueueWrapper { /// /// The `applicationUserName` should match the original /// [SKPaymentWrapper.applicationUsername] used in [addPayment]. + /// If no `applicationUserName` was used, `applicationUserName` should be null. /// /// This method either triggers [`-[SKPayment /// restoreCompletedTransactions]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506123-restorecompletedtransactions?language=objc) /// or [`-[SKPayment restoreCompletedTransactionsWithApplicationUsername:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1505992-restorecompletedtransactionswith?language=objc) /// depending on whether the `applicationUserName` is set. - Future restoreTransactions({String applicationUserName}) async { + Future restoreTransactions({String? applicationUserName}) async { await channel.invokeMethod( '-[InAppPurchasePlugin restoreTransactions:result:]', applicationUserName); } // Triage a method channel call from the platform and triggers the correct observer method. - Future _handleObserverCallbacks(MethodCall call) { + Future _handleObserverCallbacks(MethodCall call) async { assert(_observer != null, '[in_app_purchase]: (Fatal)The observer has not been set but we received a purchase transaction notification. Please ensure the observer has been set using `setTransactionObserver`. Make sure the observer is added right at the App Launch.'); + final SKTransactionObserverWrapper observer = _observer!; switch (call.method) { case 'updatedTransactions': { final List transactions = _getTransactionList(call.arguments); return Future(() { - _observer.updatedTransactions(transactions: transactions); + observer.updatedTransactions(transactions: transactions); }); } case 'removedTransactions': @@ -153,20 +156,20 @@ class SKPaymentQueueWrapper { final List transactions = _getTransactionList(call.arguments); return Future(() { - _observer.removedTransactions(transactions: transactions); + observer.removedTransactions(transactions: transactions); }); } case 'restoreCompletedTransactionsFailed': { SKError error = SKError.fromJson(call.arguments); return Future(() { - _observer.restoreCompletedTransactionsFailed(error: error); + observer.restoreCompletedTransactionsFailed(error: error); }); } case 'paymentQueueRestoreCompletedTransactionsFinished': { return Future(() { - _observer.paymentQueueRestoreCompletedTransactionsFinished(); + observer.paymentQueueRestoreCompletedTransactionsFinished(); }); } case 'shouldAddStorePayment': @@ -176,7 +179,7 @@ class SKPaymentQueueWrapper { SKProductWrapper product = SKProductWrapper.fromJson(call.arguments['product']); return Future(() { - if (_observer.shouldAddStorePayment( + if (observer.shouldAddStorePayment( payment: payment, product: product) == true) { SKPaymentQueueWrapper().addPayment(payment); @@ -186,49 +189,52 @@ class SKPaymentQueueWrapper { default: break; } - return null; + throw PlatformException( + code: 'no_such_callback', + message: 'Did not recognize the observer callback ${call.method}.'); } // Get transaction wrapper object list from arguments. - List _getTransactionList(dynamic arguments) { - final List transactions = arguments - .map( - (dynamic map) => SKPaymentTransactionWrapper.fromJson(map)) - .toList(); - return transactions; + List _getTransactionList( + List transactionsData) { + return transactionsData.map((dynamic map) { + return SKPaymentTransactionWrapper.fromJson( + Map.castFrom(map)); + }).toList(); } } /// Dart wrapper around StoreKit's /// [NSError](https://developer.apple.com/documentation/foundation/nserror?language=objc). -@JsonSerializable(nullable: true) +@JsonSerializable() class SKError { /// Creates a new [SKError] object with the provided information. - SKError( - {@required this.code, @required this.domain, @required this.userInfo}); + SKError({required this.code, required this.domain, required this.userInfo}); /// Constructs an instance of this from a key-value map of data. /// /// The map needs to have named string keys with values matching the names and /// types of all of the members on this class. The `map` parameter must not be /// null. - factory SKError.fromJson(Map map) { - assert(map != null); + factory SKError.fromJson(Map map) { return _$SKErrorFromJson(map); } /// Error [code](https://developer.apple.com/documentation/foundation/1448136-nserror_codes) /// as defined in the Cocoa Framework. + @JsonKey(defaultValue: 0) final int code; /// Error /// [domain](https://developer.apple.com/documentation/foundation/nscocoaerrordomain?language=objc) /// as defined in the Cocoa Framework. + @JsonKey(defaultValue: '') final String domain; /// A map that contains more detailed information about the error. /// /// Any key of the map must be a valid [NSErrorUserInfoKey](https://developer.apple.com/documentation/foundation/nserroruserinfokey?language=objc). + @JsonKey(defaultValue: {}) final Map userInfo; @override @@ -239,7 +245,7 @@ class SKError { if (other.runtimeType != runtimeType) { return false; } - final SKError typedOther = other; + final SKError typedOther = other as SKError; return typedOther.code == code && typedOther.domain == domain && DeepCollectionEquality.unordered() @@ -257,11 +263,11 @@ class SKError { /// not need to create the payment object explicitly; instead, use /// [SKPaymentQueueWrapper.addPayment] directly with a product identifier to /// initiate a payment. -@JsonSerializable(nullable: true) +@JsonSerializable() class SKPaymentWrapper { /// Creates a new [SKPaymentWrapper] with the provided information. SKPaymentWrapper( - {@required this.productIdentifier, + {required this.productIdentifier, this.applicationUsername, this.requestData, this.quantity = 1, @@ -272,7 +278,7 @@ class SKPaymentWrapper { /// The map needs to have named string keys with values matching the names and /// types of all of the members on this class. The `map` parameter must not be /// null. - factory SKPaymentWrapper.fromJson(Map map) { + factory SKPaymentWrapper.fromJson(Map map) { assert(map != null); return _$SKPaymentWrapperFromJson(map); } @@ -289,6 +295,7 @@ class SKPaymentWrapper { } /// The id for the product that the payment is for. + @JsonKey(defaultValue: '') final String productIdentifier; /// An opaque id for the user's account. @@ -299,7 +306,7 @@ class SKPaymentWrapper { /// account name on your server. Don’t use the Apple ID for your developer /// account, the user’s Apple ID, or the user’s plaintext account name on /// your server. - final String applicationUsername; + final String? applicationUsername; /// Reserved for future use. /// @@ -310,18 +317,26 @@ class SKPaymentWrapper { // We also provide this property to match the iOS platform. Converted to // String from NSData from ios platform using UTF8Encoding. The / default is // null. - final String requestData; + final String? requestData; /// The amount of the product this payment is for. /// /// The default is 1. The minimum is 1. The maximum is 10. + /// + /// If the object is invalid, the value could be 0. + @JsonKey(defaultValue: 0) final int quantity; - /// Produces an "ask to buy" flow in the sandbox if set to true. Default is - /// false. + /// Produces an "ask to buy" flow in the sandbox. + /// + /// Setting it to `true` will cause a transaction to be in the state [SKPaymentTransactionStateWrapper.deferred], + /// which produce an "ask to buy" prompt that interrupts the the payment flow. + /// + /// Default is `false`. /// /// See https://developer.apple.com/in-app-purchase/ for a guide on Sandbox /// testing. + @JsonKey(defaultValue: false) final bool simulatesAskToBuyInSandbox; @override @@ -332,7 +347,7 @@ class SKPaymentWrapper { if (other.runtimeType != runtimeType) { return false; } - final SKPaymentWrapper typedOther = other; + final SKPaymentWrapper typedOther = other as SKPaymentWrapper; return typedOther.productIdentifier == productIdentifier && typedOther.applicationUsername == applicationUsername && typedOther.quantity == quantity && diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart index 48a18e61d4d9..2b886597adc5 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart @@ -8,11 +8,12 @@ part of 'sk_payment_queue_wrapper.dart'; SKError _$SKErrorFromJson(Map json) { return SKError( - code: json['code'] as int, - domain: json['domain'] as String, - userInfo: (json['userInfo'] as Map)?.map( - (k, e) => MapEntry(k as String, e), - ), + code: json['code'] as int? ?? 0, + domain: json['domain'] as String? ?? '', + userInfo: (json['userInfo'] as Map?)?.map( + (k, e) => MapEntry(k as String, e), + ) ?? + {}, ); } @@ -24,11 +25,12 @@ Map _$SKErrorToJson(SKError instance) => { SKPaymentWrapper _$SKPaymentWrapperFromJson(Map json) { return SKPaymentWrapper( - productIdentifier: json['productIdentifier'] as String, - applicationUsername: json['applicationUsername'] as String, - requestData: json['requestData'] as String, - quantity: json['quantity'] as int, - simulatesAskToBuyInSandbox: json['simulatesAskToBuyInSandbox'] as bool, + productIdentifier: json['productIdentifier'] as String? ?? '', + applicationUsername: json['applicationUsername'] as String?, + requestData: json['requestData'] as String?, + quantity: json['quantity'] as int? ?? 0, + simulatesAskToBuyInSandbox: + json['simulatesAskToBuyInSandbox'] as bool? ?? false, ); } diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart index 65f6ff8871f8..9921380e6e96 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:ui' show hashValues; -import 'package:flutter/foundation.dart'; import 'package:json_annotation/json_annotation.dart'; import 'sk_product_wrapper.dart'; import 'sk_payment_queue_wrapper.dart'; @@ -20,13 +19,15 @@ part 'sk_payment_transaction_wrappers.g.dart'; /// This class is a Dart wrapper around [SKTransactionObserver](https://developer.apple.com/documentation/storekit/skpaymenttransactionobserver?language=objc). abstract class SKTransactionObserverWrapper { /// Triggered when any transactions are updated. - void updatedTransactions({List transactions}); + void updatedTransactions( + {required List transactions}); /// Triggered when any transactions are removed from the payment queue. - void removedTransactions({List transactions}); + void removedTransactions( + {required List transactions}); /// Triggered when there is an error while restoring transactions. - void restoreCompletedTransactionsFailed({SKError error}); + void restoreCompletedTransactionsFailed({required SKError error}); /// Triggered when payment queue has finished sending restored transactions. void paymentQueueRestoreCompletedTransactionsFinished(); @@ -41,7 +42,7 @@ abstract class SKTransactionObserverWrapper { /// continue the transaction later by calling [addPayment] with the /// `payment` param from this method. bool shouldAddStorePayment( - {SKPaymentWrapper payment, SKProductWrapper product}); + {required SKPaymentWrapper payment, required SKProductWrapper product}); } /// The state of a transaction. @@ -85,6 +86,10 @@ enum SKPaymentTransactionStateWrapper { /// transaction to update to another state. @JsonValue(4) deferred, + + /// Indicates the transaction is in an unspecified state. + @JsonValue(-1) + unspecified, } /// Created when a payment is added to the [SKPaymentQueueWrapper]. @@ -96,16 +101,16 @@ enum SKPaymentTransactionStateWrapper { /// /// Dart wrapper around StoreKit's /// [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction?language=objc). -@JsonSerializable(nullable: true) +@JsonSerializable() class SKPaymentTransactionWrapper { /// Creates a new [SKPaymentTransactionWrapper] with the provided information. SKPaymentTransactionWrapper({ - @required this.payment, - @required this.transactionState, - @required this.originalTransaction, - @required this.transactionTimeStamp, - @required this.transactionIdentifier, - @required this.error, + required this.payment, + required this.transactionState, + this.originalTransaction, + this.transactionTimeStamp, + this.transactionIdentifier, + this.error, }); /// Constructs an instance of this from a key value map of data. @@ -113,10 +118,7 @@ class SKPaymentTransactionWrapper { /// The map needs to have named string keys with values matching the names and /// types of all of the members on this class. The `map` parameter must not be /// null. - factory SKPaymentTransactionWrapper.fromJson(Map map) { - if (map == null) { - return null; - } + factory SKPaymentTransactionWrapper.fromJson(Map map) { return _$SKPaymentTransactionWrapperFromJson(map); } @@ -130,18 +132,21 @@ class SKPaymentTransactionWrapper { /// The original Transaction. /// - /// Only available if the [transactionState] is - /// [SKPaymentTransactionStateWrapper.restored]. When the [transactionState] + /// Only available if the [transactionState] is [SKPaymentTransactionStateWrapper.restored]. + /// Otherwise the value is `null`. + /// + /// When the [transactionState] /// is [SKPaymentTransactionStateWrapper.restored], the current transaction /// object holds a new [transactionIdentifier]. - final SKPaymentTransactionWrapper originalTransaction; + final SKPaymentTransactionWrapper? originalTransaction; /// The timestamp of the transaction. /// /// Seconds since epoch. It is only defined when the [transactionState] is /// [SKPaymentTransactionStateWrapper.purchased] or /// [SKPaymentTransactionStateWrapper.restored]. - final double transactionTimeStamp; + /// Otherwise, the value is `null`. + final double? transactionTimeStamp; /// The unique string identifer of the transaction. /// @@ -150,13 +155,15 @@ class SKPaymentTransactionWrapper { /// [SKPaymentTransactionStateWrapper.restored]. You may wish to record this /// string as part of an audit trail for App Store purchases. The value of /// this string corresponds to the same property in the receipt. - final String transactionIdentifier; + /// + /// The value is `null` if it is an unsuccessful transaction. + final String? transactionIdentifier; /// The error object /// /// Only available if the [transactionState] is /// [SKPaymentTransactionStateWrapper.failed]. - final SKError error; + final SKError? error; @override bool operator ==(Object other) { @@ -166,7 +173,8 @@ class SKPaymentTransactionWrapper { if (other.runtimeType != runtimeType) { return false; } - final SKPaymentTransactionWrapper typedOther = other; + final SKPaymentTransactionWrapper typedOther = + other as SKPaymentTransactionWrapper; return typedOther.payment == payment && typedOther.transactionState == transactionState && typedOther.originalTransaction == originalTransaction && @@ -188,8 +196,8 @@ class SKPaymentTransactionWrapper { String toString() => _$SKPaymentTransactionWrapperToJson(this).toString(); /// The payload that is used to finish this transaction. - Map toFinishMap() => { + Map toFinishMap() => { "transactionIdentifier": this.transactionIdentifier, - "productIdentifier": this.payment?.productIdentifier, + "productIdentifier": this.payment.productIdentifier, }; } diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart index bc520826d9fe..4c7af21bc151 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart @@ -8,19 +8,19 @@ part of 'sk_payment_transaction_wrappers.dart'; SKPaymentTransactionWrapper _$SKPaymentTransactionWrapperFromJson(Map json) { return SKPaymentTransactionWrapper( - payment: json['payment'] == null - ? null - : SKPaymentWrapper.fromJson(json['payment'] as Map), + payment: SKPaymentWrapper.fromJson( + Map.from(json['payment'] as Map)), transactionState: const SKTransactionStatusConverter() - .fromJson(json['transactionState'] as int), + .fromJson(json['transactionState'] as int?), originalTransaction: json['originalTransaction'] == null ? null : SKPaymentTransactionWrapper.fromJson( - json['originalTransaction'] as Map), - transactionTimeStamp: (json['transactionTimeStamp'] as num)?.toDouble(), - transactionIdentifier: json['transactionIdentifier'] as String, - error: - json['error'] == null ? null : SKError.fromJson(json['error'] as Map), + Map.from(json['originalTransaction'] as Map)), + transactionTimeStamp: (json['transactionTimeStamp'] as num?)?.toDouble(), + transactionIdentifier: json['transactionIdentifier'] as String?, + error: json['error'] == null + ? null + : SKError.fromJson(Map.from(json['error'] as Map)), ); } diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart index aa76971102cf..d77ea81c2d38 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart @@ -3,9 +3,9 @@ // found in the LICENSE file. import 'dart:ui' show hashValues; -import 'package:flutter/foundation.dart'; import 'package:collection/collection.dart'; import 'package:json_annotation/json_annotation.dart'; +import 'enum_converters.dart'; // WARNING: Changes to `@JsonSerializable` classes need to be reflected in the // below generated file. Run `flutter packages pub run build_runner watch` to @@ -20,14 +20,12 @@ part 'sk_product_wrapper.g.dart'; class SkProductResponseWrapper { /// Creates an [SkProductResponseWrapper] with the given product details. SkProductResponseWrapper( - {@required this.products, @required this.invalidProductIdentifiers}); + {required this.products, required this.invalidProductIdentifiers}); /// Constructing an instance from a map from the Objective-C layer. /// /// This method should only be used with `map` values returned by [SKRequestMaker.startProductRequest]. - /// The `map` parameter must not be null. factory SkProductResponseWrapper.fromJson(Map map) { - assert(map != null, 'Map must not be null.'); return _$SkProductResponseWrapperFromJson(map); } @@ -35,6 +33,7 @@ class SkProductResponseWrapper { /// /// One product in this list matches one valid product identifier passed to the [SKRequestMaker.startProductRequest]. /// Will be empty if the [SKRequestMaker.startProductRequest] method does not pass any correct product identifier. + @JsonKey(defaultValue: []) final List products; /// Stores product identifiers in the `productIdentifiers` from [SKRequestMaker.startProductRequest] that are not recognized by the App Store. @@ -42,6 +41,7 @@ class SkProductResponseWrapper { /// The App Store will not recognize a product identifier unless certain criteria are met. A detailed list of the criteria can be /// found here https://developer.apple.com/documentation/storekit/skproductsresponse/1505985-invalidproductidentifiers?language=objc. /// Will be empty if all the product identifiers are valid. + @JsonKey(defaultValue: []) final List invalidProductIdentifiers; @override @@ -52,7 +52,8 @@ class SkProductResponseWrapper { if (other.runtimeType != runtimeType) { return false; } - final SkProductResponseWrapper typedOther = other; + final SkProductResponseWrapper typedOther = + other as SkProductResponseWrapper; return DeepCollectionEquality().equals(typedOther.products, products) && DeepCollectionEquality().equals( typedOther.invalidProductIdentifiers, invalidProductIdentifiers); @@ -91,27 +92,32 @@ enum SKSubscriptionPeriodUnit { /// /// A period is defined by a [numberOfUnits] and a [unit], e.g for a 3 months period [numberOfUnits] is 3 and [unit] is a month. /// It is used as a property in [SKProductDiscountWrapper] and [SKProductWrapper]. -@JsonSerializable(nullable: true) +@JsonSerializable() class SKProductSubscriptionPeriodWrapper { /// Creates an [SKProductSubscriptionPeriodWrapper] for a `numberOfUnits`x`unit` period. SKProductSubscriptionPeriodWrapper( - {@required this.numberOfUnits, @required this.unit}); + {required this.numberOfUnits, required this.unit}); /// Constructing an instance from a map from the Objective-C layer. /// /// This method should only be used with `map` values returned by [SKProductDiscountWrapper.fromJson] or [SKProductWrapper.fromJson]. - /// The `map` parameter must not be null. - factory SKProductSubscriptionPeriodWrapper.fromJson(Map map) { - assert(map != null, 'Map must not be null.'); + factory SKProductSubscriptionPeriodWrapper.fromJson( + Map? map) { + if (map == null) { + return SKProductSubscriptionPeriodWrapper( + numberOfUnits: 0, unit: SKSubscriptionPeriodUnit.day); + } return _$SKProductSubscriptionPeriodWrapperFromJson(map); } /// The number of [unit] units in this period. /// - /// Must be greater than 0. + /// Must be greater than 0 if the object is valid. + @JsonKey(defaultValue: 0) final int numberOfUnits; /// The time unit used to specify the length of this period. + @SKSubscriptionPeriodUnitConverter() final SKSubscriptionPeriodUnit unit; @override @@ -122,7 +128,8 @@ class SKProductSubscriptionPeriodWrapper { if (other.runtimeType != runtimeType) { return false; } - final SKProductSubscriptionPeriodWrapper typedOther = other; + final SKProductSubscriptionPeriodWrapper typedOther = + other as SKProductSubscriptionPeriodWrapper; return typedOther.numberOfUnits == numberOfUnits && typedOther.unit == unit; } @@ -147,31 +154,34 @@ enum SKProductDiscountPaymentMode { /// User pays nothing during the discounted period. @JsonValue(2) freeTrail, + + /// Unspecified mode. + @JsonValue(-1) + unspecified, } /// Dart wrapper around StoreKit's [SKProductDiscount](https://developer.apple.com/documentation/storekit/skproductdiscount?language=objc). /// /// It is used as a property in [SKProductWrapper]. -@JsonSerializable(nullable: true) +@JsonSerializable() class SKProductDiscountWrapper { /// Creates an [SKProductDiscountWrapper] with the given discount details. SKProductDiscountWrapper( - {@required this.price, - @required this.priceLocale, - @required this.numberOfPeriods, - @required this.paymentMode, - @required this.subscriptionPeriod}); + {required this.price, + required this.priceLocale, + required this.numberOfPeriods, + required this.paymentMode, + required this.subscriptionPeriod}); /// Constructing an instance from a map from the Objective-C layer. /// /// This method should only be used with `map` values returned by [SKProductWrapper.fromJson]. - /// The `map` parameter must not be null. - factory SKProductDiscountWrapper.fromJson(Map map) { - assert(map != null, 'Map must not be null.'); + factory SKProductDiscountWrapper.fromJson(Map map) { return _$SKProductDiscountWrapperFromJson(map); } /// The discounted price, in the currency that is defined in [priceLocale]. + @JsonKey(defaultValue: '') final String price; /// Includes locale information about the price, e.g. `$` as the currency symbol for US locale. @@ -179,10 +189,12 @@ class SKProductDiscountWrapper { /// The object represent the discount period length. /// - /// The value must be >= 0. + /// The value must be >= 0 if the object is valid. + @JsonKey(defaultValue: 0) final int numberOfPeriods; /// The object indicates how the discount price is charged. + @SKProductDiscountPaymentModeConverter() final SKProductDiscountPaymentMode paymentMode; /// The object represents the duration of single subscription period for the discount. @@ -199,7 +211,8 @@ class SKProductDiscountWrapper { if (other.runtimeType != runtimeType) { return false; } - final SKProductDiscountWrapper typedOther = other; + final SKProductDiscountWrapper typedOther = + other as SKProductDiscountWrapper; return typedOther.price == price && typedOther.priceLocale == priceLocale && typedOther.numberOfPeriods == numberOfPeriods && @@ -216,40 +229,41 @@ class SKProductDiscountWrapper { /// /// A list of [SKProductWrapper] is returned in the [SKRequestMaker.startProductRequest] method, and /// should be stored for use when making a payment. -@JsonSerializable(nullable: true) +@JsonSerializable() class SKProductWrapper { /// Creates an [SKProductWrapper] with the given product details. SKProductWrapper({ - @required this.productIdentifier, - @required this.localizedTitle, - @required this.localizedDescription, - @required this.priceLocale, - @required this.subscriptionGroupIdentifier, - @required this.price, - @required this.subscriptionPeriod, - @required this.introductoryPrice, + required this.productIdentifier, + required this.localizedTitle, + required this.localizedDescription, + required this.priceLocale, + this.subscriptionGroupIdentifier, + required this.price, + this.subscriptionPeriod, + this.introductoryPrice, }); /// Constructing an instance from a map from the Objective-C layer. /// /// This method should only be used with `map` values returned by [SkProductResponseWrapper.fromJson]. - /// The `map` parameter must not be null. - factory SKProductWrapper.fromJson(Map map) { - assert(map != null, 'Map must not be null.'); + factory SKProductWrapper.fromJson(Map map) { return _$SKProductWrapperFromJson(map); } /// The unique identifier of the product. + @JsonKey(defaultValue: '') final String productIdentifier; /// The localizedTitle of the product. /// /// It is localized based on the current locale. + @JsonKey(defaultValue: '') final String localizedTitle; /// The localized description of the product. /// /// It is localized based on the current locale. + @JsonKey(defaultValue: '') final String localizedDescription; /// Includes locale information about the price, e.g. `$` as the currency symbol for US locale. @@ -257,26 +271,29 @@ class SKProductWrapper { /// The subscription group identifier. /// + /// If the product is not a subscription, the value is `null`. + /// /// A subscription group is a collection of subscription products. /// Check [SubscriptionGroup](https://developer.apple.com/app-store/subscriptions/) for more details about subscription group. - final String subscriptionGroupIdentifier; + final String? subscriptionGroupIdentifier; /// The price of the product, in the currency that is defined in [priceLocale]. + @JsonKey(defaultValue: '') final String price; /// The object represents the subscription period of the product. /// /// Can be [null] is the product is not a subscription. - final SKProductSubscriptionPeriodWrapper subscriptionPeriod; + final SKProductSubscriptionPeriodWrapper? subscriptionPeriod; /// The object represents the duration of single subscription period. /// - /// This is only available if you set up the introductory price in the App Store Connect, otherwise it will be null. + /// This is only available if you set up the introductory price in the App Store Connect, otherwise the value is `null`. /// Programmer is also responsible to determine if the user is eligible to receive it. See https://developer.apple.com/documentation/storekit/in-app_purchase/offering_introductory_pricing_in_your_app?language=objc /// for more details. /// The [subscriptionPeriod] of the discount is independent of the product's [subscriptionPeriod], /// and their units and duration do not have to be matched. - final SKProductDiscountWrapper introductoryPrice; + final SKProductDiscountWrapper? introductoryPrice; @override bool operator ==(Object other) { @@ -286,7 +303,7 @@ class SKProductWrapper { if (other.runtimeType != runtimeType) { return false; } - final SKProductWrapper typedOther = other; + final SKProductWrapper typedOther = other as SKProductWrapper; return typedOther.productIdentifier == productIdentifier && typedOther.localizedTitle == localizedTitle && typedOther.localizedDescription == localizedDescription && @@ -319,21 +336,24 @@ class SKProductWrapper { class SKPriceLocaleWrapper { /// Creates a new price locale for `currencySymbol` and `currencyCode`. SKPriceLocaleWrapper( - {@required this.currencySymbol, @required this.currencyCode}); + {required this.currencySymbol, required this.currencyCode}); /// Constructing an instance from a map from the Objective-C layer. /// /// This method should only be used with `map` values returned by [SKProductWrapper.fromJson] and [SKProductDiscountWrapper.fromJson]. - /// The `map` parameter must not be null. - factory SKPriceLocaleWrapper.fromJson(Map map) { - assert(map != null, 'Map must not be null.'); + factory SKPriceLocaleWrapper.fromJson(Map? map) { + if (map == null) { + return SKPriceLocaleWrapper(currencyCode: '', currencySymbol: ''); + } return _$SKPriceLocaleWrapperFromJson(map); } ///The currency symbol for the locale, e.g. $ for US locale. + @JsonKey(defaultValue: '') final String currencySymbol; ///The currency code for the locale, e.g. USD for US locale. + @JsonKey(defaultValue: '') final String currencyCode; @override @@ -344,7 +364,7 @@ class SKPriceLocaleWrapper { if (other.runtimeType != runtimeType) { return false; } - final SKPriceLocaleWrapper typedOther = other; + final SKPriceLocaleWrapper typedOther = other as SKPriceLocaleWrapper; return typedOther.currencySymbol == currencySymbol && typedOther.currencyCode == currencyCode; } diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart index cf27852263ba..8c2eed3d6070 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart @@ -8,12 +8,16 @@ part of 'sk_product_wrapper.dart'; SkProductResponseWrapper _$SkProductResponseWrapperFromJson(Map json) { return SkProductResponseWrapper( - products: (json['products'] as List) - .map((e) => SKProductWrapper.fromJson(e as Map)) - .toList(), - invalidProductIdentifiers: (json['invalidProductIdentifiers'] as List) - .map((e) => e as String) - .toList(), + products: (json['products'] as List?) + ?.map((e) => + SKProductWrapper.fromJson(Map.from(e as Map))) + .toList() ?? + [], + invalidProductIdentifiers: + (json['invalidProductIdentifiers'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], ); } @@ -27,8 +31,9 @@ Map _$SkProductResponseWrapperToJson( SKProductSubscriptionPeriodWrapper _$SKProductSubscriptionPeriodWrapperFromJson( Map json) { return SKProductSubscriptionPeriodWrapper( - numberOfUnits: json['numberOfUnits'] as int, - unit: _$enumDecodeNullable(_$SKSubscriptionPeriodUnitEnumMap, json['unit']), + numberOfUnits: json['numberOfUnits'] as int? ?? 0, + unit: const SKSubscriptionPeriodUnitConverter() + .fromJson(json['unit'] as int?), ); } @@ -36,61 +41,23 @@ Map _$SKProductSubscriptionPeriodWrapperToJson( SKProductSubscriptionPeriodWrapper instance) => { 'numberOfUnits': instance.numberOfUnits, - 'unit': _$SKSubscriptionPeriodUnitEnumMap[instance.unit], + 'unit': const SKSubscriptionPeriodUnitConverter().toJson(instance.unit), }; -T _$enumDecode( - Map enumValues, - dynamic source, { - T unknownValue, -}) { - if (source == null) { - throw ArgumentError('A value must be provided. Supported values: ' - '${enumValues.values.join(', ')}'); - } - - final value = enumValues.entries - .singleWhere((e) => e.value == source, orElse: () => null) - ?.key; - - if (value == null && unknownValue == null) { - throw ArgumentError('`$source` is not one of the supported values: ' - '${enumValues.values.join(', ')}'); - } - return value ?? unknownValue; -} - -T _$enumDecodeNullable( - Map enumValues, - dynamic source, { - T unknownValue, -}) { - if (source == null) { - return null; - } - return _$enumDecode(enumValues, source, unknownValue: unknownValue); -} - -const _$SKSubscriptionPeriodUnitEnumMap = { - SKSubscriptionPeriodUnit.day: 0, - SKSubscriptionPeriodUnit.week: 1, - SKSubscriptionPeriodUnit.month: 2, - SKSubscriptionPeriodUnit.year: 3, -}; - SKProductDiscountWrapper _$SKProductDiscountWrapperFromJson(Map json) { return SKProductDiscountWrapper( - price: json['price'] as String, - priceLocale: json['priceLocale'] == null - ? null - : SKPriceLocaleWrapper.fromJson(json['priceLocale'] as Map), - numberOfPeriods: json['numberOfPeriods'] as int, - paymentMode: _$enumDecodeNullable( - _$SKProductDiscountPaymentModeEnumMap, json['paymentMode']), - subscriptionPeriod: json['subscriptionPeriod'] == null - ? null - : SKProductSubscriptionPeriodWrapper.fromJson( - json['subscriptionPeriod'] as Map), + price: json['price'] as String? ?? '', + priceLocale: + SKPriceLocaleWrapper.fromJson((json['priceLocale'] as Map?)?.map( + (k, e) => MapEntry(k as String, e), + )), + numberOfPeriods: json['numberOfPeriods'] as int? ?? 0, + paymentMode: const SKProductDiscountPaymentModeConverter() + .fromJson(json['paymentMode'] as int?), + subscriptionPeriod: SKProductSubscriptionPeriodWrapper.fromJson( + (json['subscriptionPeriod'] as Map?)?.map( + (k, e) => MapEntry(k as String, e), + )), ); } @@ -100,34 +67,32 @@ Map _$SKProductDiscountWrapperToJson( 'price': instance.price, 'priceLocale': instance.priceLocale, 'numberOfPeriods': instance.numberOfPeriods, - 'paymentMode': - _$SKProductDiscountPaymentModeEnumMap[instance.paymentMode], + 'paymentMode': const SKProductDiscountPaymentModeConverter() + .toJson(instance.paymentMode), 'subscriptionPeriod': instance.subscriptionPeriod, }; -const _$SKProductDiscountPaymentModeEnumMap = { - SKProductDiscountPaymentMode.payAsYouGo: 0, - SKProductDiscountPaymentMode.payUpFront: 1, - SKProductDiscountPaymentMode.freeTrail: 2, -}; - SKProductWrapper _$SKProductWrapperFromJson(Map json) { return SKProductWrapper( - productIdentifier: json['productIdentifier'] as String, - localizedTitle: json['localizedTitle'] as String, - localizedDescription: json['localizedDescription'] as String, - priceLocale: json['priceLocale'] == null - ? null - : SKPriceLocaleWrapper.fromJson(json['priceLocale'] as Map), - subscriptionGroupIdentifier: json['subscriptionGroupIdentifier'] as String, - price: json['price'] as String, + productIdentifier: json['productIdentifier'] as String? ?? '', + localizedTitle: json['localizedTitle'] as String? ?? '', + localizedDescription: json['localizedDescription'] as String? ?? '', + priceLocale: + SKPriceLocaleWrapper.fromJson((json['priceLocale'] as Map?)?.map( + (k, e) => MapEntry(k as String, e), + )), + subscriptionGroupIdentifier: json['subscriptionGroupIdentifier'] as String?, + price: json['price'] as String? ?? '', subscriptionPeriod: json['subscriptionPeriod'] == null ? null : SKProductSubscriptionPeriodWrapper.fromJson( - json['subscriptionPeriod'] as Map), + (json['subscriptionPeriod'] as Map?)?.map( + (k, e) => MapEntry(k as String, e), + )), introductoryPrice: json['introductoryPrice'] == null ? null - : SKProductDiscountWrapper.fromJson(json['introductoryPrice'] as Map), + : SKProductDiscountWrapper.fromJson( + Map.from(json['introductoryPrice'] as Map)), ); } @@ -145,8 +110,8 @@ Map _$SKProductWrapperToJson(SKProductWrapper instance) => SKPriceLocaleWrapper _$SKPriceLocaleWrapperFromJson(Map json) { return SKPriceLocaleWrapper( - currencySymbol: json['currencySymbol'] as String, - currencyCode: json['currencyCode'] as String, + currencySymbol: json['currencySymbol'] as String? ?? '', + currencyCode: json['currencyCode'] as String? ?? '', ); } diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart index 85af9dedc7c3..16bcb77a2c70 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart @@ -14,8 +14,9 @@ class SKReceiptManager { /// There are 2 ways to do so. Either validate locally or validate with App Store. /// For more details on how to validate the receipt data, you can refer to Apple's document about [`About Receipt Validation`](https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Introduction.html#//apple_ref/doc/uid/TP40010573-CH105-SW1). /// If the receipt is invalid or missing, you can use [SKRequestMaker.startRefreshReceiptRequest] to request a new receipt. - static Future retrieveReceiptData() { - return channel.invokeMethod( - '-[InAppPurchasePlugin retrieveReceiptData:result:]'); + static Future retrieveReceiptData() async { + return (await channel.invokeMethod( + '-[InAppPurchasePlugin retrieveReceiptData:result:]')) ?? + ''; } } diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart index 959113cd66d8..c22df0a9dbdd 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart @@ -24,7 +24,7 @@ class SKRequestMaker { /// A [PlatformException] is thrown if the platform code making the request fails. Future startProductRequest( List productIdentifiers) async { - final Map productResponseMap = + final Map? productResponseMap = await channel.invokeMapMethod( '-[InAppPurchasePlugin startProductRequest:result:]', productIdentifiers, @@ -47,7 +47,8 @@ class SKRequestMaker { /// * isExpired: whether the receipt is expired. /// * isRevoked: whether the receipt has been revoked. /// * isVolumePurchase: whether the receipt is a Volume Purchase Plan receipt. - Future startRefreshReceiptRequest({Map receiptProperties}) { + Future startRefreshReceiptRequest( + {Map? receiptProperties}) { return channel.invokeMethod( '-[InAppPurchasePlugin refreshReceipt:result:]', receiptProperties, diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 6a6c525132da..f847a81291be 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,30 +1,26 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.3.5+2 +version: 0.4.0 dependencies: - async: ^2.0.8 - collection: ^1.14.11 flutter: sdk: flutter - json_annotation: ^3.0.0 - meta: ^1.1.6 + json_annotation: ^4.0.0 + meta: ^1.3.0 + collection: ^1.15.0 dev_dependencies: - build_runner: ^1.0.0 - json_serializable: ^3.2.0 + build_runner: ^1.11.1 + json_serializable: ^4.0.0 flutter_test: sdk: flutter flutter_driver: sdk: flutter - in_app_purchase_example: - path: example/ - test: ^1.5.2 - shared_preferences: ^0.5.2 + test: ^1.16.0 integration_test: path: ../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: plugin: @@ -36,5 +32,5 @@ flutter: pluginClass: InAppPurchasePlugin environment: - sdk: ">=2.3.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart index eee33a698237..d415007284c8 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart @@ -16,7 +16,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); final StubInAppPurchasePlatform stubPlatform = StubInAppPurchasePlatform(); - BillingClient billingClient; + late BillingClient billingClient; setUpAll(() => channel.setMockMethodCallHandler(stubPlatform.fakeMethodCallHandler)); @@ -96,6 +96,20 @@ void main() { equals( {'handle': 0, 'enablePendingPurchases': true})); }); + + test('handles method channel returning null', () async { + stubPlatform.addResponse( + name: methodName, + value: null, + ); + + expect( + await billingClient.startConnection( + onBillingServiceDisconnected: () {}), + equals(BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage))); + }); }); test('endConnection', () async { @@ -151,6 +165,20 @@ void main() { expect(response.billingResult, equals(billingResult)); expect(response.skuDetailsList, contains(dummySkuDetails)); }); + + test('handles null method channel response', () async { + stubPlatform.addResponse(name: queryMethodName, value: null); + + final SkuDetailsResponseWrapper response = await billingClient + .querySkuDetails( + skuType: SkuType.inapp, skusList: ['invalid']); + + BillingResultWrapper billingResult = BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage); + expect(response.billingResult, equals(billingResult)); + expect(response.skuDetailsList, isEmpty); + }); }); group('launchBillingFlow', () { @@ -197,6 +225,19 @@ void main() { expect(arguments['sku'], equals(skuDetails.sku)); expect(arguments['accountId'], isNull); }); + + test('handles method channel returning null', () async { + stubPlatform.addResponse( + name: launchMethodName, + value: null, + ); + final SkuDetailsWrapper skuDetails = dummySkuDetails; + expect( + await billingClient.launchBillingFlow(sku: skuDetails.sku), + equals(BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage))); + }); }); group('queryPurchases', () { @@ -228,10 +269,6 @@ void main() { expect(response.purchasesList, equals(expectedList)); }); - test('checks for null params', () async { - expect(() => billingClient.queryPurchases(null), throwsAssertionError); - }); - test('handles empty purchases', () async { final BillingResponse expectedCode = BillingResponse.userCanceled; const String debugMessage = 'dummy message'; @@ -251,6 +288,23 @@ void main() { expect(response.responseCode, equals(expectedCode)); expect(response.purchasesList, isEmpty); }); + + test('handles method channel returning null', () async { + stubPlatform.addResponse( + name: queryPurchasesMethodName, + value: null, + ); + final PurchasesResultWrapper response = + await billingClient.queryPurchases(SkuType.inapp); + + expect( + response.billingResult, + equals(BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage))); + expect(response.responseCode, BillingResponse.error); + expect(response.purchasesList, isEmpty); + }); }); group('queryPurchaseHistory', () { @@ -282,11 +336,6 @@ void main() { expect(response.purchaseHistoryRecordList, equals(expectedList)); }); - test('checks for null params', () async { - expect( - () => billingClient.queryPurchaseHistory(null), throwsAssertionError); - }); - test('handles empty purchases', () async { final BillingResponse expectedCode = BillingResponse.userCanceled; const String debugMessage = 'dummy message'; @@ -303,6 +352,22 @@ void main() { expect(response.billingResult, equals(expectedBillingResult)); expect(response.purchaseHistoryRecordList, isEmpty); }); + + test('handles method channel returning null', () async { + stubPlatform.addResponse( + name: queryPurchaseHistoryMethodName, + value: null, + ); + final PurchasesHistoryResult response = + await billingClient.queryPurchaseHistory(SkuType.inapp); + + expect( + response.billingResult, + equals(BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage))); + expect(response.purchaseHistoryRecordList, isEmpty); + }); }); group('consume purchases', () { @@ -322,6 +387,21 @@ void main() { expect(billingResult, equals(expectedBillingResult)); }); + + test('handles method channel returning null', () async { + stubPlatform.addResponse( + name: consumeMethodName, + value: null, + ); + final BillingResultWrapper billingResult = await billingClient + .consumeAsync('dummy token', developerPayload: 'dummy payload'); + + expect( + billingResult, + equals(BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage))); + }); }); group('acknowledge purchases', () { @@ -342,5 +422,20 @@ void main() { expect(billingResult, equals(expectedBillingResult)); }); + test('handles method channel returning null', () async { + stubPlatform.addResponse( + name: acknowledgeMethodName, + value: null, + ); + final BillingResultWrapper billingResult = + await billingClient.acknowledgePurchase('dummy token', + developerPayload: 'dummy payload'); + + expect( + billingResult, + equals(BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage))); + }); }); } diff --git a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart index 978252a3d118..7f3de2742603 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart @@ -62,6 +62,7 @@ void main() { expect(details.purchaseID, dummyPurchase.orderId); expect(details.productID, dummyPurchase.sku); expect(details.transactionDate, dummyPurchase.purchaseTime.toString()); + expect(details.verificationData, isNotNull); expect(details.verificationData.source, IAPSource.GooglePlay); expect(details.verificationData.localVerificationData, dummyPurchase.originalJson); @@ -111,6 +112,18 @@ void main() { expect(parsed.responseCode, equals(expected.responseCode)); expect(parsed.purchasesList, containsAll(expected.purchasesList)); }); + + test('parsed from empty map', () { + final PurchasesResultWrapper parsed = + PurchasesResultWrapper.fromJson({}); + expect( + parsed.billingResult, + equals(BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage))); + expect(parsed.responseCode, BillingResponse.error); + expect(parsed.purchasesList, isEmpty); + }); }); group('PurchasesHistoryResult', () { @@ -139,6 +152,17 @@ void main() { expect(parsed.purchaseHistoryRecordList, containsAll(expected.purchaseHistoryRecordList)); }); + + test('parsed from empty map', () { + final PurchasesHistoryResult parsed = + PurchasesHistoryResult.fromJson({}); + expect( + parsed.billingResult, + equals(BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage))); + expect(parsed.purchaseHistoryRecordList, isEmpty); + }); }); } diff --git a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart index c305e6df88cc..13715eeb9fc0 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart @@ -99,6 +99,33 @@ void main() { expect(parsed.billingResult, equals(expected.billingResult)); expect(parsed.skuDetailsList, containsAll(expected.skuDetailsList)); }); + + test('fromJson creates an object with default values', () { + final SkuDetailsResponseWrapper skuDetails = + SkuDetailsResponseWrapper.fromJson({}); + expect( + skuDetails.billingResult, + equals(BillingResultWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage))); + expect(skuDetails.skuDetailsList, isEmpty); + }); + }); + + group('BillingResultWrapper', () { + test('fromJson on empty map creates an object with default values', () { + final BillingResultWrapper billingResult = + BillingResultWrapper.fromJson({}); + expect(billingResult.debugMessage, kInvalidBillingResultErrorMessage); + expect(billingResult.responseCode, BillingResponse.error); + }); + + test('fromJson on null creates an object with default values', () { + final BillingResultWrapper billingResult = + BillingResultWrapper.fromJson(null); + expect(billingResult.debugMessage, kInvalidBillingResultErrorMessage); + expect(billingResult.responseCode, BillingResponse.error); + }); }); } diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index b22737ca041b..bfcab085e26a 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -15,6 +15,7 @@ import 'package:in_app_purchase/src/in_app_purchase/app_store_connection.dart'; import 'package:in_app_purchase/src/in_app_purchase/in_app_purchase_connection.dart'; import 'package:in_app_purchase/src/in_app_purchase/product_details.dart'; import 'package:in_app_purchase/store_kit_wrappers.dart'; +import '../billing_client_wrappers/purchase_wrapper_test.dart'; import '../store_kit_wrappers/sk_test_stub_objects.dart'; void main() { @@ -61,10 +62,11 @@ void main() { .queryProductDetails(['123', '456', '789'].toSet()); expect(response.productDetails, []); expect(response.notFoundIDs, ['123', '456', '789']); - expect(response.error.source, IAPSource.AppStore); - expect(response.error.code, 'error_code'); - expect(response.error.message, 'error_message'); - expect(response.error.details, {'info': 'error_info'}); + expect(response.error, isNotNull); + expect(response.error!.source, IAPSource.AppStore); + expect(response.error!.code, 'error_code'); + expect(response.error!.message, 'error_message'); + expect(response.error!.details, {'info': 'error_info'}); }); }); @@ -81,6 +83,8 @@ void main() { fakeIOSPlatform.transactions.first.transactionIdentifier); expect(response.pastPurchases.last.purchaseID, fakeIOSPlatform.transactions.last.transactionIdentifier); + expect(response.pastPurchases, isNotEmpty); + expect(response.pastPurchases.first.verificationData, isNotNull); expect( response.pastPurchases.first.verificationData.localVerificationData, 'dummy base64data'); @@ -97,7 +101,7 @@ void main() { Stream> stream = AppStoreConnection.instance.purchaseUpdatedStream; - StreamSubscription subscription; + late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { if (purchaseDetailsList.first.status == PurchaseStatus.purchased) { completer.complete(purchaseDetailsList); @@ -130,9 +134,10 @@ void main() { QueryPurchaseDetailsResponse response = await AppStoreConnection.instance.queryPastPurchases(); expect(response.pastPurchases, isEmpty); - expect(response.error.source, IAPSource.AppStore); - expect(response.error.message, 'error_test'); - expect(response.error.details, {'message': 'errorMessage'}); + expect(response.error, isNotNull); + expect(response.error!.source, IAPSource.AppStore); + expect(response.error!.message, 'error_test'); + expect(response.error!.details, {'message': 'errorMessage'}); }); test('receipt error should populate null to verificationData.data', @@ -142,18 +147,19 @@ void main() { await AppStoreConnection.instance.queryPastPurchases(); expect( response.pastPurchases.first.verificationData.localVerificationData, - null); + isEmpty); expect( response.pastPurchases.first.verificationData.serverVerificationData, - null); + isEmpty); }); }); group('refresh receipt data', () { test('should refresh receipt data', () async { - PurchaseVerificationData receiptData = + PurchaseVerificationData? receiptData = await AppStoreConnection.instance.refreshPurchaseVerificationData(); - expect(receiptData.source, IAPSource.AppStore); + expect(receiptData, isNotNull); + expect(receiptData!.source, IAPSource.AppStore); expect(receiptData.localVerificationData, 'refreshed receipt data'); expect(receiptData.serverVerificationData, 'refreshed receipt data'); }); @@ -168,7 +174,7 @@ void main() { Stream> stream = AppStoreConnection.instance.purchaseUpdatedStream; - StreamSubscription subscription; + late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { details.addAll(purchaseDetailsList); if (purchaseDetailsList.first.status == PurchaseStatus.purchased) { @@ -195,7 +201,7 @@ void main() { Stream> stream = AppStoreConnection.instance.purchaseUpdatedStream; - StreamSubscription subscription; + late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { details.addAll(purchaseDetailsList); if (purchaseDetailsList.first.status == PurchaseStatus.purchased) { @@ -228,16 +234,16 @@ void main() { fakeIOSPlatform.testTransactionFail = true; List details = []; Completer completer = Completer(); - IAPError error; + late IAPError error; Stream> stream = AppStoreConnection.instance.purchaseUpdatedStream; - StreamSubscription subscription; + late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { details.addAll(purchaseDetailsList); purchaseDetailsList.forEach((purchaseDetails) { if (purchaseDetails.status == PurchaseStatus.error) { - error = purchaseDetails.error; + error = purchaseDetails.error!; completer.complete(error); subscription.cancel(); } @@ -263,7 +269,7 @@ void main() { Completer completer = Completer(); Stream> stream = AppStoreConnection.instance.purchaseUpdatedStream; - StreamSubscription subscription; + late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { details.addAll(purchaseDetailsList); purchaseDetailsList.forEach((purchaseDetails) { @@ -288,7 +294,9 @@ void main() { group('consume purchase', () { test('should throw when calling consume purchase on iOS', () async { - expect(() => AppStoreConnection.instance.consumePurchase(null), + expect( + () => AppStoreConnection.instance + .consumePurchase(PurchaseDetails.fromPurchase(dummyPurchase)), throwsUnsupportedError); }); }); @@ -300,16 +308,16 @@ class FakeIOSPlatform { } // pre-configured store informations - String receiptData; - Set validProductIDs; - Map validProducts; - List transactions; - List finishedTransactions; - bool testRestoredTransactionsNull; - bool testTransactionFail; - PlatformException queryProductException; - PlatformException restoreException; - SKError testRestoredError; + String? receiptData; + late Set validProductIDs; + late Map validProducts; + late List transactions; + late List finishedTransactions; + late bool testRestoredTransactionsNull; + late bool testTransactionFail; + PlatformException? queryProductException; + PlatformException? restoreException; + SKError? testRestoredError; void reset() { transactions = []; @@ -317,7 +325,8 @@ class FakeIOSPlatform { validProductIDs = ['123', '456'].toSet(); validProducts = Map(); for (String validID in validProductIDs) { - Map productWrapperMap = buildProductMap(dummyProductWrapper); + Map productWrapperMap = + buildProductMap(dummyProductWrapper); productWrapperMap['productIdentifier'] = validID; validProducts[validID] = SKProductWrapper.fromJson(productWrapperMap); } @@ -350,7 +359,7 @@ class FakeIOSPlatform { SKPaymentTransactionWrapper createPendingTransaction(String id) { return SKPaymentTransactionWrapper( - transactionIdentifier: null, + transactionIdentifier: '', payment: SKPaymentWrapper(productIdentifier: id), transactionState: SKPaymentTransactionStateWrapper.purchasing, transactionTimeStamp: 123123.121, @@ -371,7 +380,7 @@ class FakeIOSPlatform { SKPaymentTransactionWrapper createFailedTransaction(String productId) { return SKPaymentTransactionWrapper( - transactionIdentifier: null, + transactionIdentifier: '', payment: SKPaymentWrapper(productIdentifier: productId), transactionState: SKPaymentTransactionStateWrapper.failed, transactionTimeStamp: 123123.121, @@ -388,7 +397,7 @@ class FakeIOSPlatform { return Future.value(true); case '-[InAppPurchasePlugin startProductRequest:result:]': if (queryProductException != null) { - throw queryProductException; + throw queryProductException!; } List productIDS = List.castFrom(call.arguments); @@ -399,7 +408,7 @@ class FakeIOSPlatform { if (!validProductIDs.contains(productID)) { invalidFound.add(productID); } else { - products.add(validProducts[productID]); + products.add(validProducts[productID]!); } } SkProductResponseWrapper response = SkProductResponseWrapper( @@ -408,11 +417,11 @@ class FakeIOSPlatform { buildProductResponseMap(response)); case '-[InAppPurchasePlugin restoreTransactions:result:]': if (restoreException != null) { - throw restoreException; + throw restoreException!; } if (testRestoredError != null) { AppStoreConnection.observer - .restoreCompletedTransactionsFailed(error: testRestoredError); + .restoreCompletedTransactionsFailed(error: testRestoredError!); return Future.sync(() {}); } if (!testRestoredTransactionsNull) { @@ -428,7 +437,6 @@ class FakeIOSPlatform { } else { throw PlatformException(code: 'no_receipt_data'); } - break; case '-[InAppPurchasePlugin refreshReceipt:result:]': receiptData = 'refreshed receipt data'; return Future.sync(() {}); @@ -445,7 +453,8 @@ class FakeIOSPlatform { .updatedTransactions(transactions: [transaction_failed]); } else { SKPaymentTransactionWrapper transaction_finished = - createPurchasedTransaction(id, transaction.transactionIdentifier); + createPurchasedTransaction( + id, transaction.transactionIdentifier ?? ''); AppStoreConnection.observer .updatedTransactions(transactions: [transaction_finished]); } diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart index 9294d2b60d1e..79c2ee436c5c 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart @@ -24,7 +24,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); final StubInAppPurchasePlatform stubPlatform = StubInAppPurchasePlatform(); - GooglePlayConnection connection; + late GooglePlayConnection connection; const String startConnectionCall = 'BillingClient#startConnection(BillingClientStateListener)'; const String endConnectionCall = 'BillingClient#endConnection()'; @@ -149,10 +149,11 @@ void main() { await connection.queryProductDetails(['invalid'].toSet()); expect(response.notFoundIDs, ['invalid']); expect(response.productDetails, isEmpty); - expect(response.error.source, IAPSource.GooglePlay); - expect(response.error.code, 'error_code'); - expect(response.error.message, 'error_message'); - expect(response.error.details, {'info': 'error_info'}); + expect(response.error, isNotNull); + expect(response.error!.source, IAPSource.GooglePlay); + expect(response.error!.code, 'error_code'); + expect(response.error!.message, 'error_message'); + expect(response.error!.details, {'info': 'error_info'}); }); }); @@ -172,8 +173,10 @@ void main() { final QueryPurchaseDetailsResponse response = await connection.queryPastPurchases(); expect(response.pastPurchases, isEmpty); - expect(response.error.message, BillingResponse.developerError.toString()); - expect(response.error.source, IAPSource.GooglePlay); + expect(response.error, isNotNull); + expect( + response.error!.message, BillingResponse.developerError.toString()); + expect(response.error!.source, IAPSource.GooglePlay); }); test('returns SkuDetailsResponseWrapper', () async { @@ -221,9 +224,10 @@ void main() { final QueryPurchaseDetailsResponse response = await connection.queryPastPurchases(); expect(response.pastPurchases, isEmpty); - expect(response.error.code, 'error_code'); - expect(response.error.message, 'error_message'); - expect(response.error.details, {'info': 'error_info'}); + expect(response.error, isNotNull); + expect(response.error!.code, 'error_code'); + expect(response.error!.message, 'error_message'); + expect(response.error!.details, {'info': 'error_info'}); }); }); @@ -277,7 +281,7 @@ void main() { PurchaseDetails purchaseDetails; Stream purchaseStream = GooglePlayConnection.instance.purchaseUpdatedStream; - StreamSubscription subscription; + late StreamSubscription subscription; subscription = purchaseStream.listen((_) { purchaseDetails = _.first; completer.complete(purchaseDetails); @@ -320,7 +324,7 @@ void main() { PurchaseDetails purchaseDetails; Stream purchaseStream = GooglePlayConnection.instance.purchaseUpdatedStream; - StreamSubscription subscription; + late StreamSubscription subscription; subscription = purchaseStream.listen((_) { purchaseDetails = _.first; completer.complete(purchaseDetails); @@ -334,9 +338,9 @@ void main() { PurchaseDetails result = await completer.future; expect(result.error, isNotNull); - expect(result.error.source, IAPSource.GooglePlay); + expect(result.error!.source, IAPSource.GooglePlay); expect(result.status, PurchaseStatus.error); - expect(result.purchaseID, isNull); + expect(result.purchaseID, isEmpty); }); test('buy consumable with auto consume, serializes and deserializes data', @@ -392,7 +396,7 @@ void main() { PurchaseDetails purchaseDetails; Stream purchaseStream = GooglePlayConnection.instance.purchaseUpdatedStream; - StreamSubscription subscription; + late StreamSubscription subscription; subscription = purchaseStream.listen((_) { purchaseDetails = _.first; completer.complete(purchaseDetails); @@ -407,7 +411,8 @@ void main() { // Verify that the result has succeeded PurchaseDetails result = await completer.future; expect(launchResult, isTrue); - expect(result.billingClientPurchase.purchaseToken, + expect(result.billingClientPurchase, isNotNull); + expect(result.billingClientPurchase!.purchaseToken, await consumeCompleter.future); expect(result.status, PurchaseStatus.purchased); expect(result.error, isNull); @@ -501,7 +506,7 @@ void main() { PurchaseDetails purchaseDetails; Stream purchaseStream = GooglePlayConnection.instance.purchaseUpdatedStream; - StreamSubscription subscription; + late StreamSubscription subscription; subscription = purchaseStream.listen((_) { purchaseDetails = _.first; completer.complete(purchaseDetails); @@ -515,11 +520,12 @@ void main() { // Verify that the result has an error for the failed consumption PurchaseDetails result = await completer.future; - expect(result.billingClientPurchase.purchaseToken, + expect(result.billingClientPurchase, isNotNull); + expect(result.billingClientPurchase!.purchaseToken, await consumeCompleter.future); expect(result.status, PurchaseStatus.error); expect(result.error, isNotNull); - expect(result.error.code, kConsumptionFailedErrorCode); + expect(result.error!.code, kConsumptionFailedErrorCode); }); test( @@ -574,7 +580,7 @@ void main() { Stream purchaseStream = GooglePlayConnection.instance.purchaseUpdatedStream; - StreamSubscription subscription; + late StreamSubscription subscription; subscription = purchaseStream.listen((_) { consumeCompleter.complete(null); subscription.cancel(); @@ -629,10 +635,6 @@ void main() { await GooglePlayConnection.instance.completePurchase( purchaseDetails, developerPayload: 'dummy payload'); - print('pending ${billingResultWrapper.responseCode}'); - print('expectedBillingResult ${expectedBillingResult.responseCode}'); - print('pending ${billingResultWrapper.debugMessage}'); - print('expectedBillingResult ${expectedBillingResult.debugMessage}'); expect(billingResultWrapper, equals(expectedBillingResult)); completer.complete(billingResultWrapper); } diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart index 92ffbc5797e3..d41a1269d6c9 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart @@ -20,6 +20,10 @@ void main() { setUp(() {}); + tearDown(() { + fakeIOSPlatform.testReturnNull = false; + }); + group('sk_request_maker', () { test('get products method channel', () async { SkProductResponseWrapper productResponseWrapper = @@ -55,7 +59,7 @@ void main() { test('get products method channel should throw exception', () async { fakeIOSPlatform.getProductRequestFailTest = true; expect( - SKRequestMaker().startProductRequest(['xxx']), + SKRequestMaker().startProductRequest(['xxx']), throwsException, ); fakeIOSPlatform.getProductRequestFailTest = false; @@ -63,10 +67,11 @@ void main() { test('refreshed receipt', () async { int receiptCountBefore = fakeIOSPlatform.refreshReceipt; - await SKRequestMaker() - .startRefreshReceiptRequest(receiptProperties: {"isExpired": true}); + await SKRequestMaker().startRefreshReceiptRequest( + receiptProperties: {"isExpired": true}); expect(fakeIOSPlatform.refreshReceipt, receiptCountBefore + 1); - expect(fakeIOSPlatform.refreshReceiptParam, {"isExpired": true}); + expect(fakeIOSPlatform.refreshReceiptParam, + {"isExpired": true}); }); }); @@ -83,6 +88,12 @@ void main() { expect(await SKPaymentQueueWrapper.canMakePayments(), true); }); + test('canMakePayment returns false if method channel returns null', + () async { + fakeIOSPlatform.testReturnNull = true; + expect(await SKPaymentQueueWrapper.canMakePayments(), false); + }); + test('transactions should return a valid list of transactions', () async { expect(await SKPaymentQueueWrapper().transactions(), isNotEmpty); }); @@ -127,20 +138,20 @@ void main() { class FakeIOSPlatform { FakeIOSPlatform() { channel.setMockMethodCallHandler(onMethodCall); - getProductRequestFailTest = false; } // get product request - List startProductRequestParam; - bool getProductRequestFailTest; + List startProductRequestParam = []; + bool getProductRequestFailTest = false; + bool testReturnNull = false; // refresh receipt request int refreshReceipt = 0; - Map refreshReceiptParam; + late Map refreshReceiptParam; // payment queue List payments = []; List> transactionsFinished = []; - String applicationNameHasTransactionRestored; + String applicationNameHasTransactionRestored = ''; Future onMethodCall(MethodCall call) { switch (call.method) { @@ -157,18 +168,24 @@ class FakeIOSPlatform { buildProductResponseMap(dummyProductResponseWrapper)); case '-[InAppPurchasePlugin refreshReceipt:result:]': refreshReceipt++; - refreshReceiptParam = call.arguments; + refreshReceiptParam = + Map.castFrom(call.arguments); return Future.sync(() {}); // receipt manager case '-[InAppPurchasePlugin retrieveReceiptData:result:]': return Future.value('receipt data'); // payment queue case '-[SKPaymentQueue canMakePayments:]': + if (testReturnNull) { + return Future.value(null); + } return Future.value(true); case '-[SKPaymentQueue transactions]': - return Future>.value([buildTransactionMap(dummyTransaction)]); + return Future>.value( + [buildTransactionMap(dummyTransaction)]); case '-[InAppPurchasePlugin addPayment:result:]': - payments.add(SKPaymentWrapper.fromJson(call.arguments)); + payments.add(SKPaymentWrapper.fromJson( + Map.from(call.arguments))); return Future.sync(() {}); case '-[InAppPurchasePlugin finishTransaction:result:]': transactionsFinished.add(Map.from(call.arguments)); @@ -182,16 +199,18 @@ class FakeIOSPlatform { } class TestPaymentTransactionObserver extends SKTransactionObserverWrapper { - void updatedTransactions({List transactions}) {} + void updatedTransactions( + {required List transactions}) {} - void removedTransactions({List transactions}) {} + void removedTransactions( + {required List transactions}) {} - void restoreCompletedTransactionsFailed({SKError error}) {} + void restoreCompletedTransactionsFailed({required SKError error}) {} void paymentQueueRestoreCompletedTransactionsFinished() {} bool shouldAddStorePayment( - {SKPaymentWrapper payment, SKProductWrapper product}) { + {required SKPaymentWrapper payment, required SKProductWrapper product}) { return true; } } diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart index 2a9066f05c53..6e1f59bf377e 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart @@ -3,11 +3,11 @@ // found in the LICENSE file. import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart'; +import 'package:in_app_purchase/store_kit_wrappers.dart'; import 'package:test/test.dart'; import 'package:in_app_purchase/src/store_kit_wrappers/sk_product_wrapper.dart'; import 'package:in_app_purchase/src/in_app_purchase/in_app_purchase_connection.dart'; import 'package:in_app_purchase/src/in_app_purchase/product_details.dart'; -import 'package:in_app_purchase/store_kit_wrappers.dart'; import 'sk_test_stub_objects.dart'; void main() { @@ -17,17 +17,17 @@ void main() { () { final SKProductSubscriptionPeriodWrapper wrapper = SKProductSubscriptionPeriodWrapper.fromJson( - buildSubscriptionPeriodMap(dummySubscription)); + buildSubscriptionPeriodMap(dummySubscription)!); expect(wrapper, equals(dummySubscription)); }); test( - 'SKProductSubscriptionPeriodWrapper should have properties to be null if map is empty', + 'SKProductSubscriptionPeriodWrapper should have properties to be default values if map is empty', () { final SKProductSubscriptionPeriodWrapper wrapper = SKProductSubscriptionPeriodWrapper.fromJson({}); - expect(wrapper.numberOfUnits, null); - expect(wrapper.unit, null); + expect(wrapper.numberOfUnits, 0); + expect(wrapper.unit, SKSubscriptionPeriodUnit.day); }); test( @@ -39,15 +39,19 @@ void main() { }); test( - 'SKProductDiscountWrapper should have properties to be null if map is empty', + 'SKProductDiscountWrapper should have properties to be default if map is empty', () { final SKProductDiscountWrapper wrapper = SKProductDiscountWrapper.fromJson({}); - expect(wrapper.price, null); - expect(wrapper.priceLocale, null); - expect(wrapper.numberOfPeriods, null); - expect(wrapper.paymentMode, null); - expect(wrapper.subscriptionPeriod, null); + expect(wrapper.price, ''); + expect(wrapper.priceLocale, + SKPriceLocaleWrapper(currencyCode: '', currencySymbol: '')); + expect(wrapper.numberOfPeriods, 0); + expect(wrapper.paymentMode, SKProductDiscountPaymentMode.payAsYouGo); + expect( + wrapper.subscriptionPeriod, + SKProductSubscriptionPeriodWrapper( + numberOfUnits: 0, unit: SKSubscriptionPeriodUnit.day)); }); test('SKProductWrapper should have property values consistent with map', @@ -57,16 +61,18 @@ void main() { expect(wrapper, equals(dummyProductWrapper)); }); - test('SKProductWrapper should have properties to be null if map is empty', + test( + 'SKProductWrapper should have properties to be default if map is empty', () { final SKProductWrapper wrapper = SKProductWrapper.fromJson({}); - expect(wrapper.productIdentifier, null); - expect(wrapper.localizedTitle, null); - expect(wrapper.localizedDescription, null); - expect(wrapper.priceLocale, null); + expect(wrapper.productIdentifier, ''); + expect(wrapper.localizedTitle, ''); + expect(wrapper.localizedDescription, ''); + expect(wrapper.priceLocale, + SKPriceLocaleWrapper(currencyCode: '', currencySymbol: '')); expect(wrapper.subscriptionGroupIdentifier, null); - expect(wrapper.price, null); + expect(wrapper.price, ''); expect(wrapper.subscriptionPeriod, null); }); @@ -132,7 +138,8 @@ void main() { PurchaseDetails.fromSKTransaction(dummyTransaction, 'receipt data'); expect(dummyTransaction.transactionIdentifier, details.purchaseID); expect(dummyTransaction.payment.productIdentifier, details.productID); - expect((dummyTransaction.transactionTimeStamp * 1000).toInt().toString(), + expect(dummyTransaction.transactionTimeStamp, isNotNull); + expect((dummyTransaction.transactionTimeStamp! * 1000).toInt().toString(), details.transactionDate); expect(details.verificationData.localVerificationData, 'receipt data'); expect(details.verificationData.serverVerificationData, 'receipt data'); @@ -141,6 +148,29 @@ void main() { expect(details.billingClientPurchase, null); expect(details.pendingCompletePurchase, true); }); + + test('SKPaymentTransactionWrapper.toFinishMap set correct value', () { + final SKPaymentTransactionWrapper transactionWrapper = + SKPaymentTransactionWrapper( + payment: dummyPayment, + transactionState: SKPaymentTransactionStateWrapper.failed, + transactionIdentifier: 'abcd'); + final Map finishMap = transactionWrapper.toFinishMap(); + expect(finishMap['transactionIdentifier'], 'abcd'); + expect(finishMap['productIdentifier'], dummyPayment.productIdentifier); + }); + + test( + 'SKPaymentTransactionWrapper.toFinishMap should set transactionIdentifier to null when necessary', + () { + final SKPaymentTransactionWrapper transactionWrapper = + SKPaymentTransactionWrapper( + payment: dummyPayment, + transactionState: SKPaymentTransactionStateWrapper.failed); + final Map finishMap = transactionWrapper.toFinishMap(); + expect(finishMap['transactionIdentifier'], null); + }); + test('Should generate correct map of the payment object', () { Map map = dummyPayment.toMap(); expect(map['productIdentifier'], dummyPayment.productIdentifier); diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart index c976e80a90a5..f7d86f5cf59b 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart @@ -74,8 +74,11 @@ Map buildLocaleMap(SKPriceLocaleWrapper local) { }; } -Map buildSubscriptionPeriodMap( - SKProductSubscriptionPeriodWrapper sub) { +Map? buildSubscriptionPeriodMap( + SKProductSubscriptionPeriodWrapper? sub) { + if (sub == null) { + return null; + } return { 'numberOfUnits': sub.numberOfUnits, 'unit': SKSubscriptionPeriodUnit.values.indexOf(sub.unit), @@ -104,7 +107,7 @@ Map buildProductMap(SKProductWrapper product) { 'price': product.price, 'subscriptionPeriod': buildSubscriptionPeriodMap(product.subscriptionPeriod), - 'introductoryPrice': buildDiscountMap(product.introductoryPrice), + 'introductoryPrice': buildDiscountMap(product.introductoryPrice!), }; } @@ -129,17 +132,16 @@ Map buildErrorMap(SKError error) { Map buildTransactionMap( SKPaymentTransactionWrapper transaction) { - if (transaction == null) { - return null; - } - Map map = { + Map map = { 'transactionState': SKPaymentTransactionStateWrapper.values .indexOf(SKPaymentTransactionStateWrapper.purchased), 'payment': transaction.payment.toMap(), - 'originalTransaction': buildTransactionMap(transaction.originalTransaction), + 'originalTransaction': transaction.originalTransaction == null + ? null + : buildTransactionMap(transaction.originalTransaction!), 'transactionTimeStamp': transaction.transactionTimeStamp, 'transactionIdentifier': transaction.transactionIdentifier, - 'error': buildErrorMap(transaction.error), + 'error': buildErrorMap(transaction.error!), }; return map; } diff --git a/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart b/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart index 312479573a68..431d8859d44d 100644 --- a/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart +++ b/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart @@ -9,19 +9,19 @@ typedef void AdditionalSteps(dynamic args); class StubInAppPurchasePlatform { Map _expectedCalls = {}; - Map _additionalSteps = {}; + Map _additionalSteps = {}; void addResponse( - {String name, + {required String name, dynamic value, - AdditionalSteps additionalStepBeforeReturn}) { + AdditionalSteps? additionalStepBeforeReturn}) { _additionalSteps[name] = additionalStepBeforeReturn; _expectedCalls[name] = value; } List _previousCalls = []; List get previousCalls => _previousCalls; - MethodCall previousCallMatching(String name) => _previousCalls - .firstWhere((MethodCall call) => call.method == name, orElse: () => null); + MethodCall previousCallMatching(String name) => + _previousCalls.firstWhere((MethodCall call) => call.method == name); int countPreviousCalls(String name) => _previousCalls.where((MethodCall call) => call.method == name).length; @@ -35,7 +35,7 @@ class StubInAppPurchasePlatform { _previousCalls.add(call); if (_expectedCalls.containsKey(call.method)) { if (_additionalSteps[call.method] != null) { - _additionalSteps[call.method](call.arguments); + _additionalSteps[call.method]!(call.arguments); } return Future.sync(() => _expectedCalls[call.method]); } else { diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index 3e9e50ebd0f4..eceb78cc970c 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -32,6 +32,7 @@ readonly NNBD_PLUGINS_LIST=( "video_player" "webview_flutter" "wifi_info_flutter" + "in_app_purchase" ) # This list contains the list of plugins that have *not* been diff --git a/script/tool/lib/src/publish_check_command.dart b/script/tool/lib/src/publish_check_command.dart index af009952856e..670fedaf2fa1 100644 --- a/script/tool/lib/src/publish_check_command.dart +++ b/script/tool/lib/src/publish_check_command.dart @@ -97,7 +97,7 @@ class PublishCheckCommand extends PluginCommand { await stdInCompleter.future; final String output = outputBuffer.toString(); - return output.contains('Package has 1 warning.') && + return output.contains('Package has 1 warning') && output.contains( 'Packages with an SDK constraint on a pre-release of the Dart SDK should themselves be published as a pre-release version.'); } From 6c10217bb166b510a9fb17f7260a55ed14c1bdfd Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Feb 2021 11:59:35 -0800 Subject: [PATCH 219/924] [path_provider] Bump platform interface package to stable NNBD (#3568) --- .../path_provider_platform_interface/CHANGELOG.md | 2 +- .../path_provider_platform_interface/pubspec.yaml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md index 97121268c790..08dc9f69c7df 100644 --- a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md +++ b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/path_provider/path_provider_platform_interface/pubspec.yaml b/packages/path_provider/path_provider_platform_interface/pubspec.yaml index 946d2ed4b4fd..68b790301270 100644 --- a/packages/path_provider/path_provider_platform_interface/pubspec.yaml +++ b/packages/path_provider/path_provider_platform_interface/pubspec.yaml @@ -3,20 +3,20 @@ description: A common platform interface for the path_provider plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_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: 2.0.0-nullsafety +version: 2.0.0 dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety.3 - platform: ^3.0.0-nullsafety.4 - plugin_platform_interface: ^1.1.0-nullsafety + meta: ^1.3.0 + platform: ^3.0.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.10.0" From 51c6eac1af9e3a3386de39027b63561e040e2e3c Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Feb 2021 12:38:11 -0800 Subject: [PATCH 220/924] [flutter_plugin_android_lifecycle] Bump version for NNBD stable (#3569) --- .../flutter_plugin_android_lifecycle/CHANGELOG.md | 11 ++--------- .../flutter_plugin_android_lifecycle/pubspec.yaml | 4 ++-- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md index e1804c5cc7f5..08f137c09434 100644 --- a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md +++ b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md @@ -1,15 +1,8 @@ -## 2.0.0-nullsafety.2 +## 2.0.0 +* Bump Dart SDK for null-safety compatibility. * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) -## 2.0.0-nullsafety.1 - -* Fix example app SDK. - -## 2.0.0-nullsafety - -* Bump Dart SDK. - ## 1.0.12 * Update Flutter SDK constraint. diff --git a/packages/flutter_plugin_android_lifecycle/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/pubspec.yaml index d94237c2101a..3f6ccb089f44 100644 --- a/packages/flutter_plugin_android_lifecycle/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/pubspec.yaml @@ -1,10 +1,10 @@ name: flutter_plugin_android_lifecycle description: Flutter plugin for accessing an Android Lifecycle within other plugins. -version: 2.0.0-nullsafety.2 +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/flutter_plugin_android_lifecycle environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13" dependencies: From 72cbcacfefc20567678264731602875addc0a62b Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Feb 2021 12:59:16 -0800 Subject: [PATCH 221/924] [package_info] Bump version for NNBD stable (#3571) Includes: - Migrating the example to NNBD - Bullet-proofing against null values from the native code; at least the ObjC code can theoretically return nulls. --- packages/package_info/CHANGELOG.md | 6 +----- .../integration_test/package_info_test.dart | 2 ++ packages/package_info/example/lib/main.dart | 4 ++-- .../macos/Runner.xcodeproj/project.pbxproj | 21 ++++++------------- packages/package_info/example/pubspec.yaml | 4 ++-- .../example/test_driver/integration_test.dart | 2 ++ packages/package_info/lib/package_info.dart | 8 +++---- packages/package_info/pubspec.yaml | 6 +++--- 8 files changed, 22 insertions(+), 31 deletions(-) diff --git a/packages/package_info/CHANGELOG.md b/packages/package_info/CHANGELOG.md index ddf01f0f3999..14a9e26639d9 100644 --- a/packages/package_info/CHANGELOG.md +++ b/packages/package_info/CHANGELOG.md @@ -1,8 +1,4 @@ -## 2.0.0-nullsafety - -* Update version to (semi-belatedly) meet 1.0-consistency promise. - -## 0.5.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/package_info/example/integration_test/package_info_test.dart b/packages/package_info/example/integration_test/package_info_test.dart index 5038509ec84f..e70c8a5f0eca 100644 --- a/packages/package_info/example/integration_test/package_info_test.dart +++ b/packages/package_info/example/integration_test/package_info_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/package_info/example/lib/main.dart b/packages/package_info/example/lib/main.dart index 91ed910ef21d..18620617d558 100644 --- a/packages/package_info/example/lib/main.dart +++ b/packages/package_info/example/lib/main.dart @@ -25,7 +25,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @@ -57,7 +57,7 @@ class _MyHomePageState extends State { Widget _infoTile(String title, String subtitle) { return ListTile( title: Text(title), - subtitle: Text(subtitle ?? 'Not set'), + subtitle: Text(subtitle.isNotEmpty ? subtitle : 'Not set'), ); } diff --git a/packages/package_info/example/macos/Runner.xcodeproj/project.pbxproj b/packages/package_info/example/macos/Runner.xcodeproj/project.pbxproj index 6e63b7eb69ae..3525d85d6678 100644 --- a/packages/package_info/example/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/package_info/example/macos/Runner.xcodeproj/project.pbxproj @@ -26,11 +26,7 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; }; - 33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9A0CC0B8F23AFE5DF719BADB /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CED91D820ABAEDEBEFEBDBDA /* Pods_Runner.framework */; }; - D73912F022F37F9E000D13A0 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; }; - D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -50,8 +46,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */, - 33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */, ); name = "Bundle Framework"; runOnlyForDeploymentPostprocessing = 0; @@ -72,7 +66,6 @@ 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FlutterMacOS.framework; path = Flutter/ephemeral/FlutterMacOS.framework; sourceTree = SOURCE_ROOT; }; 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; @@ -80,7 +73,6 @@ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; B3868D4F5169B9990BB5D1F5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; CED91D820ABAEDEBEFEBDBDA /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - D73912EF22F37F9E000D13A0 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/ephemeral/App.framework; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -88,8 +80,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D73912F022F37F9E000D13A0 /* App.framework in Frameworks */, - 33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */, 9A0CC0B8F23AFE5DF719BADB /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -145,8 +135,6 @@ 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - D73912EF22F37F9E000D13A0 /* App.framework */, - 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */, ); path = Flutter; sourceTree = ""; @@ -280,7 +268,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename\n"; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; }; 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -329,10 +317,13 @@ buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/package_info/package_info.framework", ); name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/packages/package_info/example/pubspec.yaml b/packages/package_info/example/pubspec.yaml index 0d0e1bae3c1f..a4691fcba518 100644 --- a/packages/package_info/example/pubspec.yaml +++ b/packages/package_info/example/pubspec.yaml @@ -17,11 +17,11 @@ dependencies: dev_dependencies: flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/package_info/example/test_driver/integration_test.dart b/packages/package_info/example/test_driver/integration_test.dart index f532c389a02b..437b3609d119 100644 --- a/packages/package_info/example/test_driver/integration_test.dart +++ b/packages/package_info/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart=2.9 + import 'dart:convert'; import 'dart:io'; diff --git a/packages/package_info/lib/package_info.dart b/packages/package_info/lib/package_info.dart index 51348978ffa5..5b7f4e573aa0 100644 --- a/packages/package_info/lib/package_info.dart +++ b/packages/package_info/lib/package_info.dart @@ -42,10 +42,10 @@ class PackageInfo { (await _kChannel.invokeMapMethod('getAll'))!; packageInfo = PackageInfo( - appName: map["appName"], - packageName: map["packageName"], - version: map["version"], - buildNumber: map["buildNumber"], + appName: map["appName"] ?? '', + packageName: map["packageName"] ?? '', + version: map["version"] ?? '', + buildNumber: map["buildNumber"] ?? '', ); _fromPlatform = packageInfo; return packageInfo; diff --git a/packages/package_info/pubspec.yaml b/packages/package_info/pubspec.yaml index 67fbc5f626db..2769af1f83d5 100644 --- a/packages/package_info/pubspec.yaml +++ b/packages/package_info/pubspec.yaml @@ -2,7 +2,7 @@ name: package_info description: Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/package_info -version: 2.0.0-nullsafety +version: 2.0.0 flutter: plugin: @@ -26,8 +26,8 @@ dev_dependencies: sdk: flutter integration_test: path: ../integration_test - pedantic: ^1.10.0-nullsafety + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From 4f31f3fa66425ba10e9489016384218a6337f755 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 19 Feb 2021 14:20:24 -0800 Subject: [PATCH 222/924] [image_picker_platform_interface] Bump NNBD version to stable (#3573) --- .../image_picker_platform_interface/CHANGELOG.md | 2 +- .../image_picker_platform_interface/pubspec.yaml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index fc953e4e6333..f2e017e190c5 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. * Breaking Changes: diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index d5f5ce93016b..9befba90215a 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -3,20 +3,20 @@ description: A common platform interface for the image_picker plugin. 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: 2.0.0-nullsafety +version: 2.0.0 dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety.6 - http: ^0.13.0-nullsafety.0 - plugin_platform_interface: ^1.1.0-nullsafety.2 + meta: ^1.3.0 + http: ^0.13.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.3 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.10.0" From 5817241b8b8023ccc8d6e841a8b1cd777cb170be Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Feb 2021 14:45:39 -0800 Subject: [PATCH 223/924] [flutter_plugin_android_lifecycle-sdk] Update Flutter SDK constraint --- packages/flutter_plugin_android_lifecycle/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_plugin_android_lifecycle/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/pubspec.yaml index 3f6ccb089f44..fc2805ef814b 100644 --- a/packages/flutter_plugin_android_lifecycle/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/flutter/plugins/tree/master/packages/flutter_plugin environment: sdk: ">=2.12.0-259.9.beta <3.0.0" - flutter: ">=1.12.13" + flutter: ">=1.20.0" dependencies: flutter: From 8e389350225301fdfe51d1a13678fbef17415e11 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Feb 2021 14:47:48 -0800 Subject: [PATCH 224/924] [path_provider] Bump platform packages to NNBD stable (#3575) Makes all platform packages stable null-safe releases. --- .../path_provider_linux/CHANGELOG.md | 6 +----- .../path_provider_linux/example/pubspec.yaml | 4 ++-- .../path_provider_linux/pubspec.yaml | 14 +++++++------- .../path_provider_macos/CHANGELOG.md | 8 ++------ .../path_provider_macos/example/pubspec.yaml | 6 +++--- .../path_provider_macos/pubspec.yaml | 8 ++++---- .../pubspec.yaml | 2 +- .../path_provider_windows/CHANGELOG.md | 19 +------------------ .../example/pubspec.yaml | 6 +++--- .../path_provider_windows/pubspec.yaml | 16 ++++++++-------- 10 files changed, 32 insertions(+), 57 deletions(-) diff --git a/packages/path_provider/path_provider_linux/CHANGELOG.md b/packages/path_provider/path_provider_linux/CHANGELOG.md index 126aadcffeb4..a85c6bbb4ef3 100644 --- a/packages/path_provider/path_provider_linux/CHANGELOG.md +++ b/packages/path_provider/path_provider_linux/CHANGELOG.md @@ -1,8 +1,4 @@ -## 2.0.0-nullsafety - -* Update version to (semi-belatedly) meet 1.0-consistency promise. - -## 0.2.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/path_provider/path_provider_linux/example/pubspec.yaml b/packages/path_provider/path_provider_linux/example/pubspec.yaml index 1fd55712ee44..cb778ef6ac57 100644 --- a/packages/path_provider/path_provider_linux/example/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/example/pubspec.yaml @@ -3,8 +3,8 @@ description: Demonstrates how to use the path_provider_linux plugin. publish_to: "none" environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.10.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: flutter: diff --git a/packages/path_provider/path_provider_linux/pubspec.yaml b/packages/path_provider/path_provider_linux/pubspec.yaml index c6940b1158ee..a3cdff34b6cc 100644 --- a/packages/path_provider/path_provider_linux/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: path_provider_linux description: linux implementation of the path_provider plugin -version: 2.0.0-nullsafety +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_linux flutter: @@ -11,17 +11,17 @@ flutter: pluginClass: none environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.10.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: - path: ^1.8.0-nullsafety.3 - xdg_directories: ^0.2.0-nullsafety.1 - path_provider_platform_interface: ^2.0.0-nullsafety + path: ^1.8.0 + xdg_directories: ^0.2.0 + path_provider_platform_interface: ^2.0.0 flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.3 + pedantic: ^1.10.0 diff --git a/packages/path_provider/path_provider_macos/CHANGELOG.md b/packages/path_provider/path_provider_macos/CHANGELOG.md index de7ab3e94f9d..f989efbe2a98 100644 --- a/packages/path_provider/path_provider_macos/CHANGELOG.md +++ b/packages/path_provider/path_provider_macos/CHANGELOG.md @@ -1,10 +1,6 @@ -## 2.0.0-nullsafety +## 2.0.0 -* Update version to (semi-belatedly) meet 1.0-consistency promise. - -## 0.0.5-nullsafety - -* Update Dart SDK constraint for null safety. +* Update Dart SDK constraint for null safety compatibility. ## 0.0.4+9 diff --git a/packages/path_provider/path_provider_macos/example/pubspec.yaml b/packages/path_provider/path_provider_macos/example/pubspec.yaml index 495459319ca4..db7fd9a0dea6 100644 --- a/packages/path_provider/path_provider_macos/example/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/example/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - path_provider_platform_interface: 2.0.0-nullsafety + path_provider_platform_interface: ^2.0.0 dev_dependencies: integration_test: @@ -24,5 +24,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.10.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/path_provider/path_provider_macos/pubspec.yaml b/packages/path_provider/path_provider_macos/pubspec.yaml index bab79c27a94c..14f0b9556a6a 100644 --- a/packages/path_provider/path_provider_macos/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/pubspec.yaml @@ -1,6 +1,6 @@ name: path_provider_macos description: macOS implementation of the path_provider plugin -version: 2.0.0-nullsafety +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_macos flutter: @@ -10,12 +10,12 @@ flutter: pluginClass: PathProviderPlugin environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.10.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: flutter: sdk: flutter dev_dependencies: - pedantic: ^1.8.0 + pedantic: ^1.10.0 diff --git a/packages/path_provider/path_provider_platform_interface/pubspec.yaml b/packages/path_provider/path_provider_platform_interface/pubspec.yaml index 68b790301270..3feb4e0a8ebd 100644 --- a/packages/path_provider/path_provider_platform_interface/pubspec.yaml +++ b/packages/path_provider/path_provider_platform_interface/pubspec.yaml @@ -19,4 +19,4 @@ dev_dependencies: environment: sdk: ">=2.12.0-259.9.beta <3.0.0" - flutter: ">=1.10.0" + flutter: ">=1.20.0" diff --git a/packages/path_provider/path_provider_windows/CHANGELOG.md b/packages/path_provider/path_provider_windows/CHANGELOG.md index 2e1701cc53bf..ca4621471891 100644 --- a/packages/path_provider/path_provider_windows/CHANGELOG.md +++ b/packages/path_provider/path_provider_windows/CHANGELOG.md @@ -1,21 +1,4 @@ -## 2.0.0-nullsafety - -* Update version to (semi-belatedly) meet 1.0-consistency promise. - -## 0.1.0-nullsafety.3 - -* Bump ffi dependency to 1.0.0 -* Bump win32 dependency to 2.0.0-nullsafety.12 - -## 0.1.0-nullsafety.2 - -* Bump ffi dependency to 0.3.0-nullsafety.1 - -## 0.1.0-nullsafety.1 - -* Bump win32 dependency to latest version. - -## 0.1.0-nullsafety +## 2.0.0 * Migrate to null safety diff --git a/packages/path_provider/path_provider_windows/example/pubspec.yaml b/packages/path_provider/path_provider_windows/example/pubspec.yaml index 5704502528f7..8c1f88b89cb0 100644 --- a/packages/path_provider/path_provider_windows/example/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/example/pubspec.yaml @@ -17,11 +17,11 @@ dev_dependencies: path: ../../../integration_test flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.13+hotfix.4" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/path_provider/path_provider_windows/pubspec.yaml b/packages/path_provider/path_provider_windows/pubspec.yaml index eb7d1087d5f5..d152869f197d 100644 --- a/packages/path_provider/path_provider_windows/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider_windows description: Windows implementation of the path_provider plugin homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_windows -version: 2.0.0-nullsafety +version: 2.0.0 flutter: plugin: @@ -11,19 +11,19 @@ flutter: pluginClass: none dependencies: - path_provider_platform_interface: ^2.0.0-nullsafety - meta: ^1.3.0-nullsafety.6 - path: ^1.8.0-nullsafety.3 + path_provider_platform_interface: ^2.0.0 + meta: ^1.3.0 + path: ^1.8.0 flutter: sdk: flutter ffi: ^1.0.0 - win32: ^2.0.0-nullsafety.12 + win32: ^2.0.0 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.3 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.13+hotfix.4" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" From f6c2ed4f3c5aa0c4b3ede148c51e2760bd376dea Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 19 Feb 2021 15:57:25 -0800 Subject: [PATCH 225/924] [image_picker] use nnbd version of deps to resolve ci failure (#3580) --- packages/image_picker/image_picker/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 75f9dca4e0ca..eab7f7c20974 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -26,8 +26,8 @@ dev_dependencies: integration_test: path: ../../integration_test mockito: ^5.0.0-nullsafety.7 - pedantic: ^1.8.0 - plugin_platform_interface: ^1.0.3 + pedantic: ^1.10.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" environment: sdk: ">=2.12.0-0 <3.0.0" From 127c772287608e46a034f43a1e373171bb750fa6 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 19 Feb 2021 17:46:03 -0800 Subject: [PATCH 226/924] [image_picker] NNBD stable (#3579) --- packages/image_picker/image_picker/CHANGELOG.md | 3 ++- packages/image_picker/image_picker/example/pubspec.yaml | 4 ++-- packages/image_picker/image_picker/pubspec.yaml | 9 ++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index c6b29f277ec3..97aba4536000 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,4 +1,5 @@ -## 0.7.0-nullsafety +## 0.7.0 + * Migrate to nullsafety * Breaking Changes: * Removed the deprecated methods: `ImagePicker.pickImage`, `ImagePicker.pickVideo`, diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml index eed223c1ade7..ceafc317fa82 100755 --- a/packages/image_picker/image_picker/example/pubspec.yaml +++ b/packages/image_picker/image_picker/example/pubspec.yaml @@ -6,7 +6,7 @@ dependencies: video_player: ^2.0.0-nullsafety.7 flutter: sdk: flutter - flutter_plugin_android_lifecycle: ^2.0.0-nullsafety.2 + flutter_plugin_android_lifecycle: ^2.0.0 image_picker: # When depending on this package from a real application you should use: # image_picker: ^x.y.z @@ -26,5 +26,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.10.0" diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index eab7f7c20974..96881e6f2c65 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.7.0-nullsafety +version: 0.7.0 flutter: plugin: @@ -16,11 +16,10 @@ flutter: dependencies: flutter: sdk: flutter - flutter_plugin_android_lifecycle: ^2.0.0-nullsafety.2 - image_picker_platform_interface: ^2.0.0-nullsafety + flutter_plugin_android_lifecycle: ^2.0.0 + image_picker_platform_interface: ^2.0.0 dev_dependencies: - video_player: ^2.0.0-nullsafety.7 flutter_test: sdk: flutter integration_test: @@ -30,5 +29,5 @@ dev_dependencies: plugin_platform_interface: ">=1.0.0 <3.0.0" environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.10.0" From f69e7ddce405462b462b482a2f1ad1e2b94c2ee2 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Feb 2021 20:30:51 -0800 Subject: [PATCH 227/924] [url_launcher] Fix SDK copypasta (#3583) The lower end of the SDK range was wrong due to a bad copy/paste. --- .../url_launcher/url_launcher_platform_interface/CHANGELOG.md | 4 ++++ .../url_launcher/url_launcher_platform_interface/pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md index 5cd56432ece4..d617e514035e 100644 --- a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Fix SDK range. + ## 2.0.0 * Migrate to null safety. diff --git a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml index a8761c3594ea..d3ec0aafd126 100644 --- a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml +++ b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the url_launcher plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_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: 2.0.0 +version: 2.0.1 dependencies: flutter: @@ -17,5 +17,5 @@ dev_dependencies: pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-2.12.0-259.9.beta <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.22.0" From 29c9d1cb48206abba87a30a978271143acb4a15a Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Sat, 20 Feb 2021 11:45:26 +0100 Subject: [PATCH 228/924] [camera] Solves delay when using the zoom feature on iOS. (#3562) --- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/ios/Classes/CameraPlugin.m | 2 +- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 7391f3090565..29774748a32b 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.0-nullsafety.2 + +* Solved delay when using the zoom feature on iOS. + ## 0.8.0-nullsafety.1 * Added a timeout to the pre-capture sequence on Android to prevent crashes when the camera cannot get a focus. diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index d97ce88a58d8..c1770ff6d40b 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -1068,7 +1068,7 @@ - (void)setZoomLevel:(CGFloat)zoom Result:(FlutterResult)result { result(getFlutterError(error)); return; } - [_captureDevice rampToVideoZoomFactor:zoom withRate:1]; + _captureDevice.videoZoomFactor = zoom; [_captureDevice unlockForConfiguration]; result(nil); diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 5b98c39acd99..4b820b8b64cf 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.8.0-nullsafety.1 +version: 0.8.0-nullsafety.2 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 0e3e17728a5c313e0a068f70bfa612b9bd6ba94d Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Sat, 20 Feb 2021 10:01:03 -0800 Subject: [PATCH 229/924] migrate connectivity platform interface to stable (#3585) --- .../connectivity_platform_interface/CHANGELOG.md | 6 +----- .../connectivity_platform_interface/pubspec.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md index 8e38341be42f..0b26cd52c9e9 100644 --- a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md +++ b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md @@ -1,8 +1,4 @@ -## 2.0.0-nullsafety.1 - -* Bump Dart SDK to support null safety. - -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/connectivity/connectivity_platform_interface/pubspec.yaml b/packages/connectivity/connectivity_platform_interface/pubspec.yaml index 114915a10b60..1e89972dd816 100644 --- a/packages/connectivity/connectivity_platform_interface/pubspec.yaml +++ b/packages/connectivity/connectivity_platform_interface/pubspec.yaml @@ -3,19 +3,19 @@ description: A common platform interface for the connectivity plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_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: 2.0.0-nullsafety.1 +version: 2.0.0 dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety.3 - plugin_platform_interface: ^1.1.0-nullsafety.1 + meta: ^1.3.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From a8d1a3a98509b7f79c54f0f618d55280fbfe8bf1 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Sat, 20 Feb 2021 10:26:39 -0800 Subject: [PATCH 230/924] [shared_preferences] Bump version for NNBD stable (#3586) --- .../shared_preferences_platform_interface/CHANGELOG.md | 2 +- .../shared_preferences_platform_interface/pubspec.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md b/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md index 6661e2757326..b402f6e57e88 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_platform_interface/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml b/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml index 9e5d57230761..85c64a030036 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_platform_interface/pubspec.yaml @@ -1,7 +1,7 @@ name: shared_preferences_platform_interface description: A common platform interface for the shared_preferences plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_platform_interface -version: 2.0.0-nullsafety +version: 2.0.0 dependencies: flutter: @@ -10,8 +10,8 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.8" From 90c0e90694a9567d65334286cda09713de6ef3b4 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Sat, 20 Feb 2021 11:34:30 -0800 Subject: [PATCH 231/924] [battery] Bump platform version to NNBD stable (#3587) --- .../battery/battery_platform_interface/CHANGELOG.md | 2 +- .../battery/battery_platform_interface/pubspec.yaml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/battery/battery_platform_interface/CHANGELOG.md b/packages/battery/battery_platform_interface/CHANGELOG.md index 6fc7228a89f9..2c51f2c2d352 100644 --- a/packages/battery/battery_platform_interface/CHANGELOG.md +++ b/packages/battery/battery_platform_interface/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/battery/battery_platform_interface/pubspec.yaml b/packages/battery/battery_platform_interface/pubspec.yaml index c7c4f5e8395e..61edad6cc04b 100644 --- a/packages/battery/battery_platform_interface/pubspec.yaml +++ b/packages/battery/battery_platform_interface/pubspec.yaml @@ -3,20 +3,20 @@ description: A common platform interface for the battery plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/battery # 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: 2.0.0-nullsafety +version: 2.0.0 dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety - plugin_platform_interface: ^1.1.0-nullsafety.1 + meta: ^1.3.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" dev_dependencies: flutter_test: sdk: flutter mockito: ^5.0.0-nullsafety.0 - pedantic: ^1.10.0-nullsafety + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.9.1+hotfix.4" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" From 9d00dd22b868f4ed98de8170f25e2a508a44b93a Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Sat, 20 Feb 2021 12:25:40 -0800 Subject: [PATCH 232/924] [sensors] Update to NNBD stable (#3589) Includes migrating example to null-safety. --- packages/sensors/CHANGELOG.md | 6 +--- packages/sensors/example/lib/main.dart | 20 ++++++------- packages/sensors/example/lib/snake.dart | 29 +++++++++---------- packages/sensors/example/pubspec.yaml | 7 ++--- .../test_driver/test/integration_test.dart | 2 ++ packages/sensors/pubspec.yaml | 8 ++--- 6 files changed, 34 insertions(+), 38 deletions(-) diff --git a/packages/sensors/CHANGELOG.md b/packages/sensors/CHANGELOG.md index 8ff904bf3943..295c32ad2127 100644 --- a/packages/sensors/CHANGELOG.md +++ b/packages/sensors/CHANGELOG.md @@ -1,8 +1,4 @@ -## 2.0.0-nullsafety - -* * Update version to (semi-belatedly) meet 1.0-consistency promise. - -## 0.5.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/sensors/example/lib/main.dart b/packages/sensors/example/lib/main.dart index 575e0493742f..d6f01380c534 100644 --- a/packages/sensors/example/lib/main.dart +++ b/packages/sensors/example/lib/main.dart @@ -28,7 +28,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @@ -41,21 +41,21 @@ class _MyHomePageState extends State { static const int _snakeColumns = 20; static const double _snakeCellSize = 10.0; - List _accelerometerValues; - List _userAccelerometerValues; - List _gyroscopeValues; + List? _accelerometerValues; + List? _userAccelerometerValues; + List? _gyroscopeValues; List> _streamSubscriptions = >[]; @override Widget build(BuildContext context) { - final List accelerometer = - _accelerometerValues?.map((double v) => v.toStringAsFixed(1))?.toList(); - final List gyroscope = - _gyroscopeValues?.map((double v) => v.toStringAsFixed(1))?.toList(); - final List userAccelerometer = _userAccelerometerValues + final List? accelerometer = + _accelerometerValues?.map((double v) => v.toStringAsFixed(1)).toList(); + final List? gyroscope = + _gyroscopeValues?.map((double v) => v.toStringAsFixed(1)).toList(); + final List? userAccelerometer = _userAccelerometerValues ?.map((double v) => v.toStringAsFixed(1)) - ?.toList(); + .toList(); return Scaffold( appBar: AppBar( diff --git a/packages/sensors/example/lib/snake.dart b/packages/sensors/example/lib/snake.dart index d6b2f9b48a23..72f27472dd5b 100644 --- a/packages/sensors/example/lib/snake.dart +++ b/packages/sensors/example/lib/snake.dart @@ -56,15 +56,14 @@ class SnakeBoardPainter extends CustomPainter { } class SnakeState extends State { - SnakeState(int rows, int columns, this.cellSize) { - state = GameState(rows, columns); - } + SnakeState(int rows, int columns, this.cellSize) + : state = GameState(rows, columns); double cellSize; GameState state; - AccelerometerEvent acceleration; - StreamSubscription _streamSubscription; - Timer _timer; + AccelerometerEvent? acceleration; + late StreamSubscription _streamSubscription; + late Timer _timer; @override Widget build(BuildContext context) { @@ -96,21 +95,21 @@ class SnakeState extends State { } void _step() { - final math.Point newDirection = acceleration == null + final AccelerometerEvent? currentAcceleration = acceleration; + final math.Point? newDirection = currentAcceleration == null ? null - : acceleration.x.abs() < 1.0 && acceleration.y.abs() < 1.0 + : currentAcceleration.x.abs() < 1.0 && currentAcceleration.y.abs() < 1.0 ? null - : (acceleration.x.abs() < acceleration.y.abs()) - ? math.Point(0, acceleration.y.sign.toInt()) - : math.Point(-acceleration.x.sign.toInt(), 0); + : (currentAcceleration.x.abs() < currentAcceleration.y.abs()) + ? math.Point(0, currentAcceleration.y.sign.toInt()) + : math.Point(-currentAcceleration.x.sign.toInt(), 0); state.step(newDirection); } } class GameState { - GameState(this.rows, this.columns) { - snakeLength = math.min(rows, columns) - 5; - } + GameState(this.rows, this.columns) + : snakeLength = math.min(rows, columns) - 5; int rows; int columns; @@ -119,7 +118,7 @@ class GameState { List> body = >[const math.Point(0, 0)]; math.Point direction = const math.Point(1, 0); - void step(math.Point newDirection) { + void step(math.Point? newDirection) { math.Point next = body.last + direction; next = math.Point(next.x % columns, next.y % rows); diff --git a/packages/sensors/example/pubspec.yaml b/packages/sensors/example/pubspec.yaml index d4702ac3aabe..0cd30b12df2b 100644 --- a/packages/sensors/example/pubspec.yaml +++ b/packages/sensors/example/pubspec.yaml @@ -17,12 +17,11 @@ dev_dependencies: sdk: flutter integration_test: path: ../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.0.0-dev.28.0 <3.0.0" - flutter: ">=1.9.1+hotfix.2" - + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/sensors/example/test_driver/test/integration_test.dart b/packages/sensors/example/test_driver/test/integration_test.dart index 7a2c21338786..a8a56aa90f6a 100644 --- a/packages/sensors/example/test_driver/test/integration_test.dart +++ b/packages/sensors/example/test_driver/test/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/sensors/pubspec.yaml b/packages/sensors/pubspec.yaml index 0416779f1292..da45c82b7dd7 100644 --- a/packages/sensors/pubspec.yaml +++ b/packages/sensors/pubspec.yaml @@ -2,7 +2,7 @@ name: sensors description: Flutter plugin for accessing the Android and iOS accelerometer and gyroscope sensors. homepage: https://github.com/flutter/plugins/tree/master/packages/sensors -version: 2.0.0-nullsafety +version: 2.0.0 flutter: plugin: @@ -18,14 +18,14 @@ dependencies: sdk: flutter dev_dependencies: - test: ^1.16.0-nullsafety + test: ^1.16.0 flutter_test: sdk: flutter integration_test: path: ../integration_test mockito: ^5.0.0-nullsafety.0 - pedantic: ^1.10.0-nullsafety + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From e8c8cf679e1039596b4b9d1bc4f6b8308dd0a47f Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 22 Feb 2021 10:44:33 -0800 Subject: [PATCH 233/924] [connectivity_macos] move NNBD to stable (#3588) --- .../connectivity/connectivity_macos/CHANGELOG.md | 11 ++--------- .../connectivity_macos/example/lib/main.dart | 14 +++++++------- .../connectivity_macos/example/pubspec.yaml | 6 +++--- .../integration_test/connectivity_test.dart | 7 ++++--- .../connectivity/connectivity_macos/pubspec.yaml | 6 +++--- 5 files changed, 19 insertions(+), 25 deletions(-) diff --git a/packages/connectivity/connectivity_macos/CHANGELOG.md b/packages/connectivity/connectivity_macos/CHANGELOG.md index 8547db3441c3..b3ad35a03281 100644 --- a/packages/connectivity/connectivity_macos/CHANGELOG.md +++ b/packages/connectivity/connectivity_macos/CHANGELOG.md @@ -1,14 +1,7 @@ -## 2.0.0-nullsafety - -* Update version to (semi-belatedly) meet 1.0-consistency promise. - -## 0.2.0-nullsafety.1 +## 2.0.0 * Remove placeholder Dart file. - -## 0.2.0-nullsafety - -* Update Dart SDK constraint. +* Update Dart SDK constraint for compatibility with null safety. ## 0.1.0+8 diff --git a/packages/connectivity/connectivity_macos/example/lib/main.dart b/packages/connectivity/connectivity_macos/example/lib/main.dart index 4ad30972679a..07746ed0f722 100644 --- a/packages/connectivity/connectivity_macos/example/lib/main.dart +++ b/packages/connectivity/connectivity_macos/example/lib/main.dart @@ -7,7 +7,7 @@ import 'dart:async'; import 'dart:io'; -import 'package:connectivity/connectivity.dart'; +import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -40,9 +40,9 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, this.title}) : super(key: key); - final String title; + final String? title; @override _MyHomePageState createState() => _MyHomePageState(); @@ -50,8 +50,8 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { String _connectionStatus = 'Unknown'; - final Connectivity _connectivity = Connectivity(); - StreamSubscription _connectivitySubscription; + final ConnectivityPlatform _connectivity = ConnectivityPlatform.instance; + late StreamSubscription _connectivitySubscription; @override void initState() { @@ -69,7 +69,7 @@ class _MyHomePageState extends State { // Platform messages are asynchronous, so we initialize in an async method. Future initConnectivity() async { - ConnectivityResult result; + late ConnectivityResult result; // Platform messages may fail, so we use a try/catch PlatformException. try { result = await _connectivity.checkConnectivity(); @@ -100,7 +100,7 @@ class _MyHomePageState extends State { Future _updateConnectionStatus(ConnectivityResult result) async { switch (result) { case ConnectivityResult.wifi: - String wifiName, wifiBSSID, wifiIP; + String? wifiName, wifiBSSID, wifiIP; try { if (Platform.isIOS) { diff --git a/packages/connectivity/connectivity_macos/example/pubspec.yaml b/packages/connectivity/connectivity_macos/example/pubspec.yaml index 49d24e76b717..61cf16854d8b 100644 --- a/packages/connectivity/connectivity_macos/example/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/example/pubspec.yaml @@ -4,7 +4,7 @@ description: Demonstrates how to use the connectivity plugin. dependencies: flutter: sdk: flutter - connectivity: any + connectivity_platform_interface: ^2.0.0 connectivity_macos: # When depending on this package from a real application you should use: # connectivity_macos: ^x.y.z @@ -18,11 +18,11 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.10.0" diff --git a/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart b/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart index 54a67337285a..3abe491d193b 100644 --- a/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart +++ b/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart @@ -2,19 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 import 'dart:io'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:connectivity/connectivity.dart'; +import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('Connectivity test driver', () { - Connectivity _connectivity; + ConnectivityPlatform _connectivity; setUpAll(() async { - _connectivity = Connectivity(); + _connectivity = ConnectivityPlatform.instance; }); testWidgets('test connectivity result', (WidgetTester tester) async { diff --git a/packages/connectivity/connectivity_macos/pubspec.yaml b/packages/connectivity/connectivity_macos/pubspec.yaml index 0a22a8ba5f53..781bee88b55a 100644 --- a/packages/connectivity/connectivity_macos/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/pubspec.yaml @@ -1,6 +1,6 @@ name: connectivity_macos description: macOS implementation of the connectivity plugin. -version: 2.0.0-nullsafety +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_macos flutter: @@ -10,7 +10,7 @@ flutter: pluginClass: ConnectivityPlugin environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.10.0" dependencies: @@ -18,4 +18,4 @@ dependencies: sdk: flutter dev_dependencies: - pedantic: ^1.8.0 + pedantic: ^1.10.0 From d3ab0718dcc8ba0e2cfdd3dfa5a1e7ce2e9179da Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Mon, 22 Feb 2021 19:48:31 +0100 Subject: [PATCH 234/924] [cross_file] Stable null safety release (#3593) --- packages/cross_file/CHANGELOG.md | 2 +- packages/cross_file/pubspec.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md index c9b3d1ab2522..5bbb43f9e882 100644 --- a/packages/cross_file/CHANGELOG.md +++ b/packages/cross_file/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.3.0-nullsafety +## 0.3.0 * Migrated package to null-safety. * **breaking change** According to our unit tests, the API should be backwards-compatible. Some relevant changes were made, however: diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml index af1b7e7d4c0f..8e09b21d4536 100644 --- a/packages/cross_file/pubspec.yaml +++ b/packages/cross_file/pubspec.yaml @@ -1,18 +1,18 @@ name: cross_file description: An abstraction to allow working with files across multiple platforms. homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file -version: 0.3.0-nullsafety +version: 0.3.0 dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety.3 + meta: ^1.3.0 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.3 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.22.0" From 1baec7a192368b1cd271d39993c31531ffa717d1 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 10:53:04 -0800 Subject: [PATCH 235/924] [shared_preferences] Bump platform versions to NNBD stable (#3595) --- .../shared_preferences_linux/CHANGELOG.md | 6 +----- .../example/pubspec.yaml | 6 +++--- .../shared_preferences_linux/pubspec.yaml | 18 ++++++++--------- .../shared_preferences_macos/CHANGELOG.md | 8 ++------ .../example/pubspec.yaml | 6 +++--- .../shared_preferences_macos/pubspec.yaml | 10 +++++----- .../shared_preferences_web/CHANGELOG.md | 6 +----- .../shared_preferences_web/pubspec.yaml | 12 +++++------ .../shared_preferences_windows/CHANGELOG.md | 7 +------ .../example/CHANGELOG.md | 3 --- .../example/pubspec.yaml | 8 ++++---- .../shared_preferences_windows/pubspec.yaml | 20 +++++++++---------- 12 files changed, 45 insertions(+), 65 deletions(-) delete mode 100644 packages/shared_preferences/shared_preferences_windows/example/CHANGELOG.md diff --git a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md index 1d287cf57401..a50b4e470c53 100644 --- a/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_linux/CHANGELOG.md @@ -1,8 +1,4 @@ -## 2.0.0-nullsafety - -* Update version for consistency. - -## 0.0.4-nullsafety +## 2.0.0 * Migrate to null-safety. diff --git a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml index 12b78c37ea9c..dffdbd7526d2 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml @@ -17,11 +17,11 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml index ee2288a79b4a..0730ca8d5fec 100644 --- a/packages/shared_preferences/shared_preferences_linux/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/pubspec.yaml @@ -1,6 +1,6 @@ name: shared_preferences_linux description: Linux implementation of the shared_preferences plugin -version: 2.0.0-nullsafety +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_linux flutter: @@ -11,19 +11,19 @@ flutter: pluginClass: none environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: flutter: sdk: flutter - file: ^6.0.0-nullsafety.4 - meta: ^1.0.4 - path: ^1.8.0-nullsafety.3 - path_provider_linux: ^0.2.0-nullsafety - shared_preferences_platform_interface: ^2.0.0-nullsafety + file: ^6.0.0 + meta: ^1.3.0 + path: ^1.8.0 + path_provider_linux: ^2.0.0 + shared_preferences_platform_interface: ^2.0.0 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 diff --git a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md index 002e1b7224ea..00c2f628796f 100644 --- a/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_macos/CHANGELOG.md @@ -1,10 +1,6 @@ -## 2.0.0-nullsafety +## 2.0.0 -* Update version to (semi-belatedly) meet 1.0-consistency promise. - -## 0.0.2-nullsafety - -* Update Dart SDK constraint for null safety. +* Migrate to null safety. ## 0.0.1+12 diff --git a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml index 6a8e7e4b470a..7db361fccfd5 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml @@ -4,7 +4,7 @@ description: Demonstrates how to use the shared_preferences plugin. dependencies: flutter: sdk: flutter - shared_preferences_platform_interface: ^2.0.0-nullsafety + shared_preferences_platform_interface: ^2.0.0 shared_preferences_macos: # When depending on this package from a real application you should use: # shared_preferences_macos: ^x.y.z @@ -18,11 +18,11 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.8" diff --git a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml index 4f014ecb8929..24811830c1fd 100644 --- a/packages/shared_preferences/shared_preferences_macos/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/pubspec.yaml @@ -1,6 +1,6 @@ name: shared_preferences_macos description: macOS implementation of the shared_preferences plugin. -version: 2.0.0-nullsafety +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_macos flutter: @@ -10,13 +10,13 @@ flutter: pluginClass: SharedPreferencesPlugin environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: - shared_preferences_platform_interface: ^2.0.0-nullsafety + shared_preferences_platform_interface: ^2.0.0 flutter: sdk: flutter dev_dependencies: - pedantic: ^1.8.0 + pedantic: ^1.10.0 diff --git a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md index 2526ffe4447d..ec08267fe59f 100644 --- a/packages/shared_preferences/shared_preferences_web/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_web/CHANGELOG.md @@ -1,8 +1,4 @@ -## 2.0.0-nullsafety - -* Update version to (semi-belatedly) meet 1.0-consistency promise. - -## 0.2.0-nullsafety +## 2.0.0 * Migrate to null-safety. diff --git a/packages/shared_preferences/shared_preferences_web/pubspec.yaml b/packages/shared_preferences/shared_preferences_web/pubspec.yaml index 33970f4d857d..9a14b218572a 100644 --- a/packages/shared_preferences/shared_preferences_web/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_web/pubspec.yaml @@ -1,7 +1,7 @@ name: shared_preferences_web description: Web platform implementation of shared_preferences homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_web -version: 2.0.0-nullsafety +version: 2.0.0 flutter: plugin: @@ -11,18 +11,18 @@ flutter: fileName: shared_preferences_web.dart dependencies: - shared_preferences_platform_interface: ^2.0.0-nullsafety + shared_preferences_platform_interface: ^2.0.0 flutter: sdk: flutter flutter_web_plugins: sdk: flutter - meta: ^1.1.7 + meta: ^1.3.0 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.13+hotfix.4" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md index d6a5fb336fe5..6fa4eb162083 100644 --- a/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences_windows/CHANGELOG.md @@ -1,9 +1,4 @@ - -## 2.0.0-nullsafety - -* Update version for consistency. - -## 0.0.3-nullsafety +## 2.0.0 * Migrate to null-safety. diff --git a/packages/shared_preferences/shared_preferences_windows/example/CHANGELOG.md b/packages/shared_preferences/shared_preferences_windows/example/CHANGELOG.md deleted file mode 100644 index 41cc7d8192ec..000000000000 --- a/packages/shared_preferences/shared_preferences_windows/example/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 0.0.1 - -* TODO: Describe initial release. diff --git a/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml index 575e3f8409c6..6725259c4bdc 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml @@ -2,13 +2,13 @@ name: shared_preferences_windows_example description: Demonstrates how to use the shared_preferences_windows plugin. environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: flutter: sdk: flutter - shared_preferences_windows: ^0.0.1 + shared_preferences_windows: ^2.0.0 dependency_overrides: shared_preferences_windows: @@ -24,7 +24,7 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true diff --git a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml index 0b95c0c0d14a..d804dd1ddb8f 100644 --- a/packages/shared_preferences/shared_preferences_windows/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/pubspec.yaml @@ -1,7 +1,7 @@ name: shared_preferences_windows description: Windows implementation of shared_preferences homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences_windows -version: 2.0.0-nullsafety +version: 2.0.0 flutter: @@ -12,20 +12,20 @@ flutter: pluginClass: none environment: - sdk: '>=2.12.0-0 <3.0.0' - flutter: ">=1.12.8" + sdk: '>=2.12.0-259.9.beta <3.0.0' + flutter: ">=1.20.0" dependencies: - shared_preferences_platform_interface: ^2.0.0-nullsafety + shared_preferences_platform_interface: ^2.0.0 flutter: sdk: flutter - file: ^6.0.0-nullsafety.4 - meta: ^1.1.7 - path: ^1.6.4 - path_provider_platform_interface: ^2.0.0-nullsafety - path_provider_windows: ^0.1.0-nullsafety.2 + file: ^6.0.0 + meta: ^1.3.0 + path: ^1.8.0 + path_provider_platform_interface: ^2.0.0 + path_provider_windows: ^2.0.0 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.3 + pedantic: ^1.10.0 From 6c57e87edb3c37fa807e51d952a443aaba1d42fc Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 10:54:07 -0800 Subject: [PATCH 236/924] [url_launcher] Update platforms to NNBD stable (#3584) Updates all versions to stable. Converts all desktop examples to null-safety, and migrates Linux and macOS to use platform interface for examples rather than app-facing package to eliminate circular dependencies (implementation copied directly from Windows). --- .../url_launcher_linux/CHANGELOG.md | 15 +-- .../integration_test/url_launcher_test.dart | 15 +-- .../url_launcher_linux/example/lib/main.dart | 123 ++---------------- .../url_launcher_linux/example/pubspec.yaml | 8 +- .../example/test_driver/integration_test.dart | 2 + .../url_launcher_linux/pubspec.yaml | 7 +- .../url_launcher_macos/CHANGELOG.md | 16 +-- .../integration_test/url_launcher_test.dart | 15 ++- .../url_launcher_macos/example/lib/main.dart | 123 ++---------------- .../url_launcher_macos/example/pubspec.yaml | 8 +- .../example/test_driver/integration_test.dart | 2 + .../url_launcher_macos/pubspec.yaml | 7 +- .../url_launcher_web/CHANGELOG.md | 2 +- .../url_launcher_web/example/pubspec.yaml | 2 +- .../url_launcher_web/pubspec.yaml | 8 +- .../url_launcher_windows/CHANGELOG.md | 16 +-- .../integration_test/url_launcher_test.dart | 2 + .../example/lib/main.dart | 4 +- .../url_launcher_windows/example/pubspec.yaml | 8 +- .../example/test_driver/integration_test.dart | 2 + .../url_launcher_windows/pubspec.yaml | 7 +- 21 files changed, 86 insertions(+), 306 deletions(-) diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md index bd3c15cb31fb..ec9fad53437c 100644 --- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md @@ -1,18 +1,9 @@ -## 2.0.0-nullsafety - -* Update version for consistency with other implementations. - -## 0.1.0-nullsafety.3 +## 2.0.0 +* Migrate to null safety. * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. - -## 0.1.0-nullsafety.2 - * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 0.1.0-nullsafety.1 - -* Migrate to null safety. +* Set `implementation` in pubspec.yaml ## 0.0.2+1 diff --git a/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart index d11ddb49966b..e1008fddd4e1 100644 --- a/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart @@ -2,22 +2,21 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -import 'package:url_launcher/url_launcher.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('canLaunch', (WidgetTester _) async { - expect(await canLaunch('randomstring'), false); - - // Generally all devices should have some default browser. - expect(await canLaunch('http://flutter.dev'), true); + UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; - // Desktop will not necessarily support sms:. + expect(await launcher.canLaunch('randomstring'), false); - // tel: and mailto: links may not be openable on every device. iOS - // simulators notably can't open these link types. + // Generally all devices should have some default browser. + expect(await launcher.canLaunch('http://flutter.dev'), true); }); } diff --git a/packages/url_launcher/url_launcher_linux/example/lib/main.dart b/packages/url_launcher/url_launcher_linux/example/lib/main.dart index a45862012328..f49e9fa290c5 100644 --- a/packages/url_launcher/url_launcher_linux/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_linux/example/lib/main.dart @@ -6,7 +6,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; void main() { runApp(MyApp()); @@ -26,7 +26,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override @@ -34,77 +34,24 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - Future _launched; - String _phone = ''; + Future? _launched; Future _launchInBrowser(String url) async { - if (await canLaunch(url)) { - await launch( + if (await UrlLauncherPlatform.instance.canLaunch(url)) { + await UrlLauncherPlatform.instance.launch( url, - forceSafariVC: false, - forceWebView: false, - headers: {'my_header_key': 'my_header_value'}, + useSafariVC: false, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, ); } else { throw 'Could not launch $url'; } } - Future _launchInWebViewOrVC(String url) async { - if (await canLaunch(url)) { - await launch( - url, - forceSafariVC: true, - forceWebView: true, - headers: {'my_header_key': 'my_header_value'}, - ); - } else { - throw 'Could not launch $url'; - } - } - - Future _launchInWebViewWithJavaScript(String url) async { - if (await canLaunch(url)) { - await launch( - url, - forceSafariVC: true, - forceWebView: true, - enableJavaScript: true, - ); - } else { - throw 'Could not launch $url'; - } - } - - Future _launchInWebViewWithDomStorage(String url) async { - if (await canLaunch(url)) { - await launch( - url, - forceSafariVC: true, - forceWebView: true, - enableDomStorage: true, - ); - } else { - throw 'Could not launch $url'; - } - } - - Future _launchUniversalLinkIos(String url) async { - if (await canLaunch(url)) { - final bool nativeAppLaunchSucceeded = await launch( - url, - forceSafariVC: false, - universalLinksOnly: true, - ); - if (!nativeAppLaunchSucceeded) { - await launch( - url, - forceSafariVC: true, - ); - } - } - } - Widget _launchStatus(BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasError) { return Text('Error: ${snapshot.error}'); @@ -113,14 +60,6 @@ class _MyHomePageState extends State { } } - Future _makePhoneCall(String url) async { - if (await canLaunch(url)) { - await launch(url); - } else { - throw 'Could not launch $url'; - } - } - @override Widget build(BuildContext context) { const String toLaunch = 'https://www.cylog.org/headers/'; @@ -133,19 +72,6 @@ class _MyHomePageState extends State { Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: TextField( - onChanged: (String text) => _phone = text, - decoration: const InputDecoration( - hintText: 'Input the phone number to launch')), - ), - ElevatedButton( - onPressed: () => setState(() { - _launched = _makePhoneCall('tel:$_phone'); - }), - child: const Text('Make phone call'), - ), const Padding( padding: EdgeInsets.all(16.0), child: Text(toLaunch), @@ -157,33 +83,6 @@ class _MyHomePageState extends State { child: const Text('Launch in browser'), ), const Padding(padding: EdgeInsets.all(16.0)), - ElevatedButton( - onPressed: () => setState(() { - _launched = _launchInWebViewOrVC(toLaunch); - }), - child: const Text('Launch in app'), - ), - ElevatedButton( - onPressed: () => setState(() { - _launched = _launchInWebViewWithJavaScript(toLaunch); - }), - child: const Text('Launch in app(JavaScript ON)'), - ), - ElevatedButton( - onPressed: () => setState(() { - _launched = _launchInWebViewWithDomStorage(toLaunch); - }), - child: const Text('Launch in app(DOM storage ON)'), - ), - const Padding(padding: EdgeInsets.all(16.0)), - ElevatedButton( - onPressed: () => setState(() { - _launched = _launchUniversalLinkIos(toLaunch); - }), - child: const Text( - 'Launch a universal link in a native app, fallback to Safari.(Youtube)'), - ), - const Padding(padding: EdgeInsets.all(16.0)), FutureBuilder(future: _launched, builder: _launchStatus), ], ), diff --git a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml index e95bcd0af478..63c920fba614 100644 --- a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml @@ -4,7 +4,6 @@ description: Demonstrates how to use the url_launcher plugin. dependencies: flutter: sdk: flutter - url_launcher: any url_launcher_linux: # When depending on this package from a real application you should use: # url_launcher_linux: ^x.y.z @@ -12,17 +11,18 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ + url_launcher_platform_interface: ^2.0.0 dev_dependencies: integration_test: path: ../../../integration_test flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart index 7a2c21338786..a8a56aa90f6a 100644 --- a/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml index 37a074a57436..cc974094b2d0 100644 --- a/packages/url_launcher/url_launcher_linux/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml @@ -1,17 +1,18 @@ name: url_launcher_linux description: Linux implementation of the url_launcher plugin. -version: 2.0.0-nullsafety +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux flutter: plugin: + implements: url_launcher platforms: linux: pluginClass: UrlLauncherPlugin environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: flutter: diff --git a/packages/url_launcher/url_launcher_macos/CHANGELOG.md b/packages/url_launcher/url_launcher_macos/CHANGELOG.md index 5835c15f64e0..6b0820fd5588 100644 --- a/packages/url_launcher/url_launcher_macos/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_macos/CHANGELOG.md @@ -1,18 +1,8 @@ -## 2.0.0-nullsafety - -* Update version to (semi-belatedly) meet 1.0-consistency promise. - -# 0.1.0-nullsafety.2 - -* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. - -# 0.1.0-nullsafety.1 - -* Bump SDK to support null safety. - -# 0.1.0-nullsafety +## 2.0.0 * Migrate to null safety. +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. +* Set `implementation` in pubspec.yaml ## 0.0.2+1 diff --git a/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart index 3e8d34c0b258..d0c1a8bd7325 100644 --- a/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart @@ -2,23 +2,24 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -import 'package:url_launcher/url_launcher.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('canLaunch', (WidgetTester _) async { - expect(await canLaunch('randomstring'), false); + UrlLauncherPlatform launcher = UrlLauncherPlatform.instance; + + expect(await launcher.canLaunch('randomstring'), false); // Generally all devices should have some default browser. - expect(await canLaunch('http://flutter.dev'), true); + expect(await launcher.canLaunch('http://flutter.dev'), true); // Generally all devices should have some default SMS app. - expect(await canLaunch('sms:5555555555'), true); - - // tel: and mailto: links may not be openable on every device. iOS - // simulators notably can't open these link types. + expect(await launcher.canLaunch('sms:5555555555'), true); }); } diff --git a/packages/url_launcher/url_launcher_macos/example/lib/main.dart b/packages/url_launcher/url_launcher_macos/example/lib/main.dart index a45862012328..f49e9fa290c5 100644 --- a/packages/url_launcher/url_launcher_macos/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_macos/example/lib/main.dart @@ -6,7 +6,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; void main() { runApp(MyApp()); @@ -26,7 +26,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override @@ -34,77 +34,24 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - Future _launched; - String _phone = ''; + Future? _launched; Future _launchInBrowser(String url) async { - if (await canLaunch(url)) { - await launch( + if (await UrlLauncherPlatform.instance.canLaunch(url)) { + await UrlLauncherPlatform.instance.launch( url, - forceSafariVC: false, - forceWebView: false, - headers: {'my_header_key': 'my_header_value'}, + useSafariVC: false, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, ); } else { throw 'Could not launch $url'; } } - Future _launchInWebViewOrVC(String url) async { - if (await canLaunch(url)) { - await launch( - url, - forceSafariVC: true, - forceWebView: true, - headers: {'my_header_key': 'my_header_value'}, - ); - } else { - throw 'Could not launch $url'; - } - } - - Future _launchInWebViewWithJavaScript(String url) async { - if (await canLaunch(url)) { - await launch( - url, - forceSafariVC: true, - forceWebView: true, - enableJavaScript: true, - ); - } else { - throw 'Could not launch $url'; - } - } - - Future _launchInWebViewWithDomStorage(String url) async { - if (await canLaunch(url)) { - await launch( - url, - forceSafariVC: true, - forceWebView: true, - enableDomStorage: true, - ); - } else { - throw 'Could not launch $url'; - } - } - - Future _launchUniversalLinkIos(String url) async { - if (await canLaunch(url)) { - final bool nativeAppLaunchSucceeded = await launch( - url, - forceSafariVC: false, - universalLinksOnly: true, - ); - if (!nativeAppLaunchSucceeded) { - await launch( - url, - forceSafariVC: true, - ); - } - } - } - Widget _launchStatus(BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasError) { return Text('Error: ${snapshot.error}'); @@ -113,14 +60,6 @@ class _MyHomePageState extends State { } } - Future _makePhoneCall(String url) async { - if (await canLaunch(url)) { - await launch(url); - } else { - throw 'Could not launch $url'; - } - } - @override Widget build(BuildContext context) { const String toLaunch = 'https://www.cylog.org/headers/'; @@ -133,19 +72,6 @@ class _MyHomePageState extends State { Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: TextField( - onChanged: (String text) => _phone = text, - decoration: const InputDecoration( - hintText: 'Input the phone number to launch')), - ), - ElevatedButton( - onPressed: () => setState(() { - _launched = _makePhoneCall('tel:$_phone'); - }), - child: const Text('Make phone call'), - ), const Padding( padding: EdgeInsets.all(16.0), child: Text(toLaunch), @@ -157,33 +83,6 @@ class _MyHomePageState extends State { child: const Text('Launch in browser'), ), const Padding(padding: EdgeInsets.all(16.0)), - ElevatedButton( - onPressed: () => setState(() { - _launched = _launchInWebViewOrVC(toLaunch); - }), - child: const Text('Launch in app'), - ), - ElevatedButton( - onPressed: () => setState(() { - _launched = _launchInWebViewWithJavaScript(toLaunch); - }), - child: const Text('Launch in app(JavaScript ON)'), - ), - ElevatedButton( - onPressed: () => setState(() { - _launched = _launchInWebViewWithDomStorage(toLaunch); - }), - child: const Text('Launch in app(DOM storage ON)'), - ), - const Padding(padding: EdgeInsets.all(16.0)), - ElevatedButton( - onPressed: () => setState(() { - _launched = _launchUniversalLinkIos(toLaunch); - }), - child: const Text( - 'Launch a universal link in a native app, fallback to Safari.(Youtube)'), - ), - const Padding(padding: EdgeInsets.all(16.0)), FutureBuilder(future: _launched, builder: _launchStatus), ], ), diff --git a/packages/url_launcher/url_launcher_macos/example/pubspec.yaml b/packages/url_launcher/url_launcher_macos/example/pubspec.yaml index 2e66616101c2..40bb4eaba67a 100644 --- a/packages/url_launcher/url_launcher_macos/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/example/pubspec.yaml @@ -4,7 +4,6 @@ description: Demonstrates how to use the url_launcher plugin. dependencies: flutter: sdk: flutter - url_launcher: any url_launcher_macos: # When depending on this package from a real application you should use: # url_launcher_macos: ^x.y.z @@ -12,17 +11,18 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ + url_launcher_platform_interface: ^2.0.0 dev_dependencies: integration_test: path: ../../../integration_test flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart index 7a2c21338786..a8a56aa90f6a 100644 --- a/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/url_launcher/url_launcher_macos/pubspec.yaml b/packages/url_launcher/url_launcher_macos/pubspec.yaml index bd918bfda24e..6b5e6cf2a825 100644 --- a/packages/url_launcher/url_launcher_macos/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/pubspec.yaml @@ -1,18 +1,19 @@ name: url_launcher_macos description: macOS implementation of the url_launcher plugin. -version: 2.0.0-nullsafety +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos flutter: plugin: + implements: url_launcher platforms: macos: pluginClass: UrlLauncherPlugin fileName: url_launcher_macos.dart environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: flutter: diff --git a/packages/url_launcher/url_launcher_web/CHANGELOG.md b/packages/url_launcher/url_launcher_web/CHANGELOG.md index 49d72457ecd9..7da0ba0a8095 100644 --- a/packages/url_launcher/url_launcher_web/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_web/CHANGELOG.md @@ -1,4 +1,4 @@ -# 2.0.0-nullsafety +# 2.0.0 - Migrate to null safety. diff --git a/packages/url_launcher/url_launcher_web/example/pubspec.yaml b/packages/url_launcher/url_launcher_web/example/pubspec.yaml index 5fc060fe7abe..51748610e971 100644 --- a/packages/url_launcher/url_launcher_web/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/example/pubspec.yaml @@ -18,5 +18,5 @@ dev_dependencies: sdk: flutter environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.26.0-0" # For integration_test from sdk diff --git a/packages/url_launcher/url_launcher_web/pubspec.yaml b/packages/url_launcher/url_launcher_web/pubspec.yaml index b9f957a7ee76..371a40e16f7b 100644 --- a/packages/url_launcher/url_launcher_web/pubspec.yaml +++ b/packages/url_launcher/url_launcher_web/pubspec.yaml @@ -1,7 +1,7 @@ name: url_launcher_web description: Web platform implementation of url_launcher homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_web -version: 2.0.0-nullsafety +version: 2.0.0 flutter: plugin: @@ -11,7 +11,7 @@ flutter: fileName: url_launcher_web.dart dependencies: - url_launcher_platform_interface: ^2.0.0-nullsafety + url_launcher_platform_interface: ^2.0.0 meta: ^1.3.0 # null safe flutter: sdk: flutter @@ -24,5 +24,5 @@ dev_dependencies: sdk: flutter environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.13+hotfix.5" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/url_launcher/url_launcher_windows/CHANGELOG.md b/packages/url_launcher/url_launcher_windows/CHANGELOG.md index b57785524d08..e906254eef44 100644 --- a/packages/url_launcher/url_launcher_windows/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_windows/CHANGELOG.md @@ -1,18 +1,8 @@ -## 2.0.0-nullsafety - -* Update version to (semi-belatedly) meet 1.0-consistency promise. - -## 0.1.0-nullsafety.2 - -* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. - -## 0.1.0-nullsafety.1 - -* Bump Dart SDK to support null safety. - -## 0.1.0-nullsafety +## 2.0.0 * Migrate to null-safety. +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. +* Set `implementation` in pubspec.yaml ## 0.0.2+1 diff --git a/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart index 2617150348ee..e1008fddd4e1 100644 --- a/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; diff --git a/packages/url_launcher/url_launcher_windows/example/lib/main.dart b/packages/url_launcher/url_launcher_windows/example/lib/main.dart index e6c9f477b5a4..f49e9fa290c5 100644 --- a/packages/url_launcher/url_launcher_windows/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_windows/example/lib/main.dart @@ -26,7 +26,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override @@ -34,7 +34,7 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - Future _launched; + Future? _launched; Future _launchInBrowser(String url) async { if (await UrlLauncherPlatform.instance.canLaunch(url)) { diff --git a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml index 2de2bcf14f44..8a273ba65020 100644 --- a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml @@ -4,7 +4,7 @@ description: Demonstrates the Windows implementation of the url_launcher plugin. dependencies: flutter: sdk: flutter - url_launcher_platform_interface: any + url_launcher_platform_interface: ^2.0.0 url_launcher_windows: # When depending on this package from a real application you should use: # url_launcher_windows: ^x.y.z @@ -18,11 +18,11 @@ dev_dependencies: path: ../../../integration_test flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart index 7a2c21338786..a8a56aa90f6a 100644 --- a/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/url_launcher/url_launcher_windows/pubspec.yaml b/packages/url_launcher/url_launcher_windows/pubspec.yaml index 368c3f831c2a..e5b611f86af0 100644 --- a/packages/url_launcher/url_launcher_windows/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/pubspec.yaml @@ -1,17 +1,18 @@ name: url_launcher_windows description: Windows implementation of the url_launcher plugin. -version: 2.0.0-nullsafety +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_windows flutter: plugin: + implements: url_launcher platforms: windows: pluginClass: UrlLauncherPlugin environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: flutter: From f14eaecb33f6b7d1e4d359c17e4832fe216a18f1 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 12:01:18 -0800 Subject: [PATCH 237/924] [battery] Bump version for NNBD stable (#3594) Also replaces Mockito with test/Fake since the usage is a simple fake. --- packages/battery/battery/CHANGELOG.md | 2 +- packages/battery/battery/example/pubspec.yaml | 4 ++-- packages/battery/battery/pubspec.yaml | 14 +++++++------- packages/battery/battery/test/battery_test.dart | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/battery/battery/CHANGELOG.md b/packages/battery/battery/CHANGELOG.md index d907ca33fe1e..ae9e798c364d 100644 --- a/packages/battery/battery/CHANGELOG.md +++ b/packages/battery/battery/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/battery/battery/example/pubspec.yaml b/packages/battery/battery/example/pubspec.yaml index e118a7c21540..ea3d5d39ae14 100644 --- a/packages/battery/battery/example/pubspec.yaml +++ b/packages/battery/battery/example/pubspec.yaml @@ -17,11 +17,11 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.10.0-nullsafety + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/battery/battery/pubspec.yaml b/packages/battery/battery/pubspec.yaml index 455905d62a9a..a987bd8c45a6 100644 --- a/packages/battery/battery/pubspec.yaml +++ b/packages/battery/battery/pubspec.yaml @@ -2,7 +2,7 @@ name: battery description: Flutter plugin for accessing information about the battery state (full, charging, discharging) on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/battery/battery -version: 2.0.0-nullsafety +version: 2.0.0 flutter: plugin: @@ -16,18 +16,18 @@ flutter: dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety - battery_platform_interface: ^2.0.0-nullsafety + meta: ^1.3.0 + battery_platform_interface: ^2.0.0 dev_dependencies: - mockito: ^5.0.0-nullsafety.0 flutter_test: sdk: flutter - plugin_platform_interface: ^1.1.0-nullsafety + plugin_platform_interface: ">=1.0.0 <3.0.0" integration_test: path: ../../integration_test - pedantic: ^1.10.0-nullsafety + pedantic: ^1.10.0 + test: ^1.16.3 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/battery/battery/test/battery_test.dart b/packages/battery/battery/test/battery_test.dart index 43155c59692c..ff1bf1596250 100644 --- a/packages/battery/battery/test/battery_test.dart +++ b/packages/battery/battery/test/battery_test.dart @@ -4,11 +4,11 @@ import 'dart:async'; +import 'package:battery/battery.dart'; import 'package:battery_platform_interface/battery_platform_interface.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'package:battery/battery.dart'; -import 'package:mockito/mockito.dart'; +import 'package:test/fake.dart'; void main() { group('battery', () { @@ -30,7 +30,7 @@ void main() { }); } -class MockBatteryPlatform extends Mock +class MockBatteryPlatform extends Fake with MockPlatformInterfaceMixin implements BatteryPlatform { Future batteryLevel() async { From bb3fc5ad22aca210d617d5a5c8f958bc3c629d62 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 12:04:17 -0800 Subject: [PATCH 238/924] [path_provider] Update to stable NNBD (#3582) Bumps the versions in the app-facing package to make it stable NNBD. Changes the interface of four core methods to non-nullable, and adds a new exceptions if they aren't provided by the platform implementations. The list is somewhat arbitrary, but these seem like the four that are core enough that any implementation should either provide them, or explicitly say they don't have such a concept via UnsupportedError, since there isn't an obvious way for a developer to fall back if they are unexpectedly missing. --- .../path_provider/path_provider/CHANGELOG.md | 11 +- .../path_provider/example/pubspec.yaml | 4 +- .../path_provider/lib/path_provider.dart | 52 +++++-- .../path_provider/path_provider/pubspec.yaml | 18 +-- .../test/path_provider_test.dart | 127 +++++++++++++++--- 5 files changed, 165 insertions(+), 47 deletions(-) diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index a52711bf0736..c28c617bbea4 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,11 +1,10 @@ -## 2.0.0-nullsafety.1 - -* Require latest path_provider_windows to avoid potential issues - with breaking changes in `ffi` and `win32`. - -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. +* BREAKING CHANGE: Path accessors that return non-nullable results will throw + a `MissingPlatformDirectoryException` if the platform implementation is unable + to get the corresponding directory (except on platforms where the method is + explicitly unsupported, where they will continue to throw `UnsupportedError`). ## 1.6.28 diff --git a/packages/path_provider/path_provider/example/pubspec.yaml b/packages/path_provider/path_provider/example/pubspec.yaml index cef0449ca01a..68c751a81843 100644 --- a/packages/path_provider/path_provider/example/pubspec.yaml +++ b/packages/path_provider/path_provider/example/pubspec.yaml @@ -17,11 +17,11 @@ dev_dependencies: path: ../../../integration_test flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/path_provider/path_provider/lib/path_provider.dart b/packages/path_provider/path_provider/lib/path_provider.dart index 1560c3399e72..da9c0b3d48a3 100644 --- a/packages/path_provider/path_provider/lib/path_provider.dart +++ b/packages/path_provider/path_provider/lib/path_provider.dart @@ -20,6 +20,27 @@ set disablePathProviderPlatformOverride(bool override) {} bool _manualDartRegistrationNeeded = true; +/// An exception thrown when a directory that should always be available on +/// the current platform cannot be obtained. +class MissingPlatformDirectoryException implements Exception { + /// Creates a new exception + MissingPlatformDirectoryException(this.message, {this.details}); + + /// The explanation of the exception. + final String message; + + /// Added details, if any. + /// + /// E.g., an error object from the platform implementation. + final Object? details; + + @override + String toString() { + String detailsAddition = details == null ? '' : ': $details'; + return 'MissingPlatformDirectoryException($message)$detailsAddition'; + } +} + PathProviderPlatform get _platform { // This is to manually endorse Dart implementations until automatic // registration of Dart plugins is implemented. For details see @@ -51,10 +72,14 @@ PathProviderPlatform get _platform { /// On iOS, this uses the `NSCachesDirectory` API. /// /// On Android, this uses the `getCacheDir` API on the context. -Future getTemporaryDirectory() async { +/// +/// Throws a `MissingPlatformDirectoryException` if the system is unable to +/// provide the directory. +Future getTemporaryDirectory() async { final String? path = await _platform.getTemporaryPath(); if (path == null) { - return null; + throw MissingPlatformDirectoryException( + 'Unable to get temporary directory'); } return Directory(path); } @@ -69,10 +94,14 @@ Future getTemporaryDirectory() async { /// If this directory does not exist, it is created automatically. /// /// On Android, this function uses the `getFilesDir` API on the context. -Future getApplicationSupportDirectory() async { +/// +/// Throws a `MissingPlatformDirectoryException` if the system is unable to +/// provide the directory. +Future getApplicationSupportDirectory() async { final String? path = await _platform.getApplicationSupportPath(); if (path == null) { - return null; + throw MissingPlatformDirectoryException( + 'Unable to get application support directory'); } return Directory(path); @@ -83,10 +112,13 @@ Future getApplicationSupportDirectory() async { /// /// On Android, this function throws an [UnsupportedError] as no equivalent /// path exists. -Future getLibraryDirectory() async { +/// +/// Throws a `MissingPlatformDirectoryException` if the system is unable to +/// provide the directory on a supported platform. +Future getLibraryDirectory() async { final String? path = await _platform.getLibraryPath(); if (path == null) { - return null; + throw MissingPlatformDirectoryException('Unable to get library directory'); } return Directory(path); } @@ -100,10 +132,14 @@ Future getLibraryDirectory() async { /// On Android, this uses the `getDataDirectory` API on the context. Consider /// using [getExternalStorageDirectory] instead if data is intended to be visible /// to the user. -Future getApplicationDocumentsDirectory() async { +/// +/// Throws a `MissingPlatformDirectoryException` if the system is unable to +/// provide the directory. +Future getApplicationDocumentsDirectory() async { final String? path = await _platform.getApplicationDocumentsPath(); if (path == null) { - return null; + throw MissingPlatformDirectoryException( + 'Unable to get application documents directory'); } return Directory(path); } diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index 3d79c99e2223..81941dac67b1 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 2.0.0-nullsafety.1 +version: 2.0.0 flutter: plugin: @@ -21,10 +21,10 @@ flutter: dependencies: flutter: sdk: flutter - path_provider_platform_interface: ^2.0.0-nullsafety - path_provider_macos: ^0.0.5-nullsafety - path_provider_linux: ^0.2.0-nullsafety - path_provider_windows: ^0.1.0-nullsafety.3 + path_provider_platform_interface: ^2.0.0 + path_provider_macos: ^2.0.0 + path_provider_linux: ^2.0.0 + path_provider_windows: ^2.0.0 dev_dependencies: integration_test: @@ -33,10 +33,10 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - pedantic: ^1.10.0-nullsafety - mockito: ^5.0.0-nullsafety.0 - plugin_platform_interface: ^1.1.0-nullsafety + pedantic: ^1.10.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" + test: ^1.16.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/path_provider/path_provider/test/path_provider_test.dart b/packages/path_provider/path_provider/test/path_provider_test.dart index aec5e060f631..759e9c09ffc2 100644 --- a/packages/path_provider/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/path_provider/test/path_provider_test.dart @@ -6,10 +6,10 @@ import 'dart:io' show Directory; import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:test/fake.dart'; const String kTemporaryPath = 'temporaryPath'; const String kApplicationSupportPath = 'applicationSupportPath'; @@ -20,31 +20,30 @@ const String kExternalCachePath = 'externalCachePath'; const String kExternalStoragePath = 'externalStoragePath'; void main() { - group('PathProvider', () { - TestWidgetsFlutterBinding.ensureInitialized(); - + TestWidgetsFlutterBinding.ensureInitialized(); + group('PathProvider full implementation', () { setUp(() async { - PathProviderPlatform.instance = MockPathProviderPlatform(); + PathProviderPlatform.instance = FakePathProviderPlatform(); }); test('getTemporaryDirectory', () async { - Directory? result = await getTemporaryDirectory(); - expect(result?.path, kTemporaryPath); + Directory result = await getTemporaryDirectory(); + expect(result.path, kTemporaryPath); }); test('getApplicationSupportDirectory', () async { - Directory? result = await getApplicationSupportDirectory(); - expect(result?.path, kApplicationSupportPath); + Directory result = await getApplicationSupportDirectory(); + expect(result.path, kApplicationSupportPath); }); test('getLibraryDirectory', () async { - Directory? result = await getLibraryDirectory(); - expect(result?.path, kLibraryPath); + Directory result = await getLibraryDirectory(); + expect(result.path, kLibraryPath); }); test('getApplicationDocumentsDirectory', () async { - Directory? result = await getApplicationDocumentsDirectory(); - expect(result?.path, kApplicationDocumentsPath); + Directory result = await getApplicationDocumentsDirectory(); + expect(result.path, kApplicationDocumentsPath); }); test('getExternalStorageDirectory', () async { @@ -69,42 +68,126 @@ void main() { expect(result?.path, kDownloadsPath); }); }); + + group('PathProvider null implementation', () { + setUp(() async { + PathProviderPlatform.instance = AllNullFakePathProviderPlatform(); + }); + + test('getTemporaryDirectory throws on null', () async { + expect(getTemporaryDirectory(), + throwsA(isA())); + }); + + test('getApplicationSupportDirectory throws on null', () async { + expect(getApplicationSupportDirectory(), + throwsA(isA())); + }); + + test('getLibraryDirectory throws on null', () async { + expect(getLibraryDirectory(), + throwsA(isA())); + }); + + test('getApplicationDocumentsDirectory throws on null', () async { + expect(getApplicationDocumentsDirectory(), + throwsA(isA())); + }); + + test('getExternalStorageDirectory passes null through', () async { + Directory? result = await getExternalStorageDirectory(); + expect(result, isNull); + }); + + test('getExternalCacheDirectories passes null through', () async { + List? result = await getExternalCacheDirectories(); + expect(result, isNull); + }); + + test('getExternalStorageDirectories passes null through', () async { + List? result = await getExternalStorageDirectories(); + expect(result, isNull); + }); + + test('getDownloadsDirectory passses null through', () async { + Directory? result = await getDownloadsDirectory(); + expect(result, isNull); + }); + }); } -class MockPathProviderPlatform extends Mock +class FakePathProviderPlatform extends Fake with MockPlatformInterfaceMixin implements PathProviderPlatform { - Future getTemporaryPath() async { + Future getTemporaryPath() async { return kTemporaryPath; } - Future getApplicationSupportPath() async { + Future getApplicationSupportPath() async { return kApplicationSupportPath; } - Future getLibraryPath() async { + Future getLibraryPath() async { return kLibraryPath; } - Future getApplicationDocumentsPath() async { + Future getApplicationDocumentsPath() async { return kApplicationDocumentsPath; } - Future getExternalStoragePath() async { + Future getExternalStoragePath() async { return kExternalStoragePath; } - Future> getExternalCachePaths() async { + Future?> getExternalCachePaths() async { return [kExternalCachePath]; } - Future> getExternalStoragePaths({ + Future?> getExternalStoragePaths({ StorageDirectory? type, }) async { return [kExternalStoragePath]; } - Future getDownloadsPath() async { + Future getDownloadsPath() async { return kDownloadsPath; } } + +class AllNullFakePathProviderPlatform extends Fake + with MockPlatformInterfaceMixin + implements PathProviderPlatform { + Future getTemporaryPath() async { + return null; + } + + Future getApplicationSupportPath() async { + return null; + } + + Future getLibraryPath() async { + return null; + } + + Future getApplicationDocumentsPath() async { + return null; + } + + Future getExternalStoragePath() async { + return null; + } + + Future?> getExternalCachePaths() async { + return null; + } + + Future?> getExternalStoragePaths({ + StorageDirectory? type, + }) async { + return null; + } + + Future getDownloadsPath() async { + return null; + } +} From b98d72548a2142c618b1e7e270f89ca9db67c039 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 22 Feb 2021 12:15:13 -0800 Subject: [PATCH 239/924] [connectivity_macos] fix version (#3599) --- packages/connectivity/connectivity_macos/CHANGELOG.md | 2 +- packages/connectivity/connectivity_macos/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/connectivity/connectivity_macos/CHANGELOG.md b/packages/connectivity/connectivity_macos/CHANGELOG.md index b3ad35a03281..7031e48318dd 100644 --- a/packages/connectivity/connectivity_macos/CHANGELOG.md +++ b/packages/connectivity/connectivity_macos/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0 +## 0.2.0 * Remove placeholder Dart file. * Update Dart SDK constraint for compatibility with null safety. diff --git a/packages/connectivity/connectivity_macos/pubspec.yaml b/packages/connectivity/connectivity_macos/pubspec.yaml index 781bee88b55a..b8f36c8f55b4 100644 --- a/packages/connectivity/connectivity_macos/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/pubspec.yaml @@ -1,6 +1,6 @@ name: connectivity_macos description: macOS implementation of the connectivity plugin. -version: 2.0.0 +version: 0.2.0 homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_macos flutter: From 0838c8253e8938fd92d1a3fee54ae4f4b5cd5594 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 12:29:49 -0800 Subject: [PATCH 240/924] [google_maps_flutter] Bump platform interface version for NNBD stable (#3598) --- .../CHANGELOG.md | 6 +----- .../pubspec.yaml | 14 +++++++------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index 7b2268395caf..0d5748d13f79 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,8 +1,4 @@ -## 2.0.0-nullsafety.1 - -* Fix overly-restrictive type check. - -## 2.0.0-nullsafety +## 2.0.0 * Migrated to null-safety. * BREAKING CHANGE: Removed deprecated APIs. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index 2ec9e449a335..602efe3e6c62 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,22 +3,22 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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: 2.0.0-nullsafety.1 +version: 2.0.0 dependencies: flutter: sdk: flutter - meta: ^1.0.5 - plugin_platform_interface: ^1.1.0-nullsafety.2 - stream_transform: ^2.0.0-nullsafety.0 - collection: ^1.14.13 + meta: ^1.3.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" + stream_transform: ^2.0.0 + collection: ^1.15.0 dev_dependencies: flutter_test: sdk: flutter mockito: ^5.0.0-nullsafety.0 - pedantic: ^1.8.0 + pedantic: ^1.10.0 environment: - sdk: '>=2.12.0-0 <3.0.0' + sdk: '>=2.12.0-259.9.beta <3.0.0' flutter: ">=1.9.1+hotfix.4" From 61a736f46528a9069d50800d3055d4c168bcee03 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 22 Feb 2021 12:44:04 -0800 Subject: [PATCH 241/924] [device_info_platform_interface] null safety stable release (#3597) --- .../device_info_platform_interface/CHANGELOG.md | 11 ++--------- .../device_info_platform_interface/pubspec.yaml | 12 ++++++------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/device_info/device_info_platform_interface/CHANGELOG.md b/packages/device_info/device_info_platform_interface/CHANGELOG.md index d4bc81e0f0aa..23e9bc770c95 100644 --- a/packages/device_info/device_info_platform_interface/CHANGELOG.md +++ b/packages/device_info/device_info_platform_interface/CHANGELOG.md @@ -1,16 +1,9 @@ -## 2.0.0-nullsafety.2 +## 2.0.0 +* Migrate to null safety. * Make `baseOS`, `previewSdkInt`, and `securityPatch` nullable types. * Remove default values for non-nullable types. -## 2.0.0-nullsafety.1 - -* Bump Dart SDK to support null safety. - -## 2.0.0-nullsafety - -* Migrate to null safety. - ## 1.0.2 - Update Flutter SDK constraint. diff --git a/packages/device_info/device_info_platform_interface/pubspec.yaml b/packages/device_info/device_info_platform_interface/pubspec.yaml index ca72cc753b63..3887aea3eff2 100644 --- a/packages/device_info/device_info_platform_interface/pubspec.yaml +++ b/packages/device_info/device_info_platform_interface/pubspec.yaml @@ -3,20 +3,20 @@ description: A common platform interface for the device_info plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/device_info # 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: 2.0.0-nullsafety.2 +version: 2.0.0 dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety.3 - plugin_platform_interface: ^1.1.0-nullsafety.1 + meta: ^1.3.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" dev_dependencies: flutter_test: sdk: flutter - test: ^1.10.0-nullsafety.1 - pedantic: ^1.10.0-nullsafety.1 + test: ^1.16.3 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.9.1+hotfix.4" From 0ea8ef89b63097d8d9974307f9665bb02d9ee4d7 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 12:59:52 -0800 Subject: [PATCH 242/924] [share] Bump version for NNBD stable (#3600) --- packages/share/CHANGELOG.md | 15 +++------------ packages/share/example/lib/image_previews.dart | 10 +++++----- packages/share/example/lib/main.dart | 2 +- packages/share/example/pubspec.yaml | 6 +++--- .../test_driver/test/integration_test.dart | 2 ++ packages/share/pubspec.yaml | 14 +++++++------- 6 files changed, 21 insertions(+), 28 deletions(-) diff --git a/packages/share/CHANGELOG.md b/packages/share/CHANGELOG.md index ba44db433d17..20afdea9f054 100644 --- a/packages/share/CHANGELOG.md +++ b/packages/share/CHANGELOG.md @@ -1,18 +1,9 @@ -## 2.0.0-nullsafety.3 - -* Update README with the new documentation urls. - -## 2.0.0-nullsafety.2 +## 2.0.0 +* Migrate to null safety. * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. - -## 2.0.0-nullsafety.1 - * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 2.0.0-nullsafety - -* Migrate to null safety. +* Update README with the new documentation urls. ## 0.6.5+5 diff --git a/packages/share/example/lib/image_previews.dart b/packages/share/example/lib/image_previews.dart index 61ecec43bdc7..9070749267fc 100644 --- a/packages/share/example/lib/image_previews.dart +++ b/packages/share/example/lib/image_previews.dart @@ -9,11 +9,11 @@ class ImagePreviews extends StatelessWidget { final List imagePaths; /// Callback when an image should be removed - final Function(int) onDelete; + final Function(int)? onDelete; /// Creates a widget for preview of images. [imagePaths] can not be empty /// and all contained paths need to be non empty. - const ImagePreviews(this.imagePaths, {Key key, this.onDelete}) + const ImagePreviews(this.imagePaths, {Key? key, this.onDelete}) : super(key: key); @override @@ -26,7 +26,7 @@ class ImagePreviews extends StatelessWidget { for (int i = 0; i < imagePaths.length; i++) { imageWidgets.add(_ImagePreview( imagePaths[i], - onDelete: onDelete != null ? () => onDelete(i) : null, + onDelete: onDelete != null ? () => onDelete!(i) : null, )); } @@ -39,9 +39,9 @@ class ImagePreviews extends StatelessWidget { class _ImagePreview extends StatelessWidget { final String imagePath; - final VoidCallback onDelete; + final VoidCallback? onDelete; - const _ImagePreview(this.imagePath, {Key key, this.onDelete}) + const _ImagePreview(this.imagePath, {Key? key, this.onDelete}) : super(key: key); @override diff --git a/packages/share/example/lib/main.dart b/packages/share/example/lib/main.dart index a9ebd6bb79fb..8d6a78305db9 100644 --- a/packages/share/example/lib/main.dart +++ b/packages/share/example/lib/main.dart @@ -116,7 +116,7 @@ class DemoAppState extends State { // RenderObject in its descendent tree when it's not // a RenderObjectWidget. The ElevatedButton's RenderObject // has its position and size after it's built. - final RenderBox box = context.findRenderObject(); + final RenderBox box = context.findRenderObject() as RenderBox; if (imagePaths.isNotEmpty) { await Share.shareFiles(imagePaths, diff --git a/packages/share/example/pubspec.yaml b/packages/share/example/pubspec.yaml index 372633ec19ec..2df76efb6ca2 100644 --- a/packages/share/example/pubspec.yaml +++ b/packages/share/example/pubspec.yaml @@ -11,18 +11,18 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - image_picker: ^0.6.7+4 + image_picker: ^0.7.0 dev_dependencies: flutter_driver: sdk: flutter integration_test: path: ../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.0.0-dev.28.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.9.1+hotfix.2" diff --git a/packages/share/example/test_driver/test/integration_test.dart b/packages/share/example/test_driver/test/integration_test.dart index 7a2c21338786..a8a56aa90f6a 100644 --- a/packages/share/example/test_driver/test/integration_test.dart +++ b/packages/share/example/test_driver/test/integration_test.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/share/pubspec.yaml b/packages/share/pubspec.yaml index 4d2b231bbdfb..e8a116799433 100644 --- a/packages/share/pubspec.yaml +++ b/packages/share/pubspec.yaml @@ -2,7 +2,7 @@ name: share description: Flutter plugin for sharing content via the platform share UI, using the ACTION_SEND intent on Android and UIActivityViewController on iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/share -version: 2.0.0-nullsafety.3 +version: 2.0.0 flutter: plugin: @@ -14,20 +14,20 @@ flutter: pluginClass: FLTSharePlugin dependencies: - meta: ^1.3.0-nullsafety.6 - mime: ^1.0.0-nullsafety.0 + meta: ^1.3.0 + mime: ^1.0.0 flutter: sdk: flutter dev_dependencies: - test: ^1.16.0-nullsafety.13 - mockito: ^4.1.3 + test: ^1.16.3 + mockito: ^5.0.0-nullsafety.7 flutter_test: sdk: flutter integration_test: path: ../integration_test - pedantic: ^1.10.0-nullsafety.3 + pedantic: ^1.10.0 environment: flutter: ">=1.12.13+hotfix.5" - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" From 39964495426d74f0e4149ff904ca8d702a116329 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 13:40:29 -0800 Subject: [PATCH 243/924] [android_intent] Bump version for NNBD stable (#3601) --- packages/android_intent/CHANGELOG.md | 12 +++--------- .../integration_test/android_intent_test.dart | 6 ++++++ packages/android_intent/example/pubspec.yaml | 4 ++-- .../example/test_driver/integration_test.dart | 6 ++++++ packages/android_intent/pubspec.yaml | 14 +++++++------- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/android_intent/CHANGELOG.md b/packages/android_intent/CHANGELOG.md index 3e878a50aac2..70926b4f4943 100644 --- a/packages/android_intent/CHANGELOG.md +++ b/packages/android_intent/CHANGELOG.md @@ -1,14 +1,8 @@ -## 2.0.0-nullsafety.2 - -* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. - -## 2.0.0-nullsafety.1 - -* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. ## 0.3.7+8 diff --git a/packages/android_intent/example/integration_test/android_intent_test.dart b/packages/android_intent/example/integration_test/android_intent_test.dart index 78a667b27a09..e11a5e4e4898 100644 --- a/packages/android_intent/example/integration_test/android_intent_test.dart +++ b/packages/android_intent/example/integration_test/android_intent_test.dart @@ -1,3 +1,9 @@ +// 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. + +// @dart = 2.9 + import 'dart:io'; import 'package:android_intent/android_intent.dart'; diff --git a/packages/android_intent/example/pubspec.yaml b/packages/android_intent/example/pubspec.yaml index 7a0814d4acc0..2b1aab823d12 100644 --- a/packages/android_intent/example/pubspec.yaml +++ b/packages/android_intent/example/pubspec.yaml @@ -17,12 +17,12 @@ dev_dependencies: path: ../../integration_test flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 # The following section is specific to Flutter. flutter: uses-material-design: true environment: - sdk: ">=2.3.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/android_intent/example/test_driver/integration_test.dart b/packages/android_intent/example/test_driver/integration_test.dart index 34483b996049..0378ec31ee3c 100644 --- a/packages/android_intent/example/test_driver/integration_test.dart +++ b/packages/android_intent/example/test_driver/integration_test.dart @@ -1,3 +1,9 @@ +// 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. + +// @dart = 2.9 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/android_intent/pubspec.yaml b/packages/android_intent/pubspec.yaml index c61460718fc1..ba830bddf1df 100644 --- a/packages/android_intent/pubspec.yaml +++ b/packages/android_intent/pubspec.yaml @@ -1,7 +1,7 @@ name: android_intent description: Flutter plugin for launching Android Intents. Not supported on iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/android_intent -version: 2.0.0-nullsafety.2 +version: 2.0.0 flutter: plugin: @@ -13,15 +13,15 @@ flutter: dependencies: flutter: sdk: flutter - platform: ^3.0.0-nullsafety.4 - meta: ^1.3.0-nullsafety.6 + platform: ^3.0.0 + meta: ^1.3.0 dev_dependencies: - test: ^1.16.0-nullsafety.13 - mockito: ^4.1.3 + test: ^1.16.3 + mockito: ^5.0.0-nullsafety.7 flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From 5f29f9e7c3655221bcbb9c2c306d3a1194cd4155 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 14:10:35 -0800 Subject: [PATCH 244/924] [shared_preferences] Bump app-facing version for NNBD stable (#3602) --- .../shared_preferences/CHANGELOG.md | 6 +----- .../shared_preferences/example/pubspec.yaml | 4 ++-- .../shared_preferences/pubspec.yaml | 18 +++++++++--------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index a14ebf547659..2e05c8bbff05 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,8 +1,4 @@ -## 2.0.0-nullsafety.1 - -* Fix crash when list string's type is dynamic. - -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null-safety. diff --git a/packages/shared_preferences/shared_preferences/example/pubspec.yaml b/packages/shared_preferences/shared_preferences/example/pubspec.yaml index ab6c8fe11f7f..84692d76e5a1 100644 --- a/packages/shared_preferences/shared_preferences/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/example/pubspec.yaml @@ -17,11 +17,11 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.9.1+hotfix.2" diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index fc556972a847..583600d6a78b 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences description: Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences -version: 2.0.0-nullsafety.1 +version: 2.0.0 flutter: plugin: @@ -20,19 +20,19 @@ flutter: default_package: shared_preferences_web dependencies: - meta: ^1.0.4 + meta: ^1.3.0 flutter: sdk: flutter - shared_preferences_platform_interface: ^2.0.0-nullsafety + shared_preferences_platform_interface: ^2.0.0 # The design on https://flutter.dev/go/federated-plugins was to leave # this constraint as "any". We cannot do it right now as it fails pub publish # validation, so we set a ^ constraint. # TODO(franciscojma): Revisit this (either update this part in the design or the pub tool). # https://github.com/flutter/flutter/issues/46264 - shared_preferences_linux: ^0.0.4-nullsafety - shared_preferences_macos: ^0.0.2-nullsafety - shared_preferences_web: ^0.2.0-nullsafety - shared_preferences_windows: ^0.0.3-nullsafety + shared_preferences_linux: ^2.0.0 + shared_preferences_macos: ^2.0.0 + shared_preferences_web: ^2.0.0 + shared_preferences_windows: ^2.0.0 dev_dependencies: flutter_test: @@ -41,8 +41,8 @@ dev_dependencies: sdk: flutter integration_test: path: ../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From f2696d56f2edf0279134ffba4e63dce05279e6d5 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 22 Feb 2021 15:26:08 -0800 Subject: [PATCH 245/924] [connectivity_macos] fix flutter version constraint (#3604) --- packages/connectivity/connectivity_macos/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/connectivity/connectivity_macos/pubspec.yaml b/packages/connectivity/connectivity_macos/pubspec.yaml index b8f36c8f55b4..860b16497bc6 100644 --- a/packages/connectivity/connectivity_macos/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/pubspec.yaml @@ -11,7 +11,7 @@ flutter: environment: sdk: ">=2.12.0-259.9.beta <3.0.0" - flutter: ">=1.10.0" + flutter: ">=1.20.0" dependencies: flutter: From 774d623c8e5c8f34ee3e76095145076879364793 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 15:44:01 -0800 Subject: [PATCH 246/924] [url_launcher] Bump app-facing version for NNBD stable (#3603) --- .../url_launcher/url_launcher/CHANGELOG.md | 34 +++---------------- .../url_launcher/example/pubspec.yaml | 8 ++--- .../url_launcher/url_launcher/pubspec.yaml | 22 ++++++------ 3 files changed, 19 insertions(+), 45 deletions(-) diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index f467ec4d1830..f5fb73104c50 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,35 +1,9 @@ -## 6.0.0-nullsafety.7 - -* Re-endorse `url_launcher_web` in the `nullsafety` prerelease. - -## 6.0.0-nullsafety.6 - -* Correct statement in description about which platforms url_launcher supports. - -## 6.0.0-nullsafety.5 - -* Document that the web plugin is not endorsed in the `nullsafety` prerelease for now. - -## 6.0.0-nullsafety.4 - -* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. - -## 6.0.0-nullsafety.3 - -* forceSafariVC should be nullable. - -## 6.0.0-nullsafety.2 - -* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 6.0.0-nullsafety.1 - -* Bump Dart SDK to support null safety. - -## 6.0.0-nullsafety +## 6.0.0 * Migrate to null safety. -* **Breaking change**: web plugins aren't endorsed in null-safe plugins yet. +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. +* Correct statement in description about which platforms url_launcher supports. ## 5.7.13 diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml index 520b6863ec2d..5f313f3870c5 100644 --- a/packages/url_launcher/url_launcher/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher/example/pubspec.yaml @@ -17,13 +17,13 @@ dev_dependencies: path: ../../../integration_test flutter_driver: sdk: flutter - pedantic: ^1.10.0-nullsafety.1 - mockito: ^4.1.1 - plugin_platform_interface: ^1.1.0-nullsafety.1 + pedantic: ^1.10.0 + mockito: ^5.0.0-nullsafety.7 + plugin_platform_interface: ">=1.0.0 <3.0.0" flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index d058e2fa1409..a9c2794b069a 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 6.0.0-nullsafety.7 +version: 6.0.0 flutter: plugin: @@ -24,25 +24,25 @@ flutter: dependencies: flutter: sdk: flutter - url_launcher_platform_interface: ^2.0.0-nullsafety + url_launcher_platform_interface: ^2.0.0 # The design on https://flutter.dev/go/federated-plugins was to leave # this constraint as "any". We cannot do it right now as it fails pub publish # validation, so we set a ^ constraint. # TODO(amirh): Revisit this (either update this part in the design or the pub tool). # https://github.com/flutter/flutter/issues/46264 - url_launcher_linux: ^0.1.0-nullsafety - url_launcher_macos: ^0.1.0-nullsafety - url_launcher_windows: ^0.1.0-nullsafety - url_launcher_web: ^2.0.0-nullsafety + url_launcher_linux: ^2.0.0 + url_launcher_macos: ^2.0.0 + url_launcher_windows: ^2.0.0 + url_launcher_web: ^2.0.0 dev_dependencies: flutter_test: sdk: flutter - test: ^1.10.0-nullsafety.1 - mockito: ^4.1.1 - plugin_platform_interface: ^1.1.0-nullsafety.1 - pedantic: ^1.10.0-nullsafety.1 + test: ^1.16.3 + mockito: ^5.0.0-nullsafety.7 + plugin_platform_interface: ">=1.0.0 <3.0.0" + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From d4480fbf7d554833caec9854b6c6b4da83f0cbe2 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 17:57:43 -0800 Subject: [PATCH 247/924] [android_intent] Fix Flutter SDK version (#3607) --- packages/android_intent/example/pubspec.yaml | 2 +- packages/android_intent/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/android_intent/example/pubspec.yaml b/packages/android_intent/example/pubspec.yaml index 2b1aab823d12..fd0e2d6b7844 100644 --- a/packages/android_intent/example/pubspec.yaml +++ b/packages/android_intent/example/pubspec.yaml @@ -25,4 +25,4 @@ flutter: environment: sdk: ">=2.12.0-259.9.beta <3.0.0" - flutter: ">=1.12.13+hotfix.5" + flutter: ">=1.20.0" diff --git a/packages/android_intent/pubspec.yaml b/packages/android_intent/pubspec.yaml index ba830bddf1df..e02c7a270344 100644 --- a/packages/android_intent/pubspec.yaml +++ b/packages/android_intent/pubspec.yaml @@ -24,4 +24,4 @@ dev_dependencies: environment: sdk: ">=2.12.0-259.9.beta <3.0.0" - flutter: ">=1.12.13+hotfix.5" + flutter: ">=1.20.0" From ab8fb51eecc03d497618b462ef90d3f5c3b81fab Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Mon, 22 Feb 2021 18:33:08 -0800 Subject: [PATCH 248/924] [file_selector_platform_interface] null safety stable release (#3605) --- .../CHANGELOG.md | 2 +- .../pubspec.yaml | 19 +++++++++--------- ...file_selector_platform_interface_test.dart | 20 ------------------- 3 files changed, 10 insertions(+), 31 deletions(-) diff --git a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md index 2fbe18db7bfd..ed720ca0515d 100644 --- a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md +++ b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0-nullsafety.0 +## 2.0.0 * Migration to null-safety diff --git a/packages/file_selector/file_selector_platform_interface/pubspec.yaml b/packages/file_selector/file_selector_platform_interface/pubspec.yaml index 9735bced03fb..30398a2f0d23 100644 --- a/packages/file_selector/file_selector_platform_interface/pubspec.yaml +++ b/packages/file_selector/file_selector_platform_interface/pubspec.yaml @@ -3,23 +3,22 @@ description: A common platform interface for the file_selector plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_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: 2.0.0-nullsafety.0 +version: 2.0.0 dependencies: flutter: sdk: flutter - meta: ^1.0.5 - http: ^0.13.0-nullsafety.0 - plugin_platform_interface: ^1.1.0-nullsafety.2 - cross_file: ^0.3.0-nullsafety + meta: ^1.3.0 + http: ^0.13.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" + cross_file: ^0.3.0 dev_dependencies: - test: ^1.15.0 + test: ^1.16.3 flutter_test: sdk: flutter - mockito: ^5.0.0-nullsafety.5 - pedantic: ^1.8.0 + pedantic: ^1.10.0 environment: - sdk: '>=2.12.0-0 <3.0.0' - flutter: ">=1.9.1+hotfix.4" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/file_selector/file_selector_platform_interface/test/file_selector_platform_interface_test.dart b/packages/file_selector/file_selector_platform_interface/test/file_selector_platform_interface_test.dart index 6809cee66963..56f6ae91bf28 100644 --- a/packages/file_selector/file_selector_platform_interface/test/file_selector_platform_interface_test.dart +++ b/packages/file_selector/file_selector_platform_interface/test/file_selector_platform_interface_test.dart @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:mockito/mockito.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; import 'package:file_selector_platform_interface/src/method_channel/method_channel_file_selector.dart'; @@ -16,28 +14,10 @@ void main() { isInstanceOf()); }); - test('Cannot be implemented with `implements`', () { - expect(() { - FileSelectorPlatform.instance = ImplementsFileSelectorPlatform(); - }, throwsA(isInstanceOf())); - }); - - test('Can be mocked with `implements`', () { - final FileSelectorPlatformMock mock = FileSelectorPlatformMock(); - FileSelectorPlatform.instance = mock; - }); - test('Can be extended', () { FileSelectorPlatform.instance = ExtendsFileSelectorPlatform(); }); }); } -class FileSelectorPlatformMock extends Mock - with MockPlatformInterfaceMixin - implements FileSelectorPlatform {} - -class ImplementsFileSelectorPlatform extends Mock - implements FileSelectorPlatform {} - class ExtendsFileSelectorPlatform extends FileSelectorPlatform {} From af50af79f0b546b7848a0343cc3dcbc0d346569b Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 22 Feb 2021 18:41:03 -0800 Subject: [PATCH 249/924] [connectivity] null safety stable release (#3596) --- packages/connectivity/connectivity/CHANGELOG.md | 14 ++------------ .../connectivity/example/pubspec.yaml | 6 +++--- packages/connectivity/connectivity/pubspec.yaml | 17 ++++++++--------- .../connectivity/test/connectivity_test.dart | 4 ++-- 4 files changed, 15 insertions(+), 26 deletions(-) diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index a1d0231a5bd4..c4566ae73fd0 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,19 +1,9 @@ -## 3.0.0-nullsafety.3 +## 3.0.0 +* Migrate to null safety. * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 3.0.0-nullsafety.2 - * Android: Cleanup the NetworkCallback object when a connectivity stream is cancelled -## 3.0.0-nullsafety.1 - -* Bump Dart SDK to support null safety. - -## 3.0.0-nullsafety - -* Migrate to null safety. - ## 2.0.3 * Update Flutter SDK constraint. diff --git a/packages/connectivity/connectivity/example/pubspec.yaml b/packages/connectivity/connectivity/example/pubspec.yaml index b50214619c13..6395dc38c3ae 100644 --- a/packages/connectivity/connectivity/example/pubspec.yaml +++ b/packages/connectivity/connectivity/example/pubspec.yaml @@ -15,14 +15,14 @@ dependencies: dev_dependencies: flutter_driver: sdk: flutter - test: ^1.10.0-nullsafety.1 + test: ^1.16.3 integration_test: path: ../../../integration_test - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index 7ae03553a26c..254e325203d1 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -2,7 +2,7 @@ name: connectivity description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity -version: 3.0.0-nullsafety.3 +version: 3.0.0 flutter: plugin: @@ -20,11 +20,11 @@ flutter: dependencies: flutter: sdk: flutter - meta: ^1.0.5 - connectivity_platform_interface: ^2.0.0-nullsafety.1 + meta: ^1.3.0 + connectivity_platform_interface: ^2.0.0 #TODO(cyanglaz): re-endorse the below plugins when they have migrated to nnbd. # https://github.com/flutter/flutter/issues/68669 - connectivity_macos: ^0.2.0-nullsafety + connectivity_macos: ^0.2.0 # connectivity_for_web: ^0.3.0 dev_dependencies: @@ -32,13 +32,12 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: ^1.10.0-nullsafety.1 + test: ^1.16.3 integration_test: path: ../../integration_test - mockito: ^4.1.1 - plugin_platform_interface: ^1.1.0-nullsafety.1 - pedantic: ^1.10.0-nullsafety.1 + plugin_platform_interface: ">=1.0.0 <3.0.0" + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/connectivity/connectivity/test/connectivity_test.dart b/packages/connectivity/connectivity/test/connectivity_test.dart index e83196546cd2..6747c79bb64a 100644 --- a/packages/connectivity/connectivity/test/connectivity_test.dart +++ b/packages/connectivity/connectivity/test/connectivity_test.dart @@ -8,7 +8,7 @@ import 'package:connectivity/connectivity.dart'; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'package:mockito/mockito.dart'; +import 'package:test/fake.dart'; const ConnectivityResult kCheckConnectivityResult = ConnectivityResult.wifi; const LocationAuthorizationStatus kRequestLocationResult = @@ -33,7 +33,7 @@ void main() { }); } -class MockConnectivityPlatform extends Mock +class MockConnectivityPlatform extends Fake with MockPlatformInterfaceMixin implements ConnectivityPlatform { Future checkConnectivity() async { From e21952ad3b2a80ce154feca291f6412e5836e765 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Mon, 22 Feb 2021 19:11:03 -0800 Subject: [PATCH 250/924] [video_player_platform_interface] Bump version for NNBD stable (#3578) --- .../CHANGELOG.md | 26 ++--- .../lib/messages.dart | 30 ++--- .../lib/test.dart | 2 +- .../pubspec.yaml | 11 +- .../method_channel_video_player_test.dart | 110 +++++++----------- 5 files changed, 70 insertions(+), 109 deletions(-) diff --git a/packages/video_player/video_player_platform_interface/CHANGELOG.md b/packages/video_player/video_player_platform_interface/CHANGELOG.md index 7b223f4d958c..d0c59bd05023 100644 --- a/packages/video_player/video_player_platform_interface/CHANGELOG.md +++ b/packages/video_player/video_player_platform_interface/CHANGELOG.md @@ -1,27 +1,15 @@ -## 4.0.0-nullsafety.1 +## 4.0.0 +* **Breaking Changes**: + * Migrate to null-safety + * Update to latest Pigeon. This includes a breaking change to how the test logic is exposed. * Add note about the `mixWithOthers` option being ignored on the web. - -## 4.0.0-nullsafety.0 - -* Update to latest Pigeon. - This includes a breaking change to how the test logic is exposed. - -## 3.0.0-nullsafety.3 - -* `messages.dart` sets Dart `2.12`. - -## 3.0.0-nullsafety.2 - -* Bump Dart SDK to support null safety. - -## 3.0.0-nullsafety.1 - * Make DataSource's `uri` parameter nullable. +* `messages.dart` sets Dart `2.12`. -## 3.0.0-nullsafety +## 3.0.0 -* Migrate to null safety. +* Version 3 only was published as nullsafety "previews". ## 2.2.1 diff --git a/packages/video_player/video_player_platform_interface/lib/messages.dart b/packages/video_player/video_player_platform_interface/lib/messages.dart index 3f2d78ef9ed5..dc5237f2e151 100644 --- a/packages/video_player/video_player_platform_interface/lib/messages.dart +++ b/packages/video_player/video_player_platform_interface/lib/messages.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v0.1.19), do not edit directly. +// Autogenerated from Pigeon (v0.1.21), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import // @dart = 2.12 @@ -18,7 +18,7 @@ class TextureMessage { static TextureMessage decode(Object message) { final Map pigeonMap = message as Map; - return TextureMessage()..textureId = pigeonMap['textureId'] as int; + return TextureMessage()..textureId = pigeonMap['textureId'] as int?; } } @@ -40,10 +40,10 @@ class CreateMessage { static CreateMessage decode(Object message) { final Map pigeonMap = message as Map; return CreateMessage() - ..asset = pigeonMap['asset'] as String - ..uri = pigeonMap['uri'] as String - ..packageName = pigeonMap['packageName'] as String - ..formatHint = pigeonMap['formatHint'] as String; + ..asset = pigeonMap['asset'] as String? + ..uri = pigeonMap['uri'] as String? + ..packageName = pigeonMap['packageName'] as String? + ..formatHint = pigeonMap['formatHint'] as String?; } } @@ -61,8 +61,8 @@ class LoopingMessage { static LoopingMessage decode(Object message) { final Map pigeonMap = message as Map; return LoopingMessage() - ..textureId = pigeonMap['textureId'] as int - ..isLooping = pigeonMap['isLooping'] as bool; + ..textureId = pigeonMap['textureId'] as int? + ..isLooping = pigeonMap['isLooping'] as bool?; } } @@ -80,8 +80,8 @@ class VolumeMessage { static VolumeMessage decode(Object message) { final Map pigeonMap = message as Map; return VolumeMessage() - ..textureId = pigeonMap['textureId'] as int - ..volume = pigeonMap['volume'] as double; + ..textureId = pigeonMap['textureId'] as int? + ..volume = pigeonMap['volume'] as double?; } } @@ -99,8 +99,8 @@ class PlaybackSpeedMessage { static PlaybackSpeedMessage decode(Object message) { final Map pigeonMap = message as Map; return PlaybackSpeedMessage() - ..textureId = pigeonMap['textureId'] as int - ..speed = pigeonMap['speed'] as double; + ..textureId = pigeonMap['textureId'] as int? + ..speed = pigeonMap['speed'] as double?; } } @@ -118,8 +118,8 @@ class PositionMessage { static PositionMessage decode(Object message) { final Map pigeonMap = message as Map; return PositionMessage() - ..textureId = pigeonMap['textureId'] as int - ..position = pigeonMap['position'] as int; + ..textureId = pigeonMap['textureId'] as int? + ..position = pigeonMap['position'] as int?; } } @@ -135,7 +135,7 @@ class MixWithOthersMessage { static MixWithOthersMessage decode(Object message) { final Map pigeonMap = message as Map; return MixWithOthersMessage() - ..mixWithOthers = pigeonMap['mixWithOthers'] as bool; + ..mixWithOthers = pigeonMap['mixWithOthers'] as bool?; } } diff --git a/packages/video_player/video_player_platform_interface/lib/test.dart b/packages/video_player/video_player_platform_interface/lib/test.dart index 538e9526b111..457a838e8d24 100644 --- a/packages/video_player/video_player_platform_interface/lib/test.dart +++ b/packages/video_player/video_player_platform_interface/lib/test.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v0.1.19), do not edit directly. +// Autogenerated from Pigeon (v0.1.21), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import // @dart = 2.12 diff --git a/packages/video_player/video_player_platform_interface/pubspec.yaml b/packages/video_player/video_player_platform_interface/pubspec.yaml index ed16ea1033fa..c85f483d041f 100644 --- a/packages/video_player/video_player_platform_interface/pubspec.yaml +++ b/packages/video_player/video_player_platform_interface/pubspec.yaml @@ -3,19 +3,18 @@ description: A common platform interface for the video_player plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_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: 4.0.0-nullsafety.1 +version: 4.0.0 dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety.3 + meta: ^1.3.0 flutter_test: sdk: flutter dev_dependencies: - mockito: ^4.1.1 - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.10.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart index 669fd2839897..fae4b746bf05 100644 --- a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart +++ b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart @@ -2,14 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(egarciad): Remove once Mockito is migrated to null safety. -// @dart = 2.9 - import 'dart:ui'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:video_player_platform_interface/messages.dart'; import 'package:video_player_platform_interface/method_channel_video_player.dart'; import 'package:video_player_platform_interface/test.dart'; @@ -17,13 +13,13 @@ import 'package:video_player_platform_interface/video_player_platform_interface. class _ApiLogger implements TestHostVideoPlayerApi { final List log = []; - TextureMessage textureMessage; - CreateMessage createMessage; - PositionMessage positionMessage; - LoopingMessage loopingMessage; - VolumeMessage volumeMessage; - PlaybackSpeedMessage playbackSpeedMessage; - MixWithOthersMessage mixWithOthersMessage; + TextureMessage? textureMessage; + CreateMessage? createMessage; + PositionMessage? positionMessage; + LoopingMessage? loopingMessage; + VolumeMessage? volumeMessage; + PlaybackSpeedMessage? playbackSpeedMessage; + MixWithOthersMessage? mixWithOthersMessage; @override TextureMessage create(CreateMessage arg) { @@ -101,28 +97,11 @@ void main() { expect(VideoPlayerPlatform.instance, isInstanceOf()); }); - - test('Cannot be implemented with `implements`', () { - expect(() { - VideoPlayerPlatform.instance = ImplementsVideoPlayerPlatform(); - }, throwsA(isInstanceOf())); - }); - - test('Can be mocked with `implements`', () { - final ImplementsVideoPlayerPlatform mock = - ImplementsVideoPlayerPlatform(); - when(mock.isMock).thenReturn(true); - VideoPlayerPlatform.instance = mock; - }); - - test('Can be extended', () { - VideoPlayerPlatform.instance = ExtendsVideoPlayerPlatform(); - }); }); group('$MethodChannelVideoPlayer', () { final MethodChannelVideoPlayer player = MethodChannelVideoPlayer(); - _ApiLogger log; + late _ApiLogger log; setUp(() { log = _ApiLogger(); @@ -140,108 +119,108 @@ void main() { test('dispose', () async { await player.dispose(1); expect(log.log.last, 'dispose'); - expect(log.textureMessage.textureId, 1); + expect(log.textureMessage?.textureId, 1); }); test('create with asset', () async { - final int textureId = await player.create(DataSource( + final int? textureId = await player.create(DataSource( sourceType: DataSourceType.asset, asset: 'someAsset', package: 'somePackage', )); expect(log.log.last, 'create'); - expect(log.createMessage.asset, 'someAsset'); - expect(log.createMessage.packageName, 'somePackage'); + expect(log.createMessage?.asset, 'someAsset'); + expect(log.createMessage?.packageName, 'somePackage'); expect(textureId, 3); }); test('create with network', () async { - final int textureId = await player.create(DataSource( + final int? textureId = await player.create(DataSource( sourceType: DataSourceType.network, uri: 'someUri', formatHint: VideoFormat.dash, )); expect(log.log.last, 'create'); - expect(log.createMessage.uri, 'someUri'); - expect(log.createMessage.formatHint, 'dash'); + expect(log.createMessage?.uri, 'someUri'); + expect(log.createMessage?.formatHint, 'dash'); expect(textureId, 3); }); test('create with file', () async { - final int textureId = await player.create(DataSource( + final int? textureId = await player.create(DataSource( sourceType: DataSourceType.file, uri: 'someUri', )); expect(log.log.last, 'create'); - expect(log.createMessage.uri, 'someUri'); + expect(log.createMessage?.uri, 'someUri'); expect(textureId, 3); }); test('setLooping', () async { await player.setLooping(1, true); expect(log.log.last, 'setLooping'); - expect(log.loopingMessage.textureId, 1); - expect(log.loopingMessage.isLooping, true); + expect(log.loopingMessage?.textureId, 1); + expect(log.loopingMessage?.isLooping, true); }); test('play', () async { await player.play(1); expect(log.log.last, 'play'); - expect(log.textureMessage.textureId, 1); + expect(log.textureMessage?.textureId, 1); }); test('pause', () async { await player.pause(1); expect(log.log.last, 'pause'); - expect(log.textureMessage.textureId, 1); + expect(log.textureMessage?.textureId, 1); }); test('setMixWithOthers', () async { await player.setMixWithOthers(true); expect(log.log.last, 'setMixWithOthers'); - expect(log.mixWithOthersMessage.mixWithOthers, true); + expect(log.mixWithOthersMessage?.mixWithOthers, true); await player.setMixWithOthers(false); expect(log.log.last, 'setMixWithOthers'); - expect(log.mixWithOthersMessage.mixWithOthers, false); + expect(log.mixWithOthersMessage?.mixWithOthers, false); }); test('setVolume', () async { await player.setVolume(1, 0.7); expect(log.log.last, 'setVolume'); - expect(log.volumeMessage.textureId, 1); - expect(log.volumeMessage.volume, 0.7); + expect(log.volumeMessage?.textureId, 1); + expect(log.volumeMessage?.volume, 0.7); }); test('setPlaybackSpeed', () async { await player.setPlaybackSpeed(1, 1.5); expect(log.log.last, 'setPlaybackSpeed'); - expect(log.playbackSpeedMessage.textureId, 1); - expect(log.playbackSpeedMessage.speed, 1.5); + expect(log.playbackSpeedMessage?.textureId, 1); + expect(log.playbackSpeedMessage?.speed, 1.5); }); test('seekTo', () async { await player.seekTo(1, const Duration(milliseconds: 12345)); expect(log.log.last, 'seekTo'); - expect(log.positionMessage.textureId, 1); - expect(log.positionMessage.position, 12345); + expect(log.positionMessage?.textureId, 1); + expect(log.positionMessage?.position, 12345); }); test('getPosition', () async { final Duration position = await player.getPosition(1); expect(log.log.last, 'position'); - expect(log.textureMessage.textureId, 1); + expect(log.textureMessage?.textureId, 1); expect(position, const Duration(milliseconds: 234)); }); test('videoEventsFor', () async { - ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler( + ServicesBinding.instance?.defaultBinaryMessenger.setMockMessageHandler( "flutter.io/videoPlayer/videoEvents123", - (ByteData message) async { + (ByteData? message) async { final MethodCall methodCall = const StandardMethodCodec().decodeMethodCall(message); if (methodCall.method == 'listen') { - await ServicesBinding.instance.defaultBinaryMessenger + await ServicesBinding.instance?.defaultBinaryMessenger .handlePlatformMessage( "flutter.io/videoPlayer/videoEvents123", const StandardMethodCodec() @@ -251,18 +230,18 @@ void main() { 'width': 1920, 'height': 1080, }), - (ByteData data) {}); + (ByteData? data) {}); - await ServicesBinding.instance.defaultBinaryMessenger + await ServicesBinding.instance?.defaultBinaryMessenger .handlePlatformMessage( "flutter.io/videoPlayer/videoEvents123", const StandardMethodCodec() .encodeSuccessEnvelope({ 'event': 'completed', }), - (ByteData data) {}); + (ByteData? data) {}); - await ServicesBinding.instance.defaultBinaryMessenger + await ServicesBinding.instance?.defaultBinaryMessenger .handlePlatformMessage( "flutter.io/videoPlayer/videoEvents123", const StandardMethodCodec() @@ -273,25 +252,25 @@ void main() { [1235, 4000], ], }), - (ByteData data) {}); + (ByteData? data) {}); - await ServicesBinding.instance.defaultBinaryMessenger + await ServicesBinding.instance?.defaultBinaryMessenger .handlePlatformMessage( "flutter.io/videoPlayer/videoEvents123", const StandardMethodCodec() .encodeSuccessEnvelope({ 'event': 'bufferingStart', }), - (ByteData data) {}); + (ByteData? data) {}); - await ServicesBinding.instance.defaultBinaryMessenger + await ServicesBinding.instance?.defaultBinaryMessenger .handlePlatformMessage( "flutter.io/videoPlayer/videoEvents123", const StandardMethodCodec() .encodeSuccessEnvelope({ 'event': 'bufferingEnd', }), - (ByteData data) {}); + (ByteData? data) {}); return const StandardMethodCodec().encodeSuccessEnvelope(null); } else if (methodCall.method == 'cancel') { @@ -328,8 +307,3 @@ void main() { }); }); } - -class ImplementsVideoPlayerPlatform extends Mock - implements VideoPlayerPlatform {} - -class ExtendsVideoPlayerPlatform extends VideoPlayerPlatform {} From f47dbdf372feefea9268f3c03d9b2b4cd3ae2626 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 22 Feb 2021 20:11:21 -0800 Subject: [PATCH 251/924] [android_alarm_manager] Bump version for NNBD stable (#3608) --- packages/android_alarm_manager/CHANGELOG.md | 2 +- packages/android_alarm_manager/example/pubspec.yaml | 10 +++++----- packages/android_alarm_manager/pubspec.yaml | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/android_alarm_manager/CHANGELOG.md b/packages/android_alarm_manager/CHANGELOG.md index b06f23c45a30..10ad02a5ac43 100644 --- a/packages/android_alarm_manager/CHANGELOG.md +++ b/packages/android_alarm_manager/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/android_alarm_manager/example/pubspec.yaml b/packages/android_alarm_manager/example/pubspec.yaml index 029a60493193..b92f45c73d35 100644 --- a/packages/android_alarm_manager/example/pubspec.yaml +++ b/packages/android_alarm_manager/example/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - shared_preferences: ^2.0.0-nullsafety + shared_preferences: ^2.0.0 integration_test: path: ../../integration_test - path_provider: ^2.0.0-nullsafety + path_provider: ^2.0.0 dev_dependencies: espresso: ^0.0.1+3 @@ -22,11 +22,11 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: '>=2.12.0-0 <3.0.0' - flutter: ">=1.12.13+hotfix.5" + sdk: '>=2.12.0-259.9.beta <3.0.0' + flutter: ">=1.20.0" diff --git a/packages/android_alarm_manager/pubspec.yaml b/packages/android_alarm_manager/pubspec.yaml index ab1937242859..3934de6f06fe 100644 --- a/packages/android_alarm_manager/pubspec.yaml +++ b/packages/android_alarm_manager/pubspec.yaml @@ -1,7 +1,7 @@ name: android_alarm_manager description: Flutter plugin for accessing the Android AlarmManager service, and running Dart code in the background when alarms fire. -version: 2.0.0-nullsafety +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/android_alarm_manager dependencies: @@ -11,7 +11,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: plugin: @@ -21,5 +21,5 @@ flutter: pluginClass: AndroidAlarmManagerPlugin environment: - sdk: '>=2.12.0-0 <3.0.0' - flutter: ">=1.12.13+hotfix.5" + sdk: '>=2.12.0-259.9.beta <3.0.0' + flutter: ">=1.20.0" From f081633ecf0e419755f6008b42de18a91ec2d31d Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 23 Feb 2021 10:25:48 -0800 Subject: [PATCH 252/924] [local_auth] Bump version for NNBD stable (#3615) --- packages/local_auth/CHANGELOG.md | 29 ++++++------------------ packages/local_auth/example/pubspec.yaml | 4 ++-- packages/local_auth/pubspec.yaml | 14 ++++++------ 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index 152ffb603e10..b4d58395295f 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,32 +1,17 @@ -## 1.1.0-nullsafety +## 1.1.0 -* Allow pin, passcode, and pattern authentication with `authenticate` method +* Migrate to null safety. +* Allow pin, passcode, and pattern authentication with `authenticate` method. +* Fix incorrect error handling switch case fallthrough. +* Update README for Android Integration. +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)). * **Breaking change**. Parameter names refactored to use the generic `biometric` prefix in place of `fingerprint` in the `AndroidAuthMessages` class * `fingerprintHint` is now `biometricHint` * `fingerprintNotRecognized`is now `biometricNotRecognized` * `fingerprintSuccess`is now `biometricSuccess` * `fingerprintRequiredTitle` is now `biometricRequiredTitle` -## 1.0.0-nullsafety.4 - -* Fix incorrect error handling switch case fallthrough. - -## 1.0.0-nullsafety.3 - -* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. - -## 1.0.0-nullsafety.2 - -* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 1.0.0-nullsafety.1 - -* Update README for Android Integration. - -## 1.0.0-nullsafety - -* Migrate to null safety. - ## 0.6.3+5 * Update Flutter SDK constraint. diff --git a/packages/local_auth/example/pubspec.yaml b/packages/local_auth/example/pubspec.yaml index 364f604a31d8..d50940f6b63c 100644 --- a/packages/local_auth/example/pubspec.yaml +++ b/packages/local_auth/example/pubspec.yaml @@ -17,11 +17,11 @@ dev_dependencies: path: ../../integration_test flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 79870cc57da2..337006aa196f 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth description: Flutter plugin for Android and iOS devices to allow local authentication via fingerprint, touch ID, face ID, passcode, pin, or pattern. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 1.0.0-nullsafety.4 +version: 1.1.0 flutter: plugin: @@ -16,10 +16,10 @@ flutter: dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety.3 - intl: ^0.17.0-nullsafety.2 - platform: ^3.0.0-nullsafety.4 - flutter_plugin_android_lifecycle: ^2.0.0-nullsafety + meta: ^1.3.0 + intl: ^0.17.0 + platform: ^3.0.0 + flutter_plugin_android_lifecycle: ^2.0.0 dev_dependencies: integration_test: @@ -28,8 +28,8 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From bba55439a7800f5fec39f764855eb5482a13401f Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 23 Feb 2021 10:41:03 -0800 Subject: [PATCH 253/924] quick action stable (#3618) --- packages/quick_actions/CHANGELOG.md | 2 +- .../example/integration_test/quick_actions_test.dart | 1 + packages/quick_actions/example/lib/main.dart | 2 +- packages/quick_actions/example/pubspec.yaml | 4 ++-- .../example/test_driver/integration_test.dart | 1 + packages/quick_actions/pubspec.yaml | 11 +++++------ 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/quick_actions/CHANGELOG.md b/packages/quick_actions/CHANGELOG.md index 774ccac1bb44..1b6de34ca375 100644 --- a/packages/quick_actions/CHANGELOG.md +++ b/packages/quick_actions/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.5.0-nullsafety +## 0.5.0 * Migrate to null safety. diff --git a/packages/quick_actions/example/integration_test/quick_actions_test.dart b/packages/quick_actions/example/integration_test/quick_actions_test.dart index 03ecfe491d93..43822c9e8b2b 100644 --- a/packages/quick_actions/example/integration_test/quick_actions_test.dart +++ b/packages/quick_actions/example/integration_test/quick_actions_test.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:quick_actions/quick_actions.dart'; diff --git a/packages/quick_actions/example/lib/main.dart b/packages/quick_actions/example/lib/main.dart index fc289810ea24..a7e9d5e4c031 100644 --- a/packages/quick_actions/example/lib/main.dart +++ b/packages/quick_actions/example/lib/main.dart @@ -25,7 +25,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key}) : super(key: key); + MyHomePage({Key? key}) : super(key: key); @override _MyHomePageState createState() => _MyHomePageState(); diff --git a/packages/quick_actions/example/pubspec.yaml b/packages/quick_actions/example/pubspec.yaml index deba400ccd9f..ded88685c41b 100644 --- a/packages/quick_actions/example/pubspec.yaml +++ b/packages/quick_actions/example/pubspec.yaml @@ -17,11 +17,11 @@ dev_dependencies: sdk: flutter integration_test: path: ../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.0.0-dev.28.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.9.1+hotfix.2" diff --git a/packages/quick_actions/example/test_driver/integration_test.dart b/packages/quick_actions/example/test_driver/integration_test.dart index 7a2c21338786..0352d4aaeb2d 100644 --- a/packages/quick_actions/example/test_driver/integration_test.dart +++ b/packages/quick_actions/example/test_driver/integration_test.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/quick_actions/pubspec.yaml b/packages/quick_actions/pubspec.yaml index 46bc53e63ce6..dc500e2516e1 100644 --- a/packages/quick_actions/pubspec.yaml +++ b/packages/quick_actions/pubspec.yaml @@ -2,7 +2,7 @@ name: quick_actions description: Flutter plugin for creating shortcuts on home screen, also known as Quick Actions on iOS and App Shortcuts on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/quick_actions -version: 0.5.0-nullsafety +version: 0.5.0 flutter: plugin: @@ -16,17 +16,16 @@ flutter: dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety + meta: ^1.3.0 dev_dependencies: - test: ^1.16.0-nullsafety - mockito: ^5.0.0-nullsafety.0 + test: ^1.16.3 flutter_test: sdk: flutter integration_test: path: ../integration_test - pedantic: ^1.10.0-nullsafety + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From 082efa88b13533f834784c1975520fadecdf8ab3 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 23 Feb 2021 10:51:05 -0800 Subject: [PATCH 254/924] [ios_platform_images] Bump version for stable NNBD (#3616) --- packages/ios_platform_images/CHANGELOG.md | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 6 +-- .../contents.xcworkspacedata | 10 ++++ .../ios_platform_images/example/pubspec.yaml | 47 ++----------------- packages/ios_platform_images/pubspec.yaml | 43 ++--------------- 5 files changed, 20 insertions(+), 88 deletions(-) create mode 100644 packages/ios_platform_images/example/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/packages/ios_platform_images/CHANGELOG.md b/packages/ios_platform_images/CHANGELOG.md index bae98440f668..bb87b7d6ff81 100644 --- a/packages/ios_platform_images/CHANGELOG.md +++ b/packages/ios_platform_images/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.2.0-nullsafety +## 0.2.0 * Migrate to null safety. diff --git a/packages/ios_platform_images/example/ios/Runner.xcodeproj/project.pbxproj b/packages/ios_platform_images/example/ios/Runner.xcodeproj/project.pbxproj index 03bbe666a0ed..ba0b25c0015b 100644 --- a/packages/ios_platform_images/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/ios_platform_images/example/ios/Runner.xcodeproj/project.pbxproj @@ -229,9 +229,12 @@ files = ( ); inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/ios_platform_images/ios_platform_images.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ios_platform_images.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -310,7 +313,6 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -387,7 +389,6 @@ }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -443,7 +444,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; diff --git a/packages/ios_platform_images/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/ios_platform_images/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/ios_platform_images/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/ios_platform_images/example/pubspec.yaml b/packages/ios_platform_images/example/pubspec.yaml index 7802a2b0fe0a..552790ea74af 100644 --- a/packages/ios_platform_images/example/pubspec.yaml +++ b/packages/ios_platform_images/example/pubspec.yaml @@ -4,15 +4,13 @@ publish_to: 'none' homepage: https://github.com/flutter/plugins/tree/master/packages/ios_platform_images/ios_platform_images environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 + cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: @@ -24,46 +22,7 @@ dev_dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - pedantic: ^1.8.0 + pedantic: ^1.10.0 -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/ios_platform_images/pubspec.yaml b/packages/ios_platform_images/pubspec.yaml index 6284f7c96871..820542bcc362 100644 --- a/packages/ios_platform_images/pubspec.yaml +++ b/packages/ios_platform_images/pubspec.yaml @@ -1,10 +1,10 @@ name: ios_platform_images description: A plugin to share images between Flutter and iOS in add-to-app setups. -version: 0.2.0-nullsafety +version: 0.2.0 homepage: https://github.com/flutter/plugins/tree/master/packages/ios_platform_images/ios_platform_images environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" dependencies: @@ -14,47 +14,10 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety + pedantic: ^1.10.0 -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. flutter: - # This section identifies this Flutter project as a plugin project. - # The androidPackage and pluginClass identifiers should not ordinarily - # be modified. They are used by the tooling to maintain consistency when - # adding or updating assets for this project. plugin: platforms: ios: pluginClass: IosPlatformImagesPlugin - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages From b45875f01ece18dc1d1b01697c6d067eba5a7f8e Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 23 Feb 2021 11:31:03 -0800 Subject: [PATCH 255/924] [espresso] Update SDK requirement for null-safety (#3614) --- packages/espresso/CHANGELOG.md | 4 +++ packages/espresso/example/lib/main.dart | 2 +- packages/espresso/example/pubspec.yaml | 48 ++----------------------- packages/espresso/pubspec.yaml | 8 ++--- script/nnbd_plugins.sh | 1 + 5 files changed, 13 insertions(+), 50 deletions(-) diff --git a/packages/espresso/CHANGELOG.md b/packages/espresso/CHANGELOG.md index fe43202b7654..454736454cdf 100644 --- a/packages/espresso/CHANGELOG.md +++ b/packages/espresso/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0 + +* Update SDK requirement for null-safety compatibility. + ## 0.0.1+9 * Update Flutter SDK constraint. diff --git a/packages/espresso/example/lib/main.dart b/packages/espresso/example/lib/main.dart index c74423f507e8..958d26a0c149 100644 --- a/packages/espresso/example/lib/main.dart +++ b/packages/espresso/example/lib/main.dart @@ -27,7 +27,7 @@ class MyApp extends StatelessWidget { } class _MyHomePage extends StatefulWidget { - _MyHomePage({Key key, this.title}) : super(key: key); + _MyHomePage({Key? key, required this.title}) : super(key: key); // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect diff --git a/packages/espresso/example/pubspec.yaml b/packages/espresso/example/pubspec.yaml index 4854d85cb281..6e824acb4080 100644 --- a/packages/espresso/example/pubspec.yaml +++ b/packages/espresso/example/pubspec.yaml @@ -3,22 +3,19 @@ description: Demonstrates how to use the espresso plugin. publish_to: 'none' environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 - dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 espresso: # When depending on this package from a real application you should use: @@ -28,44 +25,5 @@ dev_dependencies: # the parent directory to use the current plugin's version. path: ../ -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/espresso/pubspec.yaml b/packages/espresso/pubspec.yaml index e79c46e73e40..90b485fdc48d 100644 --- a/packages/espresso/pubspec.yaml +++ b/packages/espresso/pubspec.yaml @@ -1,11 +1,11 @@ name: espresso description: Java classes for testing Flutter apps using Espresso. -version: 0.0.1+9 +version: 0.1.0 homepage: https://github.com/flutter/plugins/espresso environment: - sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.10.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" dependencies: flutter: @@ -14,7 +14,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0 + pedantic: ^1.10.0 # The following section is specific to Flutter. flutter: diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index eceb78cc970c..fb5f8eac44e9 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -13,6 +13,7 @@ readonly NNBD_PLUGINS_LIST=( "connectivity" "cross_file" "device_info" + "espresso" "file_selector" "flutter_plugin_android_lifecycle" "flutter_webview" From 34d0aa57f00f7b39bc2a1057c60f1794b86b71b8 Mon Sep 17 00:00:00 2001 From: Vishnu Agarwal <53317018+vishnuagbly@users.noreply.github.com> Date: Wed, 24 Feb 2021 01:07:39 +0530 Subject: [PATCH 256/924] [google_maps_flutter] fixed a small bug in example app. (#3590) in _onMarkerTapped function we were changing markers[markerId] to defaultMarker and than again markers[markerId] to hueGreen marker, while instead we should have changed markers[selectedMarker] to defaultMarker first instead of markers[markerId] --- .../google_maps_flutter/google_maps_flutter/CHANGELOG.md | 4 ++++ .../google_maps_flutter/example/lib/place_marker.dart | 7 ++++--- .../google_maps_flutter/google_maps_flutter/pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index 549aa4e06f3c..ef64aac534a5 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-nullsafety.1 + +* Fix in example app to properly change marker icon. + ## 2.0.0-nullsafety * Migrate to null-safety diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart index 576808c38a5e..c650ca34c1b0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart @@ -53,10 +53,11 @@ class PlaceMarkerBodyState extends State { final Marker? tappedMarker = markers[markerId]; if (tappedMarker != null) { setState(() { - if (markers.containsKey(markerId)) { - final Marker resetOld = markers[markerId]! + final MarkerId? previousMarkerId = selectedMarker; + if (previousMarkerId != null && markers.containsKey(previousMarkerId)) { + final Marker resetOld = markers[previousMarkerId]! .copyWith(iconParam: BitmapDescriptor.defaultMarker); - markers[markerId] = resetOld; + markers[previousMarkerId] = resetOld; } selectedMarker = markerId; final Marker newMarker = tappedMarker.copyWith( diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 8e9ab62d5f38..fbab15231b25 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 2.0.0-nullsafety +version: 2.0.0-nullsafety.1 dependencies: flutter: From 36a14570ae462e9f448dc565a0b33c286f5b2742 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 23 Feb 2021 12:06:42 -0800 Subject: [PATCH 257/924] [google_sign_in_web] Ignore analyzer checks in generated files. (#3622) These checks are currently breaking the engine/framework rolls. --- .../google_sign_in_web/lib/src/generated/gapi.dart | 2 ++ .../google_sign_in_web/lib/src/generated/gapiauth2.dart | 2 ++ 2 files changed, 4 insertions(+) diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart index 97ae9b48dc1b..95f07490d3e6 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// ignore_for_file: public_member_api_docs, unused_element + @JS() library gapi; diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart index ed7a2816d55e..8c8d23378e3e 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// ignore_for_file: public_member_api_docs, unused_element + @JS() library gapiauth2; From 7413abf088fa49703034e68fdf87215ddef0a7a3 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 23 Feb 2021 12:17:06 -0800 Subject: [PATCH 258/924] [google_sign_in] Bump platform interface version for NNBD stable (#3617) --- .../google_sign_in_platform_interface/CHANGELOG.md | 4 ++-- .../google_sign_in_platform_interface/pubspec.yaml | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md b/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md index f01d03080af7..dd6c22fbef29 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md @@ -1,6 +1,6 @@ -## 2.0.0-nullsafety +## 2.0.0 -* Migration to nnbd. +* Migrate to null-safety. ## 1.1.3 diff --git a/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml b/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml index 4480debc9ba3..56b4033dcb88 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml @@ -3,20 +3,20 @@ description: A common platform interface for the google_sign_in plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in_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: 2.0.0-nullsafety +version: 2.0.0 dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety.6 - quiver: ^3.0.0-nullsafety.2 + meta: ^1.3.0 + quiver: ^3.0.0 dev_dependencies: flutter_test: sdk: flutter mockito: ^5.0.0-nullsafety.1 - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From 73aefe620202349b56a9c4e7487580657b299596 Mon Sep 17 00:00:00 2001 From: Darshan Rander Date: Wed, 24 Feb 2021 02:21:04 +0530 Subject: [PATCH 259/924] [shared_preferences] Removed deprecated AsyncTask API (#3481) --- .../shared_preferences/CHANGELOG.md | 4 +++ .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../MethodCallHandlerImpl.java | 34 +++++++++++++------ .../shared_preferences/pubspec.yaml | 2 +- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 2e05c8bbff05..74555f59c27f 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Removed deprecated [AsyncTask](https://developer.android.com/reference/android/os/AsyncTask) was deprecated in API level 30 ([#3481](https://github.com/flutter/plugins/pull/3481)) + ## 2.0.0 * Migrate to null-safety. diff --git a/packages/shared_preferences/shared_preferences/android/gradle/wrapper/gradle-wrapper.properties b/packages/shared_preferences/shared_preferences/android/gradle/wrapper/gradle-wrapper.properties index caf54fa2801c..3c9d0852bfa5 100644 --- a/packages/shared_preferences/shared_preferences/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/shared_preferences/shared_preferences/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java index 33f2474592fa..f2c0f298578c 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java @@ -6,7 +6,8 @@ import android.content.Context; import android.content.SharedPreferences; -import android.os.AsyncTask; +import android.os.Handler; +import android.os.Looper; import android.util.Base64; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -21,6 +22,10 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; /** * Implementation of the {@link MethodChannel.MethodCallHandler} for the plugin. It is also @@ -118,17 +123,24 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { private void commitAsync( final SharedPreferences.Editor editor, final MethodChannel.Result result) { - new AsyncTask() { - @Override - protected Boolean doInBackground(Void... voids) { - return editor.commit(); - } + final ExecutorService executor = + new ThreadPoolExecutor(0, 1, 30L, TimeUnit.SECONDS, new SynchronousQueue()); + final Handler handler = new Handler(Looper.getMainLooper()); - @Override - protected void onPostExecute(Boolean value) { - result.success(value); - } - }.execute(); + executor.execute( + new Runnable() { + @Override + public void run() { + final boolean response = editor.commit(); + handler.post( + new Runnable() { + @Override + public void run() { + result.success(response); + } + }); + } + }); } private List decodeList(String encodedList) throws IOException { diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 583600d6a78b..1809a979c6f3 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences description: Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences -version: 2.0.0 +version: 2.0.1 flutter: plugin: From bc355f1ae386da64ab10a4729d70bee2910f60d8 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 23 Feb 2021 12:52:37 -0800 Subject: [PATCH 260/924] [webview_flutter] release null safety to stable(#3619) --- packages/webview_flutter/CHANGELOG.md | 22 ++----------------- packages/webview_flutter/example/pubspec.yaml | 4 ++-- packages/webview_flutter/pubspec.yaml | 6 ++--- 3 files changed, 7 insertions(+), 25 deletions(-) diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 0a060ef0cf2d..fb448d245127 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,31 +1,13 @@ -## 2.0.0-nullsafety.6 +## 2.0.0 +* Migration to null-safety. * Added support for progress tracking. - -## 2.0.0-nullsafety.5 - * Add section to the wiki explaining how to use Material components. - -## 2.0.0-nullsafety.4 - * Update integration test to workaround an iOS 14 issue with `evaluateJavascript`. - -## 2.0.0-nullsafety.3 - * Fix `onWebResourceError` on iOS. - -## 2.0.0-nullsafety.2 - * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 2.0.0-nullsafety.1 - * Added `allowsInlineMediaPlayback` property. -## 2.0.0-nullsafety - -* Migration to null-safety. - ## 1.0.8 * Update Flutter SDK constraint. diff --git a/packages/webview_flutter/example/pubspec.yaml b/packages/webview_flutter/example/pubspec.yaml index b61b6df590ce..d7688b720f3f 100644 --- a/packages/webview_flutter/example/pubspec.yaml +++ b/packages/webview_flutter/example/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_example description: Demonstrates how to use the webview_flutter plugin. environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" dependencies: flutter: @@ -22,7 +22,7 @@ dev_dependencies: sdk: flutter integration_test: path: ../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 flutter: uses-material-design: true diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 5d8e512b5aa5..bae19fd8b726 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,10 +1,10 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. -version: 2.0.0-nullsafety.5 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter +version: 2.0.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.22.0" dependencies: @@ -16,7 +16,7 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 flutter: plugin: From a2cb89410f1bb244b25ecf2d096486dc7eab1bd4 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 23 Feb 2021 12:58:26 -0800 Subject: [PATCH 261/924] [wifi_info_flutter_platform_interface] null safety stable release (#3620) --- .../wifi_info_flutter_platform_interface/CHANGELOG.md | 2 +- .../wifi_info_flutter_platform_interface/pubspec.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md index 043a3d31b68d..cb770cb2d279 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml index 1d830f0af5f6..8e2eff392df7 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml @@ -1,20 +1,20 @@ name: wifi_info_flutter_platform_interface description: A common platform interface for the wifi_info_flutter plugin. -version: 2.0.0-nullsafety +version: 2.0.0 # 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 homepage: https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter/wifi_info_flutter_platform_interface environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.17.0" dependencies: - plugin_platform_interface: ^1.1.0-nullsafety + plugin_platform_interface: ">=1.0.0 <3.0.0" flutter: sdk: flutter dev_dependencies: - pedantic: ^1.10.0-nullsafety + pedantic: ^1.10.0 flutter_test: sdk: flutter From bd886154e54de9001c2ce2ee1180b5378cffdb7a Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 23 Feb 2021 22:06:03 +0100 Subject: [PATCH 262/924] [camera] Fix example from README.md (#3592) --- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/README.md | 11 ++++++----- packages/camera/camera/pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 29774748a32b..079aa1685bd5 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.0-nullsafety.3 + +* Updates the example code listed in the [README.md](README.md), so it runs without errors when you simply copy/ paste it into a Flutter App. + ## 0.8.0-nullsafety.2 * Solved delay when using the zoom feature on iOS. diff --git a/packages/camera/camera/README.md b/packages/camera/camera/README.md index b9fdd7384297..fb6144face9b 100644 --- a/packages/camera/camera/README.md +++ b/packages/camera/camera/README.md @@ -79,6 +79,7 @@ List cameras; Future main() async { WidgetsFlutterBinding.ensureInitialized(); + cameras = await availableCameras(); runApp(CameraApp()); } @@ -94,7 +95,7 @@ class _CameraAppState extends State { @override void initState() { super.initState(); - controller = CameraController(cameras[0], ResolutionPreset.medium); + controller = CameraController(cameras[0], ResolutionPreset.max); controller.initialize().then((_) { if (!mounted) { return; @@ -114,12 +115,12 @@ class _CameraAppState extends State { if (!controller.value.isInitialized) { return Container(); } - return AspectRatio( - aspectRatio: - controller.value.aspectRatio, - child: CameraPreview(controller)); + return MaterialApp( + home: CameraPreview(controller), + ); } } + ``` For a more elaborate usage example see [here](https://github.com/flutter/plugins/tree/master/packages/camera/camera/example). diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 4b820b8b64cf..2d620505def2 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.8.0-nullsafety.2 +version: 0.8.0-nullsafety.3 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: From 3b4202514f4de3c868345a96b8a384ecc063a6bd Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 23 Feb 2021 14:12:55 -0800 Subject: [PATCH 263/924] [device_info_platform_interface] handle null value from method channel (#3609) --- .../lib/device_info_platform_interface.dart | 2 - .../method_channel_device_info.dart | 16 +- .../lib/model/android_device_info.dart | 104 ++++++--- .../lib/model/ios_device_info.dart | 58 +++-- .../test/method_channel_device_info_test.dart | 216 ++++++++++++++++++ 5 files changed, 344 insertions(+), 52 deletions(-) diff --git a/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart b/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart index 808b7adf9dc7..2dd41dcc580f 100644 --- a/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart +++ b/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart @@ -7,10 +7,8 @@ import 'dart:async'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'method_channel/method_channel_device_info.dart'; - import 'model/android_device_info.dart'; import 'model/ios_device_info.dart'; - export 'model/android_device_info.dart'; export 'model/ios_device_info.dart'; diff --git a/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart b/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart index 7bd02e97436d..331f718989ce 100644 --- a/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart @@ -1,8 +1,11 @@ +// 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:async'; import 'package:flutter/services.dart'; import 'package:meta/meta.dart'; - import 'package:device_info_platform_interface/device_info_platform_interface.dart'; /// An implementation of [DeviceInfoPlatform] that uses method channels. @@ -13,16 +16,15 @@ class MethodChannelDeviceInfo extends DeviceInfoPlatform { // Method channel for Android devices Future androidInfo() async { - return AndroidDeviceInfo.fromMap( - (await channel.invokeMethod('getAndroidDeviceInfo')) - .cast(), - ); + return AndroidDeviceInfo.fromMap((await channel + .invokeMapMethod('getAndroidDeviceInfo')) ?? + {}); } // Method channel for iOS devices Future iosInfo() async { return IosDeviceInfo.fromMap( - (await channel.invokeMethod('getIosDeviceInfo')).cast(), - ); + (await channel.invokeMapMethod('getIosDeviceInfo')) ?? + {}); } } diff --git a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart index 4fb940c3effa..c5210ab10f50 100644 --- a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart @@ -38,39 +38,63 @@ class AndroidDeviceInfo { final AndroidBuildVersion version; /// The name of the underlying board, like "goldfish". + /// + /// The value is an empty String if it is not available. final String board; /// The system bootloader version number. + /// + /// The value is an empty String if it is not available. final String bootloader; /// The consumer-visible brand with which the product/hardware will be associated, if any. + /// + /// The value is an empty String if it is not available. final String brand; /// The name of the industrial design. + /// + /// The value is an empty String if it is not available. final String device; /// A build ID string meant for displaying to the user. + /// + /// The value is an empty String if it is not available. final String display; /// A string that uniquely identifies this build. + /// + /// The value is an empty String if it is not available. final String fingerprint; /// The name of the hardware (from the kernel command line or /proc). + /// + /// The value is an empty String if it is not available. final String hardware; /// Hostname. + /// + /// The value is an empty String if it is not available. final String host; /// Either a changelist number, or a label like "M4-rc20". + /// + /// The value is an empty String if it is not available. final String id; /// The manufacturer of the product/hardware. + /// + /// The value is an empty String if it is not available. final String manufacturer; /// The end-user-visible name for the end product. + /// + /// The value is an empty String if it is not available. final String model; /// The name of the overall product. + /// + /// The value is an empty String if it is not available. final String product; /// An ordered list of 32 bit ABIs supported by this device. @@ -83,15 +107,23 @@ class AndroidDeviceInfo { final List supportedAbis; /// Comma-separated tags describing the build, like "unsigned,debug". + /// + /// The value is an empty String if it is not available. final String tags; /// The type of build, like "user" or "eng". + /// + /// The value is an empty String if it is not available. final String type; - /// `false` if the application is running in an emulator, `true` otherwise. + /// The value is `true` if the application is running on a physical device. + /// + /// The value is `false` when the application is running on a emulator, or the value is unavailable. final bool isPhysicalDevice; /// The Android hardware device ID that is unique between the device + user and app signing. + /// + /// The value is an empty String if it is not available. final String androidId; /// Describes what features are available on the current device. @@ -113,35 +145,41 @@ class AndroidDeviceInfo { /// Deserializes from the message received from [_kChannel]. static AndroidDeviceInfo fromMap(Map map) { return AndroidDeviceInfo( - version: - AndroidBuildVersion._fromMap(map['version']!.cast()), - board: map['board']!, - bootloader: map['bootloader']!, - brand: map['brand']!, - device: map['device']!, - display: map['display']!, - fingerprint: map['fingerprint']!, - hardware: map['hardware']!, - host: map['host']!, - id: map['id']!, - manufacturer: map['manufacturer']!, - model: map['model']!, - product: map['product']!, - supported32BitAbis: _fromList(map['supported32BitAbis']!), - supported64BitAbis: _fromList(map['supported64BitAbis']!), - supportedAbis: _fromList(map['supportedAbis']!), - tags: map['tags']!, - type: map['type']!, - isPhysicalDevice: map['isPhysicalDevice']!, - androidId: map['androidId']!, - systemFeatures: _fromList(map['systemFeatures']!), + version: AndroidBuildVersion._fromMap(map['version'] != null + ? map['version'].cast() + : {}), + board: map['board'] ?? '', + bootloader: map['bootloader'] ?? '', + brand: map['brand'] ?? '', + device: map['device'] ?? '', + display: map['display'] ?? '', + fingerprint: map['fingerprint'] ?? '', + hardware: map['hardware'] ?? '', + host: map['host'] ?? '', + id: map['id'] ?? '', + manufacturer: map['manufacturer'] ?? '', + model: map['model'] ?? '', + product: map['product'] ?? '', + supported32BitAbis: _fromList(map['supported32BitAbis']), + supported64BitAbis: _fromList(map['supported64BitAbis']), + supportedAbis: _fromList(map['supportedAbis']), + tags: map['tags'] ?? '', + type: map['type'] ?? '', + isPhysicalDevice: map['isPhysicalDevice'] ?? false, + androidId: map['androidId'] ?? '', + systemFeatures: _fromList(map['systemFeatures']), ); } /// Deserializes message as List static List _fromList(dynamic message) { - final List list = message; - return List.from(list); + if (message == null) { + return []; + } + assert(message is List); + final List list = List.from(message) + ..removeWhere((value) => value == null); + return list.cast(); } } @@ -173,17 +211,25 @@ class AndroidBuildVersion { final String? securityPatch; /// The current development codename, or the string "REL" if this is a release build. + /// + /// The value is an empty String if it is not available. final String codename; /// The internal value used by the underlying source control to represent this build. + /// + /// The value is an empty String if it is not available. final String incremental; /// The user-visible version string. + /// + /// The value is an empty String if it is not available. final String release; /// The user-visible SDK version of the framework. /// /// Possible values are defined in: https://developer.android.com/reference/android/os/Build.VERSION_CODES.html + /// + /// The value is -1 if it is unavailable. final int sdkInt; /// Deserializes from the map message received from [_kChannel]. @@ -192,10 +238,10 @@ class AndroidBuildVersion { baseOS: map['baseOS'], previewSdkInt: map['previewSdkInt'], securityPatch: map['securityPatch'], - codename: map['codename']!, - incremental: map['incremental']!, - release: map['release']!, - sdkInt: map['sdkInt']!, + codename: map['codename'] ?? '', + incremental: map['incremental'] ?? '', + release: map['release'] ?? '', + sdkInt: map['sdkInt'] ?? -1, ); } } diff --git a/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart index eb6e5874073b..20ec8362f66d 100644 --- a/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart @@ -19,40 +19,60 @@ class IosDeviceInfo { }); /// Device name. + /// + /// The value is an empty String if it is not available. final String name; /// The name of the current operating system. + /// + /// The value is an empty String if it is not available. final String systemName; /// The current operating system version. + /// + /// The value is an empty String if it is not available. final String systemVersion; /// Device model. + /// + /// The value is an empty String if it is not available. final String model; /// Localized name of the device model. + /// + /// The value is an empty String if it is not available. final String localizedModel; /// Unique UUID value identifying the current device. + /// + /// The value is an empty String if it is not available. final String identifierForVendor; - /// `false` if the application is running in a simulator, `true` otherwise. + /// The value is `true` if the application is running on a physical device. + /// + /// The value is `false` when the application is running on a simulator, or the value is unavailable. final bool isPhysicalDevice; /// Operating system information derived from `sys/utsname.h`. + /// + /// The value is an empty String if it is not available. final IosUtsname utsname; /// Deserializes from the map message received from [_kChannel]. static IosDeviceInfo fromMap(Map map) { return IosDeviceInfo( - name: map['name']!, - systemName: map['systemName']!, - systemVersion: map['systemVersion']!, - model: map['model']!, - localizedModel: map['localizedModel']!, - identifierForVendor: map['identifierForVendor']!, - isPhysicalDevice: map['isPhysicalDevice'] == 'true', - utsname: IosUtsname._fromMap(map['utsname']!.cast()), + name: map['name'] ?? '', + systemName: map['systemName'] ?? '', + systemVersion: map['systemVersion'] ?? '', + model: map['model'] ?? '', + localizedModel: map['localizedModel'] ?? '', + identifierForVendor: map['identifierForVendor'] ?? '', + isPhysicalDevice: map['isPhysicalDevice'] != null + ? map['isPhysicalDevice'] == 'true' + : false, + utsname: IosUtsname._fromMap(map['utsname'] != null + ? map['utsname'].cast() + : {}), ); } } @@ -69,28 +89,38 @@ class IosUtsname { }); /// Operating system name. + /// + /// The value is an empty String if it is not available. final String sysname; /// Network node name. + /// + /// The value is an empty String if it is not available. final String nodename; /// Release level. + /// + /// The value is an empty String if it is not available. final String release; /// Version level. + /// + /// The value is an empty String if it is not available. final String version; /// Hardware type (e.g. 'iPhone7,1' for iPhone 6 Plus). + /// + /// The value is an empty String if it is not available. final String machine; /// Deserializes from the map message received from [_kChannel]. static IosUtsname _fromMap(Map map) { return IosUtsname._( - sysname: map['sysname']!, - nodename: map['nodename']!, - release: map['release']!, - version: map['version']!, - machine: map['machine']!, + sysname: map['sysname'] ?? '', + nodename: map['nodename'] ?? '', + release: map['release'] ?? '', + version: map['version'] ?? '', + machine: map['machine'] ?? '', ); } } diff --git a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart index 15963854ab12..03ff4b53cda9 100644 --- a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart +++ b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart @@ -158,4 +158,220 @@ void main() { expect(result.utsname.machine, "x86_64"); }); }); + + group( + "$MethodChannelDeviceInfo handles null value in the map returned from method channel", + () { + MethodChannelDeviceInfo methodChannelDeviceInfo; + + setUp(() async { + methodChannelDeviceInfo = MethodChannelDeviceInfo(); + + methodChannelDeviceInfo.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + switch (methodCall.method) { + case 'getAndroidDeviceInfo': + return ({ + "version": null, + "board": null, + "bootloader": null, + "brand": null, + "device": null, + "display": null, + "fingerprint": null, + "hardware": null, + "host": null, + "id": null, + "manufacturer": null, + "model": null, + "product": null, + "supported32BitAbis": null, + "supported64BitAbis": null, + "supportedAbis": null, + "tags": null, + "type": null, + "isPhysicalDevice": null, + "androidId": null, + "systemFeatures": null, + }); + case 'getIosDeviceInfo': + return ({ + "name": null, + "systemName": null, + "systemVersion": null, + "model": null, + "localizedModel": null, + "identifierForVendor": null, + "isPhysicalDevice": null, + "utsname": null, + }); + default: + return null; + } + }); + }); + + test("androidInfo hanels null", () async { + final AndroidDeviceInfo result = + await methodChannelDeviceInfo.androidInfo(); + + expect(result.version.securityPatch, null); + expect(result.version.sdkInt, -1); + expect(result.version.release, ''); + expect(result.version.previewSdkInt, null); + expect(result.version.incremental, ''); + expect(result.version.codename, ''); + expect(result.board, ''); + expect(result.bootloader, ''); + expect(result.brand, ''); + expect(result.device, ''); + expect(result.display, ''); + expect(result.fingerprint, ''); + expect(result.hardware, ''); + expect(result.host, ''); + expect(result.id, ''); + expect(result.manufacturer, ''); + expect(result.model, ''); + expect(result.product, ''); + expect(result.supported32BitAbis, []); + expect(result.supported64BitAbis, []); + expect(result.supportedAbis, []); + expect(result.tags, ''); + expect(result.type, ''); + expect(result.isPhysicalDevice, false); + expect(result.androidId, ''); + expect(result.systemFeatures, []); + }); + + test("iosInfo handles null", () async { + final IosDeviceInfo result = await methodChannelDeviceInfo.iosInfo(); + expect(result.name, ''); + expect(result.systemName, ''); + expect(result.systemVersion, ''); + expect(result.model, ''); + expect(result.localizedModel, ''); + expect(result.identifierForVendor, ''); + expect(result.isPhysicalDevice, false); + expect(result.utsname.sysname, ''); + expect(result.utsname.nodename, ''); + expect(result.utsname.release, ''); + expect(result.utsname.version, ''); + expect(result.utsname.machine, ''); + }); + }); + + group("$MethodChannelDeviceInfo handles method channel returns null", () { + MethodChannelDeviceInfo methodChannelDeviceInfo; + + setUp(() async { + methodChannelDeviceInfo = MethodChannelDeviceInfo(); + + methodChannelDeviceInfo.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + switch (methodCall.method) { + case 'getAndroidDeviceInfo': + return null; + case 'getIosDeviceInfo': + return null; + default: + return null; + } + }); + }); + + test("androidInfo handles null", () async { + final AndroidDeviceInfo result = + await methodChannelDeviceInfo.androidInfo(); + + expect(result.version.securityPatch, null); + expect(result.version.sdkInt, -1); + expect(result.version.release, ''); + expect(result.version.previewSdkInt, null); + expect(result.version.incremental, ''); + expect(result.version.codename, ''); + expect(result.board, ''); + expect(result.bootloader, ''); + expect(result.brand, ''); + expect(result.device, ''); + expect(result.display, ''); + expect(result.fingerprint, ''); + expect(result.hardware, ''); + expect(result.host, ''); + expect(result.id, ''); + expect(result.manufacturer, ''); + expect(result.model, ''); + expect(result.product, ''); + expect(result.supported32BitAbis, []); + expect(result.supported64BitAbis, []); + expect(result.supportedAbis, []); + expect(result.tags, ''); + expect(result.type, ''); + expect(result.isPhysicalDevice, false); + expect(result.androidId, ''); + expect(result.systemFeatures, []); + }); + + test("iosInfo handles null", () async { + final IosDeviceInfo result = await methodChannelDeviceInfo.iosInfo(); + expect(result.name, ''); + expect(result.systemName, ''); + expect(result.systemVersion, ''); + expect(result.model, ''); + expect(result.localizedModel, ''); + expect(result.identifierForVendor, ''); + expect(result.isPhysicalDevice, false); + expect(result.utsname.sysname, ''); + expect(result.utsname.nodename, ''); + expect(result.utsname.release, ''); + expect(result.utsname.version, ''); + expect(result.utsname.machine, ''); + }); + }); + + group("$MethodChannelDeviceInfo android handles null values in list", () { + MethodChannelDeviceInfo methodChannelDeviceInfo; + + setUp(() async { + methodChannelDeviceInfo = MethodChannelDeviceInfo(); + + methodChannelDeviceInfo.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + switch (methodCall.method) { + case 'getAndroidDeviceInfo': + return ({ + "supported32BitAbis": ["x86", null], + "supported64BitAbis": ["x86_64", null], + "supportedAbis": ["x86_64", "x86", null], + "systemFeatures": [ + "android.hardware.sensor.proximity", + "android.software.adoptable_storage", + "android.hardware.sensor.accelerometer", + "android.hardware.faketouch", + "android.software.backup", + "android.hardware.touchscreen", + null + ], + }); + default: + return null; + } + }); + }); + + test("androidInfo hanels null in list", () async { + final AndroidDeviceInfo result = + await methodChannelDeviceInfo.androidInfo(); + expect(result.supported32BitAbis, ['x86']); + expect(result.supported64BitAbis, ['x86_64']); + expect(result.supportedAbis, ['x86_64', 'x86']); + expect(result.systemFeatures, [ + "android.hardware.sensor.proximity", + "android.software.adoptable_storage", + "android.hardware.sensor.accelerometer", + "android.hardware.faketouch", + "android.software.backup", + "android.hardware.touchscreen" + ]); + }); + }); } From 07e37f51a58da0c413a05d9bf794365b87c72b22 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 23 Feb 2021 14:36:02 -0800 Subject: [PATCH 264/924] [google_maps_flutter] Bump app-facing version for NNBD stable (#3623) --- .../google_maps_flutter/CHANGELOG.md | 6 +-- .../google_maps_flutter/example/pubspec.yaml | 43 +------------------ .../google_maps_flutter/pubspec.yaml | 16 +++---- 3 files changed, 11 insertions(+), 54 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index ef64aac534a5..dae5caf89a60 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,8 +1,4 @@ -## 2.0.0-nullsafety.1 - -* Fix in example app to properly change marker icon. - -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null-safety * BREAKING CHANGE: Passing an unknown map object ID (e.g., MarkerId) to a diff --git a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml index 181550d32877..35d0da3488be 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml @@ -2,15 +2,13 @@ name: google_maps_flutter_example description: Demonstrates how to use the google_maps_flutter plugin. environment: - sdk: '>=2.12.0-0 <3.0.0' + sdk: '>=2.12.0-259.9.beta <3.0.0' flutter: ">=1.22.0" dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.0 google_maps_flutter: # When depending on this package from a real application you should use: @@ -26,46 +24,9 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.8.0 + pedantic: ^1.10.0 -# For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec - -# The following section is specific to Flutter. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true - - # To add assets to your application, add an assets section, like this: assets: - assets/ - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.io/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.io/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.io/custom-fonts/#from-packages diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index fbab15231b25..3d0e79473a33 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,13 +1,13 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 2.0.0-nullsafety.1 +version: 2.0.0 dependencies: flutter: sdk: flutter - flutter_plugin_android_lifecycle: ^2.0.0-nullsafety.2 - google_maps_flutter_platform_interface: ^2.0.0-nullsafety.1 + flutter_plugin_android_lifecycle: ^2.0.0 + google_maps_flutter_platform_interface: ^2.0.0 dev_dependencies: flutter_test: @@ -17,10 +17,10 @@ dev_dependencies: # https://github.com/dart-lang/pub/issues/2101 is resolved. flutter_driver: sdk: flutter - test: ^1.16.0-nullsafety.17 - pedantic: ^1.10.0-nullsafety.3 - plugin_platform_interface: ^1.1.0-nullsafety.2 - stream_transform: ^2.0.0-nullsafety.0 + test: ^1.16.0 + pedantic: ^1.10.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" + stream_transform: ^2.0.0 flutter: plugin: @@ -32,5 +32,5 @@ flutter: pluginClass: FLTGoogleMapsPlugin environment: - sdk: '>=2.12.0-0 <3.0.0' + sdk: '>=2.12.0-259.9.beta <3.0.0' flutter: ">=1.22.0" From 29c3f1fd37de821ebd942f6f86999a09b1ba0a3f Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 23 Feb 2021 15:10:32 -0800 Subject: [PATCH 265/924] [video_player_web] Bump version for NNBD stable (#3574) --- .../video_player/video_player_web/CHANGELOG.md | 18 ++---------------- .../video_player/video_player_web/pubspec.yaml | 12 ++++++------ .../test/video_player_web_test.dart | 4 +++- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/packages/video_player/video_player_web/CHANGELOG.md b/packages/video_player/video_player_web/CHANGELOG.md index 4c58311508a2..63d4e10ef8da 100644 --- a/packages/video_player/video_player_web/CHANGELOG.md +++ b/packages/video_player/video_player_web/CHANGELOG.md @@ -1,23 +1,9 @@ -## 2.0.0-nullsafety.4 +## 2.0.0 +* Migrate to null safety. * Calling `setMixWithOthers()` now is silently ignored instead of throwing an exception. - -## 2.0.0-nullsafety.3 - -* Updated to video_player_platform_interface 4.0. - -## 2.0.0-nullsafety.2 - * Fixed an issue where `isBuffering` was not updating on Web. -## 2.0.0-nullsafety.1 - -* Bump Dart SDK to support null safety. - -## 2.0.0-nullsafety - -* Migrate to null safety. - ## 0.1.4+2 * Update Flutter SDK constraint. diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml index d9628535e353..7404896e04a4 100644 --- a/packages/video_player/video_player_web/pubspec.yaml +++ b/packages/video_player/video_player_web/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player_web description: Web platform implementation of video_player. homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_web -version: 2.0.0-nullsafety.4 +version: 2.0.0 flutter: plugin: @@ -15,14 +15,14 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - meta: ^1.3.0-nullsafety.3 - video_player_platform_interface: ^4.0.0-nullsafety.0 + meta: ^1.3.0 + video_player_platform_interface: ^4.0.0 dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.12.8" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/video_player/video_player_web/test/video_player_web_test.dart b/packages/video_player/video_player_web/test/video_player_web_test.dart index 604bebf4e17a..aee5b0350570 100644 --- a/packages/video_player/video_player_web/test/video_player_web_test.dart +++ b/packages/video_player/video_player_web/test/video_player_web_test.dart @@ -98,7 +98,9 @@ void main() { await VideoPlayerPlatform.instance.setVolume(videoPlayerId, 0); await VideoPlayerPlatform.instance.play(videoPlayerId); - expect(eventStream, emitsError(isA())); + expect(() async { + await eventStream.last; + }, throwsA(isA())); }); test('can pause', () { From 22007382fa7b95354b41f4ee68ab1e89e665ff4e Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Wed, 24 Feb 2021 05:00:12 -0800 Subject: [PATCH 266/924] [video_player] Bump app-facing version for NNBD stable (#3624) --- .../video_player/video_player/CHANGELOG.md | 53 +++---------------- .../video_player/example/pubspec.yaml | 4 +- .../video_player/video_player/pubspec.yaml | 14 ++--- 3 files changed, 17 insertions(+), 54 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index f79a05f0e036..57ba54e0a7bc 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,50 +1,13 @@ -## 2.0.0-nullsafety.11 - -* Setting the `mixWithOthers` `VideoPlayerOptions` in web now is silently ignored instead of throwing an exception. - -## 2.0.0-nullsafety.10 - -* Updated to video_player_platform_interface 4.0. - -## 2.0.0-nullsafety.9 - -* Fixed an issue where a crash can occur after a closing a video player view on iOS. - -## 2.0.0-nullsafety.8 - -* Migrated from deprecated `defaultBinaryMessenger`. - -## 2.0.0-nullsafety.7 - -* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. - -## 2.0.0-nullsafety.6 - -* Fix `VideoPlayerValue toString()` test. - -## 2.0.0-nullsafety.5 +## 2.0.0 +* Migrate to null safety. +* Fix an issue where `isBuffering` was not updating on Android. * Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 2.0.0-nullsafety.4 - -* Fixed an issue where `isBuffering` was not updating on Android. - -## 2.0.0-nullsafety.3 - -* Dart null safety requires `2.12`. - -## 2.0.0-nullsafety.2 - -* Bump SDK version. - -## 2.0.0-nullsafety.1 - -* Merge master. - -## 2.0.0-nullsafety - -* Migration to null safety. +* Fix `VideoPlayerValue toString()` test. +* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. +* Migrate from deprecated `defaultBinaryMessenger`. +* Fix an issue where a crash can occur after a closing a video player view on iOS. +* Setting the `mixWithOthers` `VideoPlayerOptions` in web now is silently ignored instead of throwing an exception. ## 1.0.2 diff --git a/packages/video_player/video_player/example/pubspec.yaml b/packages/video_player/video_player/example/pubspec.yaml index 620186afc880..4bfb3e5fefad 100644 --- a/packages/video_player/video_player/example/pubspec.yaml +++ b/packages/video_player/video_player/example/pubspec.yaml @@ -22,7 +22,7 @@ dev_dependencies: integration_test: path: ../../../integration_test test: any - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 flutter: uses-material-design: true @@ -32,5 +32,5 @@ flutter: - assets/bumble_bee_captions.srt environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 39289d159195..fedc46c721b1 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -version: 2.0.0-nullsafety.11 +version: 2.0.0 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: @@ -16,8 +16,8 @@ flutter: default_package: video_player_web dependencies: - meta: ^1.3.0-nullsafety.3 - video_player_platform_interface: ^4.0.0-nullsafety.0 + meta: ^1.3.0 + video_player_platform_interface: ^4.0.0 # The design on https://flutter.dev/go/federated-plugins was to leave # this constraint as "any". We cannot do it right now as it fails pub publish @@ -25,7 +25,7 @@ dependencies: # the constraints on the interface pins it. # TODO(amirh): Revisit this (either update this part in the design or the pub tool). # https://github.com/flutter/flutter/issues/46264 - video_player_web: ^2.0.0-nullsafety.1 + video_player_web: ^2.0.0 flutter: sdk: flutter @@ -33,9 +33,9 @@ dependencies: sdk: flutter dev_dependencies: - pedantic: ^1.10.0-nullsafety.1 - pigeon: ^0.1.19 + pedantic: ^1.10.0 + pigeon: ^0.1.21 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From f42e6c3ab292510acf3b929b14e392ec1fff7593 Mon Sep 17 00:00:00 2001 From: LI DONGZE Date: Wed, 24 Feb 2021 09:22:52 -0800 Subject: [PATCH 267/924] [url_launcher] Update result to `True` when the url was loaded successfully. (#3475) * Update FLTURLLauncherPlugin.m Update result to `True` when the url was loaded successfully. * Update pubspec.yaml * Update CHANGELOG.md * Undo the re-addition of pre-release changelogs. Co-authored-by: Ben Li Co-authored-by: stuartmorgan --- packages/url_launcher/url_launcher/CHANGELOG.md | 4 ++++ .../url_launcher/ios/Classes/FLTURLLauncherPlugin.m | 2 +- packages/url_launcher/url_launcher/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index f5fb73104c50..01f3e787fc9c 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.0.1 + +* Update result to `True` on iOS when the url was loaded successfully. + ## 6.0.0 * Migrate to null safety. diff --git a/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m b/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m index 39013b3ca039..ac05417473a3 100644 --- a/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m +++ b/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m @@ -34,7 +34,7 @@ - (instancetype)initWithUrl:url withFlutterResult:result { - (void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully API_AVAILABLE(ios(9.0)) { if (didLoadSuccessfully) { - self.flutterResult(nil); + self.flutterResult(@YES); } else { self.flutterResult([FlutterError errorWithCode:@"Error" diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index a9c2794b069a..4036748a2d2e 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 6.0.0 +version: 6.0.1 flutter: plugin: From 499156ed5f8b2d46e45dd0745f9e837ea9912b6f Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 24 Feb 2021 17:13:57 -0800 Subject: [PATCH 268/924] [quick_action] fix delegate methods not called on iOS (#3621) --- .cirrus.yml | 7 +- packages/quick_actions/CHANGELOG.md | 1 + .../ios/Runner.xcodeproj/project.pbxproj | 161 ++++++++++++++---- .../contents.xcworkspacedata | 7 - .../xcshareddata/xcschemes/Runner.xcscheme | 10 ++ .../xcschemes/RunnerUITests.xcscheme | 52 ++++++ .../example/ios/RunnerUITests/Info.plist | 22 +++ .../example/ios/RunnerUITests/RunnerUITests.m | 61 +++++++ packages/quick_actions/example/lib/main.dart | 10 +- .../ios/Classes/FLTQuickActionsPlugin.m | 1 + 10 files changed, 292 insertions(+), 40 deletions(-) delete mode 100644 packages/quick_actions/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme create mode 100644 packages/quick_actions/example/ios/RunnerUITests/Info.plist create mode 100644 packages/quick_actions/example/ios/RunnerUITests/RunnerUITests.m diff --git a/.cirrus.yml b/.cirrus.yml index 2b6ee2b7f969..6b3614178b11 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -183,7 +183,7 @@ task: - name: build-ipas+drive-examples env: PATH: $PATH:/usr/local/bin - PLUGINS_TO_SKIP_XCTESTS: "battery/battery,camera/camera,connectivity/connectivity,device_info/device_info,espresso,google_maps_flutter/google_maps_flutter,google_sign_in/google_sign_in,in_app_purchase,integration_test,ios_platform_images,local_auth,package_info,path_provider/path_provider,quick_actions,sensors,shared_preferences/shared_preferences,url_launcher/url_launcher,video_player/video_player,webview_flutter,wifi_info_flutter/wifi_info_flutter" + PLUGINS_TO_SKIP_XCTESTS: "battery/battery,camera/camera,connectivity/connectivity,device_info/device_info,espresso,google_maps_flutter/google_maps_flutter,google_sign_in/google_sign_in,in_app_purchase,integration_test,ios_platform_images,local_auth,package_info,path_provider/path_provider,sensors,shared_preferences/shared_preferences,url_launcher/url_launcher,video_player/video_player,webview_flutter,wifi_info_flutter/wifi_info_flutter" matrix: PLUGIN_SHARDING: "--shardIndex 0 --shardCount 4" PLUGIN_SHARDING: "--shardIndex 1 --shardCount 4" @@ -201,8 +201,11 @@ task: - flutter channel $CHANNEL - flutter upgrade - ./script/incremental_build.sh build-examples --ipa - - ./script/incremental_build.sh drive-examples --ios - ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=14.3" + # `drive-examples` contains integration tests, which changes the UI of the application. + # This UI change sometimes affects `xctest`. + # So we run `drive-examples` after `xctest`, changing the order will result ci failure. + - ./script/incremental_build.sh drive-examples --ios task: # Xcode 11 task diff --git a/packages/quick_actions/CHANGELOG.md b/packages/quick_actions/CHANGELOG.md index 1b6de34ca375..276ddfbf24c4 100644 --- a/packages/quick_actions/CHANGELOG.md +++ b/packages/quick_actions/CHANGELOG.md @@ -1,6 +1,7 @@ ## 0.5.0 * Migrate to null safety. +* Fixes quick actions not working on iOS. ## 0.4.0+12 diff --git a/packages/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj b/packages/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj index fdd275fcede5..dba32819ce42 100644 --- a/packages/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj @@ -9,11 +9,8 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 686BE83025E58CCF00862533 /* RunnerUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 686BE82F25E58CCF00862533 /* RunnerUITests.m */; }; 83C36CAF23D629E5ABE75B2A /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CCC799F2B0AB50A9C34344F0 /* libPods-Runner.a */; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -21,6 +18,16 @@ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 686BE83225E58CCF00862533 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -28,8 +35,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -40,14 +45,15 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 5278439583922091276A37C9 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 686BE82D25E58CCF00862533 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 686BE82F25E58CCF00862533 /* RunnerUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RunnerUITests.m; sourceTree = ""; }; + 686BE83125E58CCF00862533 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -59,12 +65,17 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 686BE82A25E58CCF00862533 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 83C36CAF23D629E5ABE75B2A /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -72,12 +83,19 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 686BE82E25E58CCF00862533 /* RunnerUITests */ = { + isa = PBXGroup; + children = ( + 686BE82F25E58CCF00862533 /* RunnerUITests.m */, + 686BE83125E58CCF00862533 /* Info.plist */, + ); + path = RunnerUITests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -90,6 +108,7 @@ children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, + 686BE82E25E58CCF00862533 /* RunnerUITests */, 97C146EF1CF9000F007C117D /* Products */, D0FE95BE2380323DD75CB891 /* Pods */, A44AD0D63DEF785A2A2DEE28 /* Frameworks */, @@ -100,6 +119,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 686BE82D25E58CCF00862533 /* RunnerUITests.xctest */, ); name = Products; sourceTree = ""; @@ -148,6 +168,24 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 686BE82C25E58CCF00862533 /* RunnerUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 686BE83625E58CCF00862533 /* Build configuration list for PBXNativeTarget "RunnerUITests" */; + buildPhases = ( + 686BE82925E58CCF00862533 /* Sources */, + 686BE82A25E58CCF00862533 /* Frameworks */, + 686BE82B25E58CCF00862533 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 686BE83325E58CCF00862533 /* PBXTargetDependency */, + ); + name = RunnerUITests; + productName = RunnerUITests; + productReference = 686BE82D25E58CCF00862533 /* RunnerUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -159,7 +197,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - FEDDF02AA7C2BA0D1905BD95 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -179,6 +216,11 @@ LastUpgradeCheck = 1100; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { + 686BE82C25E58CCF00862533 = { + CreatedOnToolsVersion = 12.4; + ProvisioningStyle = Automatic; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; }; @@ -198,11 +240,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 686BE82C25E58CCF00862533 /* RunnerUITests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 686BE82B25E58CCF00862533 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -229,7 +279,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -263,24 +313,17 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - FEDDF02AA7C2BA0D1905BD95 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 686BE82925E58CCF00862533 /* Sources */ = { + isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( + 686BE83025E58CCF00862533 /* RunnerUITests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -293,6 +336,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 686BE83325E58CCF00862533 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 686BE83225E58CCF00862533 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -313,9 +364,53 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 686BE83425E58CCF00862533 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = RunnerUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.google.RunnerUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Runner; + }; + name = Debug; + }; + 686BE83525E58CCF00862533 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = RunnerUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.google.RunnerUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Runner; + }; + name = Release; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -372,7 +467,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -466,6 +560,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 686BE83625E58CCF00862533 /* Build configuration list for PBXNativeTarget "RunnerUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 686BE83425E58CCF00862533 /* Debug */, + 686BE83525E58CCF00862533 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/packages/quick_actions/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/quick_actions/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16ed0f..000000000000 --- a/packages/quick_actions/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/packages/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 3bb3697ef41c..9850cc113026 100644 --- a/packages/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -37,6 +37,16 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/quick_actions/example/ios/RunnerUITests/Info.plist b/packages/quick_actions/example/ios/RunnerUITests/Info.plist new file mode 100644 index 000000000000..64d65ca49577 --- /dev/null +++ b/packages/quick_actions/example/ios/RunnerUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/packages/quick_actions/example/ios/RunnerUITests/RunnerUITests.m b/packages/quick_actions/example/ios/RunnerUITests/RunnerUITests.m new file mode 100644 index 000000000000..f78081b98a01 --- /dev/null +++ b/packages/quick_actions/example/ios/RunnerUITests/RunnerUITests.m @@ -0,0 +1,61 @@ +// Copyright 2019 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 +#import + +static const int kElementWaitingTime = 30; + +@interface RunnerUITests : XCTestCase + +@end + +@implementation RunnerUITests + +- (void)setUp { + [super setUp]; + self.continueAfterFailure = NO; +} + +- (void)testQuickAction { + XCUIApplication *app = [[XCUIApplication alloc] init]; + [app launch]; + XCUIElement *actionsReady = app.otherElements[@"actions ready"]; + if (![actionsReady waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find the actionsReady in the app with %@ seconds", + @(kElementWaitingTime)); + } + + [[XCUIDevice sharedDevice] pressButton:XCUIDeviceButtonHome]; + + XCUIApplication *springboard = + [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.springboard"]; + XCUIElement *quickActionsAppIcon = springboard.icons[@"quick_actions_example"]; + if (![quickActionsAppIcon waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", springboard.debugDescription); + XCTFail(@"Failed due to not able to find the example app from springboard with %@ seconds", + @(kElementWaitingTime)); + } + + [quickActionsAppIcon pressForDuration:2]; + XCUIElement *actionOne = springboard.buttons[@"Action one"]; + if (![actionOne waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", springboard.debugDescription); + XCTFail(@"Failed due to not able to find the actionOne button from springboard with %@ seconds", + @(kElementWaitingTime)); + } + + [actionOne tap]; + + XCUIElement *actionOneConfirmation = app.otherElements[@"action_one"]; + if (![actionOneConfirmation waitForExistenceWithTimeout:kElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", springboard.debugDescription); + XCTFail(@"Failed due to not able to find the actionOneConfirmation in the app with %@ seconds", + @(kElementWaitingTime)); + } + XCTAssertTrue(actionOneConfirmation.exists); +} + +@end diff --git a/packages/quick_actions/example/lib/main.dart b/packages/quick_actions/example/lib/main.dart index a7e9d5e4c031..08d8f4a1fbce 100644 --- a/packages/quick_actions/example/lib/main.dart +++ b/packages/quick_actions/example/lib/main.dart @@ -41,7 +41,9 @@ class _MyHomePageState extends State { final QuickActions quickActions = QuickActions(); quickActions.initialize((String shortcutType) { setState(() { - if (shortcutType != null) shortcut = shortcutType; + if (shortcutType != null) { + shortcut = shortcutType; + } }); }); @@ -59,7 +61,11 @@ class _MyHomePageState extends State { type: 'action_two', localizedTitle: 'Action two', icon: 'ic_launcher'), - ]); + ]).then((value) { + setState(() { + shortcut = "actions ready"; + }); + }); } @override diff --git a/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.m b/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.m index 88ff7397af8a..c99c016ed1ed 100644 --- a/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.m +++ b/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.m @@ -19,6 +19,7 @@ + (void)registerWithRegistrar:(NSObject *)registrar { FLTQuickActionsPlugin *instance = [[FLTQuickActionsPlugin alloc] init]; instance.channel = channel; [registrar addMethodCallDelegate:instance channel:channel]; + [registrar addApplicationDelegate:instance]; } - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { From 96faf2cff39d7ed65cc52222e5d22e9769311269 Mon Sep 17 00:00:00 2001 From: Darshan Rander Date: Thu, 25 Feb 2021 07:34:20 +0530 Subject: [PATCH 269/924] [file_selector_web] Migrated to null-safety (#3550) Co-authored-by: David Iglesias Teixeira --- .../file_selector_web/CHANGELOG.md | 4 + .../file_selector_web/example/README.md | 21 +++++ .../integration_test/dom_helper_test.dart | 16 ++-- .../file_selector_web_test.dart | 76 ++++++++++++------- .../file_selector_web/example/lib/main.dart | 25 ++++++ .../file_selector_web/example/pubspec.yaml | 21 +++++ .../run_test.sh} | 0 .../test_driver/integration_test.dart | 0 .../file_selector_web/example/web/index.html | 12 +++ .../lib/file_selector_web.dart | 34 ++++----- .../file_selector_web/lib/src/dom_helper.dart | 35 +++++---- .../file_selector_web/lib/src/utils.dart | 14 ++-- .../file_selector_web/pubspec.yaml | 16 ++-- .../test/more_tests_exist_elsewhere_test.dart | 10 +++ .../file_selector_web/test/utils_test.dart | 2 - 15 files changed, 199 insertions(+), 87 deletions(-) create mode 100644 packages/file_selector/file_selector_web/example/README.md rename packages/file_selector/file_selector_web/{ => example}/integration_test/dom_helper_test.dart (91%) rename packages/file_selector/file_selector_web/{ => example}/integration_test/file_selector_web_test.dart (59%) create mode 100644 packages/file_selector/file_selector_web/example/lib/main.dart create mode 100644 packages/file_selector/file_selector_web/example/pubspec.yaml rename packages/file_selector/file_selector_web/{run_integration_test => example/run_test.sh} (100%) rename packages/file_selector/file_selector_web/{ => example}/test_driver/integration_test.dart (100%) create mode 100644 packages/file_selector/file_selector_web/example/web/index.html create mode 100644 packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md index 619aa769d5f6..4caad4b975f9 100644 --- a/packages/file_selector/file_selector_web/CHANGELOG.md +++ b/packages/file_selector/file_selector_web/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.8.0 + +- Migrated to null-safety + # 0.7.0+1 - Add dummy `ios` dir, so flutter sdk can be lower than 1.20 diff --git a/packages/file_selector/file_selector_web/example/README.md b/packages/file_selector/file_selector_web/example/README.md new file mode 100644 index 000000000000..6187e55841c9 --- /dev/null +++ b/packages/file_selector/file_selector_web/example/README.md @@ -0,0 +1,21 @@ +# Testing + +This package utilizes the `integration_test` package to run its tests in a web browser. + +See [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests) for more info. + +## Running the tests + +Make sure you have updated to the latest Flutter master. + +1. Check what version of Chrome is running on the machine you're running tests on. + +2. Download and install driver for that version from here: + * + +3. Start the driver using `chromedriver --port=4444` + +4. Run tests: `flutter drive -d web-server --browser-name=chrome --driver=test_driver/integration_test.dart --target=integration_test/TEST_NAME.dart`, or (in Linux): + + * Single: `./run_test.sh integration_test/TEST_NAME.dart` + * All: `./run_test.sh` diff --git a/packages/file_selector/file_selector_web/integration_test/dom_helper_test.dart b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart similarity index 91% rename from packages/file_selector/file_selector_web/integration_test/dom_helper_test.dart rename to packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart index a942c0db10bf..274aed93659e 100644 --- a/packages/file_selector/file_selector_web/integration_test/dom_helper_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:html'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; @@ -11,19 +9,19 @@ import 'package:file_selector_web/src/dom_helper.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; void main() { - group('FileSelectorWeb', () { + group('dom_helper', () { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - DomHelper domHelper; - FileUploadInputElement input; + late DomHelper domHelper; + late FileUploadInputElement input; - FileList FileListItems(List files) { + FileList? createFileList(List files) { final dataTransfer = DataTransfer(); - files.forEach(dataTransfer.items.add); - return dataTransfer.files; + files.forEach(dataTransfer.items!.add); + return dataTransfer.files as FileList?; } void setFilesAndTriggerChange(List files) { - input.files = FileListItems(files); + input.files = createFileList(files); input.dispatchEvent(Event('change')); } diff --git a/packages/file_selector/file_selector_web/integration_test/file_selector_web_test.dart b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart similarity index 59% rename from packages/file_selector/file_selector_web/integration_test/file_selector_web_test.dart rename to packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart index abd31dd9fcc6..5442fedf5408 100644 --- a/packages/file_selector/file_selector_web/integration_test/file_selector_web_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart @@ -2,11 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - +import 'dart:html'; import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:integration_test/integration_test.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; import 'package:file_selector_web/file_selector_web.dart'; @@ -15,18 +13,18 @@ import 'package:file_selector_web/src/dom_helper.dart'; void main() { group('FileSelectorWeb', () { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - MockDomHelper mockDomHelper; - FileSelectorWeb plugin; - - setUp(() { - mockDomHelper = MockDomHelper(); - plugin = FileSelectorWeb(domHelper: mockDomHelper); - }); group('openFile', () { - final mockFile = createXFile('1001', 'identity.png'); - testWidgets('works', (WidgetTester _) async { + final mockFile = createXFile('1001', 'identity.png'); + + final mockDomHelper = MockDomHelper() + ..setFiles([mockFile]) + ..expectAccept('.jpg,.jpeg,image/png,image/*') + ..expectMultiple(false); + + final plugin = FileSelectorWeb(domHelper: mockDomHelper); + final typeGroup = XTypeGroup( label: 'images', extensions: ['jpg', 'jpeg'], @@ -34,11 +32,6 @@ void main() { webWildCards: ['image/*'], ); - when(mockDomHelper.getFiles( - accept: '.jpg,.jpeg,image/png,image/*', - multiple: false, - )).thenAnswer((_) async => [mockFile]); - final file = await plugin.openFile(acceptedTypeGroups: [typeGroup]); expect(file.name, mockFile.name); @@ -49,20 +42,22 @@ void main() { }); group('openFiles', () { - final mockFile1 = createXFile('123456', 'file1.txt'); - final mockFile2 = createXFile('', 'file2.txt'); - testWidgets('works', (WidgetTester _) async { + final mockFile1 = createXFile('123456', 'file1.txt'); + final mockFile2 = createXFile('', 'file2.txt'); + + final mockDomHelper = MockDomHelper() + ..setFiles([mockFile1, mockFile2]) + ..expectAccept('.txt') + ..expectMultiple(true); + + final plugin = FileSelectorWeb(domHelper: mockDomHelper); + final typeGroup = XTypeGroup( label: 'files', extensions: ['.txt'], ); - when(mockDomHelper.getFiles( - accept: '.txt', - multiple: true, - )).thenAnswer((_) async => [mockFile1, mockFile2]); - final files = await plugin.openFiles(acceptedTypeGroups: [typeGroup]); expect(files.length, 2); @@ -81,7 +76,36 @@ void main() { }); } -class MockDomHelper extends Mock implements DomHelper {} +class MockDomHelper implements DomHelper { + List _files = []; + String _expectedAccept = ''; + bool _expectedMultiple = false; + + @override + Future> getFiles({ + String accept = '', + bool multiple = false, + FileUploadInputElement? input, + }) { + expect(accept, _expectedAccept, + reason: 'Expected "accept" value does not match.'); + expect(multiple, _expectedMultiple, + reason: 'Expected "multiple" value does not match.'); + return Future.value(_files); + } + + void setFiles(List files) { + _files = files; + } + + void expectAccept(String accept) { + _expectedAccept = accept; + } + + void expectMultiple(bool multiple) { + _expectedMultiple = multiple; + } +} XFile createXFile(String content, String name) { final data = Uint8List.fromList(content.codeUnits); diff --git a/packages/file_selector/file_selector_web/example/lib/main.dart b/packages/file_selector/file_selector_web/example/lib/main.dart new file mode 100644 index 000000000000..e1a38dcdcd46 --- /dev/null +++ b/packages/file_selector/file_selector_web/example/lib/main.dart @@ -0,0 +1,25 @@ +// Copyright 2013 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/material.dart'; + +void main() { + runApp(MyApp()); +} + +/// App for testing +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + Widget build(BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: Text('Testing... Look at the console output for results!'), + ); + } +} diff --git a/packages/file_selector/file_selector_web/example/pubspec.yaml b/packages/file_selector/file_selector_web/example/pubspec.yaml new file mode 100644 index 000000000000..cae4b13a8207 --- /dev/null +++ b/packages/file_selector/file_selector_web/example/pubspec.yaml @@ -0,0 +1,21 @@ +name: file_selector_web_integration_tests +publish_to: none + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + build_runner: ^1.10.0 + file_selector_web: + path: ../ + flutter_driver: + sdk: flutter + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + +environment: + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.27.0-0" # For integration_test from sdk diff --git a/packages/file_selector/file_selector_web/run_integration_test b/packages/file_selector/file_selector_web/example/run_test.sh similarity index 100% rename from packages/file_selector/file_selector_web/run_integration_test rename to packages/file_selector/file_selector_web/example/run_test.sh diff --git a/packages/file_selector/file_selector_web/test_driver/integration_test.dart b/packages/file_selector/file_selector_web/example/test_driver/integration_test.dart similarity index 100% rename from packages/file_selector/file_selector_web/test_driver/integration_test.dart rename to packages/file_selector/file_selector_web/example/test_driver/integration_test.dart diff --git a/packages/file_selector/file_selector_web/example/web/index.html b/packages/file_selector/file_selector_web/example/web/index.html new file mode 100644 index 000000000000..dc8d0cfe0428 --- /dev/null +++ b/packages/file_selector/file_selector_web/example/web/index.html @@ -0,0 +1,12 @@ + + + + + Browser Tests + + + + + diff --git a/packages/file_selector/file_selector_web/lib/file_selector_web.dart b/packages/file_selector/file_selector_web/lib/file_selector_web.dart index 48f57ee880c8..1c411ca0a2f0 100644 --- a/packages/file_selector/file_selector_web/lib/file_selector_web.dart +++ b/packages/file_selector/file_selector_web/lib/file_selector_web.dart @@ -13,7 +13,7 @@ import 'package:file_selector_web/src/utils.dart'; /// /// This class implements the `package:file_selector` functionality for the web. class FileSelectorWeb extends FileSelectorPlatform { - final _domHelper; + final DomHelper _domHelper; /// Registers this class as the default instance of [FileSelectorPlatform]. static void registerWith(Registrar registrar) { @@ -23,14 +23,14 @@ class FileSelectorWeb extends FileSelectorPlatform { /// Default constructor, initializes _domHelper that we can use /// to interact with the DOM. /// overrides parameter allows for testing to override functions - FileSelectorWeb({@visibleForTesting DomHelper domHelper}) + FileSelectorWeb({@visibleForTesting DomHelper? domHelper}) : _domHelper = domHelper ?? DomHelper(); @override Future openFile({ - List acceptedTypeGroups, - String initialDirectory, - String confirmButtonText, + List? acceptedTypeGroups, + String? initialDirectory, + String? confirmButtonText, }) async { final files = await _openFiles(acceptedTypeGroups: acceptedTypeGroups); return files.first; @@ -38,31 +38,31 @@ class FileSelectorWeb extends FileSelectorPlatform { @override Future> openFiles({ - List acceptedTypeGroups, - String initialDirectory, - String confirmButtonText, + List? acceptedTypeGroups, + String? initialDirectory, + String? confirmButtonText, }) async { return _openFiles(acceptedTypeGroups: acceptedTypeGroups, multiple: true); } @override - Future getSavePath({ - List acceptedTypeGroups, - String initialDirectory, - String suggestedName, - String confirmButtonText, + Future getSavePath({ + List? acceptedTypeGroups, + String? initialDirectory, + String? suggestedName, + String? confirmButtonText, }) async => null; @override - Future getDirectoryPath({ - String initialDirectory, - String confirmButtonText, + Future getDirectoryPath({ + String? initialDirectory, + String? confirmButtonText, }) async => null; Future> _openFiles({ - List acceptedTypeGroups, + List? acceptedTypeGroups, bool multiple = false, }) async { final accept = acceptedTypesToString(acceptedTypeGroups); diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart index a965cebe97f9..5c578b6f4639 100644 --- a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart +++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart @@ -14,7 +14,7 @@ class DomHelper { /// Default constructor, initializes the container DOM element. DomHelper() { - final body = querySelector('body'); + final body = querySelector('body')!; body.children.add(_container); } @@ -22,42 +22,45 @@ class DomHelper { Future> getFiles({ String accept = '', bool multiple = false, - @visibleForTesting FileUploadInputElement input, + @visibleForTesting FileUploadInputElement? input, }) { - final Completer> _completer = Completer(); - input = input ?? FileUploadInputElement(); + final Completer> completer = Completer(); + final FileUploadInputElement inputElement = + input ?? FileUploadInputElement(); _container.children.add( - input + inputElement ..accept = accept ..multiple = multiple, ); - input.onChange.first.then((_) { - final List files = input.files.map(_convertFileToXFile).toList(); - input.remove(); - _completer.complete(files); + inputElement.onChange.first.then((_) { + final List files = + inputElement.files!.map(_convertFileToXFile).toList(); + inputElement.remove(); + completer.complete(files); }); - input.onError.first.then((event) { - final ErrorEvent error = event; + inputElement.onError.first.then((event) { + final ErrorEvent error = event as ErrorEvent; final platformException = PlatformException( code: error.type, message: error.message, ); - input.remove(); - _completer.completeError(platformException); + inputElement.remove(); + completer.completeError(platformException); }); - input.click(); + inputElement.click(); - return _completer.future; + return completer.future; } XFile _convertFileToXFile(File file) => XFile( Url.createObjectUrl(file), name: file.name, length: file.size, - lastModified: DateTime.fromMillisecondsSinceEpoch(file.lastModified), + lastModified: DateTime.fromMillisecondsSinceEpoch( + file.lastModified ?? DateTime.now().millisecondsSinceEpoch), ); } diff --git a/packages/file_selector/file_selector_web/lib/src/utils.dart b/packages/file_selector/file_selector_web/lib/src/utils.dart index 4ddd7ddcbda5..6be58c2aa0ec 100644 --- a/packages/file_selector/file_selector_web/lib/src/utils.dart +++ b/packages/file_selector/file_selector_web/lib/src/utils.dart @@ -5,19 +5,19 @@ import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; /// Convert list of XTypeGroups to a comma-separated string -String acceptedTypesToString(List acceptedTypes) { +String acceptedTypesToString(List? acceptedTypes) { if (acceptedTypes == null) return ''; final List allTypes = []; for (final group in acceptedTypes) { _assertTypeGroupIsValid(group); if (group.extensions != null) { - allTypes.addAll(group.extensions.map(_normalizeExtension)); + allTypes.addAll(group.extensions!.map(_normalizeExtension)); } if (group.mimeTypes != null) { - allTypes.addAll(group.mimeTypes); + allTypes.addAll(group.mimeTypes!); } if (group.webWildCards != null) { - allTypes.addAll(group.webWildCards); + allTypes.addAll(group.webWildCards!); } } return allTypes.join(','); @@ -26,9 +26,9 @@ String acceptedTypesToString(List acceptedTypes) { /// Make sure that at least one of its fields is populated. void _assertTypeGroupIsValid(XTypeGroup group) { assert( - !((group.extensions == null || group.extensions.isEmpty) && - (group.mimeTypes == null || group.mimeTypes.isEmpty) && - (group.webWildCards == null || group.webWildCards.isEmpty)), + !((group.extensions == null || group.extensions!.isEmpty) && + (group.mimeTypes == null || group.mimeTypes!.isEmpty) && + (group.webWildCards == null || group.webWildCards!.isEmpty)), 'At least one of extensions / mimeTypes / webWildCards is required for web.'); } diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml index a170d5f39607..55424a7a4c1c 100644 --- a/packages/file_selector/file_selector_web/pubspec.yaml +++ b/packages/file_selector/file_selector_web/pubspec.yaml @@ -1,7 +1,7 @@ name: file_selector_web description: Web platform implementation of file_selector homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_web -version: 0.7.0+1 +version: 0.8.0 flutter: plugin: @@ -11,22 +11,18 @@ flutter: fileName: file_selector_web.dart dependencies: - file_selector_platform_interface: ^1.0.2 - platform_detect: ^1.4.0 + file_selector_platform_interface: ^2.0.0 flutter: sdk: flutter flutter_web_plugins: sdk: flutter - meta: ^1.1.7 + meta: ^1.3.0 dev_dependencies: flutter_test: sdk: flutter - mockito: ^4.1.1 - pedantic: ^1.8.0 - integration_test: - path: ../../integration_test + pedantic: ^1.10.0 environment: - sdk: ">=2.2.0 <3.0.0" - flutter: ">=1.10.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart b/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart new file mode 100644 index 000000000000..e9faa3af4808 --- /dev/null +++ b/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart @@ -0,0 +1,10 @@ +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Tell the user where to find the real tests', () { + print('---'); + print('This package also uses integration_test to run additional tests.'); + print('See `example/README.md` for more info.'); + print('---'); + }); +} diff --git a/packages/file_selector/file_selector_web/test/utils_test.dart b/packages/file_selector/file_selector_web/test/utils_test.dart index 9fa187eede5b..e3e47c00f176 100644 --- a/packages/file_selector/file_selector_web/test/utils_test.dart +++ b/packages/file_selector/file_selector_web/test/utils_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'package:flutter_test/flutter_test.dart'; import 'package:file_selector_web/src/utils.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; From 82016374219b0433a3bf2de62e7f01f349d6c039 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 24 Feb 2021 18:49:33 -0800 Subject: [PATCH 270/924] [device_info] null safety stable (#3626) --- packages/device_info/device_info/CHANGELOG.md | 11 ++--------- packages/device_info/device_info/example/pubspec.yaml | 4 ++-- packages/device_info/device_info/pubspec.yaml | 10 +++++----- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/packages/device_info/device_info/CHANGELOG.md b/packages/device_info/device_info/CHANGELOG.md index 910d265b7c3e..f849131eff19 100644 --- a/packages/device_info/device_info/CHANGELOG.md +++ b/packages/device_info/device_info/CHANGELOG.md @@ -1,14 +1,7 @@ -## 2.0.0-nullsafety.2 - -* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 2.0.0-nullsafety.1 - -* Bump Dart SDK to support null safety. - -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. +* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) ## 1.0.1 diff --git a/packages/device_info/device_info/example/pubspec.yaml b/packages/device_info/device_info/example/pubspec.yaml index 1f636977c2a9..bc7d00ef87f0 100644 --- a/packages/device_info/device_info/example/pubspec.yaml +++ b/packages/device_info/device_info/example/pubspec.yaml @@ -17,11 +17,11 @@ dev_dependencies: sdk: flutter integration_test: path: ../../../integration_test - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.10.0-56.0.dev <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/device_info/device_info/pubspec.yaml b/packages/device_info/device_info/pubspec.yaml index bcdc7c8b54d1..0196338223a6 100644 --- a/packages/device_info/device_info/pubspec.yaml +++ b/packages/device_info/device_info/pubspec.yaml @@ -2,7 +2,7 @@ name: device_info description: Flutter plugin providing detailed information about the device (make, model, etc.), and Android or iOS version the app is running on. homepage: https://github.com/flutter/plugins/tree/master/packages/device_info -version: 2.0.0-nullsafety.2 +version: 2.0.0 flutter: plugin: @@ -16,13 +16,13 @@ flutter: dependencies: flutter: sdk: flutter - device_info_platform_interface: ^2.0.0-nullsafety.1 + device_info_platform_interface: ^2.0.0 dev_dependencies: - test: ^1.10.0-nullsafety.1 + test: ^1.16.3 flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From 494e9f912eb1976c34f59ee1fda7253364be281d Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Wed, 24 Feb 2021 20:01:03 -0800 Subject: [PATCH 271/924] [file_selector] Return a non-null value from getSavePath on web (#3630) --- packages/file_selector/file_selector_web/CHANGELOG.md | 5 +++++ .../example/integration_test/file_selector_web_test.dart | 8 ++++++++ .../file_selector_web/lib/file_selector_web.dart | 5 ++++- packages/file_selector/file_selector_web/pubspec.yaml | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md index 4caad4b975f9..3eb7c3b94494 100644 --- a/packages/file_selector/file_selector_web/CHANGELOG.md +++ b/packages/file_selector/file_selector_web/CHANGELOG.md @@ -1,3 +1,8 @@ +# 0.8.1 + +- Return a non-null value from `getSavePath` for consistency with + API expectations that null indicates canceling. + # 0.8.0 - Migrated to null-safety diff --git a/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart index 5442fedf5408..ea9569bf00a9 100644 --- a/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart @@ -73,6 +73,14 @@ void main() { expect(await files[1].lastModified(), isNotNull); }); }); + + group('getSavePath', () { + testWidgets('returns non-null', (WidgetTester _) async { + final plugin = FileSelectorWeb(); + final savePath = plugin.getSavePath(); + expect(await savePath, isNotNull); + }); + }); }); } diff --git a/packages/file_selector/file_selector_web/lib/file_selector_web.dart b/packages/file_selector/file_selector_web/lib/file_selector_web.dart index 1c411ca0a2f0..cf95e403effc 100644 --- a/packages/file_selector/file_selector_web/lib/file_selector_web.dart +++ b/packages/file_selector/file_selector_web/lib/file_selector_web.dart @@ -45,6 +45,9 @@ class FileSelectorWeb extends FileSelectorPlatform { return _openFiles(acceptedTypeGroups: acceptedTypeGroups, multiple: true); } + // This is intended to be passed to XFile, which ignores the path, but 'null' + // indicates a canceled save on other platforms, so provide a non-null dummy + // value. @override Future getSavePath({ List? acceptedTypeGroups, @@ -52,7 +55,7 @@ class FileSelectorWeb extends FileSelectorPlatform { String? suggestedName, String? confirmButtonText, }) async => - null; + ''; @override Future getDirectoryPath({ diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml index 55424a7a4c1c..17f0f476cbac 100644 --- a/packages/file_selector/file_selector_web/pubspec.yaml +++ b/packages/file_selector/file_selector_web/pubspec.yaml @@ -1,7 +1,7 @@ name: file_selector_web description: Web platform implementation of file_selector homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_web -version: 0.8.0 +version: 0.8.1 flutter: plugin: From 98e289b95733fe78287cc08c6d99fb70f55a2bf4 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Wed, 24 Feb 2021 20:17:34 -0800 Subject: [PATCH 272/924] [cross_file] Fix base class nullability (#3629) Without this, the dummy ("interface") XFile implementation of these properties has different nullability than the others, and the analyzer doesn't match what the runtime actually sees. --- packages/cross_file/CHANGELOG.md | 5 +++++ packages/cross_file/lib/src/types/base.dart | 4 ++-- packages/cross_file/pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md index 5bbb43f9e882..94bf4b29322a 100644 --- a/packages/cross_file/CHANGELOG.md +++ b/packages/cross_file/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.3.1 + +* Fix nullability of `XFileBase`'s `path` and `name` to match the + implementations to avoid potential analyzer issues. + ## 0.3.0 * Migrated package to null-safety. diff --git a/packages/cross_file/lib/src/types/base.dart b/packages/cross_file/lib/src/types/base.dart index 2a59c1c2b246..4522b7343c9b 100644 --- a/packages/cross_file/lib/src/types/base.dart +++ b/packages/cross_file/lib/src/types/base.dart @@ -31,14 +31,14 @@ abstract class XFileBase { /// Accessing the data contained in the picked file by its path /// is platform-dependant (and won't work on web), so use the /// byte getters in the CrossFile instance instead. - String? get path { + String get path { throw UnimplementedError('.path has not been implemented.'); } /// The name of the file as it was selected by the user in their device. /// /// Use only for cosmetic reasons, do not try to use this as a path. - String? get name { + String get name { throw UnimplementedError('.name has not been implemented.'); } diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml index 8e09b21d4536..66d3f46a84e3 100644 --- a/packages/cross_file/pubspec.yaml +++ b/packages/cross_file/pubspec.yaml @@ -1,7 +1,7 @@ name: cross_file description: An abstraction to allow working with files across multiple platforms. homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file -version: 0.3.0 +version: 0.3.1 dependencies: flutter: From bc11badd441bebe2a28f8e9d5c63effae8eb133b Mon Sep 17 00:00:00 2001 From: Rahul Raj <64.rahulraj@gmail.com> Date: Thu, 25 Feb 2021 10:45:42 +0530 Subject: [PATCH 273/924] [in_app_purchase] Add support for InApp subscription upgrade/downgrade (#2822) --- AUTHORS | 1 + packages/in_app_purchase/CHANGELOG.md | 4 + packages/in_app_purchase/README.md | 24 +++ .../inapppurchase/MethodCallHandlerImpl.java | 50 +++++- packages/in_app_purchase/example/README.md | 3 +- .../inapppurchase/MethodCallHandlerTest.java | 167 +++++++++++++++++- .../in_app_purchase/example/lib/main.dart | 43 ++++- .../billing_client_wrapper.dart | 55 +++++- .../enum_converters.dart | 22 +++ .../enum_converters.g.dart | 13 +- .../in_app_purchase/app_store_connection.dart | 9 + .../google_play_connection.dart | 6 +- .../src/in_app_purchase/purchase_details.dart | 35 +++- packages/in_app_purchase/pubspec.yaml | 2 +- .../billing_client_wrapper_test.dart | 58 ++++++ .../purchase_wrapper_test.dart | 14 ++ 16 files changed, 491 insertions(+), 15 deletions(-) diff --git a/AUTHORS b/AUTHORS index 1f2b9cba2f16..dbf9d190931b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -62,3 +62,4 @@ Juan Alvarez Aleksandr Yurkovskiy Anton Borries Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index 79f64d5bda53..0dbc2427ccd6 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.1 + +* Support InApp subscription upgrade/downgrade. + ## 0.4.0 * Migrate to nullsafety. diff --git a/packages/in_app_purchase/README.md b/packages/in_app_purchase/README.md index 431f2810c165..321864b2a233 100644 --- a/packages/in_app_purchase/README.md +++ b/packages/in_app_purchase/README.md @@ -178,6 +178,30 @@ and `AppStore` that the purchase has been finished. WARNING! Failure to call `InAppPurchaseConnection.completePurchase` and get a successful response within 3 days of the purchase will result a refund. +### Upgrading or Downgrading an existing InApp Subscription + +In order to upgrade/downgrade an existing InApp subscription on `PlayStore`, +you need to provide an instance of `ChangeSubscriptionParam` with the old +`PurchaseDetails` that the user needs to migrate from, and an optional `ProrationMode` +with the `PurchaseParam` object while calling `InAppPurchaseConnection.buyNonConsumable`. +`AppStore` does not require this since they provides a subscription grouping mechanism. +Each subscription you offer must be assigned to a subscription group. +So the developers can group related subscriptions together to prevents users from +accidentally purchasing multiple subscriptions. +Please refer to the 'Creating a Subscription Group' sections of [Apple's subscription guide](https://developer.apple.com/app-store/subscriptions/) + + +```dart +final PurchaseDetails oldPurchaseDetails = ...; +PurchaseParam purchaseParam = PurchaseParam( + productDetails: productDetails, + changeSubscriptionParam: ChangeSubscriptionParam( + oldPurchaseDetails: oldPurchaseDetails, + prorationMode: ProrationMode.immediateWithTimeProration)); +InAppPurchaseConnection.instance + .buyNonConsumable(purchaseParam: purchaseParam); +``` + ## Development This plugin uses diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java index f1e715e239a2..58d077673a03 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java @@ -20,6 +20,7 @@ import com.android.billingclient.api.BillingClient; import com.android.billingclient.api.BillingClientStateListener; import com.android.billingclient.api.BillingFlowParams; +import com.android.billingclient.api.BillingFlowParams.ProrationMode; import com.android.billingclient.api.BillingResult; import com.android.billingclient.api.ConsumeParams; import com.android.billingclient.api.ConsumeResponseListener; @@ -39,6 +40,8 @@ class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler, Application.ActivityLifecycleCallbacks { private static final String TAG = "InAppPurchasePlugin"; + private static final String LOAD_SKU_DOC_URL = + "https://github.com/flutter/plugins/blob/master/packages/in_app_purchase/README.md#loading-products-for-sale"; @Nullable private BillingClient billingClient; private final BillingClientFactory billingClientFactory; @@ -120,7 +123,13 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { break; case InAppPurchasePlugin.MethodNames.LAUNCH_BILLING_FLOW: launchBillingFlow( - (String) call.argument("sku"), (String) call.argument("accountId"), result); + (String) call.argument("sku"), + (String) call.argument("accountId"), + (String) call.argument("oldSku"), + call.hasArgument("prorationMode") + ? (int) call.argument("prorationMode") + : ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, + result); break; case InAppPurchasePlugin.MethodNames.QUERY_PURCHASES: queryPurchases((String) call.argument("skuType"), result); @@ -189,7 +198,11 @@ public void onSkuDetailsResponse( } private void launchBillingFlow( - String sku, @Nullable String accountId, MethodChannel.Result result) { + String sku, + @Nullable String accountId, + @Nullable String oldSku, + int prorationMode, + MethodChannel.Result result) { if (billingClientError(result)) { return; } @@ -198,7 +211,26 @@ private void launchBillingFlow( if (skuDetails == null) { result.error( "NOT_FOUND", - "Details for sku " + sku + " are not available. Has this ID already been fetched?", + String.format( + "Details for sku %s are not available. It might because skus were not fetched prior to the call. Please fetch the skus first. An example of how to fetch the skus could be found here: %s", + sku, LOAD_SKU_DOC_URL), + null); + return; + } + + if (oldSku == null + && prorationMode != ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY) { + result.error( + "IN_APP_PURCHASE_REQUIRE_OLD_SKU", + "launchBillingFlow failed because oldSku is null. You must provide a valid oldSku in order to use a proration mode.", + null); + return; + } else if (oldSku != null && !cachedSkus.containsKey(oldSku)) { + result.error( + "IN_APP_PURCHASE_INVALID_OLD_SKU", + String.format( + "Details for sku %s are not available. It might because skus were not fetched prior to the call. Please fetch the skus first. An example of how to fetch the skus could be found here: %s", + oldSku, LOAD_SKU_DOC_URL), null); return; } @@ -218,6 +250,12 @@ private void launchBillingFlow( if (accountId != null && !accountId.isEmpty()) { paramsBuilder.setAccountId(accountId); } + if (oldSku != null && !oldSku.isEmpty()) { + paramsBuilder.setOldSku(oldSku); + } + // The proration mode value has to match one of the following declared in + // https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode + paramsBuilder.setReplaceSkusProrationMode(prorationMode); result.success( Translator.fromBillingResult( billingClient.launchBillingFlow(activity, paramsBuilder.build()))); @@ -252,7 +290,8 @@ private void queryPurchases(String skuType, MethodChannel.Result result) { return; } - // Like in our connect call, consider the billing client responding a "success" here regardless of status code. + // Like in our connect call, consider the billing client responding a "success" here regardless + // of status code. result.success(fromPurchasesResult(billingClient.queryPurchases(skuType))); } @@ -295,7 +334,8 @@ public void onBillingSetupFinished(BillingResult billingResult) { return; } alreadyFinished = true; - // Consider the fact that we've finished a success, leave it to the Dart side to validate the responseCode. + // Consider the fact that we've finished a success, leave it to the Dart side to + // validate the responseCode. result.success(Translator.fromBillingResult(billingResult)); } diff --git a/packages/in_app_purchase/example/README.md b/packages/in_app_purchase/example/README.md index 9fcad23d19ae..6dd5b38d7003 100644 --- a/packages/in_app_purchase/example/README.md +++ b/packages/in_app_purchase/example/README.md @@ -30,7 +30,8 @@ below. - `consumable`: A managed product. - `upgrade`: A managed product. - - `subscription`: A subscription. + - `subscription_silver`: A lower level subscription. + - `subscription_gold`: A higher level subscription. Make sure that all of the products are set to `ACTIVE`. diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java index c6a9b4114a75..cc7bc4a9b9b1 100644 --- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java +++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java @@ -18,6 +18,7 @@ import static io.flutter.plugins.inapppurchase.Translator.fromSkuDetailsList; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; +import static java.util.Collections.unmodifiableList; import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -261,7 +262,7 @@ public void querySkuDetailsAsync_clientDisconnected() { } @Test - public void launchBillingFlow_ok_nullAccountId() { + public void launchBillingFlow_ok_null_AccountId() { // Fetch the sku details first and then prepare the launch billing flow call String skuId = "foo"; queryForSkus(singletonList(skuId)); @@ -292,6 +293,40 @@ public void launchBillingFlow_ok_nullAccountId() { verify(result, times(1)).success(fromBillingResult(billingResult)); } + @Test + public void launchBillingFlow_ok_null_OldSku() { + // Fetch the sku details first and then prepare the launch billing flow call + String skuId = "foo"; + String accountId = "account"; + queryForSkus(singletonList(skuId)); + HashMap arguments = new HashMap<>(); + arguments.put("sku", skuId); + arguments.put("accountId", accountId); + arguments.put("oldSku", null); + MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments); + + // Launch the billing flow + BillingResult billingResult = + BillingResult.newBuilder() + .setResponseCode(100) + .setDebugMessage("dummy debug message") + .build(); + when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult); + methodChannelHandler.onMethodCall(launchCall, result); + + // Verify we pass the arguments to the billing flow + ArgumentCaptor billingFlowParamsCaptor = + ArgumentCaptor.forClass(BillingFlowParams.class); + verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); + BillingFlowParams params = billingFlowParamsCaptor.getValue(); + assertEquals(params.getSku(), skuId); + assertEquals(params.getAccountId(), accountId); + assertNull(params.getOldSku()); + // Verify we pass the response code to result + verify(result, never()).error(any(), any(), any()); + verify(result, times(1)).success(fromBillingResult(billingResult)); + } + @Test public void launchBillingFlow_ok_null_Activity() { methodChannelHandler.setActivity(null); @@ -311,6 +346,42 @@ public void launchBillingFlow_ok_null_Activity() { verify(result, never()).success(any()); } + @Test + public void launchBillingFlow_ok_oldSku() { + // Fetch the sku details first and query the method call + String skuId = "foo"; + String accountId = "account"; + String oldSkuId = "oldFoo"; + queryForSkus(unmodifiableList(asList(skuId, oldSkuId))); + HashMap arguments = new HashMap<>(); + arguments.put("sku", skuId); + arguments.put("accountId", accountId); + arguments.put("oldSku", oldSkuId); + MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments); + + // Launch the billing flow + BillingResult billingResult = + BillingResult.newBuilder() + .setResponseCode(100) + .setDebugMessage("dummy debug message") + .build(); + when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult); + methodChannelHandler.onMethodCall(launchCall, result); + + // Verify we pass the arguments to the billing flow + ArgumentCaptor billingFlowParamsCaptor = + ArgumentCaptor.forClass(BillingFlowParams.class); + verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); + BillingFlowParams params = billingFlowParamsCaptor.getValue(); + assertEquals(params.getSku(), skuId); + assertEquals(params.getAccountId(), accountId); + assertEquals(params.getOldSku(), oldSkuId); + + // Verify we pass the response code to result + verify(result, never()).error(any(), any(), any()); + verify(result, times(1)).success(fromBillingResult(billingResult)); + } + @Test public void launchBillingFlow_ok_AccountId() { // Fetch the sku details first and query the method call @@ -344,6 +415,79 @@ public void launchBillingFlow_ok_AccountId() { verify(result, times(1)).success(fromBillingResult(billingResult)); } + @Test + public void launchBillingFlow_ok_Proration() { + // Fetch the sku details first and query the method call + String skuId = "foo"; + String oldSkuId = "oldFoo"; + String accountId = "account"; + int prorationMode = BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE; + queryForSkus(unmodifiableList(asList(skuId, oldSkuId))); + HashMap arguments = new HashMap<>(); + arguments.put("sku", skuId); + arguments.put("accountId", accountId); + arguments.put("oldSku", oldSkuId); + arguments.put("prorationMode", prorationMode); + MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments); + + // Launch the billing flow + BillingResult billingResult = + BillingResult.newBuilder() + .setResponseCode(100) + .setDebugMessage("dummy debug message") + .build(); + when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult); + methodChannelHandler.onMethodCall(launchCall, result); + + // Verify we pass the arguments to the billing flow + ArgumentCaptor billingFlowParamsCaptor = + ArgumentCaptor.forClass(BillingFlowParams.class); + verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); + BillingFlowParams params = billingFlowParamsCaptor.getValue(); + assertEquals(params.getSku(), skuId); + assertEquals(params.getAccountId(), accountId); + assertEquals(params.getOldSku(), oldSkuId); + assertEquals(params.getReplaceSkusProrationMode(), prorationMode); + + // Verify we pass the response code to result + verify(result, never()).error(any(), any(), any()); + verify(result, times(1)).success(fromBillingResult(billingResult)); + } + + @Test + public void launchBillingFlow_ok_Proration_with_null_OldSku() { + // Fetch the sku details first and query the method call + String skuId = "foo"; + String accountId = "account"; + String queryOldSkuId = "oldFoo"; + String oldSkuId = null; + int prorationMode = BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE; + queryForSkus(unmodifiableList(asList(skuId, queryOldSkuId))); + HashMap arguments = new HashMap<>(); + arguments.put("sku", skuId); + arguments.put("accountId", accountId); + arguments.put("oldSku", oldSkuId); + arguments.put("prorationMode", prorationMode); + MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments); + + // Launch the billing flow + BillingResult billingResult = + BillingResult.newBuilder() + .setResponseCode(100) + .setDebugMessage("dummy debug message") + .build(); + when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult); + methodChannelHandler.onMethodCall(launchCall, result); + + // Assert that we sent an error back. + verify(result) + .error( + contains("IN_APP_PURCHASE_REQUIRE_OLD_SKU"), + contains("launchBillingFlow failed because oldSku is null"), + any()); + verify(result, never()).success(any()); + } + @Test public void launchBillingFlow_clientDisconnected() { // Prepare the launch call after disconnecting the client @@ -381,6 +525,27 @@ public void launchBillingFlow_skuNotFound() { verify(result, never()).success(any()); } + @Test + public void launchBillingFlow_oldSkuNotFound() { + // Try to launch the billing flow for a random sku ID + establishConnectedBillingClient(null, null); + String skuId = "foo"; + String accountId = "account"; + String oldSkuId = "oldSku"; + queryForSkus(singletonList(skuId)); + HashMap arguments = new HashMap<>(); + arguments.put("sku", skuId); + arguments.put("accountId", accountId); + arguments.put("oldSku", oldSkuId); + MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments); + + methodChannelHandler.onMethodCall(launchCall, result); + + // Assert that we sent an error back. + verify(result).error(contains("IN_APP_PURCHASE_INVALID_OLD_SKU"), contains(oldSkuId), any()); + verify(result, never()).success(any()); + } + @Test public void queryPurchases() { establishConnectedBillingClient(null, null); diff --git a/packages/in_app_purchase/example/lib/main.dart b/packages/in_app_purchase/example/lib/main.dart index 82cd509b30be..c9f0bb6ece25 100644 --- a/packages/in_app_purchase/example/lib/main.dart +++ b/packages/in_app_purchase/example/lib/main.dart @@ -19,10 +19,14 @@ void main() { const bool _kAutoConsume = true; const String _kConsumableId = 'consumable'; +const String _kUpgradeId = 'upgrade'; +const String _kSilverSubscriptionId = 'subscription_silver'; +const String _kGoldSubscriptionId = 'subscription_gold'; const List _kProductIds = [ _kConsumableId, - 'upgrade', - 'subscription' + _kUpgradeId, + _kSilverSubscriptionId, + _kGoldSubscriptionId, ]; class _MyApp extends StatefulWidget { @@ -252,9 +256,22 @@ class _MyAppState extends State<_MyApp> { primary: Colors.white, ), onPressed: () { + // NOTE: If you are making a subscription purchase/upgrade/downgrade, we recommend you to + // verify the latest status of you your subscription by using server side receipt validation + // and update the UI accordingly. The subscription purchase status shown + // inside the app may not be accurate. + final oldSubscription = + _getOldSubscription(productDetails, purchases); PurchaseParam purchaseParam = PurchaseParam( productDetails: productDetails, - applicationUserName: null); + applicationUserName: null, + changeSubscriptionParam: Platform.isAndroid && + oldSubscription != null + ? ChangeSubscriptionParam( + oldPurchaseDetails: oldSubscription, + prorationMode: + ProrationMode.immediateWithTimeProration) + : null); if (productDetails.id == _kConsumableId) { _connection.buyConsumable( purchaseParam: purchaseParam, @@ -387,4 +404,24 @@ class _MyAppState extends State<_MyApp> { } }); } + + PurchaseDetails? _getOldSubscription( + ProductDetails productDetails, Map purchases) { + // This is just to demonstrate a subscription upgrade or downgrade. + // This method assumes that you have only 2 subscriptions under a group, 'subscription_silver' & 'subscription_gold'. + // The 'subscription_silver' subscription can be upgraded to 'subscription_gold' and + // the 'subscription_gold' subscription can be downgraded to 'subscription_silver'. + // Please remember to replace the logic of finding the old subscription Id as per your app. + // The old subscription is only required on Android since Apple handles this internally + // by using the subscription group feature in iTunesConnect. + PurchaseDetails? oldSubscription; + if (productDetails.id == _kSilverSubscriptionId && + purchases[_kGoldSubscriptionId] != null) { + oldSubscription = purchases[_kGoldSubscriptionId]; + } else if (productDetails.id == _kGoldSubscriptionId && + purchases[_kSilverSubscriptionId] != null) { + oldSubscription = purchases[_kSilverSubscriptionId]; + } + return oldSubscription; + } } diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart index 9f96c05e15f9..a0ba91556094 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart @@ -173,12 +173,25 @@ class BillingClient { /// skuDetails](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder.html#setskudetails) /// and [the given /// accountId](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder.html#setAccountId(java.lang.String)). + /// + /// When this method is called to purchase a subscription, an optional `oldSku` + /// can be passed in. This will tell Google Play that rather than purchasing a new subscription, + /// the user needs to upgrade/downgrade the existing subscription. + /// The [oldSku](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setoldsku) is the SKU id that the user is upgrading or downgrading from. + /// The [prorationMode](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setreplaceskusprorationmode) is the mode of proration during subscription upgrade/downgrade. + /// This value will only be effective if the `oldSku` is also set. Future launchBillingFlow( - {required String sku, String? accountId}) async { + {required String sku, + String? accountId, + String? oldSku, + ProrationMode? prorationMode}) async { assert(sku != null); final Map arguments = { 'sku': sku, 'accountId': accountId, + 'oldSku': oldSku, + 'prorationMode': ProrationModeConverter().toJson(prorationMode ?? + ProrationMode.unknownSubscriptionUpgradeDowngradePolicy) }; return BillingResultWrapper.fromJson( (await channel.invokeMapMethod( @@ -390,3 +403,43 @@ enum SkuType { @JsonValue('subs') subs, } + +/// Enum representing the proration mode. +/// +/// When upgrading or downgrading a subscription, set this mode to provide details +/// about the proration that will be applied when the subscription changes. +/// +/// Wraps [`BillingFlowParams.ProrationMode`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode) +/// See the linked documentation for an explanation of the different constants. +enum ProrationMode { +// WARNING: Changes to this class need to be reflected in our generated code. +// Run `flutter packages pub run build_runner watch` to rebuild and watch for +// further changes. + + /// Unknown upgrade or downgrade policy. + @JsonValue(0) + unknownSubscriptionUpgradeDowngradePolicy, + + /// Replacement takes effect immediately, and the remaining time will be prorated and credited to the user. + /// + /// This is the current default behavior. + @JsonValue(1) + immediateWithTimeProration, + + /// Replacement takes effect immediately, and the billing cycle remains the same. + /// + /// The price for the remaining period will be charged. + /// This option is only available for subscription upgrade. + @JsonValue(2) + immediateAndChargeProratedPrice, + + /// Replacement takes effect immediately, and the new price will be charged on next recurrence time. + /// + /// The billing cycle stays the same. + @JsonValue(3) + immediateWithoutProration, + + /// Replacement takes effect when the old plan expires, and the new price will be charged at the same time. + @JsonValue(4) + deferred, +} diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart index 30828d8882a7..469d71b63637 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart @@ -50,12 +50,34 @@ class SkuTypeConverter implements JsonConverter { String toJson(SkuType object) => _$SkuTypeEnumMap[object]!; } +/// Serializer for [ProrationMode]. +/// +/// Use these in `@JsonSerializable()` classes by annotating them with +/// `@ProrationModeConverter()`. +class ProrationModeConverter implements JsonConverter { + /// Default const constructor. + const ProrationModeConverter(); + + @override + ProrationMode fromJson(int? json) { + if (json == null) { + return ProrationMode.unknownSubscriptionUpgradeDowngradePolicy; + } + return _$enumDecode( + _$ProrationModeEnumMap.cast(), json); + } + + @override + int toJson(ProrationMode object) => _$ProrationModeEnumMap[object]!; +} + // Define a class so we generate serializer helper methods for the enums @JsonSerializable() class _SerializedEnums { late BillingResponse response; late SkuType type; late PurchaseStateWrapper purchaseState; + late ProrationMode prorationMode; } /// Serializer for [PurchaseStateWrapper]. diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart index 5d59dd8888b7..4186a2a24252 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart @@ -11,7 +11,9 @@ _SerializedEnums _$_SerializedEnumsFromJson(Map json) { ..response = _$enumDecode(_$BillingResponseEnumMap, json['response']) ..type = _$enumDecode(_$SkuTypeEnumMap, json['type']) ..purchaseState = - _$enumDecode(_$PurchaseStateWrapperEnumMap, json['purchaseState']); + _$enumDecode(_$PurchaseStateWrapperEnumMap, json['purchaseState']) + ..prorationMode = + _$enumDecode(_$ProrationModeEnumMap, json['prorationMode']); } Map _$_SerializedEnumsToJson(_SerializedEnums instance) => @@ -19,6 +21,7 @@ Map _$_SerializedEnumsToJson(_SerializedEnums instance) => 'response': _$BillingResponseEnumMap[instance.response], 'type': _$SkuTypeEnumMap[instance.type], 'purchaseState': _$PurchaseStateWrapperEnumMap[instance.purchaseState], + 'prorationMode': _$ProrationModeEnumMap[instance.prorationMode], }; K _$enumDecode( @@ -72,3 +75,11 @@ const _$PurchaseStateWrapperEnumMap = { PurchaseStateWrapper.purchased: 1, PurchaseStateWrapper.pending: 2, }; + +const _$ProrationModeEnumMap = { + ProrationMode.unknownSubscriptionUpgradeDowngradePolicy: 0, + ProrationMode.immediateWithTimeProration: 1, + ProrationMode.immediateAndChargeProratedPrice: 2, + ProrationMode.immediateWithoutProration: 3, + ProrationMode.deferred: 4, +}; diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index 50560a666a40..d4601fd809db 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -56,6 +56,15 @@ class AppStoreConnection implements InAppPurchaseConnection { @override Future buyNonConsumable({required PurchaseParam purchaseParam}) async { + assert( + purchaseParam.changeSubscriptionParam == null, + "`purchaseParam.changeSubscriptionParam` must be null. It is not supported on iOS " + "as Apple provides a subscription grouping mechanism. " + "Each subscription you offer must be assigned to a subscription group. " + "So the developers can group related subscriptions together to prevents users " + "from accidentally purchasing multiple subscriptions. " + "Please refer to the 'Creating a Subscription Group' sections of " + "Apple's subscription guide (https://developer.apple.com/app-store/subscriptions/)"); await _skPaymentQueueWrapper.addPayment(SKPaymentWrapper( productIdentifier: purchaseParam.productDetails.id, quantity: 1, diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart index ef0b7d2efa59..1a47f3ebd095 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart @@ -63,7 +63,11 @@ class GooglePlayConnection BillingResultWrapper billingResultWrapper = await billingClient.launchBillingFlow( sku: purchaseParam.productDetails.id, - accountId: purchaseParam.applicationUserName); + accountId: purchaseParam.applicationUserName, + oldSku: purchaseParam + .changeSubscriptionParam?.oldPurchaseDetails.productID, + prorationMode: + purchaseParam.changeSubscriptionParam?.prorationMode); return billingResultWrapper.responseCode == BillingResponse.ok; } diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart b/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart index c211d2a4cdb8..b4a509055f14 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart @@ -90,7 +90,8 @@ class PurchaseParam { {required this.productDetails, this.applicationUserName, this.sandboxTesting = false, - this.simulatesAskToBuyInSandbox = false}); + this.simulatesAskToBuyInSandbox = false, + this.changeSubscriptionParam}); /// The product to create payment for. /// @@ -117,6 +118,38 @@ class PurchaseParam { /// /// See also [SKPaymentWrapper.simulatesAskToBuyInSandbox]. final bool simulatesAskToBuyInSandbox; + + /// The 'changeSubscriptionParam' is only available on Android, for upgrading or + /// downgrading an existing subscription. + /// + /// This does not require on iOS since Apple provides a way to group related subscriptions + /// together in iTunesConnect. So when a subscription upgrade or downgrade is requested, + /// Apple finds the old subscription details from the group and handle it automatically. + final ChangeSubscriptionParam? changeSubscriptionParam; +} + +/// This parameter object which is only applicable on Android for upgrading or downgrading an existing subscription. +/// +/// This does not require on iOS since iTunesConnect provides a subscription grouping mechanism. +/// Each subscription you offer must be assigned to a subscription group. +/// So the developers can group related subscriptions together to prevent users from +/// accidentally purchasing multiple subscriptions. +/// +/// Please refer to the 'Creating a Subscription Group' sections of [Apple's subscription guide](https://developer.apple.com/app-store/subscriptions/) +class ChangeSubscriptionParam { + /// Creates a new change subscription param object with given data + ChangeSubscriptionParam( + {required this.oldPurchaseDetails, this.prorationMode}); + + /// The purchase object of the existing subscription that the user needs to + /// upgrade/downgrade from. + final PurchaseDetails oldPurchaseDetails; + + /// The proration mode. + /// + /// This is an optional parameter that indicates how to handle the existing + /// subscription when the new subscription comes into effect. + final ProrationMode? prorationMode; } /// Represents the transaction details of a purchase. diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index f847a81291be..6175e8cbf1dc 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.4.0 +version: 0.4.1 dependencies: flutter: diff --git a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart index d415007284c8..3aa62ddd96a1 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart @@ -207,6 +207,64 @@ void main() { expect(arguments['accountId'], equals(accountId)); }); + test( + 'serializes and deserializes data on change subscription without proration', + () async { + const String debugMessage = 'dummy message'; + final BillingResponse responseCode = BillingResponse.ok; + final BillingResultWrapper expectedBillingResult = BillingResultWrapper( + responseCode: responseCode, debugMessage: debugMessage); + stubPlatform.addResponse( + name: launchMethodName, + value: buildBillingResultMap(expectedBillingResult), + ); + final SkuDetailsWrapper skuDetails = dummySkuDetails; + final String accountId = "hashedAccountId"; + + expect( + await billingClient.launchBillingFlow( + sku: skuDetails.sku, + accountId: accountId, + oldSku: dummyOldPurchase.sku), + equals(expectedBillingResult)); + Map arguments = + stubPlatform.previousCallMatching(launchMethodName).arguments; + expect(arguments['sku'], equals(skuDetails.sku)); + expect(arguments['accountId'], equals(accountId)); + expect(arguments['oldSku'], equals(dummyOldPurchase.sku)); + }); + + test( + 'serializes and deserializes data on change subscription with proration', + () async { + const String debugMessage = 'dummy message'; + final BillingResponse responseCode = BillingResponse.ok; + final BillingResultWrapper expectedBillingResult = BillingResultWrapper( + responseCode: responseCode, debugMessage: debugMessage); + stubPlatform.addResponse( + name: launchMethodName, + value: buildBillingResultMap(expectedBillingResult), + ); + final SkuDetailsWrapper skuDetails = dummySkuDetails; + final String accountId = "hashedAccountId"; + final prorationMode = ProrationMode.immediateAndChargeProratedPrice; + + expect( + await billingClient.launchBillingFlow( + sku: skuDetails.sku, + accountId: accountId, + oldSku: dummyOldPurchase.sku, + prorationMode: prorationMode), + equals(expectedBillingResult)); + Map arguments = + stubPlatform.previousCallMatching(launchMethodName).arguments; + expect(arguments['sku'], equals(skuDetails.sku)); + expect(arguments['accountId'], equals(accountId)); + expect(arguments['oldSku'], equals(dummyOldPurchase.sku)); + expect(arguments['prorationMode'], + ProrationModeConverter().toJson(prorationMode)); + }); + test('handles null accountId', () async { const String debugMessage = 'dummy message'; final BillingResponse responseCode = BillingResponse.ok; diff --git a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart index 7f3de2742603..df5b8f5bde22 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart @@ -46,6 +46,20 @@ final PurchaseHistoryRecordWrapper dummyPurchaseHistoryRecord = developerPayload: 'dummy payload', ); +final PurchaseWrapper dummyOldPurchase = PurchaseWrapper( + orderId: 'oldOrderId', + packageName: 'oldPackageName', + purchaseTime: 0, + signature: 'oldSignature', + sku: 'oldSku', + purchaseToken: 'oldPurchaseToken', + isAutoRenewing: false, + originalJson: '', + developerPayload: 'old dummy payload', + isAcknowledged: true, + purchaseState: PurchaseStateWrapper.purchased, +); + void main() { group('PurchaseWrapper', () { test('converts from map', () { From a109b3c76fd01c3e09befe6535c7331d4a79543d Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 24 Feb 2021 21:39:20 -0800 Subject: [PATCH 274/924] [wifi_info_flutter] null safety stable (#3627) --- packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md | 2 +- .../wifi_info_flutter/example/lib/main.dart | 8 ++++---- .../wifi_info_flutter/example/pubspec.yaml | 5 ++--- .../test_driver/integration_test/wifi_info_test.dart | 1 + .../example/test_driver/test/integration_test.dart | 1 + packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml | 6 +++--- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md b/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md index c98140eedcf0..c76009ec95fb 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md +++ b/packages/wifi_info_flutter/wifi_info_flutter/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.0.0-nullsafety +## 2.0.0 * Migrate to null safety. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart b/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart index 8c64c5d9a421..b92e55028a45 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart @@ -42,7 +42,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @@ -54,7 +54,7 @@ class _MyHomePageState extends State { String _connectionStatus = 'Unknown'; final Connectivity _connectivity = Connectivity(); final WifiInfo _wifiInfo = WifiInfo(); - StreamSubscription _connectivitySubscription; + late StreamSubscription _connectivitySubscription; @override void initState() { @@ -72,7 +72,7 @@ class _MyHomePageState extends State { // Platform messages are asynchronous, so we initialize in an async method. Future initConnectivity() async { - ConnectivityResult result; + late ConnectivityResult result; // Platform messages may fail, so we use a try/catch PlatformException. try { result = await _connectivity.checkConnectivity(); @@ -103,7 +103,7 @@ class _MyHomePageState extends State { Future _updateConnectionStatus(ConnectivityResult result) async { switch (result) { case ConnectivityResult.wifi: - String wifiName, wifiBSSID, wifiIP; + String? wifiName, wifiBSSID, wifiIP; try { if (!kIsWeb && Platform.isIOS) { diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml index 0f0adbf7b4a1..bd424859abf2 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml @@ -3,10 +3,10 @@ description: Demonstrates how to use the wifi_info_flutter plugin. publish_to: 'none' environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" dependencies: - connectivity: 0.4.9+3 + connectivity: ^3.0.0 flutter: sdk: flutter wifi_info_flutter: @@ -16,7 +16,6 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - cupertino_icons: ^1.0.0 dev_dependencies: integration_test: diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart index 103dc54a1eaa..6fe4737ae7a1 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 import 'dart:io'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart index 8a77ec87bbac..d59272c77431 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 import 'dart:convert'; import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; diff --git a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml index 0fbc27866201..7b58d481f6c7 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml @@ -1,16 +1,16 @@ name: wifi_info_flutter description: A new flutter plugin project. -version: 2.0.0-nullsafety homepage: https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter/wifi_info_flutter +version: 2.0.0 environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.20.0" dependencies: flutter: sdk: flutter - wifi_info_flutter_platform_interface: ^2.0.0-nullsafety + wifi_info_flutter_platform_interface: ^2.0.0 dev_dependencies: integration_test: From fff1420b2860e18ab3738ec065ae97891a83b552 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 25 Feb 2021 09:54:42 +0100 Subject: [PATCH 275/924] [camera_platform_interface] Stable null safety release. (#3610) * Stable null safety release camera_platform_interface * Update minimum plugin_platform_interface version * Update version of cross_file to 0.3.1 --- .../camera_platform_interface/CHANGELOG.md | 4 ++-- .../camera_platform_interface/pubspec.yaml | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index ab3d559bf2fb..f7f78197d204 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,6 +1,6 @@ -## 2.0.0-nullsafety +## 2.0.0 -- Migrate to null safety. +- Stable null safety release. ## 1.6.0 diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index 5817ce5c3fb0..10897073dc5c 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,22 +3,22 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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: 2.0.0-nullsafety +version: 2.0.0 dependencies: flutter: sdk: flutter - meta: ^1.3.0-nullsafety.6 - plugin_platform_interface: ^1.1.0-nullsafety.2 - cross_file: ^0.3.0-nullsafety - stream_transform: ^2.0.0-nullsafety.0 + meta: ^1.3.0 + plugin_platform_interface: ">=1.0.0 <3.0.0" + cross_file: ^0.3.1 + stream_transform: ^2.0.0 dev_dependencies: flutter_test: sdk: flutter - async: ^2.5.0-nullsafety.3 - pedantic: ^1.10.0-nullsafety.3 + async: ^2.5.0 + pedantic: ^1.10.0 environment: - sdk: '>=2.12.0-0 <3.0.0' + sdk: '>=2.12.0-259.9.beta <3.0.0' flutter: ">=1.22.0" From 1de6d96f5b06b0657a21680a2a55a77b1be95808 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 25 Feb 2021 08:42:04 -0800 Subject: [PATCH 276/924] [file_selector] Migrate to null safety (#3631) Migrates the app-facing package to null safety. Includes replacing Mockito with a custom fake/mock. Fixes an issue where the example didn't handle dialogs being canceled, which was highlighted by the NNBD migration. (Previously, they would cause null assertions at runtime, which wasn't noticed during development. NNBD for the win!) Fixes flutter/flutter#75235 --- .../file_selector/file_selector/CHANGELOG.md | 4 + .../example/lib/get_directory_page.dart | 6 +- .../example/lib/open_image_page.dart | 4 + .../lib/open_multiple_images_page.dart | 4 + .../example/lib/open_text_page.dart | 6 +- .../example/lib/save_text_page.dart | 6 +- .../file_selector/example/pubspec.yaml | 57 +---- .../file_selector/lib/file_selector.dart | 30 +-- .../file_selector/file_selector/pubspec.yaml | 15 +- .../test/file_selector_test.dart | 203 +++++++++++++----- 10 files changed, 197 insertions(+), 138 deletions(-) diff --git a/packages/file_selector/file_selector/CHANGELOG.md b/packages/file_selector/file_selector/CHANGELOG.md index fe01ffec47b6..64ac5959a7c0 100644 --- a/packages/file_selector/file_selector/CHANGELOG.md +++ b/packages/file_selector/file_selector/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.0 + +Migrate to null safety. + ## 0.7.0+2 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/file_selector/file_selector/example/lib/get_directory_page.dart b/packages/file_selector/file_selector/example/lib/get_directory_page.dart index 6463fb532957..cf4cde9fa9a8 100644 --- a/packages/file_selector/file_selector/example/lib/get_directory_page.dart +++ b/packages/file_selector/file_selector/example/lib/get_directory_page.dart @@ -5,9 +5,13 @@ import 'package:flutter/material.dart'; class GetDirectoryPage extends StatelessWidget { void _getDirectoryPath(BuildContext context) async { final String confirmButtonText = 'Choose'; - final String directoryPath = await getDirectoryPath( + final String? directoryPath = await getDirectoryPath( confirmButtonText: confirmButtonText, ); + if (directoryPath == null) { + // Operation was canceled by the user. + return; + } await showDialog( context: context, builder: (context) => TextDisplay(directoryPath), diff --git a/packages/file_selector/file_selector/example/lib/open_image_page.dart b/packages/file_selector/file_selector/example/lib/open_image_page.dart index 593a1d60aed8..986bfe712893 100644 --- a/packages/file_selector/file_selector/example/lib/open_image_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_image_page.dart @@ -11,6 +11,10 @@ class OpenImagePage extends StatelessWidget { extensions: ['jpg', 'png'], ); final List files = await openFiles(acceptedTypeGroups: [typeGroup]); + if (files.isEmpty) { + // Operation was canceled by the user. + return; + } final XFile file = files[0]; final String fileName = file.name; final String filePath = file.path; diff --git a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart index 58b59cd91b03..c6f73f5aed12 100644 --- a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart @@ -18,6 +18,10 @@ class OpenMultipleImagesPage extends StatelessWidget { jpgsTypeGroup, pngTypeGroup, ]); + if (files.isEmpty) { + // Operation was canceled by the user. + return; + } await showDialog( context: context, builder: (context) => MultipleImagesDisplay(files), diff --git a/packages/file_selector/file_selector/example/lib/open_text_page.dart b/packages/file_selector/file_selector/example/lib/open_text_page.dart index 299d0e2dc21a..74d79dd72b19 100644 --- a/packages/file_selector/file_selector/example/lib/open_text_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_text_page.dart @@ -8,7 +8,11 @@ class OpenTextPage extends StatelessWidget { label: 'text', extensions: ['txt', 'json'], ); - final XFile file = await openFile(acceptedTypeGroups: [typeGroup]); + final XFile? file = await openFile(acceptedTypeGroups: [typeGroup]); + if (file == null) { + // Operation was canceled by the user. + return; + } final String fileName = file.name; final String fileContent = await file.readAsString(); diff --git a/packages/file_selector/file_selector/example/lib/save_text_page.dart b/packages/file_selector/file_selector/example/lib/save_text_page.dart index 47408662ecee..82046c35128a 100644 --- a/packages/file_selector/file_selector/example/lib/save_text_page.dart +++ b/packages/file_selector/file_selector/example/lib/save_text_page.dart @@ -8,7 +8,11 @@ class SaveTextPage extends StatelessWidget { final TextEditingController _contentController = TextEditingController(); void _saveFile() async { - final String path = await getSavePath(); + String? path = await getSavePath(); + if (path == null) { + // Operation was canceled by the user. + return; + } final String text = _contentController.text; final String fileName = _nameController.text; final Uint8List fileData = Uint8List.fromList(text.codeUnits); diff --git a/packages/file_selector/file_selector/example/pubspec.yaml b/packages/file_selector/file_selector/example/pubspec.yaml index 3af2a67e9e93..580237cad5ac 100644 --- a/packages/file_selector/file_selector/example/pubspec.yaml +++ b/packages/file_selector/file_selector/example/pubspec.yaml @@ -1,24 +1,12 @@ name: example description: A new Flutter project. -# The following line prevents the package from being accidentally published to -# pub.dev using `pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" dependencies: flutter: @@ -32,52 +20,9 @@ dependencies: # the parent directory to use the current plugin's version. path: ../ - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.3 - dev_dependencies: flutter_test: sdk: flutter -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/file_selector/file_selector/lib/file_selector.dart b/packages/file_selector/file_selector/lib/file_selector.dart index 080eac4460ac..cdb2bf9c726d 100644 --- a/packages/file_selector/file_selector/lib/file_selector.dart +++ b/packages/file_selector/file_selector/lib/file_selector.dart @@ -10,10 +10,10 @@ export 'package:file_selector_platform_interface/file_selector_platform_interfac show XFile, XTypeGroup; /// Open file dialog for loading files and return a file path -Future openFile({ - List acceptedTypeGroups, - String initialDirectory, - String confirmButtonText, +Future openFile({ + List acceptedTypeGroups = const [], + String? initialDirectory, + String? confirmButtonText, }) { return FileSelectorPlatform.instance.openFile( acceptedTypeGroups: acceptedTypeGroups, @@ -23,9 +23,9 @@ Future openFile({ /// Open file dialog for loading files and return a list of file paths Future> openFiles({ - List acceptedTypeGroups, - String initialDirectory, - String confirmButtonText, + List acceptedTypeGroups = const [], + String? initialDirectory, + String? confirmButtonText, }) { return FileSelectorPlatform.instance.openFiles( acceptedTypeGroups: acceptedTypeGroups, @@ -34,11 +34,11 @@ Future> openFiles({ } /// Saves File to user's file system -Future getSavePath({ - List acceptedTypeGroups, - String initialDirectory, - String suggestedName, - String confirmButtonText, +Future getSavePath({ + List acceptedTypeGroups = const [], + String? initialDirectory, + String? suggestedName, + String? confirmButtonText, }) async { return FileSelectorPlatform.instance.getSavePath( acceptedTypeGroups: acceptedTypeGroups, @@ -48,9 +48,9 @@ Future getSavePath({ } /// Gets a directory path from a user's file system -Future getDirectoryPath({ - String initialDirectory, - String confirmButtonText, +Future getDirectoryPath({ + String? initialDirectory, + String? confirmButtonText, }) async { return FileSelectorPlatform.instance.getDirectoryPath( initialDirectory: initialDirectory, confirmButtonText: confirmButtonText); diff --git a/packages/file_selector/file_selector/pubspec.yaml b/packages/file_selector/file_selector/pubspec.yaml index a55b7f4e06e7..34b459cca720 100644 --- a/packages/file_selector/file_selector/pubspec.yaml +++ b/packages/file_selector/file_selector/pubspec.yaml @@ -1,21 +1,20 @@ name: file_selector description: Flutter plugin for opening and saving files. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector -version: 0.7.0+2 +version: 0.8.0 dependencies: flutter: sdk: flutter - file_selector_platform_interface: ^1.0.0 + file_selector_platform_interface: ^2.0.0 dev_dependencies: flutter_test: sdk: flutter - test: ^1.3.0 - mockito: ^4.1.1 - plugin_platform_interface: ^1.0.0 - pedantic: ^1.8.0 + test: ^1.16.3 + plugin_platform_interface: ">=1.0.0 <3.0.0" + pedantic: ^1.10.0 environment: - sdk: ">=2.1.0 <3.0.0" - flutter: ">=1.12.13+hotfix.5" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/file_selector/file_selector/test/file_selector_test.dart b/packages/file_selector/file_selector/test/file_selector_test.dart index 15756cc2b622..b16f234bb3b8 100644 --- a/packages/file_selector/file_selector/test/file_selector_test.dart +++ b/packages/file_selector/file_selector/test/file_selector_test.dart @@ -3,13 +3,13 @@ // found in the LICENSE file. import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:file_selector/file_selector.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:test/fake.dart'; void main() { - MockFileSelector mock; + late FakeFileSelector fakePlatformImplementation; final initialDirectory = '/home/flutteruser'; final confirmButtonText = 'Use this profile picture'; final suggestedName = 'suggested_name'; @@ -25,19 +25,20 @@ void main() { ]; setUp(() { - mock = MockFileSelector(); - FileSelectorPlatform.instance = mock; + fakePlatformImplementation = FakeFileSelector(); + FileSelectorPlatform.instance = fakePlatformImplementation; }); group('openFile', () { final expectedFile = XFile('path'); test('works', () async { - when(mock.openFile( - initialDirectory: initialDirectory, - confirmButtonText: confirmButtonText, - acceptedTypeGroups: acceptedTypeGroups, - )).thenAnswer((_) => Future.value(expectedFile)); + fakePlatformImplementation + ..setExpectations( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + acceptedTypeGroups: acceptedTypeGroups) + ..setFileResponse([expectedFile]); final file = await openFile( initialDirectory: initialDirectory, @@ -49,7 +50,7 @@ void main() { }); test('works with no arguments', () async { - when(mock.openFile()).thenAnswer((_) => Future.value(expectedFile)); + fakePlatformImplementation.setFileResponse([expectedFile]); final file = await openFile(); @@ -57,24 +58,27 @@ void main() { }); test('sets the initial directory', () async { - when(mock.openFile(initialDirectory: initialDirectory)) - .thenAnswer((_) => Future.value(expectedFile)); + fakePlatformImplementation + ..setExpectations(initialDirectory: initialDirectory) + ..setFileResponse([expectedFile]); final file = await openFile(initialDirectory: initialDirectory); expect(file, expectedFile); }); test('sets the button confirmation label', () async { - when(mock.openFile(confirmButtonText: confirmButtonText)) - .thenAnswer((_) => Future.value(expectedFile)); + fakePlatformImplementation + ..setExpectations(confirmButtonText: confirmButtonText) + ..setFileResponse([expectedFile]); final file = await openFile(confirmButtonText: confirmButtonText); expect(file, expectedFile); }); test('sets the accepted type groups', () async { - when(mock.openFile(acceptedTypeGroups: acceptedTypeGroups)) - .thenAnswer((_) => Future.value(expectedFile)); + fakePlatformImplementation + ..setExpectations(acceptedTypeGroups: acceptedTypeGroups) + ..setFileResponse([expectedFile]); final file = await openFile(acceptedTypeGroups: acceptedTypeGroups); expect(file, expectedFile); @@ -85,11 +89,12 @@ void main() { final expectedFiles = [XFile('path')]; test('works', () async { - when(mock.openFiles( - initialDirectory: initialDirectory, - confirmButtonText: confirmButtonText, - acceptedTypeGroups: acceptedTypeGroups, - )).thenAnswer((_) => Future.value(expectedFiles)); + fakePlatformImplementation + ..setExpectations( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + acceptedTypeGroups: acceptedTypeGroups) + ..setFileResponse(expectedFiles); final file = await openFiles( initialDirectory: initialDirectory, @@ -101,7 +106,7 @@ void main() { }); test('works with no arguments', () async { - when(mock.openFiles()).thenAnswer((_) => Future.value(expectedFiles)); + fakePlatformImplementation.setFileResponse(expectedFiles); final files = await openFiles(); @@ -109,24 +114,27 @@ void main() { }); test('sets the initial directory', () async { - when(mock.openFiles(initialDirectory: initialDirectory)) - .thenAnswer((_) => Future.value(expectedFiles)); + fakePlatformImplementation + ..setExpectations(initialDirectory: initialDirectory) + ..setFileResponse(expectedFiles); final files = await openFiles(initialDirectory: initialDirectory); expect(files, expectedFiles); }); test('sets the button confirmation label', () async { - when(mock.openFiles(confirmButtonText: confirmButtonText)) - .thenAnswer((_) => Future.value(expectedFiles)); + fakePlatformImplementation + ..setExpectations(confirmButtonText: confirmButtonText) + ..setFileResponse(expectedFiles); final files = await openFiles(confirmButtonText: confirmButtonText); expect(files, expectedFiles); }); test('sets the accepted type groups', () async { - when(mock.openFiles(acceptedTypeGroups: acceptedTypeGroups)) - .thenAnswer((_) => Future.value(expectedFiles)); + fakePlatformImplementation + ..setExpectations(acceptedTypeGroups: acceptedTypeGroups) + ..setFileResponse(expectedFiles); final files = await openFiles(acceptedTypeGroups: acceptedTypeGroups); expect(files, expectedFiles); @@ -137,12 +145,13 @@ void main() { final expectedSavePath = '/example/path'; test('works', () async { - when(mock.getSavePath( - initialDirectory: initialDirectory, - confirmButtonText: confirmButtonText, - acceptedTypeGroups: acceptedTypeGroups, - suggestedName: suggestedName, - )).thenAnswer((_) => Future.value(expectedSavePath)); + fakePlatformImplementation + ..setExpectations( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + acceptedTypeGroups: acceptedTypeGroups, + suggestedName: suggestedName) + ..setPathResponse(expectedSavePath); final savePath = await getSavePath( initialDirectory: initialDirectory, @@ -155,32 +164,34 @@ void main() { }); test('works with no arguments', () async { - when(mock.getSavePath()) - .thenAnswer((_) => Future.value(expectedSavePath)); + fakePlatformImplementation.setPathResponse(expectedSavePath); final savePath = await getSavePath(); expect(savePath, expectedSavePath); }); test('sets the initial directory', () async { - when(mock.getSavePath(initialDirectory: initialDirectory)) - .thenAnswer((_) => Future.value(expectedSavePath)); + fakePlatformImplementation + ..setExpectations(initialDirectory: initialDirectory) + ..setPathResponse(expectedSavePath); final savePath = await getSavePath(initialDirectory: initialDirectory); expect(savePath, expectedSavePath); }); test('sets the button confirmation label', () async { - when(mock.getSavePath(confirmButtonText: confirmButtonText)) - .thenAnswer((_) => Future.value(expectedSavePath)); + fakePlatformImplementation + ..setExpectations(confirmButtonText: confirmButtonText) + ..setPathResponse(expectedSavePath); final savePath = await getSavePath(confirmButtonText: confirmButtonText); expect(savePath, expectedSavePath); }); test('sets the accepted type groups', () async { - when(mock.getSavePath(acceptedTypeGroups: acceptedTypeGroups)) - .thenAnswer((_) => Future.value(expectedSavePath)); + fakePlatformImplementation + ..setExpectations(acceptedTypeGroups: acceptedTypeGroups) + ..setPathResponse(expectedSavePath); final savePath = await getSavePath(acceptedTypeGroups: acceptedTypeGroups); @@ -188,8 +199,9 @@ void main() { }); test('sets the suggested name', () async { - when(mock.getSavePath(suggestedName: suggestedName)) - .thenAnswer((_) => Future.value(expectedSavePath)); + fakePlatformImplementation + ..setExpectations(suggestedName: suggestedName) + ..setPathResponse(expectedSavePath); final savePath = await getSavePath(suggestedName: suggestedName); expect(savePath, expectedSavePath); @@ -200,10 +212,11 @@ void main() { final expectedDirectoryPath = '/example/path'; test('works', () async { - when(mock.getDirectoryPath( - initialDirectory: initialDirectory, - confirmButtonText: confirmButtonText, - )).thenAnswer((_) => Future.value(expectedDirectoryPath)); + fakePlatformImplementation + ..setExpectations( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText) + ..setPathResponse(expectedDirectoryPath); final directoryPath = await getDirectoryPath( initialDirectory: initialDirectory, @@ -214,16 +227,16 @@ void main() { }); test('works with no arguments', () async { - when(mock.getDirectoryPath()) - .thenAnswer((_) => Future.value(expectedDirectoryPath)); + fakePlatformImplementation.setPathResponse(expectedDirectoryPath); final directoryPath = await getDirectoryPath(); expect(directoryPath, expectedDirectoryPath); }); test('sets the initial directory', () async { - when(mock.getDirectoryPath(initialDirectory: initialDirectory)) - .thenAnswer((_) => Future.value(expectedDirectoryPath)); + fakePlatformImplementation + ..setExpectations(initialDirectory: initialDirectory) + ..setPathResponse(expectedDirectoryPath); final directoryPath = await getDirectoryPath(initialDirectory: initialDirectory); @@ -231,8 +244,9 @@ void main() { }); test('sets the button confirmation label', () async { - when(mock.getDirectoryPath(confirmButtonText: confirmButtonText)) - .thenAnswer((_) => Future.value(expectedDirectoryPath)); + fakePlatformImplementation + ..setExpectations(confirmButtonText: confirmButtonText) + ..setPathResponse(expectedDirectoryPath); final directoryPath = await getDirectoryPath(confirmButtonText: confirmButtonText); @@ -241,6 +255,83 @@ void main() { }); } -class MockFileSelector extends Mock +class FakeFileSelector extends Fake with MockPlatformInterfaceMixin - implements FileSelectorPlatform {} + implements FileSelectorPlatform { + // Expectations. + List? acceptedTypeGroups = const []; + String? initialDirectory; + String? confirmButtonText; + String? suggestedName; + // Return values. + List? files; + String? path; + + void setExpectations({ + List acceptedTypeGroups = const [], + String? initialDirectory, + String? suggestedName, + String? confirmButtonText, + }) { + this.acceptedTypeGroups = acceptedTypeGroups; + this.initialDirectory = initialDirectory; + this.suggestedName = suggestedName; + this.confirmButtonText = confirmButtonText; + } + + void setFileResponse(List files) { + this.files = files; + } + + void setPathResponse(String path) { + this.path = path; + } + + @override + Future openFile({ + List? acceptedTypeGroups, + String? initialDirectory, + String? confirmButtonText, + }) async { + expect(acceptedTypeGroups, this.acceptedTypeGroups); + expect(initialDirectory, this.initialDirectory); + expect(suggestedName, this.suggestedName); + return files?[0]; + } + + @override + Future> openFiles({ + List? acceptedTypeGroups, + String? initialDirectory, + String? confirmButtonText, + }) async { + expect(acceptedTypeGroups, this.acceptedTypeGroups); + expect(initialDirectory, this.initialDirectory); + expect(suggestedName, this.suggestedName); + return files!; + } + + @override + Future getSavePath({ + List? acceptedTypeGroups, + String? initialDirectory, + String? suggestedName, + String? confirmButtonText, + }) async { + expect(acceptedTypeGroups, this.acceptedTypeGroups); + expect(initialDirectory, this.initialDirectory); + expect(suggestedName, this.suggestedName); + expect(confirmButtonText, this.confirmButtonText); + return path; + } + + @override + Future getDirectoryPath({ + String? initialDirectory, + String? confirmButtonText, + }) async { + expect(initialDirectory, this.initialDirectory); + expect(confirmButtonText, this.confirmButtonText); + return path; + } +} From a03b66f072ff230718565de4efbfb26856ba2e71 Mon Sep 17 00:00:00 2001 From: Floris Devreese Date: Thu, 25 Feb 2021 21:08:00 +0100 Subject: [PATCH 277/924] embedded_views_preview not required since v1.0.0 (#3625) `io.flutter.embedded_views_preview` is not required since version `1.0.0`, so doesn't need to be in the example. --- .../google_maps_flutter/example/ios/Runner/Info.plist | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/Info.plist b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/Info.plist index 372490e1a367..0fa9c73c5d42 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/Info.plist +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/Info.plist @@ -47,7 +47,5 @@ UIViewControllerBasedStatusBarAppearance - io.flutter.embedded_views_preview - From eab25525f702be43f6b492848afde5a65575444d Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Thu, 25 Feb 2021 21:09:38 +0100 Subject: [PATCH 278/924] Fix typo in image_picker_for_web README.md (#2835) --- packages/image_picker/image_picker_for_web/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker_for_web/README.md b/packages/image_picker/image_picker_for_web/README.md index 074053c9b956..8c9f2c73b8fe 100644 --- a/packages/image_picker/image_picker_for_web/README.md +++ b/packages/image_picker/image_picker_for_web/README.md @@ -5,7 +5,7 @@ A web implementation of [`image_picker`][1]. ## Limitations on the web platform Since Web Browsers don't offer direct access to their users' file system, -this plugin provides a `PickedFile` abstraction to make access access uniform +this plugin provides a `PickedFile` abstraction to make access uniform across platforms. The web version of the plugin puts network-accessible URIs as the `path` From f61498008e73334600a5728a72ee962e1f9c4be1 Mon Sep 17 00:00:00 2001 From: K K Date: Fri, 26 Feb 2021 01:43:29 +0530 Subject: [PATCH 279/924] [url_launcher] Added a note to the README (#2031) The action won't work on the simulator works on physical iOS device which was not mentioned here so it was added Co-authored-by: Michael Klimushyn Co-authored-by: Stuart Morgan --- packages/url_launcher/url_launcher/CHANGELOG.md | 1 + packages/url_launcher/url_launcher/README.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 01f3e787fc9c..2d188366dfa5 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,6 +1,7 @@ ## 6.0.1 * Update result to `True` on iOS when the url was loaded successfully. +* Added a README note about required applications. ## 6.0.0 diff --git a/packages/url_launcher/url_launcher/README.md b/packages/url_launcher/url_launcher/README.md index bc399c73df7d..daf21738d9b7 100644 --- a/packages/url_launcher/url_launcher/README.md +++ b/packages/url_launcher/url_launcher/README.md @@ -51,6 +51,10 @@ Common schemes supported by both iOS and Android: More details can be found here for [iOS](https://developer.apple.com/library/content/featuredarticles/iPhoneURLScheme_Reference/Introduction/Introduction.html) and [Android](https://developer.android.com/guide/components/intents-common.html) +**Note**: URL schemes are only supported if there are apps installed on the device that can +support them. For example, iOS simulators don't have a default email or phone +apps installed, so can't open `tel:` or `mailto:` links. + ### Encoding URLs URLs must be properly encoded, especially when including spaces or other special characters. This can be done using the [`Uri` class](https://api.dart.dev/stable/2.7.1/dart-core/Uri-class.html): From cb64042b577f23c86316b48d1e136e6495a4af66 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Thu, 25 Feb 2021 13:46:03 -0800 Subject: [PATCH 280/924] Make executor an instance property (#3633) --- .gitignore | 3 +++ packages/shared_preferences/shared_preferences/CHANGELOG.md | 4 ++++ .../plugins/sharedpreferences/MethodCallHandlerImpl.java | 6 ++++-- packages/shared_preferences/shared_preferences/pubspec.yaml | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index d7560505f166..3582a15fae57 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ build/ .project .classpath .settings + +# Downloaded by the plugin tools. +google-java-format-1.3-all-deps.jar diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 74555f59c27f..63c042a1194e 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.2 + +* Don't create additional thread pools when method channel is called. + ## 2.0.1 * Removed deprecated [AsyncTask](https://developer.android.com/reference/android/os/AsyncTask) was deprecated in API level 30 ([#3481](https://github.com/flutter/plugins/pull/3481)) diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java index f2c0f298578c..d58cc32ed625 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java @@ -43,12 +43,16 @@ class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { private final android.content.SharedPreferences preferences; + private final ExecutorService executor; + /** * Constructs a {@link MethodCallHandlerImpl} instance. Creates a {@link * android.content.SharedPreferences} based on the {@code context}. */ MethodCallHandlerImpl(Context context) { preferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); + executor = + new ThreadPoolExecutor(0, 1, 30L, TimeUnit.SECONDS, new SynchronousQueue()); } @Override @@ -123,8 +127,6 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { private void commitAsync( final SharedPreferences.Editor editor, final MethodChannel.Result result) { - final ExecutorService executor = - new ThreadPoolExecutor(0, 1, 30L, TimeUnit.SECONDS, new SynchronousQueue()); final Handler handler = new Handler(Looper.getMainLooper()); executor.execute( diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 1809a979c6f3..6f6ab1fee6e8 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences description: Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences -version: 2.0.1 +version: 2.0.2 flutter: plugin: From a0d99ee3de7c8e6a23301ac6d99ea88c4038f3ed Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Thu, 25 Feb 2021 14:26:03 -0800 Subject: [PATCH 281/924] [google_sign_in_web] Migrate to null-safety (#3628) --- .../google_sign_in_web/CHANGELOG.md | 4 + .../google_sign_in_web/example/README.md | 21 + .../integration_test/auth2_test.dart} | 19 +- .../integration_test/gapi_load_test.dart} | 7 +- .../gapi_mocks/gapi_mocks.dart | 0 .../gapi_mocks/src/auth2_init.dart | 0 .../gapi_mocks/src/gapi.dart | 0 .../gapi_mocks/src/google_user.dart | 0 .../gapi_mocks/src/test_iife.dart | 0 .../integration_test/gapi_utils_test.dart} | 52 ++- .../integration_test}/src/test_utils.dart | 0 .../{test => example}/lib/main.dart | 0 .../{test => example}/pubspec.yaml | 12 +- .../{test/run_test => example/run_test.sh} | 7 +- .../test_driver/integration_driver.dart} | 0 .../{test => example}/web/index.html | 0 .../lib/google_sign_in_web.dart | 64 +-- .../lib/src/generated/gapi.dart | 435 +----------------- .../lib/src/generated/gapiauth2.dart | 257 ++++++----- .../google_sign_in_web/lib/src/load_gapi.dart | 2 +- .../google_sign_in_web/lib/src/utils.dart | 35 +- .../google_sign_in_web/pubspec.yaml | 18 +- .../google_sign_in_web/test/README.md | 18 +- .../gapi_load_integration_test.dart | 7 - .../gapi_utils_integration_test.dart | 7 - .../test/tests_exist_elsewhere_test.dart | 10 + 26 files changed, 322 insertions(+), 653 deletions(-) create mode 100644 packages/google_sign_in/google_sign_in_web/example/README.md rename packages/google_sign_in/google_sign_in_web/{test/test_driver/auth2_integration.dart => example/integration_test/auth2_test.dart} (91%) rename packages/google_sign_in/google_sign_in_web/{test/test_driver/gapi_load_integration.dart => example/integration_test/gapi_load_test.dart} (92%) rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/gapi_mocks/gapi_mocks.dart (100%) rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/gapi_mocks/src/auth2_init.dart (100%) rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/gapi_mocks/src/gapi.dart (100%) rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/gapi_mocks/src/google_user.dart (100%) rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/gapi_mocks/src/test_iife.dart (100%) rename packages/google_sign_in/google_sign_in_web/{test/test_driver/gapi_utils_integration.dart => example/integration_test/gapi_utils_test.dart} (54%) rename packages/google_sign_in/google_sign_in_web/{test/test_driver => example/integration_test}/src/test_utils.dart (100%) rename packages/google_sign_in/google_sign_in_web/{test => example}/lib/main.dart (100%) rename packages/google_sign_in/google_sign_in_web/{test => example}/pubspec.yaml (57%) rename packages/google_sign_in/google_sign_in_web/{test/run_test => example/run_test.sh} (57%) rename packages/google_sign_in/google_sign_in_web/{test/test_driver/auth2_integration_test.dart => example/test_driver/integration_driver.dart} (100%) rename packages/google_sign_in/google_sign_in_web/{test => example}/web/index.html (100%) delete mode 100644 packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration_test.dart delete mode 100644 packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration_test.dart create mode 100644 packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart diff --git a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md index d1353f723fd5..a5c9e9d2f2bb 100644 --- a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.0 + +* Migrate to null-safety. + ## 0.9.2+1 * Update Flutter SDK constraint. diff --git a/packages/google_sign_in/google_sign_in_web/example/README.md b/packages/google_sign_in/google_sign_in_web/example/README.md new file mode 100644 index 000000000000..0ec01e025570 --- /dev/null +++ b/packages/google_sign_in/google_sign_in_web/example/README.md @@ -0,0 +1,21 @@ +# Testing + +This package utilizes the `integration_test` package to run its tests in a web browser. + +See [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests) for more info. + +## Running the tests + +Make sure you have updated to the latest Flutter master. + +1. Check what version of Chrome is running on the machine you're running tests on. + +2. Download and install driver for that version from here: + * + +3. Start the driver using `chromedriver --port=4444` + +4. Run tests: `flutter drive -d web-server --browser-name=chrome --driver=test_driver/integration_driver.dart --target=integration_test/TEST_NAME.dart`, or (in Linux): + + * Single: `./run_test.sh integration_test/TEST_NAME.dart` + * All: `./run_test.sh` diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/auth2_integration.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart similarity index 91% rename from packages/google_sign_in/google_sign_in_web/test/test_driver/auth2_integration.dart rename to packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart index e2f16f2aee43..b80080935d42 100644 --- a/packages/google_sign_in/google_sign_in_web/test/test_driver/auth2_integration.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart @@ -3,11 +3,12 @@ // found in the LICENSE file. import 'package:flutter/services.dart'; -import 'package:integration_test/integration_test.dart'; - import 'package:flutter_test/flutter_test.dart'; import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; import 'package:google_sign_in_web/google_sign_in_web.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:js/js_util.dart' as js_util; + import 'gapi_mocks/gapi_mocks.dart' as gapi_mocks; import 'src/test_utils.dart'; @@ -25,7 +26,7 @@ void main() { idToken: expectedTokenData.idToken, ); - GoogleSignInPlugin plugin; + late GoogleSignInPlugin plugin; group('plugin.init() throws a catchable exception', () { setUp(() { @@ -54,7 +55,8 @@ void main() { ); fail('plugin.init should have thrown an exception!'); } catch (e) { - expect(e.code, 'idpiframe_initialization_failed'); + final String code = js_util.getProperty(e, 'code') as String; + expect(code, 'idpiframe_initialization_failed'); } }); }); @@ -62,7 +64,7 @@ void main() { group('other methods also throw catchable exceptions on init fail', () { // This function ensures that init gets called, but for some reason, we // ignored that it has thrown stuff... - void _discardInit() async { + Future _discardInit() async { try { await plugin.init( hostedDomain: 'foo', @@ -135,13 +137,13 @@ void main() { }); testWidgets('signInSilently', (WidgetTester tester) async { - GoogleSignInUserData actualUser = await plugin.signInSilently(); + GoogleSignInUserData actualUser = (await plugin.signInSilently())!; expect(actualUser, expectedUserData); }); testWidgets('signIn', (WidgetTester tester) async { - GoogleSignInUserData actualUser = await plugin.signIn(); + GoogleSignInUserData actualUser = (await plugin.signIn())!; expect(actualUser, expectedUserData); }); @@ -185,7 +187,8 @@ void main() { await plugin.signIn(); fail('plugin.signIn() should have thrown an exception!'); } catch (e) { - expect(e.code, 'popup_closed_by_user'); + final String code = js_util.getProperty(e, 'code') as String; + expect(code, 'popup_closed_by_user'); } }); }); diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart similarity index 92% rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration.dart rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart index 540369cae370..e0729bcf9b5e 100644 --- a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart @@ -4,18 +4,19 @@ import 'dart:html' as html; -import 'package:integration_test/integration_test.dart'; - import 'package:flutter_test/flutter_test.dart'; import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; import 'package:google_sign_in_web/google_sign_in_web.dart'; +import 'package:integration_test/integration_test.dart'; + import 'gapi_mocks/gapi_mocks.dart' as gapi_mocks; import 'src/test_utils.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - gapiUrl = toBase64Url(gapi_mocks.auth2InitSuccess(GoogleSignInUserData())); + gapiUrl = toBase64Url(gapi_mocks.auth2InitSuccess( + GoogleSignInUserData(email: 'test@test.com', id: '1234'))); testWidgets('Plugin is initialized after GAPI fully loads and init is called', (WidgetTester tester) async { diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/gapi_mocks.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart similarity index 100% rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/gapi_mocks.dart rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/auth2_init.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart similarity index 100% rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/auth2_init.dart rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/gapi.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart similarity index 100% rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/gapi.dart rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/google_user.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart similarity index 100% rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/google_user.dart rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/test_iife.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart similarity index 100% rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_mocks/src/test_iife.dart rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart similarity index 54% rename from packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration.dart rename to packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart index 55b942842b33..e03974a145b7 100644 --- a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart @@ -1,27 +1,21 @@ // Copyright 2019 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 'package:flutter_test/flutter_test.dart'; - -import 'package:integration_test/integration_test.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'package:google_sign_in_web/src/generated/gapiauth2.dart' as gapi; import 'package:google_sign_in_web/src/utils.dart'; -import 'package:mockito/mockito.dart'; - -class MockGoogleUser extends Mock implements gapi.GoogleUser {} - -class MockBasicProfile extends Mock implements gapi.BasicProfile {} +import 'package:integration_test/integration_test.dart'; void main() { // The non-null use cases are covered by the auth2_test.dart file. IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('gapiUserToPluginUserData', () { - var mockUser; + late FakeGoogleUser fakeUser; setUp(() { - mockUser = MockGoogleUser(); + fakeUser = FakeGoogleUser(); }); testWidgets('null user -> null response', (WidgetTester tester) async { @@ -30,21 +24,45 @@ void main() { testWidgets('not signed-in user -> null response', (WidgetTester tester) async { - when(mockUser.isSignedIn()).thenReturn(false); - expect(gapiUserToPluginUserData(mockUser), isNull); + expect(gapiUserToPluginUserData(fakeUser), isNull); }); testWidgets('signed-in, but null profile user -> null response', (WidgetTester tester) async { - when(mockUser.isSignedIn()).thenReturn(true); - expect(gapiUserToPluginUserData(mockUser), isNull); + fakeUser.setIsSignedIn(true); + expect(gapiUserToPluginUserData(fakeUser), isNull); }); testWidgets('signed-in, null userId in profile user -> null response', (WidgetTester tester) async { - when(mockUser.isSignedIn()).thenReturn(true); - when(mockUser.getBasicProfile()).thenReturn(MockBasicProfile()); - expect(gapiUserToPluginUserData(mockUser), isNull); + fakeUser.setIsSignedIn(true); + fakeUser.setBasicProfile(FakeBasicProfile()); + expect(gapiUserToPluginUserData(fakeUser), isNull); }); }); } + +class FakeGoogleUser extends Fake implements gapi.GoogleUser { + bool _isSignedIn = false; + gapi.BasicProfile? _basicProfile; + + @override + bool isSignedIn() => _isSignedIn; + @override + gapi.BasicProfile? getBasicProfile() => _basicProfile; + + void setIsSignedIn(bool isSignedIn) { + _isSignedIn = isSignedIn; + } + + void setBasicProfile(gapi.BasicProfile basicProfile) { + _basicProfile = basicProfile; + } +} + +class FakeBasicProfile extends Fake implements gapi.BasicProfile { + String? _id; + + @override + String? getId() => _id; +} diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/src/test_utils.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart similarity index 100% rename from packages/google_sign_in/google_sign_in_web/test/test_driver/src/test_utils.dart rename to packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart diff --git a/packages/google_sign_in/google_sign_in_web/test/lib/main.dart b/packages/google_sign_in/google_sign_in_web/example/lib/main.dart similarity index 100% rename from packages/google_sign_in/google_sign_in_web/test/lib/main.dart rename to packages/google_sign_in/google_sign_in_web/example/lib/main.dart diff --git a/packages/google_sign_in/google_sign_in_web/test/pubspec.yaml b/packages/google_sign_in/google_sign_in_web/example/pubspec.yaml similarity index 57% rename from packages/google_sign_in/google_sign_in_web/test/pubspec.yaml rename to packages/google_sign_in/google_sign_in_web/example/pubspec.yaml index dd0354e81498..385b2ea0861e 100644 --- a/packages/google_sign_in/google_sign_in_web/test/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_web/example/pubspec.yaml @@ -1,23 +1,23 @@ -name: regular_integration_tests +name: google_sign_in_web_integration_tests publish_to: none environment: - sdk: ">=2.2.2 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.27.0-0" # For integration_test from sdk dependencies: flutter: sdk: flutter dev_dependencies: - google_sign_in: ^4.5.3 + http: ^0.13.0 + js: ^0.6.3 flutter_driver: sdk: flutter flutter_test: sdk: flutter - http: ^0.12.2 - mockito: ^4.1.1 integration_test: - path: ../../../integration_test + sdk: flutter dependency_overrides: google_sign_in_web: diff --git a/packages/google_sign_in/google_sign_in_web/test/run_test b/packages/google_sign_in/google_sign_in_web/example/run_test.sh similarity index 57% rename from packages/google_sign_in/google_sign_in_web/test/run_test rename to packages/google_sign_in/google_sign_in_web/example/run_test.sh index 74a8526a0fa3..0f76f4a47e16 100755 --- a/packages/google_sign_in/google_sign_in_web/test/run_test +++ b/packages/google_sign_in/google_sign_in_web/example/run_test.sh @@ -1,17 +1,20 @@ #!/usr/bin/bash + if pgrep -lf chromedriver > /dev/null; then echo "chromedriver is running." if [ $# -eq 0 ]; then echo "No target specified, running all tests..." - find test_driver/ -iname *_integration.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --target='{}' + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target='{}' else echo "Running test target: $1..." set -x - flutter drive -d web-server --web-port=7357 --browser-name=chrome --target=$1 + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target=$1 fi else echo "chromedriver is not running." fi + + diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/auth2_integration_test.dart b/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart similarity index 100% rename from packages/google_sign_in/google_sign_in_web/test/test_driver/auth2_integration_test.dart rename to packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart diff --git a/packages/google_sign_in/google_sign_in_web/test/web/index.html b/packages/google_sign_in/google_sign_in_web/example/web/index.html similarity index 100% rename from packages/google_sign_in/google_sign_in_web/test/web/index.html rename to packages/google_sign_in/google_sign_in_web/example/web/index.html diff --git a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart index dd82852fa350..41e8106802de 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart @@ -6,8 +6,8 @@ import 'dart:async'; import 'dart:html' as html; import 'package:flutter/services.dart'; -import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; +import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart'; import 'package:js/js.dart'; import 'package:meta/meta.dart'; @@ -37,8 +37,8 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { _isGapiInitialized = gapi.inject(gapiUrl).then((_) => gapi.init()); } - Future _isGapiInitialized; - Future _isAuthInitialized; + late Future _isGapiInitialized; + late Future _isAuthInitialized; bool _isInitCalled = false; // This method throws if init hasn't been called at some point in the past. @@ -58,7 +58,7 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { return Future.wait([_isGapiInitialized, _isAuthInitialized]); } - String _autoDetectedClientId; + String? _autoDetectedClientId; /// Factory method that initializes the plugin with [GoogleSignInPlatform]. static void registerWith(Registrar registrar) { @@ -66,12 +66,13 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { } @override - Future init( - {@required String hostedDomain, - List scopes = const [], - SignInOption signInOption = SignInOption.standard, - String clientId}) async { - final String appClientId = clientId ?? _autoDetectedClientId; + Future init({ + List scopes = const [], + SignInOption signInOption = SignInOption.standard, + String? hostedDomain, + String? clientId, + }) async { + final String? appClientId = clientId ?? _autoDetectedClientId; assert( appClientId != null, 'ClientID not set. Either set it on a ' @@ -90,7 +91,7 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { hosted_domain: hostedDomain, // The js lib wants a space-separated list of values scope: scopes.join(' '), - client_id: appClientId, + client_id: appClientId!, )); Completer isAuthInitialized = Completer(); @@ -119,18 +120,18 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { } @override - Future signInSilently() async { + Future signInSilently() async { await initialized; return gapiUserToPluginUserData( - await auth2.getAuthInstance().currentUser.get()); + await auth2.getAuthInstance()?.currentUser?.get()); } @override - Future signIn() async { + Future signIn() async { await initialized; try { - return gapiUserToPluginUserData(await auth2.getAuthInstance().signIn()); + return gapiUserToPluginUserData(await auth2.getAuthInstance()?.signIn()); } on auth2.GoogleAuthSignInError catch (reason) { throw PlatformException( code: reason.error, @@ -143,30 +144,33 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { @override Future getTokens( - {@required String email, bool shouldRecoverAuth}) async { + {required String email, bool? shouldRecoverAuth}) async { await initialized; - final auth2.GoogleUser currentUser = + final auth2.GoogleUser? currentUser = auth2.getAuthInstance()?.currentUser?.get(); - final auth2.AuthResponse response = currentUser.getAuthResponse(); + final auth2.AuthResponse? response = currentUser?.getAuthResponse(); return GoogleSignInTokenData( - idToken: response.id_token, accessToken: response.access_token); + idToken: response?.id_token, accessToken: response?.access_token); } @override Future signOut() async { await initialized; - return auth2.getAuthInstance().signOut(); + return auth2.getAuthInstance()?.signOut(); } @override Future disconnect() async { await initialized; - final auth2.GoogleUser currentUser = + final auth2.GoogleUser? currentUser = auth2.getAuthInstance()?.currentUser?.get(); + + if (currentUser == null) return; + return currentUser.disconnect(); } @@ -174,16 +178,19 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { Future isSignedIn() async { await initialized; - final auth2.GoogleUser currentUser = + final auth2.GoogleUser? currentUser = auth2.getAuthInstance()?.currentUser?.get(); + + if (currentUser == null) return false; + return currentUser.isSignedIn(); } @override - Future clearAuthCache({String token}) async { + Future clearAuthCache({required String token}) async { await initialized; - return auth2.getAuthInstance().disconnect(); + return auth2.getAuthInstance()?.disconnect(); } @override @@ -194,14 +201,15 @@ class GoogleSignInPlugin extends GoogleSignInPlatform { if (currentUser == null) return false; - final grantedScopes = currentUser.getGrantedScopes(); + final grantedScopes = currentUser.getGrantedScopes() ?? ''; final missingScopes = scopes.where((scope) => !grantedScopes.contains(scope)); if (missingScopes.isEmpty) return true; - return currentUser - .grant(auth2.SigninOptions(scope: missingScopes.join(" "))) ?? - false; + final response = await currentUser + .grant(auth2.SigninOptions(scope: missingScopes.join(' '))); + + return response != null; } } diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart index 95f07490d3e6..f0f886ce7880 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart @@ -2,448 +2,53 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: public_member_api_docs, unused_element - -@JS() -library gapi; - -import "package:js/js.dart"; -import "package:js/js_util.dart" show promiseToFuture; - /// Type definitions for Google API Client /// Project: https://github.com/google/google-api-javascript-client /// Definitions by: Frank M , grant /// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped /// TypeScript Version: 2.3 -/// The OAuth 2.0 token object represents the OAuth 2.0 token and any associated data. -@anonymous -@JS() -abstract class GoogleApiOAuth2TokenObject { - /// The OAuth 2.0 token. Only present in successful responses - external String get access_token; - external set access_token(String v); - - /// Details about the error. Only present in error responses - external String get error; - external set error(String v); - - /// The duration, in seconds, the token is valid for. Only present in successful responses - external String get expires_in; - external set expires_in(String v); - external GoogleApiOAuth2TokenSessionState get session_state; - external set session_state(GoogleApiOAuth2TokenSessionState v); +// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/gapi - /// The Google API scopes related to this token - external String get state; - external set state(String v); - external factory GoogleApiOAuth2TokenObject( - {String access_token, - String error, - String expires_in, - GoogleApiOAuth2TokenSessionState session_state, - String state}); -} +// ignore_for_file: public_member_api_docs, unused_element -@anonymous @JS() -abstract class GoogleApiOAuth2TokenSessionState { - external dynamic /*{ - authuser: string, - }*/ - get extraQueryParams; - external set extraQueryParams( - dynamic - /*{ - authuser: string, - }*/ - v); - external factory GoogleApiOAuth2TokenSessionState( - {dynamic - /*{ - authuser: string, - }*/ - extraQueryParams}); -} +library gapi; -/// Fix for #8215 -/// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/8215 -/// Usage example: -/// https://developers.google.com/identity/sign-in/web/session-state +import 'package:js/js.dart'; // Module gapi typedef void LoadCallback( - [dynamic args1, - dynamic args2, - dynamic args3, - dynamic args4, - dynamic args5]); + [dynamic? args1, + dynamic? args2, + dynamic? args3, + dynamic? args4, + dynamic? args5]); @anonymous @JS() abstract class LoadConfig { external LoadCallback get callback; external set callback(LoadCallback v); - external Function get onerror; - external set onerror(Function v); - external num get timeout; - external set timeout(num v); - external Function get ontimeout; - external set ontimeout(Function v); + external Function? get onerror; + external set onerror(Function? v); + external num? get timeout; + external set timeout(num? v); + external Function? get ontimeout; + external set ontimeout(Function? v); external factory LoadConfig( {LoadCallback callback, - Function onerror, - num timeout, - Function ontimeout}); + Function? onerror, + num? timeout, + Function? ontimeout}); } /*type CallbackOrConfig = LoadConfig | LoadCallback;*/ /// Pragmatically initialize gapi class member. /// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiloadlibraries-callbackorconfig -@JS("gapi.load") +@JS('gapi.load') external void load( String apiName, dynamic /*LoadConfig|LoadCallback*/ callback); // End module gapi -// Module gapi.auth -/// Initiates the OAuth 2.0 authorization process. The browser displays a popup window prompting the user authenticate and authorize. After the user authorizes, the popup closes and the callback function fires. -@JS("gapi.auth.authorize") -external void authorize( - dynamic - /*{ - /** - * The application's client ID. - */ - client_id?: string; - /** - * If true, then login uses "immediate mode", which means that the token is refreshed behind the scenes, and no UI is shown to the user. - */ - immediate?: boolean; - /** - * The OAuth 2.0 response type property. Default: token - */ - response_type?: string; - /** - * The auth scope or scopes to authorize. Auth scopes for individual APIs can be found in their documentation. - */ - scope?: any; - /** - * The user to sign in as. -1 to toggle a multi-account chooser, 0 to default to the user's current account, and 1 to automatically sign in if the user is signed into Google Plus. - */ - authuser?: number; - }*/ - params, - dynamic callback(GoogleApiOAuth2TokenObject token)); - -/// Initializes the authorization feature. Call this when the client loads to prevent popup blockers from blocking the auth window on gapi.auth.authorize calls. -@JS("gapi.auth.init") -external void init(dynamic callback()); - -/// Retrieves the OAuth 2.0 token for the application. -@JS("gapi.auth.getToken") -external GoogleApiOAuth2TokenObject getToken(); - -/// Sets the OAuth 2.0 token for the application. -@JS("gapi.auth.setToken") -external void setToken(GoogleApiOAuth2TokenObject token); - -/// Initiates the client-side Google+ Sign-In OAuth 2.0 flow. -/// When the method is called, the OAuth 2.0 authorization dialog is displayed to the user and when they accept, the callback function is called. -@JS("gapi.auth.signIn") -external void signIn( - dynamic - /*{ - /** - * Your OAuth 2.0 client ID that you obtained from the Google Developers Console. - */ - clientid?: string; - /** - * Directs the sign-in button to store user and session information in a session cookie and HTML5 session storage on the user's client for the purpose of minimizing HTTP traffic and distinguishing between multiple Google accounts a user might be signed into. - */ - cookiepolicy?: string; - /** - * A function in the global namespace, which is called when the sign-in button is rendered and also called after a sign-in flow completes. - */ - callback?: () => void; - /** - * If true, all previously granted scopes remain granted in each incremental request, for incremental authorization. The default value true is correct for most use cases; use false only if employing delegated auth, where you pass the bearer token to a less-trusted component with lower programmatic authority. - */ - includegrantedscopes?: boolean; - /** - * If your app will write moments, list the full URI of the types of moments that you intend to write. - */ - requestvisibleactions?: any; - /** - * The OAuth 2.0 scopes for the APIs that you would like to use as a space-delimited list. - */ - scope?: any; - /** - * If you have an Android app, you can drive automatic Android downloads from your web sign-in flow. - */ - apppackagename?: string; - }*/ - params); - -/// Signs a user out of your app without logging the user out of Google. This method will only work when the user is signed in with Google+ Sign-In. -@JS("gapi.auth.signOut") -external void signOut(); -// End module gapi.auth - -// Module gapi.client -@anonymous -@JS() -abstract class RequestOptions { - /// The URL to handle the request - external String get path; - external set path(String v); - - /// The HTTP request method to use. Default is GET - external String get method; - external set method(String v); - - /// URL params in key-value pair form - external dynamic get params; - external set params(dynamic v); - - /// Additional HTTP request headers - external dynamic get headers; - external set headers(dynamic v); - - /// The HTTP request body (applies to PUT or POST). - external dynamic get body; - external set body(dynamic v); - - /// If supplied, the request is executed immediately and no gapi.client.HttpRequest object is returned - external dynamic Function() get callback; - external set callback(dynamic Function() v); - external factory RequestOptions( - {String path, - String method, - dynamic params, - dynamic headers, - dynamic body, - dynamic Function() callback}); -} - -@anonymous -@JS() -abstract class _RequestOptions { - @JS("gapi.client.init") - external Promise client_init( - dynamic - /*{ - /** - * The API Key to use. - */ - apiKey?: string; - /** - * An array of discovery doc URLs or discovery doc JSON objects. - */ - discoveryDocs?: string[]; - /** - * The app's client ID, found and created in the Google Developers Console. - */ - clientId?: string; - /** - * The scopes to request, as a space-delimited string. - */ - scope?: string, - - hosted_domain?: string; - }*/ - args); -} - -extension RequestOptionsExtensions on RequestOptions {} - -@anonymous -@JS() -abstract class TokenObject { - /// The access token to use in requests. - external String get access_token; - external set access_token(String v); - external factory TokenObject({String access_token}); -} - -/// Creates a HTTP request for making RESTful requests. -/// An object encapsulating the various arguments for this method. -@JS("gapi.client.request") -external HttpRequest request(RequestOptions args); - -/// Creates an RPC Request directly. The method name and version identify the method to be executed and the RPC params are provided upon RPC creation. -@JS("gapi.client.rpcRequest") -external RpcRequest rpcRequest(String method, - [String version, dynamic rpcParams]); - -/// Sets the API key for the application. -@JS("gapi.client.setApiKey") -external void setApiKey(String apiKey); - -/// Retrieves the OAuth 2.0 token for the application. -@JS("gapi.client.getToken") -external GoogleApiOAuth2TokenObject client_getToken(); - -/// Sets the authentication token to use in requests. -/// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiclientsettokentokenobject -@JS("gapi.client.setToken") -external void client_setToken(TokenObject /*TokenObject|Null*/ token); - -@anonymous -@JS() -abstract class HttpRequestFulfilled { - external T get result; - external set result(T v); - external String get body; - external set body(String v); - external List get headers; - external set headers(List v); - external num get status; - external set status(num v); - external String get statusText; - external set statusText(String v); - external factory HttpRequestFulfilled( - {T result, - String body, - List headers, - num status, - String statusText}); -} - -@anonymous -@JS() -abstract class _HttpRequestFulfilled { - /*external Promise client_load(String name, String version);*/ - /*external void client_load(String name, String version, dynamic callback(), - [String url]); -*/ - @JS("gapi.client.load") - external dynamic /*Promise|void*/ client_load( - String name, String version, - [dynamic callback(), String url]); -} - -extension HttpRequestFulfilledExtensions on HttpRequestFulfilled {} - -@anonymous -@JS() -abstract class HttpRequestRejected { - external dynamic /*dynamic|bool*/ get result; - external set result(dynamic /*dynamic|bool*/ v); - external String get body; - external set body(String v); - external List get headers; - external set headers(List v); - external num get status; - external set status(num v); - external String get statusText; - external set statusText(String v); - external factory HttpRequestRejected( - {dynamic /*dynamic|bool*/ result, - String body, - List headers, - num status, - String statusText}); -} - -/// HttpRequest supports promises. -/// See Google API Client JavaScript Using Promises https://developers.google.com/api-client-library/javascript/features/promises -@JS("gapi.client.HttpRequestPromise") -class HttpRequestPromise {} - -@JS("gapi.client.HttpRequestPromise") -abstract class _HttpRequestPromise { - /// Taken and adapted from https://github.com/Microsoft/TypeScript/blob/v2.3.1/lib/lib.es5.d.ts#L1343 - external Promise then/**/( - [dynamic /*TResult1|PromiseLike Function(HttpRequestFulfilled)|dynamic|Null*/ onfulfilled, - dynamic /*TResult2|PromiseLike Function(HttpRequestRejected)|dynamic|Null*/ onrejected, - dynamic opt_context]); -} - -extension HttpRequestPromiseExtensions on HttpRequestPromise { - Future then( - [dynamic /*TResult1|PromiseLike Function(HttpRequestFulfilled)|dynamic|Null*/ onfulfilled, - dynamic /*TResult2|PromiseLike Function(HttpRequestRejected)|dynamic|Null*/ onrejected, - dynamic opt_context]) { - final Object t = this; - final _HttpRequestPromise tt = t; - return promiseToFuture(tt.then(onfulfilled, onrejected, opt_context)); - } -} - -/// An object encapsulating an HTTP request. This object is not instantiated directly, rather it is returned by gapi.client.request. -@JS("gapi.client.HttpRequest") -class HttpRequest extends HttpRequestPromise { - /// Executes the request and runs the supplied callback on response. - external void execute( - dynamic callback( - - /// contains the response parsed as JSON. If the response is not JSON, this field will be false. - T jsonResp, - - /// is the HTTP response. It is JSON, and can be parsed to an object - dynamic - /*{ - body: string; - headers: any[]; - status: number; - statusText: string; - }*/ - rawResp)); -} - -/// Represents an HTTP Batch operation. Individual HTTP requests are added with the add method and the batch is executed using execute. -@JS("gapi.client.HttpBatch") -class HttpBatch { - /// Adds a gapi.client.HttpRequest to the batch. - external void add(HttpRequest httpRequest, - [dynamic - /*{ - /** - * Identifies the response for this request in the map of batch responses. If one is not provided, the system generates a random ID. - */ - id: string; - callback: ( - /** - * is the response for this request only. Its format is defined by the API method being called. - */ - individualResponse: any, - /** - * is the raw batch ID-response map as a string. It contains all responses to all requests in the batch. - */ - rawBatchResponse: any - ) => any - }*/ - opt_params]); - - /// Executes all requests in the batch. The supplied callback is executed on success or failure. - external void execute( - dynamic callback( - - /// is an ID-response map of each requests response. - dynamic responseMap, - - /// is the same response, but as an unparsed JSON-string. - String rawBatchResponse)); -} - -/// Similar to gapi.client.HttpRequest except this object encapsulates requests generated by registered methods. -@JS("gapi.client.RpcRequest") -class RpcRequest { - /// Executes the request and runs the supplied callback with the response. - external void callback( - void callback( - - /// contains the response parsed as JSON. If the response is not JSON, this field will be false. - dynamic jsonResp, - - /// is the same as jsonResp, except it is a raw string that has not been parsed. It is typically used when the response is not JSON. - String rawResp)); -} - -// End module gapi.client -@JS() -abstract class Promise { - external factory Promise( - void executor(void resolve(T result), Function reject)); - external Promise then(void onFulfilled(T result), [Function onRejected]); -} +// Manually removed gapi.auth and gapi.client, unused by this plugin. diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart index 8c8d23378e3e..b2b5c368b6ab 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart @@ -2,14 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: public_member_api_docs, unused_element - -@JS() -library gapiauth2; - -import "package:js/js.dart"; -import "package:js/js_util.dart" show promiseToFuture; - /// Type definitions for non-npm package Google Sign-In API 0.0 /// Project: https://developers.google.com/identity/sign-in/web/ /// Definitions by: Derek Lawless @@ -18,14 +10,24 @@ import "package:js/js_util.dart" show promiseToFuture; /// +// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/gapi.auth2 + +// ignore_for_file: public_member_api_docs, unused_element + +@JS() +library gapiauth2; + +import 'package:js/js.dart'; +import 'package:js/js_util.dart' show promiseToFuture; + @anonymous @JS() class GoogleAuthInitFailureError { external String get error; - external set error(String value); + external set error(String? value); external String get details; - external set details(String value); + external set details(String? value); } @anonymous @@ -35,16 +37,23 @@ class GoogleAuthSignInError { external set error(String value); } +@anonymous +@JS() +class OfflineAccessResponse { + external String? get code; + external set code(String? value); +} + // Module gapi.auth2 /// GoogleAuth is a singleton class that provides methods to allow the user to sign in with a Google account, /// get the user's current sign-in status, get specific data from the user's Google profile, /// request additional scopes, and sign out from the current account. -@JS("gapi.auth2.GoogleAuth") +@JS('gapi.auth2.GoogleAuth') class GoogleAuth { external IsSignedIn get isSignedIn; external set isSignedIn(IsSignedIn v); - external CurrentUser get currentUser; - external set currentUser(CurrentUser v); + external CurrentUser? get currentUser; + external set currentUser(CurrentUser? v); /// Calls the onInit function when the GoogleAuth object is fully initialized, or calls the onFailure function if /// initialization fails. @@ -59,7 +68,7 @@ class GoogleAuth { /// Attaches the sign-in flow to the specified container's click handler. external dynamic attachClickHandler( - dynamic container, + dynamic? container, SigninOptions options, dynamic onsuccess(GoogleUser googleUser), dynamic onfailure(String reason)); @@ -70,22 +79,20 @@ class GoogleAuth { abstract class _GoogleAuth { external Promise signIn( [dynamic /*SigninOptions|SigninOptionsBuilder*/ options]); - external Promise grantOfflineAccess( - [OfflineAccessOptions options]); + external Promise grantOfflineAccess( + [OfflineAccessOptions? options]); } extension GoogleAuthExtensions on GoogleAuth { Future signIn( [dynamic /*SigninOptions|SigninOptionsBuilder*/ options]) { - final Object t = this; - final _GoogleAuth tt = t; + final _GoogleAuth tt = this as _GoogleAuth; return promiseToFuture(tt.signIn(options)); } - Future grantOfflineAccess( - [OfflineAccessOptions options]) { - final Object t = this; - final _GoogleAuth tt = t; + Future grantOfflineAccess( + [OfflineAccessOptions? options]) { + final _GoogleAuth tt = this as _GoogleAuth; return promiseToFuture(tt.grantOfflineAccess(options)); } } @@ -118,42 +125,52 @@ abstract class SigninOptions { /// The package name of the Android app to install over the air. /// See Android app installs from your web site: /// https://developers.google.com/identity/sign-in/web/android-app-installs - external String get app_package_name; - external set app_package_name(String v); + external String? get app_package_name; + external set app_package_name(String? v); /// Fetch users' basic profile information when they sign in. /// Adds 'profile', 'email' and 'openid' to the requested scopes. /// True if unspecified. - external bool get fetch_basic_profile; - external set fetch_basic_profile(bool v); + external bool? get fetch_basic_profile; + external set fetch_basic_profile(bool? v); /// Specifies whether to prompt the user for re-authentication. /// See OpenID Connect Request Parameters: /// https://openid.net/specs/openid-connect-basic-1_0.html#RequestParameters - external String get prompt; - external set prompt(String v); + external String? get prompt; + external set prompt(String? v); /// The scopes to request, as a space-delimited string. /// Optional if fetch_basic_profile is not set to false. - external String get scope; - external set scope(String v); + external String? get scope; + external set scope(String? v); /// The UX mode to use for the sign-in flow. /// By default, it will open the consent flow in a popup. - external String /*'popup'|'redirect'*/ get ux_mode; - external set ux_mode(String /*'popup'|'redirect'*/ v); + external String? /*'popup'|'redirect'*/ get ux_mode; + external set ux_mode(String? /*'popup'|'redirect'*/ v); /// If using ux_mode='redirect', this parameter allows you to override the default redirect_uri that will be used at the end of the consent flow. /// The default redirect_uri is the current URL stripped of query parameters and hash fragment. - external String get redirect_uri; - external set redirect_uri(String v); + external String? get redirect_uri; + external set redirect_uri(String? v); + + // When your app knows which user it is trying to authenticate, it can provide this parameter as a hint to the authentication server. + // Passing this hint suppresses the account chooser and either pre-fill the email box on the sign-in form, or select the proper session (if the user is using multiple sign-in), + // which can help you avoid problems that occur if your app logs in the wrong user account. The value can be either an email address or the sub string, + // which is equivalent to the user's Google ID. + // https://developers.google.com/identity/protocols/OpenIDConnect?hl=en#authenticationuriparameters + external String? get login_hint; + external set login_hint(String? v); + external factory SigninOptions( {String app_package_name, bool fetch_basic_profile, String prompt, String scope, String /*'popup'|'redirect'*/ ux_mode, - String redirect_uri}); + String redirect_uri, + String login_hint}); } /// Definitions by: John @@ -162,12 +179,12 @@ abstract class SigninOptions { @anonymous @JS() abstract class OfflineAccessOptions { - external String get scope; - external set scope(String v); - external String /*'select_account'|'consent'*/ get prompt; - external set prompt(String /*'select_account'|'consent'*/ v); - external String get app_package_name; - external set app_package_name(String v); + external String? get scope; + external set scope(String? v); + external String? /*'select_account'|'consent'*/ get prompt; + external set prompt(String? /*'select_account'|'consent'*/ v); + external String? get app_package_name; + external set app_package_name(String? v); external factory OfflineAccessOptions( {String scope, String /*'select_account'|'consent'*/ prompt, @@ -180,98 +197,99 @@ abstract class OfflineAccessOptions { @JS() abstract class ClientConfig { /// The app's client ID, found and created in the Google Developers Console. - external String get client_id; - external set client_id(String v); + external String? get client_id; + external set client_id(String? v); /// The domains for which to create sign-in cookies. Either a URI, single_host_origin, or none. /// Defaults to single_host_origin if unspecified. - external String get cookie_policy; - external set cookie_policy(String v); + external String? get cookie_policy; + external set cookie_policy(String? v); /// The scopes to request, as a space-delimited string. Optional if fetch_basic_profile is not set to false. - external String get scope; - external set scope(String v); + external String? get scope; + external set scope(String? v); /// Fetch users' basic profile information when they sign in. Adds 'profile' and 'email' to the requested scopes. True if unspecified. - external bool get fetch_basic_profile; - external set fetch_basic_profile(bool v); + external bool? get fetch_basic_profile; + external set fetch_basic_profile(bool? v); /// The Google Apps domain to which users must belong to sign in. This is susceptible to modification by clients, /// so be sure to verify the hosted domain property of the returned user. Use GoogleUser.getHostedDomain() on the client, /// and the hd claim in the ID Token on the server to verify the domain is what you expected. - external String get hosted_domain; - external set hosted_domain(String v); + external String? get hosted_domain; + external set hosted_domain(String? v); /// Used only for OpenID 2.0 client migration. Set to the value of the realm that you are currently using for OpenID 2.0, /// as described in OpenID 2.0 (Migration). - external String get openid_realm; - external set openid_realm(String v); + external String? get openid_realm; + external set openid_realm(String? v); /// The UX mode to use for the sign-in flow. /// By default, it will open the consent flow in a popup. - external String /*'popup'|'redirect'*/ get ux_mode; - external set ux_mode(String /*'popup'|'redirect'*/ v); + external String? /*'popup'|'redirect'*/ get ux_mode; + external set ux_mode(String? /*'popup'|'redirect'*/ v); /// If using ux_mode='redirect', this parameter allows you to override the default redirect_uri that will be used at the end of the consent flow. /// The default redirect_uri is the current URL stripped of query parameters and hash fragment. - external String get redirect_uri; - external set redirect_uri(String v); + external String? get redirect_uri; + external set redirect_uri(String? v); external factory ClientConfig( {String client_id, String cookie_policy, String scope, bool fetch_basic_profile, - String hosted_domain, + String? hosted_domain, String openid_realm, String /*'popup'|'redirect'*/ ux_mode, String redirect_uri}); } -@JS("gapi.auth2.SigninOptionsBuilder") +@JS('gapi.auth2.SigninOptionsBuilder') class SigninOptionsBuilder { external dynamic setAppPackageName(String name); external dynamic setFetchBasicProfile(bool fetch); external dynamic setPrompt(String prompt); external dynamic setScope(String scope); + external dynamic setLoginHint(String hint); } @anonymous @JS() abstract class BasicProfile { - external String getId(); - external String getName(); - external String getGivenName(); - external String getFamilyName(); - external String getImageUrl(); - external String getEmail(); + external String? getId(); + external String? getName(); + external String? getGivenName(); + external String? getFamilyName(); + external String? getImageUrl(); + external String? getEmail(); } /// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauth2authresponse @anonymous @JS() abstract class AuthResponse { - external String get access_token; - external set access_token(String v); - external String get id_token; - external set id_token(String v); - external String get login_hint; - external set login_hint(String v); - external String get scope; - external set scope(String v); - external num get expires_in; - external set expires_in(num v); - external num get first_issued_at; - external set first_issued_at(num v); - external num get expires_at; - external set expires_at(num v); + external String? get access_token; + external set access_token(String? v); + external String? get id_token; + external set id_token(String? v); + external String? get login_hint; + external set login_hint(String? v); + external String? get scope; + external set scope(String? v); + external num? get expires_in; + external set expires_in(num? v); + external num? get first_issued_at; + external set first_issued_at(num? v); + external num? get expires_at; + external set expires_at(num? v); external factory AuthResponse( - {String access_token, - String id_token, - String login_hint, - String scope, - num expires_in, - num first_issued_at, - num expires_at}); + {String? access_token, + String? id_token, + String? login_hint, + String? scope, + num? expires_in, + num? first_issued_at, + num? expires_at}); } /// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauth2authorizeconfig @@ -282,22 +300,22 @@ abstract class AuthorizeConfig { external set client_id(String v); external String get scope; external set scope(String v); - external String get response_type; - external set response_type(String v); - external String get prompt; - external set prompt(String v); - external String get cookie_policy; - external set cookie_policy(String v); - external String get hosted_domain; - external set hosted_domain(String v); - external String get login_hint; - external set login_hint(String v); - external String get app_package_name; - external set app_package_name(String v); - external String get openid_realm; - external set openid_realm(String v); - external bool get include_granted_scopes; - external set include_granted_scopes(bool v); + external String? get response_type; + external set response_type(String? v); + external String? get prompt; + external set prompt(String? v); + external String? get cookie_policy; + external set cookie_policy(String? v); + external String? get hosted_domain; + external set hosted_domain(String? v); + external String? get login_hint; + external set login_hint(String? v); + external String? get app_package_name; + external set app_package_name(String? v); + external String? get openid_realm; + external set openid_realm(String? v); + external bool? get include_granted_scopes; + external set include_granted_scopes(bool? v); external factory AuthorizeConfig( {String client_id, String scope, @@ -350,34 +368,31 @@ abstract class AuthorizeResponse { @JS() abstract class GoogleUser { /// Get the user's unique ID string. - external String getId(); + external String? getId(); /// Returns true if the user is signed in. external bool isSignedIn(); /// Get the user's Google Apps domain if the user signed in with a Google Apps account. - external String getHostedDomain(); + external String? getHostedDomain(); /// Get the scopes that the user granted as a space-delimited string. - external String getGrantedScopes(); + external String? getGrantedScopes(); /// Get the user's basic profile information. - external BasicProfile getBasicProfile(); + external BasicProfile? getBasicProfile(); /// Get the response object from the user's auth session. + // This returns an empty JS object when the user hasn't attempted to sign in. external AuthResponse getAuthResponse([bool includeAuthorizationData]); /// Returns true if the user granted the specified scopes. external bool hasGrantedScopes(String scopes); - /// Signs in the user. Use this method to request additional scopes for incremental - /// authorization or to sign in a user after the user has signed out. - /// When you use GoogleUser.signIn(), the sign-in flow skips the account chooser step. - /// See GoogleAuth.signIn(). - external dynamic signIn( - [dynamic /*SigninOptions|SigninOptionsBuilder*/ options]); - - /// See GoogleUser.signIn() + // Has the API for grant and grantOfflineAccess changed? + /// Request additional scopes to the user. + /// + /// See GoogleAuth.signIn() for the list of parameters and the error code. external dynamic grant( [dynamic /*SigninOptions|SigninOptionsBuilder*/ options]); @@ -393,35 +408,35 @@ abstract class GoogleUser { @anonymous @JS() abstract class _GoogleUser { + /// Forces a refresh of the access token, and then returns a Promise for the new AuthResponse. external Promise reloadAuthResponse(); } extension GoogleUserExtensions on GoogleUser { Future reloadAuthResponse() { - final Object t = this; - final _GoogleUser tt = t; + final _GoogleUser tt = this as _GoogleUser; return promiseToFuture(tt.reloadAuthResponse()); } } /// Initializes the GoogleAuth object. /// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauth2initparams -@JS("gapi.auth2.init") +@JS('gapi.auth2.init') external GoogleAuth init(ClientConfig params); /// Returns the GoogleAuth object. You must initialize the GoogleAuth object with gapi.auth2.init() before calling this method. -@JS("gapi.auth2.getAuthInstance") -external GoogleAuth getAuthInstance(); +@JS('gapi.auth2.getAuthInstance') +external GoogleAuth? getAuthInstance(); /// Performs a one time OAuth 2.0 authorization. /// Reference: https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauth2authorizeparams-callback -@JS("gapi.auth2.authorize") +@JS('gapi.auth2.authorize') external void authorize( AuthorizeConfig params, void callback(AuthorizeResponse response)); // End module gapi.auth2 // Module gapi.signin2 -@JS("gapi.signin2.render") +@JS('gapi.signin2.render') external void render( dynamic id, dynamic diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart b/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart index f954ff1dce6b..0d3e4165227c 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart @@ -20,7 +20,7 @@ external set gapiOnloadCallback(Function callback); /// This is only exposed for testing. It shouldn't be accessed by users of the /// plugin as it could break at any point. @visibleForTesting -const String kGapiOnloadCallbackFunctionName = "gapiOnloadCallback"; +const String kGapiOnloadCallbackFunctionName = 'gapiOnloadCallback'; String _addOnloadToScript(String url) => url.startsWith('data:') ? url : '$url?onload=$kGapiOnloadCallbackFunctionName'; diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart b/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart index 36bb52dce0f3..98cb24efaeeb 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart @@ -9,13 +9,22 @@ import 'package:google_sign_in_platform_interface/google_sign_in_platform_interf import 'generated/gapiauth2.dart' as auth2; -/// Injects a bunch of libraries in the and returns a -/// Future that resolves when all load. -Future injectJSLibraries(List libraries, - {html.HtmlElement target /*, Duration timeout */}) { +/// Injects a list of JS [libraries] as `script` tags into a [target] [html.HtmlElement]. +/// +/// If [target] is not provided, it defaults to the web app's `head` tag (see `web/index.html`). +/// [libraries] is a list of URLs that are used as the `src` attribute of `script` tags +/// to which an `onLoad` listener is attached (one per URL). +/// +/// Returns a [Future] that resolves when all of the `script` tags `onLoad` events trigger. +Future injectJSLibraries( + List libraries, { + html.HtmlElement? target, +}) { final List> loading = >[]; final List tags = []; + final html.Element targetElement = target ?? html.querySelector('head')!; + libraries.forEach((String library) { final html.ScriptElement script = html.ScriptElement() ..async = true @@ -25,24 +34,26 @@ Future injectJSLibraries(List libraries, loading.add(script.onLoad.first); tags.add(script); }); - (target ?? html.querySelector('head')).children.addAll(tags); + + targetElement.children.addAll(tags); return Future.wait(loading); } -/// Utility method that converts `currentUser` to the equivalent -/// [GoogleSignInUserData]. +/// Utility method that converts `currentUser` to the equivalent [GoogleSignInUserData]. +/// /// This method returns `null` when the [currentUser] is not signed in. -GoogleSignInUserData gapiUserToPluginUserData(auth2.GoogleUser currentUser) { +GoogleSignInUserData? gapiUserToPluginUserData(auth2.GoogleUser? currentUser) { final bool isSignedIn = currentUser?.isSignedIn() ?? false; - final auth2.BasicProfile profile = currentUser?.getBasicProfile(); + final auth2.BasicProfile? profile = currentUser?.getBasicProfile(); if (!isSignedIn || profile?.getId() == null) { return null; } + return GoogleSignInUserData( displayName: profile?.getName(), - email: profile?.getEmail(), - id: profile?.getId(), + email: profile?.getEmail() ?? '', + id: profile?.getId() ?? '', photoUrl: profile?.getImageUrl(), - idToken: currentUser.getAuthResponse()?.id_token, + idToken: currentUser?.getAuthResponse().id_token, ); } diff --git a/packages/google_sign_in/google_sign_in_web/pubspec.yaml b/packages/google_sign_in/google_sign_in_web/pubspec.yaml index ac9d36bd15be..ae6807cd9231 100644 --- a/packages/google_sign_in/google_sign_in_web/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_web/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_web description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android, iOS and Web. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in_web -version: 0.9.2+1 +version: 0.10.0 flutter: plugin: @@ -12,23 +12,19 @@ flutter: fileName: google_sign_in_web.dart dependencies: - google_sign_in_platform_interface: ^1.1.0 + google_sign_in_platform_interface: ^2.0.0 flutter: sdk: flutter flutter_web_plugins: sdk: flutter - meta: ^1.1.7 - js: ^0.6.1 + meta: ^1.3.0 + js: ^0.6.3 dev_dependencies: flutter_test: sdk: flutter - google_sign_in: ^4.0.14 - pedantic: ^1.8.0 - mockito: ^4.1.1 - integration_test: - path: ../../integration_test + pedantic: ^1.10.0 environment: - sdk: ">=2.6.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/google_sign_in/google_sign_in_web/test/README.md b/packages/google_sign_in/google_sign_in_web/test/README.md index 7c48d024ba57..7c5b4ad682ba 100644 --- a/packages/google_sign_in/google_sign_in_web/test/README.md +++ b/packages/google_sign_in/google_sign_in_web/test/README.md @@ -1,17 +1,5 @@ -# Running browser_tests +## test -Make sure you have updated to the latest Flutter master. +This package uses integration tests for testing. -1. Check what version of Chrome is running on the machine you're running tests on. - -2. Download and install driver for that version from here: - * - -3. Start the driver using `chromedriver --port=4444` - -4. Change into the `test` directory of your clone. - -5. Run tests: `flutter drive -d web-server --browser-name=chrome --target=test_driver/TEST_NAME_integration.dart`, or (in Linux): - - * Single: `./run_test test_driver/TEST_NAME_integration.dart` - * All: `./run_test` +See `example/README.md` for more info. diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration_test.dart b/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration_test.dart deleted file mode 100644 index 39444c0daa24..000000000000 --- a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_load_integration_test.dart +++ /dev/null @@ -1,7 +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 'package:integration_test/integration_test_driver.dart'; - -Future main() async => integrationDriver(); diff --git a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration_test.dart b/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration_test.dart deleted file mode 100644 index 39444c0daa24..000000000000 --- a/packages/google_sign_in/google_sign_in_web/test/test_driver/gapi_utils_integration_test.dart +++ /dev/null @@ -1,7 +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 'package:integration_test/integration_test_driver.dart'; - -Future main() async => integrationDriver(); diff --git a/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart b/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart new file mode 100644 index 000000000000..334f52186d9d --- /dev/null +++ b/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart @@ -0,0 +1,10 @@ +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Tell the user where to find the real tests', () { + print('---'); + print('This package uses integration_test for its tests.'); + print('See `example/README.md` for more info.'); + print('---'); + }); +} From 7668398fc4f8c3f61905cd23bfef138b2ba77685 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 26 Feb 2021 04:10:06 -0800 Subject: [PATCH 282/924] [google_sign_in] Bump app-facing version for NNBD stable (#3637) --- .../google_sign_in/CHANGELOG.md | 9 +---- .../google_sign_in/example/lib/main.dart | 39 ++++++++++--------- .../google_sign_in/example/pubspec.yaml | 6 +-- .../google_sign_in/pubspec.yaml | 17 ++++---- 4 files changed, 34 insertions(+), 37 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md index 85c8cc491105..57d1c9be3743 100644 --- a/packages/google_sign_in/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,11 +1,6 @@ -## 5.0.0-nullsafety.1 +## 5.0.0 -* Document that the web plugin is not endorsed in the `nullsafety` prerelease for now. - -## 5.0.0-nullsafety - -* Migrate to nnbd. -* **Breaking change**: web plugins aren't endorsed in null-safe plugins yet. +* Migrate to null safety. ## 4.5.9 diff --git a/packages/google_sign_in/google_sign_in/example/lib/main.dart b/packages/google_sign_in/google_sign_in/example/lib/main.dart index a738c248a4a4..e003225af5cc 100755 --- a/packages/google_sign_in/google_sign_in/example/lib/main.dart +++ b/packages/google_sign_in/google_sign_in/example/lib/main.dart @@ -33,31 +33,31 @@ class SignInDemo extends StatefulWidget { } class SignInDemoState extends State { - GoogleSignInAccount _currentUser; - String _contactText; + GoogleSignInAccount? _currentUser; + String _contactText = ''; @override void initState() { super.initState(); - _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account) { + _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount? account) { setState(() { _currentUser = account; }); if (_currentUser != null) { - _handleGetContact(); + _handleGetContact(_currentUser!); } }); _googleSignIn.signInSilently(); } - Future _handleGetContact() async { + Future _handleGetContact(GoogleSignInAccount user) async { setState(() { _contactText = "Loading contact info..."; }); final http.Response response = await http.get( - 'https://people.googleapis.com/v1/people/me/connections' - '?requestMask.includeField=person.names', - headers: await _currentUser.authHeaders, + Uri.parse('https://people.googleapis.com/v1/people/me/connections' + '?requestMask.includeField=person.names'), + headers: await user.authHeaders, ); if (response.statusCode != 200) { setState(() { @@ -68,7 +68,7 @@ class SignInDemoState extends State { return; } final Map data = json.decode(response.body); - final String namedContact = _pickFirstNamedContact(data); + final String? namedContact = _pickFirstNamedContact(data); setState(() { if (namedContact != null) { _contactText = "I see you know $namedContact!"; @@ -78,14 +78,14 @@ class SignInDemoState extends State { }); } - String _pickFirstNamedContact(Map data) { - final List connections = data['connections']; - final Map contact = connections?.firstWhere( + String? _pickFirstNamedContact(Map data) { + final List? connections = data['connections']; + final Map? contact = connections?.firstWhere( (dynamic contact) => contact['names'] != null, orElse: () => null, ); if (contact != null) { - final Map name = contact['names'].firstWhere( + final Map? name = contact['names'].firstWhere( (dynamic name) => name['displayName'] != null, orElse: () => null, ); @@ -107,26 +107,27 @@ class SignInDemoState extends State { Future _handleSignOut() => _googleSignIn.disconnect(); Widget _buildBody() { - if (_currentUser != null) { + GoogleSignInAccount? user = _currentUser; + if (user != null) { return Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ ListTile( leading: GoogleUserCircleAvatar( - identity: _currentUser, + identity: user, ), - title: Text(_currentUser.displayName ?? ''), - subtitle: Text(_currentUser.email ?? ''), + title: Text(user.displayName ?? ''), + subtitle: Text(user.email), ), const Text("Signed in successfully."), - Text(_contactText ?? ''), + Text(_contactText), ElevatedButton( child: const Text('SIGN OUT'), onPressed: _handleSignOut, ), ElevatedButton( child: const Text('REFRESH'), - onPressed: _handleGetContact, + onPressed: () => _handleGetContact(user), ), ], ); diff --git a/packages/google_sign_in/google_sign_in/example/pubspec.yaml b/packages/google_sign_in/google_sign_in/example/pubspec.yaml index e35aa9ace6a3..b5a1f3e1c2cc 100755 --- a/packages/google_sign_in/google_sign_in/example/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/example/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - http: ^0.12.0 + http: ^0.13.0 dev_dependencies: - pedantic: ^1.8.0 + pedantic: ^1.10.0 integration_test: path: ../../../integration_test flutter_driver: @@ -24,5 +24,5 @@ flutter: uses-material-design: true environment: - sdk: ">=2.0.0-dev.28.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.4" diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index ca1fe8d829b8..06fa12c0f4c0 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in -version: 5.0.0-nullsafety.1 +version: 5.0.0 flutter: plugin: @@ -12,25 +12,26 @@ flutter: pluginClass: GoogleSignInPlugin ios: pluginClass: FLTGoogleSignInPlugin - #web: - # default_package: google_sign_in_web + web: + default_package: google_sign_in_web dependencies: - google_sign_in_platform_interface: ^2.0.0-nullsafety + google_sign_in_platform_interface: ^2.0.0 + google_sign_in_web: ^0.10.0 flutter: sdk: flutter - meta: ^1.3.0-nullsafety.6 + meta: ^1.3.0 dev_dependencies: - http: ^0.12.0 + http: ^0.13.0 flutter_driver: sdk: flutter flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.1 + pedantic: ^1.10.0 integration_test: path: ../../integration_test environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.5" From ad650f94f95664a913fc913147fa03a8e0057c91 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 26 Feb 2021 09:29:05 -0800 Subject: [PATCH 283/924] [file_selector] Endorse web (#3643) --- packages/file_selector/file_selector/CHANGELOG.md | 4 ++++ packages/file_selector/file_selector/pubspec.yaml | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/file_selector/file_selector/CHANGELOG.md b/packages/file_selector/file_selector/CHANGELOG.md index 64ac5959a7c0..cea752e51558 100644 --- a/packages/file_selector/file_selector/CHANGELOG.md +++ b/packages/file_selector/file_selector/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.1 + +Endorse the web implementation. + ## 0.8.0 Migrate to null safety. diff --git a/packages/file_selector/file_selector/pubspec.yaml b/packages/file_selector/file_selector/pubspec.yaml index 34b459cca720..3d03de09e9f2 100644 --- a/packages/file_selector/file_selector/pubspec.yaml +++ b/packages/file_selector/file_selector/pubspec.yaml @@ -1,12 +1,19 @@ name: file_selector description: Flutter plugin for opening and saving files. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector -version: 0.8.0 +version: 0.8.1 + +flutter: + plugin: + platforms: + web: + default_package: file_selector_web dependencies: flutter: sdk: flutter file_selector_platform_interface: ^2.0.0 + file_selector_web: ^0.8.1 dev_dependencies: flutter_test: From aead5acb35c6fe2798986e9caf2c89379ec519bc Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 26 Feb 2021 10:19:07 -0800 Subject: [PATCH 284/924] [extension_google_sign_in_as_googleapis_auth] Migrate to null safety (#3642) Migrates to NNBD. Replaces Mockito-based fakes with test's Fake. --- .../CHANGELOG.md | 5 +++ .../example/lib/main.dart | 3 +- .../example/pubspec.yaml | 6 +-- ...ion_google_sign_in_as_googleapis_auth.dart | 15 ++++--- .../pubspec.yaml | 16 +++---- ...oogle_sign_in_as_googleapis_auth_test.dart | 42 +++++++++++-------- 6 files changed, 53 insertions(+), 34 deletions(-) diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md index 4afb1a0e98bf..5e29f340599b 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.0 + +* Migrate to null safety. +* Fixes the requested scopes to use the `GoogleSignIn` instance's `scopes`. + ## 1.0.4 * Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart index 597ab563ae5b..0ec62a832648 100755 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart @@ -56,7 +56,8 @@ class SignInDemoState extends State { _contactText = 'Loading contact info...'; }); - final peopleApi = PeopleApi(await _googleSignIn.authenticatedClient()); + final peopleApi = + PeopleServiceApi(await _googleSignIn.authenticatedClient()); final response = await peopleApi.people.connections.list( 'people/me', personFields: 'names', diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml index 48dfef644a5c..d3b428d190c9 100755 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml @@ -4,7 +4,7 @@ description: Example of Google Sign-In plugin and googleapis. dependencies: flutter: sdk: flutter - google_sign_in: ^4.4.1 + google_sign_in: ^5.0.0 extension_google_sign_in_as_googleapis_auth: # When depending on this package from a real application you should use: # extension_google_sign_in_as_googleapis_auth: ^x.y.z @@ -12,10 +12,10 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - googleapis: ^0.55.0 + googleapis: ^1.0.0 dev_dependencies: - pedantic: ^1.8.0 + pedantic: ^1.10.0 integration_test: path: ../../../integration_test flutter_driver: diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart index eec45cc0e89a..8c8ede5eee1a 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart @@ -15,15 +15,20 @@ import 'package:http/http.dart' as http; /// client that can be used with the rest of the `googleapis` libraries. extension GoogleApisGoogleSignInAuth on GoogleSignIn { /// Retrieve a `googleapis` authenticated client. - Future authenticatedClient({ - @visibleForTesting GoogleSignInAuthentication debugAuthentication, - @visibleForTesting List debugScopes = const [], + Future authenticatedClient({ + @visibleForTesting GoogleSignInAuthentication? debugAuthentication, + @visibleForTesting List? debugScopes, }) async { - final auth = debugAuthentication ?? await currentUser.authentication; + final GoogleSignInAuthentication? auth = + debugAuthentication ?? await currentUser?.authentication; + final String? oathTokenString = auth?.accessToken; + if (oathTokenString == null) { + return null; + } final credentials = googleapis_auth.AccessCredentials( googleapis_auth.AccessToken( 'Bearer', - auth.accessToken, + oathTokenString, // We don't know when the token expires, so we assume "never" DateTime.now().toUtc().add(Duration(days: 365)), ), diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml index 9da5f0baa848..7d86b67196d0 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml @@ -6,23 +6,23 @@ name: extension_google_sign_in_as_googleapis_auth description: A bridge package between google_sign_in and googleapis_auth, to create Authenticated Clients from google_sign_in user credentials. -version: 1.0.4 +version: 2.0.0 homepage: https://github.com/flutter/plugins/google_sign_in/extension_google_sign_in_as_googleapis_auth dependencies: flutter: sdk: flutter - google_sign_in: ^4.4.1 - googleapis_auth: ^0.2.11+1 - meta: ^1.1.8 - http: ^0.12.1 + google_sign_in: ^5.0.0 + googleapis_auth: ^1.0.0 + meta: ^1.3.0 + http: ^0.13.0 dev_dependencies: - mockito: ^4.1.1 - pedantic: ^1.9.0 + pedantic: ^1.10.0 + test: ^1.16.3 flutter_test: sdk: flutter environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.12.13+hotfix.4" diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart index 9f86703d4bb8..508f366eacde 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart @@ -7,25 +7,25 @@ import 'package:google_sign_in/google_sign_in.dart'; import 'package:googleapis_auth/auth.dart' as auth; import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; -import 'package:mockito/mockito.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:test/fake.dart'; -// Mocks so I don't have to prepare all the GoogleSignIn environment. -class MockGoogleSignIn extends Mock implements GoogleSignIn {} +const SOME_FAKE_ACCESS_TOKEN = 'this-is-something-not-null'; +const DEBUG_FAKE_SCOPES = ['some-scope', 'another-scope']; +const SIGN_IN_FAKE_SCOPES = ['some-scope', 'another-scope']; -class MockGoogleSignInAuthentication extends Mock - implements GoogleSignInAuthentication {} +class FakeGoogleSignIn extends Fake implements GoogleSignIn { + final List scopes = SIGN_IN_FAKE_SCOPES; +} -const SOME_FAKE_ACCESS_TOKEN = 'this-is-something-not-null'; -const SOME_FAKE_SCOPES = ['some-scope', 'another-scope']; +class FakeGoogleSignInAuthentication extends Fake + implements GoogleSignInAuthentication { + final String accessToken = SOME_FAKE_ACCESS_TOKEN; +} void main() { - GoogleSignIn signIn = MockGoogleSignIn(); - final authMock = MockGoogleSignInAuthentication(); - - setUp(() { - when(authMock.accessToken).thenReturn(SOME_FAKE_ACCESS_TOKEN); - }); + GoogleSignIn signIn = FakeGoogleSignIn(); + final authMock = FakeGoogleSignInAuthentication(); test('authenticatedClient returns an authenticated client', () async { final client = await signIn.authenticatedClient( @@ -34,13 +34,21 @@ void main() { expect(client, isA()); }); + test('authenticatedClient uses GoogleSignIn scopes by default', () async { + final client = (await signIn.authenticatedClient( + debugAuthentication: authMock, + ))!; + expect(client.credentials.accessToken.data, equals(SOME_FAKE_ACCESS_TOKEN)); + expect(client.credentials.scopes, equals(SIGN_IN_FAKE_SCOPES)); + }); + test('authenticatedClient returned client contains the passed-in credentials', () async { - final client = await signIn.authenticatedClient( + final client = (await signIn.authenticatedClient( debugAuthentication: authMock, - debugScopes: SOME_FAKE_SCOPES, - ); + debugScopes: DEBUG_FAKE_SCOPES, + ))!; expect(client.credentials.accessToken.data, equals(SOME_FAKE_ACCESS_TOKEN)); - expect(client.credentials.scopes, equals(SOME_FAKE_SCOPES)); + expect(client.credentials.scopes, equals(DEBUG_FAKE_SCOPES)); }); } From 4afca62b46315dcdbfa2b043d703aaf4ebf6960c Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 26 Feb 2021 11:40:19 -0800 Subject: [PATCH 285/924] Fix Cirrus script for firebase testlab tests (#3634) --- .cirrus.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 6b3614178b11..5a25b773ea33 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -105,11 +105,11 @@ task: - export CIRRUS_COMMIT_MESSAGE="" - ./script/incremental_build.sh build-examples --apk - ./script/incremental_build.sh java-test # must come after apk build - - if [[ $GCLOUD_FIREBASE_TESTLAB_KEY == ENCRYPTED* ]]; then - - echo "This user does not have permission to run Firebase Test Lab tests." - - else + - if [[ -n "$GCLOUD_FIREBASE_TESTLAB_KEY" ]]; then - echo $GCLOUD_FIREBASE_TESTLAB_KEY > ${HOME}/gcloud-service-key.json - ./script/incremental_build.sh firebase-test-lab --device model=flame,version=29 --device model=starqlteue,version=26 + - else + - echo "This user does not have permission to run Firebase Test Lab tests." - fi - export CIRRUS_CHANGE_MESSAGE=`cat /tmp/cirrus_change_message.txt` - export CIRRUS_COMMIT_MESSAGE=`cat /tmp/cirrus_commit_message.txt` From 4b4913c8dd82be0b3ff847edbc81b78c033ea67f Mon Sep 17 00:00:00 2001 From: Juanjo Tugores Date: Fri, 26 Feb 2021 16:31:02 -0600 Subject: [PATCH 286/924] [file_selector_platform_interface]: Verify that extensions don't have leading dots. (#3451) --- .../file_selector_platform_interface/CHANGELOG.md | 4 ++++ .../lib/src/types/x_type_group/x_type_group.dart | 7 +++++-- .../file_selector_platform_interface/pubspec.yaml | 2 +- .../test/method_channel_file_selector_test.dart | 12 ++++++------ .../test/x_type_group_test.dart | 9 ++++++++- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md index ed720ca0515d..8fcc3e06ef49 100644 --- a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md +++ b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Replace extensions with leading dots. + ## 2.0.0 * Migration to null-safety diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart index f3f05e2ab3a6..7b3cb12be9f1 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart @@ -10,11 +10,11 @@ class XTypeGroup { /// allowed. XTypeGroup({ this.label, - this.extensions, + List? extensions, this.mimeTypes, this.macUTIs, this.webWildCards, - }); + }) : this.extensions = _removeLeadingDots(extensions); /// The 'name' or reference to this group of types final String? label; @@ -41,4 +41,7 @@ class XTypeGroup { 'webWildCards': webWildCards, }; } + + static List? _removeLeadingDots(List? exts) => + exts?.map((ext) => ext.startsWith('.') ? ext.substring(1) : ext).toList(); } diff --git a/packages/file_selector/file_selector_platform_interface/pubspec.yaml b/packages/file_selector/file_selector_platform_interface/pubspec.yaml index 30398a2f0d23..980730eb2676 100644 --- a/packages/file_selector/file_selector_platform_interface/pubspec.yaml +++ b/packages/file_selector/file_selector_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the file_selector plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_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: 2.0.0 +version: 2.0.1 dependencies: flutter: diff --git a/packages/file_selector/file_selector_platform_interface/test/method_channel_file_selector_test.dart b/packages/file_selector/file_selector_platform_interface/test/method_channel_file_selector_test.dart index 99f9fe0f0e3b..c863ad361112 100644 --- a/packages/file_selector/file_selector_platform_interface/test/method_channel_file_selector_test.dart +++ b/packages/file_selector/file_selector_platform_interface/test/method_channel_file_selector_test.dart @@ -29,14 +29,14 @@ void main() { test('passes the accepted type groups correctly', () async { final group = XTypeGroup( label: 'text', - extensions: ['.txt'], + extensions: ['txt'], mimeTypes: ['text/plain'], macUTIs: ['public.text'], ); final groupTwo = XTypeGroup( label: 'image', - extensions: ['.jpg'], + extensions: ['jpg'], mimeTypes: ['image/jpg'], macUTIs: ['public.image'], webWildCards: ['image/*']); @@ -90,14 +90,14 @@ void main() { test('passes the accepted type groups correctly', () async { final group = XTypeGroup( label: 'text', - extensions: ['.txt'], + extensions: ['txt'], mimeTypes: ['text/plain'], macUTIs: ['public.text'], ); final groupTwo = XTypeGroup( label: 'image', - extensions: ['.jpg'], + extensions: ['jpg'], mimeTypes: ['image/jpg'], macUTIs: ['public.image'], webWildCards: ['image/*']); @@ -152,14 +152,14 @@ void main() { test('passes the accepted type groups correctly', () async { final group = XTypeGroup( label: 'text', - extensions: ['.txt'], + extensions: ['txt'], mimeTypes: ['text/plain'], macUTIs: ['public.text'], ); final groupTwo = XTypeGroup( label: 'image', - extensions: ['.jpg'], + extensions: ['jpg'], mimeTypes: ['image/jpg'], macUTIs: ['public.image'], webWildCards: ['image/*']); diff --git a/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart b/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart index bde89f46405d..21bbac5d0f90 100644 --- a/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart +++ b/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart @@ -9,7 +9,7 @@ void main() { group('XTypeGroup', () { test('toJSON() creates correct map', () { final label = 'test group'; - final extensions = ['.txt', '.jpg']; + final extensions = ['txt', 'jpg']; final mimeTypes = ['text/plain']; final macUTIs = ['public.plain-text']; final webWildCards = ['image/*']; @@ -41,5 +41,12 @@ void main() { expect(jsonMap['macUTIs'], null); expect(jsonMap['webWildCards'], null); }); + + test('Leading dots are removed from extensions', () { + final extensions = ['.txt', '.jpg']; + final group = XTypeGroup(extensions: extensions); + + expect(group.extensions, ['txt', 'jpg']); + }); }); } From c1c4514b9967960c9a33e73d5ca6037385f240ef Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Fri, 26 Feb 2021 14:36:05 -0800 Subject: [PATCH 287/924] [image_picker_for_web] Bump version for NNBD stable (#3635) --- .../image_picker/image_picker_for_web/CHANGELOG.md | 7 ++----- .../image_picker/image_picker_for_web/pubspec.yaml | 13 ++++++------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/image_picker/image_picker_for_web/CHANGELOG.md b/packages/image_picker/image_picker_for_web/CHANGELOG.md index fcc6c9980c29..7b2c4077e28d 100644 --- a/packages/image_picker/image_picker_for_web/CHANGELOG.md +++ b/packages/image_picker/image_picker_for_web/CHANGELOG.md @@ -1,10 +1,7 @@ -# 2.0.0-nullsafety.1 - -* Add doc comments to point out that some arguments aren't supported on the web. - -# 2.0.0-nullsafety +# 2.0.0 * Migrate to null safety. +* Add doc comments to point out that some arguments aren't supported on the web. # 0.1.0+3 diff --git a/packages/image_picker/image_picker_for_web/pubspec.yaml b/packages/image_picker/image_picker_for_web/pubspec.yaml index adc636192c69..045be48eb1c5 100644 --- a/packages/image_picker/image_picker_for_web/pubspec.yaml +++ b/packages/image_picker/image_picker_for_web/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_for_web description: Web platform implementation of image_picker homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_for_web -version: 2.0.0-nullsafety.1 +version: 2.0.0 flutter: plugin: @@ -12,19 +12,18 @@ flutter: fileName: image_picker_for_web.dart dependencies: - image_picker_platform_interface: ^2.0.0-nullsafety + image_picker_platform_interface: ^2.0.0 + meta: ^1.3.0 flutter: sdk: flutter flutter_web_plugins: sdk: flutter - meta: ^1.3.0-nullsafety.6 - js: ^0.6.3-nullsafety.3 dev_dependencies: + pedantic: ^1.10.0 flutter_test: sdk: flutter - pedantic: ^1.10.0 environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.10.0" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" From a0fe2225e2550d4a1a4214c7582dad90feff5d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petrus=20Nguy=E1=BB=85n=20Th=C3=A1i=20H=E1=BB=8Dc?= Date: Sat, 27 Feb 2021 07:31:04 +0700 Subject: [PATCH 288/924] [shared_preferences] Don't create additional Handler when method channel is called. (#3639) --- .../shared_preferences/shared_preferences/CHANGELOG.md | 4 ++++ .../plugins/sharedpreferences/MethodCallHandlerImpl.java | 9 +++++++-- .../sharedpreferences/SharedPreferencesPlugin.java | 5 ++++- .../shared_preferences/shared_preferences/pubspec.yaml | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 63c042a1194e..1516163b8807 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.3 + +* Android: don't create additional Handler when method channel is called. + ## 2.0.2 * Don't create additional thread pools when method channel is called. diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java index d58cc32ed625..4f55d882005f 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java @@ -44,6 +44,7 @@ class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { private final android.content.SharedPreferences preferences; private final ExecutorService executor; + private final Handler handler; /** * Constructs a {@link MethodCallHandlerImpl} instance. Creates a {@link @@ -53,6 +54,7 @@ class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { preferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); executor = new ThreadPoolExecutor(0, 1, 30L, TimeUnit.SECONDS, new SynchronousQueue()); + handler = new Handler(Looper.getMainLooper()); } @Override @@ -125,10 +127,13 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { } } + public void teardown() { + handler.removeCallbacksAndMessages(null); + executor.shutdown(); + } + private void commitAsync( final SharedPreferences.Editor editor, final MethodChannel.Result result) { - final Handler handler = new Handler(Looper.getMainLooper()); - executor.execute( new Runnable() { @Override diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java index be627f3ce613..83163f82d9ec 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java @@ -13,6 +13,7 @@ public class SharedPreferencesPlugin implements FlutterPlugin { private static final String CHANNEL_NAME = "plugins.flutter.io/shared_preferences"; private MethodChannel channel; + private MethodCallHandlerImpl handler; @SuppressWarnings("deprecation") public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) { @@ -32,11 +33,13 @@ public void onDetachedFromEngine(FlutterPlugin.FlutterPluginBinding binding) { private void setupChannel(BinaryMessenger messenger, Context context) { channel = new MethodChannel(messenger, CHANNEL_NAME); - MethodCallHandlerImpl handler = new MethodCallHandlerImpl(context); + handler = new MethodCallHandlerImpl(context); channel.setMethodCallHandler(handler); } private void teardownChannel() { + handler.teardown(); + handler = null; channel.setMethodCallHandler(null); channel = null; } diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 6f6ab1fee6e8..899266a4d6f0 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences description: Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences -version: 2.0.2 +version: 2.0.3 flutter: plugin: From 4155c431a93a946f18f5399799706ed147ce2a37 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 1 Mar 2021 09:23:54 -0800 Subject: [PATCH 289/924] migrate tests to null safety (#3645) --- packages/connectivity/connectivity/CHANGELOG.md | 4 ++++ packages/connectivity/connectivity/pubspec.yaml | 2 +- .../connectivity/connectivity/test/connectivity_test.dart | 6 ++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index c4566ae73fd0..2f471890695a 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.1 + +* Migrate tests to null safety. + ## 3.0.0 * Migrate to null safety. diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index 254e325203d1..3aec6274f4b9 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -2,7 +2,7 @@ name: connectivity description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity -version: 3.0.0 +version: 3.0.1 flutter: plugin: diff --git a/packages/connectivity/connectivity/test/connectivity_test.dart b/packages/connectivity/connectivity/test/connectivity_test.dart index 6747c79bb64a..c95d0862444f 100644 --- a/packages/connectivity/connectivity/test/connectivity_test.dart +++ b/packages/connectivity/connectivity/test/connectivity_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(cyanglaz): Remove once Mockito is migrated to null safety. -// @dart = 2.9 import 'package:connectivity/connectivity.dart'; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -18,8 +16,8 @@ const LocationAuthorizationStatus kGetLocationResult = void main() { group('Connectivity', () { - Connectivity connectivity; - MockConnectivityPlatform fakePlatform; + late Connectivity connectivity; + late MockConnectivityPlatform fakePlatform; setUp(() async { fakePlatform = MockConnectivityPlatform(); ConnectivityPlatform.instance = fakePlatform; From c42db71b8f805fffaddf6641b764098a50cc49bb Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 1 Mar 2021 09:25:52 -0800 Subject: [PATCH 290/924] Update pull_request_label.yml (#3647) --- .github/workflows/pull_request_label.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull_request_label.yml b/.github/workflows/pull_request_label.yml index 7b048d33e669..6b93864d3f3a 100644 --- a/.github/workflows/pull_request_label.yml +++ b/.github/workflows/pull_request_label.yml @@ -16,7 +16,7 @@ jobs: label: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v3 + - uses: actions/labeler@9794b1493b6f1fa7b006c5f8635a19c76c98be95 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" sync-labels: true @@ -25,7 +25,7 @@ jobs: if: github.event.action == 'closed' && github.event.pull_request.merged == true runs-on: ubuntu-latest steps: - - uses: actions/labeler@v3 + - uses: actions/labeler@9794b1493b6f1fa7b006c5f8635a19c76c98be95 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" configuration-path: .github/post_merge_labeler.yml From 98a90d65564e123aa1877f1c0f31489020ebe6fd Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 1 Mar 2021 11:46:33 -0800 Subject: [PATCH 291/924] Update plugin_platform_interface min version (#3650) To avoid intra-repo plugin conflicts during the NNBD stable migration, `plugin_platform_interface` allowed either 1.x or 2.0. However, 1.0.x isn't null-safe so this can cause apps that don't have all their packages fully updated can fail to run in strong mode (due to having an old local `plugin_platform_interface`. Now that everything has been updated, we can bump all the minimums so that people updating their plugins will get new versions of the dependency. --- packages/battery/battery/CHANGELOG.md | 4 ++++ packages/battery/battery/pubspec.yaml | 4 ++-- packages/battery/battery_platform_interface/CHANGELOG.md | 4 ++++ packages/battery/battery_platform_interface/pubspec.yaml | 4 ++-- packages/camera/camera_platform_interface/CHANGELOG.md | 6 +++++- packages/camera/camera_platform_interface/pubspec.yaml | 4 ++-- packages/connectivity/connectivity/CHANGELOG.md | 4 ++++ packages/connectivity/connectivity/pubspec.yaml | 4 ++-- .../connectivity_platform_interface/CHANGELOG.md | 6 +++++- .../connectivity_platform_interface/pubspec.yaml | 4 ++-- .../device_info/device_info_platform_interface/CHANGELOG.md | 4 ++++ .../device_info/device_info_platform_interface/pubspec.yaml | 4 ++-- packages/file_selector/file_selector/CHANGELOG.md | 4 ++++ packages/file_selector/file_selector/pubspec.yaml | 4 ++-- .../file_selector_platform_interface/CHANGELOG.md | 4 ++++ .../file_selector_platform_interface/pubspec.yaml | 4 ++-- .../google_maps_flutter/google_maps_flutter/CHANGELOG.md | 4 ++++ .../google_maps_flutter/google_maps_flutter/pubspec.yaml | 4 ++-- .../google_maps_flutter_platform_interface/CHANGELOG.md | 4 ++++ .../google_maps_flutter_platform_interface/pubspec.yaml | 4 ++-- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ packages/image_picker/image_picker/pubspec.yaml | 4 ++-- .../image_picker_platform_interface/CHANGELOG.md | 4 ++++ .../image_picker_platform_interface/pubspec.yaml | 4 ++-- packages/path_provider/path_provider/CHANGELOG.md | 4 ++++ packages/path_provider/path_provider/pubspec.yaml | 4 ++-- .../path_provider_platform_interface/CHANGELOG.md | 4 ++++ .../path_provider_platform_interface/pubspec.yaml | 4 ++-- packages/url_launcher/url_launcher/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher/example/pubspec.yaml | 2 +- packages/url_launcher/url_launcher/pubspec.yaml | 4 ++-- .../url_launcher_platform_interface/CHANGELOG.md | 4 ++++ .../url_launcher_platform_interface/pubspec.yaml | 4 ++-- .../wifi_info_flutter_platform_interface/CHANGELOG.md | 4 ++++ .../wifi_info_flutter_platform_interface/pubspec.yaml | 4 ++-- 35 files changed, 105 insertions(+), 37 deletions(-) diff --git a/packages/battery/battery/CHANGELOG.md b/packages/battery/battery/CHANGELOG.md index ae9e798c364d..ab1d98c7962f 100644 --- a/packages/battery/battery/CHANGELOG.md +++ b/packages/battery/battery/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 * Migrate to null safety. diff --git a/packages/battery/battery/pubspec.yaml b/packages/battery/battery/pubspec.yaml index a987bd8c45a6..b705955efdef 100644 --- a/packages/battery/battery/pubspec.yaml +++ b/packages/battery/battery/pubspec.yaml @@ -2,7 +2,7 @@ name: battery description: Flutter plugin for accessing information about the battery state (full, charging, discharging) on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/battery/battery -version: 2.0.0 +version: 2.0.1 flutter: plugin: @@ -22,7 +22,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 integration_test: path: ../../integration_test pedantic: ^1.10.0 diff --git a/packages/battery/battery_platform_interface/CHANGELOG.md b/packages/battery/battery_platform_interface/CHANGELOG.md index 2c51f2c2d352..a9106dd78ce9 100644 --- a/packages/battery/battery_platform_interface/CHANGELOG.md +++ b/packages/battery/battery_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 * Migrate to null safety. diff --git a/packages/battery/battery_platform_interface/pubspec.yaml b/packages/battery/battery_platform_interface/pubspec.yaml index 61edad6cc04b..1303c22b5614 100644 --- a/packages/battery/battery_platform_interface/pubspec.yaml +++ b/packages/battery/battery_platform_interface/pubspec.yaml @@ -3,13 +3,13 @@ description: A common platform interface for the battery plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/battery # 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: 2.0.0 +version: 2.0.1 dependencies: flutter: sdk: flutter meta: ^1.3.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 dev_dependencies: flutter_test: diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index f7f78197d204..49214d24d18e 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,10 +1,14 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 - Stable null safety release. ## 1.6.0 -- Added VideoRecordedEvent to support ending a video recording in the native implementation. +- Added VideoRecordedEvent to support ending a video recording in the native implementation. ## 1.5.0 diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index 10897073dc5c..12c5bc48b9ec 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -3,13 +3,13 @@ description: A common platform interface for the camera plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera_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: 2.0.0 +version: 2.0.1 dependencies: flutter: sdk: flutter meta: ^1.3.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 cross_file: ^0.3.1 stream_transform: ^2.0.0 diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index 2f471890695a..57de797ff045 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.2 + +* Update platform_plugin_interface version requirement. + ## 3.0.1 * Migrate tests to null safety. diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index 3aec6274f4b9..eeef53c4faa4 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -2,7 +2,7 @@ name: connectivity description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity -version: 3.0.1 +version: 3.0.2 flutter: plugin: @@ -35,7 +35,7 @@ dev_dependencies: test: ^1.16.3 integration_test: path: ../../integration_test - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 pedantic: ^1.10.0 environment: diff --git a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md index 0b26cd52c9e9..ee75d03ccc65 100644 --- a/packages/connectivity/connectivity_platform_interface/CHANGELOG.md +++ b/packages/connectivity/connectivity_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 * Migrate to null safety. @@ -12,7 +16,7 @@ ## 1.0.5 -* Remove dart:io Platform checks from the MethodChannel implementation. This is +* Remove dart:io Platform checks from the MethodChannel implementation. This is tripping the analysis of other versions of the plugin. ## 1.0.4 diff --git a/packages/connectivity/connectivity_platform_interface/pubspec.yaml b/packages/connectivity/connectivity_platform_interface/pubspec.yaml index 1e89972dd816..5cc953aeb1b4 100644 --- a/packages/connectivity/connectivity_platform_interface/pubspec.yaml +++ b/packages/connectivity/connectivity_platform_interface/pubspec.yaml @@ -3,13 +3,13 @@ description: A common platform interface for the connectivity plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_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: 2.0.0 +version: 2.0.1 dependencies: flutter: sdk: flutter meta: ^1.3.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 dev_dependencies: flutter_test: diff --git a/packages/device_info/device_info_platform_interface/CHANGELOG.md b/packages/device_info/device_info_platform_interface/CHANGELOG.md index 23e9bc770c95..438d5bccad40 100644 --- a/packages/device_info/device_info_platform_interface/CHANGELOG.md +++ b/packages/device_info/device_info_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 * Migrate to null safety. diff --git a/packages/device_info/device_info_platform_interface/pubspec.yaml b/packages/device_info/device_info_platform_interface/pubspec.yaml index 3887aea3eff2..4753c70984a4 100644 --- a/packages/device_info/device_info_platform_interface/pubspec.yaml +++ b/packages/device_info/device_info_platform_interface/pubspec.yaml @@ -3,13 +3,13 @@ description: A common platform interface for the device_info plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/device_info # 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: 2.0.0 +version: 2.0.1 dependencies: flutter: sdk: flutter meta: ^1.3.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 dev_dependencies: flutter_test: diff --git a/packages/file_selector/file_selector/CHANGELOG.md b/packages/file_selector/file_selector/CHANGELOG.md index cea752e51558..2f8a4d0754f1 100644 --- a/packages/file_selector/file_selector/CHANGELOG.md +++ b/packages/file_selector/file_selector/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.2 + +* Update platform_plugin_interface version requirement. + ## 0.8.1 Endorse the web implementation. diff --git a/packages/file_selector/file_selector/pubspec.yaml b/packages/file_selector/file_selector/pubspec.yaml index 3d03de09e9f2..d8d610266641 100644 --- a/packages/file_selector/file_selector/pubspec.yaml +++ b/packages/file_selector/file_selector/pubspec.yaml @@ -1,7 +1,7 @@ name: file_selector description: Flutter plugin for opening and saving files. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector -version: 0.8.1 +version: 0.8.2 flutter: plugin: @@ -19,7 +19,7 @@ dev_dependencies: flutter_test: sdk: flutter test: ^1.16.3 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 pedantic: ^1.10.0 environment: diff --git a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md index 8fcc3e06ef49..ba595addfcaf 100644 --- a/packages/file_selector/file_selector_platform_interface/CHANGELOG.md +++ b/packages/file_selector/file_selector_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.2 + +* Update platform_plugin_interface version requirement. + ## 2.0.1 * Replace extensions with leading dots. diff --git a/packages/file_selector/file_selector_platform_interface/pubspec.yaml b/packages/file_selector/file_selector_platform_interface/pubspec.yaml index 980730eb2676..74b9d08c77ec 100644 --- a/packages/file_selector/file_selector_platform_interface/pubspec.yaml +++ b/packages/file_selector/file_selector_platform_interface/pubspec.yaml @@ -3,14 +3,14 @@ description: A common platform interface for the file_selector plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/file_selector/file_selector_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: 2.0.1 +version: 2.0.2 dependencies: flutter: sdk: flutter meta: ^1.3.0 http: ^0.13.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 cross_file: ^0.3.0 dev_dependencies: diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index dae5caf89a60..eb16024575bb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 * Migrate to null-safety diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 3d0e79473a33..d30c9d030de6 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 2.0.0 +version: 2.0.1 dependencies: flutter: @@ -19,7 +19,7 @@ dev_dependencies: sdk: flutter test: ^1.16.0 pedantic: ^1.10.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 stream_transform: ^2.0.0 flutter: diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index 0d5748d13f79..b0ad668c8ddc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 * Migrated to null-safety. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index 602efe3e6c62..0796b71fbb62 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,13 +3,13 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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: 2.0.0 +version: 2.0.1 dependencies: flutter: sdk: flutter meta: ^1.3.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 stream_transform: ^2.0.0 collection: ^1.15.0 diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 97aba4536000..4673c01f506e 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.1 + +* Update platform_plugin_interface version requirement. + ## 0.7.0 * Migrate to nullsafety diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 96881e6f2c65..fb351b3ece75 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.7.0 +version: 0.7.1 flutter: plugin: @@ -26,7 +26,7 @@ dev_dependencies: path: ../../integration_test mockito: ^5.0.0-nullsafety.7 pedantic: ^1.10.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 environment: sdk: ">=2.12.0-259.9.beta <3.0.0" diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index f2e017e190c5..598f83b4b09b 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 * Migrate to null safety. diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 9befba90215a..3443f158dc56 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -3,14 +3,14 @@ description: A common platform interface for the image_picker plugin. 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: 2.0.0 +version: 2.0.1 dependencies: flutter: sdk: flutter meta: ^1.3.0 http: ^0.13.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 dev_dependencies: flutter_test: diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md index c28c617bbea4..ad812266139a 100644 --- a/packages/path_provider/path_provider/CHANGELOG.md +++ b/packages/path_provider/path_provider/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 * Migrate to null safety. diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index 81941dac67b1..3ee67007f97d 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -1,7 +1,7 @@ name: path_provider description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider -version: 2.0.0 +version: 2.0.1 flutter: plugin: @@ -34,7 +34,7 @@ dev_dependencies: flutter_driver: sdk: flutter pedantic: ^1.10.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 test: ^1.16.0 environment: diff --git a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md index 08dc9f69c7df..eec0fe3866b5 100644 --- a/packages/path_provider/path_provider_platform_interface/CHANGELOG.md +++ b/packages/path_provider/path_provider_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 * Migrate to null safety. diff --git a/packages/path_provider/path_provider_platform_interface/pubspec.yaml b/packages/path_provider/path_provider_platform_interface/pubspec.yaml index 3feb4e0a8ebd..eb445c9b8873 100644 --- a/packages/path_provider/path_provider_platform_interface/pubspec.yaml +++ b/packages/path_provider/path_provider_platform_interface/pubspec.yaml @@ -3,14 +3,14 @@ description: A common platform interface for the path_provider plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_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: 2.0.0 +version: 2.0.1 dependencies: flutter: sdk: flutter meta: ^1.3.0 platform: ^3.0.0 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 dev_dependencies: flutter_test: diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 2d188366dfa5..9741f53ed329 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.0.2 + +* Update platform_plugin_interface version requirement. + ## 6.0.1 * Update result to `True` on iOS when the url was loaded successfully. diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml index 5f313f3870c5..0bc027de90a8 100644 --- a/packages/url_launcher/url_launcher/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher/example/pubspec.yaml @@ -19,7 +19,7 @@ dev_dependencies: sdk: flutter pedantic: ^1.10.0 mockito: ^5.0.0-nullsafety.7 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 flutter: uses-material-design: true diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 4036748a2d2e..f337c8bed525 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 6.0.1 +version: 6.0.2 flutter: plugin: @@ -40,7 +40,7 @@ dev_dependencies: sdk: flutter test: ^1.16.3 mockito: ^5.0.0-nullsafety.7 - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 pedantic: ^1.10.0 environment: diff --git a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md index d617e514035e..72fa83157377 100644 --- a/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md +++ b/packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.2 + +* Update platform_plugin_interface version requirement. + ## 2.0.1 * Fix SDK range. diff --git a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml index d3ec0aafd126..ee334f0e9a47 100644 --- a/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml +++ b/packages/url_launcher/url_launcher_platform_interface/pubspec.yaml @@ -3,12 +3,12 @@ description: A common platform interface for the url_launcher plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_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: 2.0.1 +version: 2.0.2 dependencies: flutter: sdk: flutter - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 dev_dependencies: flutter_test: diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md index cb770cb2d279..34f8e84cd780 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Update platform_plugin_interface version requirement. + ## 2.0.0 * Migrate to null safety. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml index 8e2eff392df7..b39f01ac4096 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: wifi_info_flutter_platform_interface description: A common platform interface for the wifi_info_flutter plugin. -version: 2.0.0 +version: 2.0.1 # 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 homepage: https://github.com/flutter/plugins/tree/master/packages/wifi_info_flutter/wifi_info_flutter_platform_interface @@ -10,7 +10,7 @@ environment: flutter: ">=1.17.0" dependencies: - plugin_platform_interface: ">=1.0.0 <3.0.0" + plugin_platform_interface: ^2.0.0 flutter: sdk: flutter From 088bdee478d9a33a1b398f8da2595bf359041cc6 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 1 Mar 2021 12:16:04 -0800 Subject: [PATCH 292/924] [in_app_purchase] migrate playing billing library to v3 (#3636) --- packages/in_app_purchase/CHANGELOG.md | 13 ++++ packages/in_app_purchase/android/build.gradle | 4 +- .../inapppurchase/MethodCallHandlerImpl.java | 35 ++++----- .../plugins/inapppurchase/Translator.java | 1 - .../example/android/app/build.gradle | 4 +- .../inapppurchase/MethodCallHandlerTest.java | 42 ++++++----- .../billing_client_wrapper.dart | 37 +++++----- .../purchase_wrapper.dart | 2 + .../sku_details_wrapper.dart | 14 +--- .../sku_details_wrapper.g.dart | 4 +- .../in_app_purchase/app_store_connection.dart | 7 +- .../google_play_connection.dart | 19 +++-- .../in_app_purchase_connection.dart | 10 +-- .../billing_client_wrapper_test.dart | 74 +++++++++++++++---- .../sku_details_wrapper_test.dart | 4 +- .../google_play_connection_test.dart | 5 +- 16 files changed, 160 insertions(+), 115 deletions(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index 0dbc2427ccd6..535295a2f8af 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,16 @@ +## 0.5.0 + +* Migrate to Google Billing Library 3.0 + * Add `obfuscatedProfileId`, `purchaseToken` in [BillingClientWrapper.launchBillingFlow]. + * **Breaking Change** + * Removed `developerPayload` in [BillingClientWrapper.acknowledgePurchase], [BillingClientWrapper.consumeAsync], [InAppPurchaseConnection.completePurchase], [InAppPurchaseConnection.consumePurchase]. + * Removed `isRewarded` from [SkuDetailsWrapper]. + * [SkuDetailsWrapper.introductoryPriceCycles] now returns `int` instead of `String`. + * Above breaking changes are inline with the breaking changes introduced in [Google Play Billing 3.0 release](https://developer.android.com/google/play/billing/release-notes#3-0). + * Additional information on some the changes: + * [Dropping reward SKU support](https://support.google.com/googleplay/android-developer/answer/9155268?hl=en) + * [Developer payload](https://developer.android.com/google/play/billing/developer-payload) + ## 0.4.1 * Support InApp subscription upgrade/downgrade. diff --git a/packages/in_app_purchase/android/build.gradle b/packages/in_app_purchase/android/build.gradle index 2539f507ed26..8d5840b4daff 100644 --- a/packages/in_app_purchase/android/build.gradle +++ b/packages/in_app_purchase/android/build.gradle @@ -35,9 +35,9 @@ android { dependencies { implementation 'androidx.annotation:annotation:1.0.0' - implementation 'com.android.billingclient:billing:2.0.3' + implementation 'com.android.billingclient:billing:3.0.2' testImplementation 'junit:junit:4.12' - testImplementation 'org.mockito:mockito-core:2.17.0' + testImplementation 'org.mockito:mockito-core:3.6.0' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' } diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java index 58d077673a03..d90fc6040454 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java @@ -125,7 +125,9 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { launchBillingFlow( (String) call.argument("sku"), (String) call.argument("accountId"), + (String) call.argument("obfuscatedProfileId"), (String) call.argument("oldSku"), + (String) call.argument("purchaseToken"), call.hasArgument("prorationMode") ? (int) call.argument("prorationMode") : ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, @@ -138,16 +140,10 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { queryPurchaseHistoryAsync((String) call.argument("skuType"), result); break; case InAppPurchasePlugin.MethodNames.CONSUME_PURCHASE_ASYNC: - consumeAsync( - (String) call.argument("purchaseToken"), - (String) call.argument("developerPayload"), - result); + consumeAsync((String) call.argument("purchaseToken"), result); break; case InAppPurchasePlugin.MethodNames.ACKNOWLEDGE_PURCHASE: - acknowledgePurchase( - (String) call.argument("purchaseToken"), - (String) call.argument("developerPayload"), - result); + acknowledgePurchase((String) call.argument("purchaseToken"), result); break; default: result.notImplemented(); @@ -200,7 +196,9 @@ public void onSkuDetailsResponse( private void launchBillingFlow( String sku, @Nullable String accountId, + @Nullable String obfuscatedProfileId, @Nullable String oldSku, + @Nullable String purchaseToken, int prorationMode, MethodChannel.Result result) { if (billingClientError(result)) { @@ -248,10 +246,13 @@ private void launchBillingFlow( BillingFlowParams.Builder paramsBuilder = BillingFlowParams.newBuilder().setSkuDetails(skuDetails); if (accountId != null && !accountId.isEmpty()) { - paramsBuilder.setAccountId(accountId); + paramsBuilder.setObfuscatedAccountId(accountId); + } + if (obfuscatedProfileId != null && !obfuscatedProfileId.isEmpty()) { + paramsBuilder.setObfuscatedProfileId(obfuscatedProfileId); } if (oldSku != null && !oldSku.isEmpty()) { - paramsBuilder.setOldSku(oldSku); + paramsBuilder.setOldSku(oldSku, purchaseToken); } // The proration mode value has to match one of the following declared in // https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode @@ -261,8 +262,7 @@ private void launchBillingFlow( billingClient.launchBillingFlow(activity, paramsBuilder.build()))); } - private void consumeAsync( - String purchaseToken, String developerPayload, final MethodChannel.Result result) { + private void consumeAsync(String purchaseToken, final MethodChannel.Result result) { if (billingClientError(result)) { return; } @@ -277,9 +277,6 @@ public void onConsumeResponse(BillingResult billingResult, String outToken) { ConsumeParams.Builder paramsBuilder = ConsumeParams.newBuilder().setPurchaseToken(purchaseToken); - if (developerPayload != null) { - paramsBuilder.setDeveloperPayload(developerPayload); - } ConsumeParams params = paramsBuilder.build(); billingClient.consumeAsync(params, listener); @@ -348,16 +345,12 @@ public void onBillingServiceDisconnected() { }); } - private void acknowledgePurchase( - String purchaseToken, @Nullable String developerPayload, final MethodChannel.Result result) { + private void acknowledgePurchase(String purchaseToken, final MethodChannel.Result result) { if (billingClientError(result)) { return; } AcknowledgePurchaseParams params = - AcknowledgePurchaseParams.newBuilder() - .setDeveloperPayload(developerPayload) - .setPurchaseToken(purchaseToken) - .build(); + AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchaseToken).build(); billingClient.acknowledgePurchase( params, new AcknowledgePurchaseResponseListener() { diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java index 80b6f1362255..73180ec5ec05 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java @@ -31,7 +31,6 @@ static HashMap fromSkuDetail(SkuDetails detail) { info.put("priceCurrencyCode", detail.getPriceCurrencyCode()); info.put("sku", detail.getSku()); info.put("type", detail.getType()); - info.put("isRewarded", detail.isRewarded()); info.put("subscriptionPeriod", detail.getSubscriptionPeriod()); info.put("originalPrice", detail.getOriginalPrice()); info.put("originalPriceAmountMicros", detail.getOriginalPriceAmountMicros()); diff --git a/packages/in_app_purchase/example/android/app/build.gradle b/packages/in_app_purchase/example/android/app/build.gradle index 261c7f0fe58e..c95804685219 100644 --- a/packages/in_app_purchase/example/android/app/build.gradle +++ b/packages/in_app_purchase/example/android/app/build.gradle @@ -106,9 +106,9 @@ flutter { } dependencies { - implementation 'com.android.billingclient:billing:1.2' + implementation 'com.android.billingclient:billing:3.0.2' testImplementation 'junit:junit:4.12' - testImplementation 'org.mockito:mockito-core:2.17.0' + testImplementation 'org.mockito:mockito-core:3.6.0' testImplementation 'org.json:json:20180813' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java index cc7bc4a9b9b1..eef43346f655 100644 --- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java +++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java @@ -22,6 +22,7 @@ import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.eq; @@ -60,6 +61,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.json.JSONException; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -79,7 +81,7 @@ public class MethodCallHandlerTest { @Before public void setUp() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this); factory = (@NonNull Context context, @NonNull MethodChannel channel, @@ -261,14 +263,18 @@ public void querySkuDetailsAsync_clientDisconnected() { verify(result, never()).success(any()); } + // Test launchBillingFlow not crash if `accountId` is `null` + // Ideally, we should check if the `accountId` is null in the parameter; however, + // since PBL 3.0, the `accountId` variable is not public. @Test - public void launchBillingFlow_ok_null_AccountId() { + public void launchBillingFlow_null_AccountId_do_not_crash() { // Fetch the sku details first and then prepare the launch billing flow call String skuId = "foo"; queryForSkus(singletonList(skuId)); HashMap arguments = new HashMap<>(); arguments.put("sku", skuId); arguments.put("accountId", null); + arguments.put("obfuscatedProfileId", null); MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments); // Launch the billing flow @@ -286,7 +292,6 @@ public void launchBillingFlow_ok_null_AccountId() { verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); assertEquals(params.getSku(), skuId); - assertNull(params.getAccountId()); // Verify we pass the response code to result verify(result, never()).error(any(), any(), any()); @@ -320,7 +325,6 @@ public void launchBillingFlow_ok_null_OldSku() { verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); assertEquals(params.getSku(), skuId); - assertEquals(params.getAccountId(), accountId); assertNull(params.getOldSku()); // Verify we pass the response code to result verify(result, never()).error(any(), any(), any()); @@ -374,7 +378,6 @@ public void launchBillingFlow_ok_oldSku() { verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); assertEquals(params.getSku(), skuId); - assertEquals(params.getAccountId(), accountId); assertEquals(params.getOldSku(), oldSkuId); // Verify we pass the response code to result @@ -408,7 +411,6 @@ public void launchBillingFlow_ok_AccountId() { verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); assertEquals(params.getSku(), skuId); - assertEquals(params.getAccountId(), accountId); // Verify we pass the response code to result verify(result, never()).error(any(), any(), any()); @@ -420,6 +422,7 @@ public void launchBillingFlow_ok_Proration() { // Fetch the sku details first and query the method call String skuId = "foo"; String oldSkuId = "oldFoo"; + String purchaseToken = "purchaseTokenFoo"; String accountId = "account"; int prorationMode = BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE; queryForSkus(unmodifiableList(asList(skuId, oldSkuId))); @@ -427,6 +430,7 @@ public void launchBillingFlow_ok_Proration() { arguments.put("sku", skuId); arguments.put("accountId", accountId); arguments.put("oldSku", oldSkuId); + arguments.put("purchaseToken", purchaseToken); arguments.put("prorationMode", prorationMode); MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments); @@ -445,8 +449,8 @@ public void launchBillingFlow_ok_Proration() { verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); assertEquals(params.getSku(), skuId); - assertEquals(params.getAccountId(), accountId); assertEquals(params.getOldSku(), oldSkuId); + assertEquals(params.getOldSkuPurchaseToken(), purchaseToken); assertEquals(params.getReplaceSkusProrationMode(), prorationMode); // Verify we pass the response code to result @@ -668,11 +672,7 @@ public void consumeAsync() { methodChannelHandler.onMethodCall(new MethodCall(CONSUME_PURCHASE_ASYNC, arguments), result); - ConsumeParams params = - ConsumeParams.newBuilder() - .setDeveloperPayload("mockPayload") - .setPurchaseToken("mockToken") - .build(); + ConsumeParams params = ConsumeParams.newBuilder().setPurchaseToken("mockToken").build(); // Verify we pass the data to result verify(mockBillingClient).consumeAsync(refEq(params), listenerCaptor.capture()); @@ -703,10 +703,7 @@ public void acknowledgePurchase() { methodChannelHandler.onMethodCall(new MethodCall(ACKNOWLEDGE_PURCHASE, arguments), result); AcknowledgePurchaseParams params = - AcknowledgePurchaseParams.newBuilder() - .setDeveloperPayload("mockPayload") - .setPurchaseToken("mockToken") - .build(); + AcknowledgePurchaseParams.newBuilder().setPurchaseToken("mockToken").build(); // Verify we pass the data to result verify(mockBillingClient).acknowledgePurchase(refEq(params), listenerCaptor.capture()); @@ -774,6 +771,7 @@ private void queryForSkus(List skusList) { verify(mockBillingClient).querySkuDetailsAsync(any(), listenerCaptor.capture()); List skuDetailsResponse = skusList.stream().map(this::buildSkuDetails).collect(toList()); + BillingResult billingResult = BillingResult.newBuilder() .setResponseCode(100) @@ -783,8 +781,16 @@ private void queryForSkus(List skusList) { } private SkuDetails buildSkuDetails(String id) { - SkuDetails details = mock(SkuDetails.class); - when(details.getSku()).thenReturn(id); + String json = + String.format( + "{\"packageName\": \"dummyPackageName\",\"productId\":\"%s\",\"type\":\"inapp\",\"price\":\"$0.99\",\"price_amount_micros\":990000,\"price_currency_code\":\"USD\",\"title\":\"Example title\",\"description\":\"Example description.\",\"original_price\":\"$0.99\",\"original_price_micros\":990000}", + id); + SkuDetails details = null; + try { + details = new SkuDetails(json); + } catch (JSONException e) { + fail("buildSkuDetails failed with JSONException " + e.toString()); + } return details; } diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart index a0ba91556094..f14e8dbec6bd 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart @@ -155,8 +155,13 @@ class BillingClient { /// The [skuDetails] needs to have already been fetched in a [querySkuDetails] /// call. The [accountId] is an optional hashed string associated with the user /// that's unique to your app. It's used by Google to detect unusual behavior. - /// Do not pass in a cleartext [accountId], use your developer ID, or use the - /// user's Google ID for this field. + /// Do not pass in a cleartext [accountId], and do not use this field to store any Personally Identifiable Information (PII) + /// such as emails in cleartext. Attempting to store PII in this field will result in purchases being blocked. + /// Google Play recommends that you use either encryption or a one-way hash to generate an obfuscated identifier to send to Google Play. + /// + /// Specifies an optional [obfuscatedProfileId] that is uniquely associated with the user's profile in your app. + /// Some applications allow users to have multiple profiles within a single account. Use this method to send the user's profile identifier to Google. + /// Setting this field requests the user's obfuscated account id. /// /// Calling this attemps to show the Google Play purchase UI. The user is free /// to complete the transaction there. @@ -169,27 +174,33 @@ class BillingClient { /// [`BillingClient#launchBillingFlow`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#launchbillingflow). /// It constructs a /// [`BillingFlowParams`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams) - /// instance by [setting the given - /// skuDetails](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder.html#setskudetails) - /// and [the given - /// accountId](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder.html#setAccountId(java.lang.String)). + /// instance by [setting the given skuDetails](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder.html#setskudetails), + /// [the given accountId](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setObfuscatedAccountId(java.lang.String)) + /// and the [obfuscatedProfileId] (https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setobfuscatedprofileid). /// /// When this method is called to purchase a subscription, an optional `oldSku` /// can be passed in. This will tell Google Play that rather than purchasing a new subscription, /// the user needs to upgrade/downgrade the existing subscription. - /// The [oldSku](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setoldsku) is the SKU id that the user is upgrading or downgrading from. + /// The [oldSku](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setoldsku) and [purchaseToken] are the SKU id and purchase token that the user is upgrading or downgrading from. + /// [purchaseToken] must not be `null` if [oldSku] is not `null`. /// The [prorationMode](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setreplaceskusprorationmode) is the mode of proration during subscription upgrade/downgrade. /// This value will only be effective if the `oldSku` is also set. Future launchBillingFlow( {required String sku, String? accountId, + String? obfuscatedProfileId, String? oldSku, + String? purchaseToken, ProrationMode? prorationMode}) async { assert(sku != null); + assert((oldSku == null) == (purchaseToken == null), + 'oldSku and purchaseToken must both be set, or both be null.'); final Map arguments = { 'sku': sku, 'accountId': accountId, + 'obfuscatedProfileId': obfuscatedProfileId, 'oldSku': oldSku, + 'purchaseToken': purchaseToken, 'prorationMode': ProrationModeConverter().toJson(prorationMode ?? ProrationMode.unknownSubscriptionUpgradeDowngradePolicy) }; @@ -250,18 +261,14 @@ class BillingClient { /// Consuming can only be done on an item that's owned, and as a result of consumption, the user will no longer own it. /// Consumption is done asynchronously. The method returns a Future containing a [BillingResultWrapper]. /// - /// The `developerPayload` is the developer data associated with the purchase to be consumed, it defaults to null. - /// /// This wraps [`BillingClient#consumeAsync(String, ConsumeResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#consumeAsync(java.lang.String,%20com.android.billingclient.api.ConsumeResponseListener)) - Future consumeAsync(String purchaseToken, - {String? developerPayload}) async { + Future consumeAsync(String purchaseToken) async { assert(purchaseToken != null); return BillingResultWrapper.fromJson((await channel .invokeMapMethod( 'BillingClient#consumeAsync(String, ConsumeResponseListener)', { 'purchaseToken': purchaseToken, - 'developerPayload': developerPayload, })) ?? {}); } @@ -282,18 +289,14 @@ class BillingClient { /// Please refer to [acknowledge](https://developer.android.com/google/play/billing/billing_library_overview#acknowledge) for more /// details. /// - /// The `developerPayload` is the developer data associated with the purchase to be consumed, it defaults to null. - /// /// This wraps [`BillingClient#acknowledgePurchase(String, AcknowledgePurchaseResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#acknowledgePurchase(com.android.billingclient.api.AcknowledgePurchaseParams,%20com.android.billingclient.api.AcknowledgePurchaseResponseListener)) - Future acknowledgePurchase(String purchaseToken, - {String? developerPayload}) async { + Future acknowledgePurchase(String purchaseToken) async { assert(purchaseToken != null); return BillingResultWrapper.fromJson((await channel.invokeMapMethod( 'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)', { 'purchaseToken': purchaseToken, - 'developerPayload': developerPayload, })) ?? {}); } diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart index 05472278968a..929b58292a2f 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -120,6 +120,8 @@ class PurchaseWrapper { /// The payload specified by the developer when the purchase was acknowledged or consumed. /// /// The value is `null` if it wasn't specified when the purchase was acknowledged or consumed. + /// The `developerPayload` is removed from [BillingClientWrapper.acknowledgePurchase], [BillingClientWrapper.consumeAsync], [InAppPurchaseConnection.completePurchase], [InAppPurchaseConnection.consumePurchase] + /// after plugin version `0.5.0`. As a result, this will be `null` for new purchases that happen after updating to `0.5.0`. final String? developerPayload; /// Whether the purchase has been acknowledged. diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart index b3872958e5b9..f93dd60284f8 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart @@ -42,7 +42,6 @@ class SkuDetailsWrapper { required this.subscriptionPeriod, required this.title, required this.type, - required this.isRewarded, required this.originalPrice, required this.originalPriceAmountMicros, }); @@ -71,9 +70,10 @@ class SkuDetailsWrapper { @JsonKey(defaultValue: '') final String introductoryPriceMicros; - /// The number of billing perios that [introductoryPrice] is valid for ("2"). - @JsonKey(defaultValue: '') - final String introductoryPriceCycles; + /// The number of subscription billing periods for which the user will be given the introductory price, such as 3. + /// Returns 0 if the SKU is not a subscription or doesn't have an introductory period. + @JsonKey(defaultValue: 0) + final int introductoryPriceCycles; /// The billing period of [introductoryPrice], in ISO 8601 format. @JsonKey(defaultValue: '') @@ -106,10 +106,6 @@ class SkuDetailsWrapper { /// The [SkuType] of the product. final SkuType type; - /// False if the product is paid. - @JsonKey(defaultValue: false) - final bool isRewarded; - /// The original price that the user purchased this product for. @JsonKey(defaultValue: '') final String originalPrice; @@ -138,7 +134,6 @@ class SkuDetailsWrapper { typedOther.subscriptionPeriod == subscriptionPeriod && typedOther.title == title && typedOther.type == type && - typedOther.isRewarded == isRewarded && typedOther.originalPrice == originalPrice && typedOther.originalPriceAmountMicros == originalPriceAmountMicros; } @@ -158,7 +153,6 @@ class SkuDetailsWrapper { subscriptionPeriod.hashCode, title.hashCode, type.hashCode, - isRewarded.hashCode, originalPrice, originalPriceAmountMicros); } diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart index 247dbd54b666..a14affdf9ed3 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart @@ -12,7 +12,7 @@ SkuDetailsWrapper _$SkuDetailsWrapperFromJson(Map json) { freeTrialPeriod: json['freeTrialPeriod'] as String? ?? '', introductoryPrice: json['introductoryPrice'] as String? ?? '', introductoryPriceMicros: json['introductoryPriceMicros'] as String? ?? '', - introductoryPriceCycles: json['introductoryPriceCycles'] as String? ?? '', + introductoryPriceCycles: json['introductoryPriceCycles'] as int? ?? 0, introductoryPricePeriod: json['introductoryPricePeriod'] as String? ?? '', price: json['price'] as String? ?? '', priceAmountMicros: json['priceAmountMicros'] as int? ?? 0, @@ -21,7 +21,6 @@ SkuDetailsWrapper _$SkuDetailsWrapperFromJson(Map json) { subscriptionPeriod: json['subscriptionPeriod'] as String? ?? '', title: json['title'] as String? ?? '', type: const SkuTypeConverter().fromJson(json['type'] as String?), - isRewarded: json['isRewarded'] as bool? ?? false, originalPrice: json['originalPrice'] as String? ?? '', originalPriceAmountMicros: json['originalPriceAmountMicros'] as int? ?? 0, ); @@ -42,7 +41,6 @@ Map _$SkuDetailsWrapperToJson(SkuDetailsWrapper instance) => 'subscriptionPeriod': instance.subscriptionPeriod, 'title': instance.title, 'type': const SkuTypeConverter().toJson(instance.type), - 'isRewarded': instance.isRewarded, 'originalPrice': instance.originalPrice, 'originalPriceAmountMicros': instance.originalPriceAmountMicros, }; diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index d4601fd809db..79a4a61fb328 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -84,8 +84,8 @@ class AppStoreConnection implements InAppPurchaseConnection { } @override - Future completePurchase(PurchaseDetails purchase, - {String? developerPayload}) async { + Future completePurchase( + PurchaseDetails purchase) async { if (purchase.skPaymentTransaction == null) { throw ArgumentError( 'completePurchase unsuccessful. The `purchase.skPaymentTransaction` is not valid'); @@ -96,8 +96,7 @@ class AppStoreConnection implements InAppPurchaseConnection { } @override - Future consumePurchase(PurchaseDetails purchase, - {String? developerPayload}) { + Future consumePurchase(PurchaseDetails purchase) { throw UnsupportedError('consume purchase is not available on Android'); } diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart index 1a47f3ebd095..c45512ed353f 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart @@ -66,6 +66,8 @@ class GooglePlayConnection accountId: purchaseParam.applicationUserName, oldSku: purchaseParam .changeSubscriptionParam?.oldPurchaseDetails.productID, + purchaseToken: purchaseParam.changeSubscriptionParam + ?.oldPurchaseDetails.verificationData.serverVerificationData, prorationMode: purchaseParam.changeSubscriptionParam?.prorationMode); return billingResultWrapper.responseCode == BillingResponse.ok; @@ -81,8 +83,8 @@ class GooglePlayConnection } @override - Future completePurchase(PurchaseDetails purchase, - {String? developerPayload}) async { + Future completePurchase( + PurchaseDetails purchase) async { if (purchase.billingClientPurchase!.isAcknowledged) { return BillingResultWrapper(responseCode: BillingResponse.ok); } @@ -90,21 +92,18 @@ class GooglePlayConnection throw ArgumentError( 'completePurchase unsuccessful. The `purchase.verificationData` is not valid'); } - return await billingClient.acknowledgePurchase( - purchase.verificationData.serverVerificationData, - developerPayload: developerPayload); + return await billingClient + .acknowledgePurchase(purchase.verificationData.serverVerificationData); } @override - Future consumePurchase(PurchaseDetails purchase, - {String? developerPayload}) { + Future consumePurchase(PurchaseDetails purchase) { if (purchase.verificationData == null) { throw ArgumentError( 'consumePurchase unsuccessful. The `purchase.verificationData` is not valid'); } - return billingClient.consumeAsync( - purchase.verificationData.serverVerificationData, - developerPayload: developerPayload); + return billingClient + .consumeAsync(purchase.verificationData.serverVerificationData); } @override diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart index 81a0e92cc591..aac5eae93e55 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart @@ -204,10 +204,7 @@ abstract class InAppPurchaseConnection { /// /// Warning! Failure to call this method and get a successful response within 3 days of the purchase will result a refund on Android. /// The [consumePurchase] acts as an implicit [completePurchase] on Android. - /// - /// The optional parameter `developerPayload` (defaults to `null`) only works on Android. - Future completePurchase(PurchaseDetails purchase, - {String? developerPayload}); + Future completePurchase(PurchaseDetails purchase); /// (Play only) Mark that the user has consumed a product. /// @@ -215,11 +212,8 @@ abstract class InAppPurchaseConnection { /// delivered. The user won't be able to buy the same product again until the /// purchase of the product is consumed. /// - /// The `developerPayload` (defaults to `null`) can be specified to be associated with this consumption. - /// /// This throws an [UnsupportedError] on iOS. - Future consumePurchase(PurchaseDetails purchase, - {String? developerPayload}); + Future consumePurchase(PurchaseDetails purchase); /// Query all previous purchases. /// diff --git a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart index 3aa62ddd96a1..7ba560257b39 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart @@ -196,15 +196,53 @@ void main() { ); final SkuDetailsWrapper skuDetails = dummySkuDetails; final String accountId = "hashedAccountId"; + final String profileId = "hashedProfileId"; expect( await billingClient.launchBillingFlow( - sku: skuDetails.sku, accountId: accountId), + sku: skuDetails.sku, + accountId: accountId, + obfuscatedProfileId: profileId), equals(expectedBillingResult)); Map arguments = stubPlatform.previousCallMatching(launchMethodName).arguments; expect(arguments['sku'], equals(skuDetails.sku)); expect(arguments['accountId'], equals(accountId)); + expect(arguments['obfuscatedProfileId'], equals(profileId)); + }); + + test( + 'Change subscription throws assertion error `oldSku` and `purchaseToken` has different nullability', + () async { + const String debugMessage = 'dummy message'; + final BillingResponse responseCode = BillingResponse.ok; + final BillingResultWrapper expectedBillingResult = BillingResultWrapper( + responseCode: responseCode, debugMessage: debugMessage); + stubPlatform.addResponse( + name: launchMethodName, + value: buildBillingResultMap(expectedBillingResult), + ); + final SkuDetailsWrapper skuDetails = dummySkuDetails; + final String accountId = 'hashedAccountId'; + final String profileId = 'hashedProfileId'; + + expect( + billingClient.launchBillingFlow( + sku: skuDetails.sku, + accountId: accountId, + obfuscatedProfileId: profileId, + oldSku: dummyOldPurchase.sku, + purchaseToken: null), + throwsAssertionError); + + expect( + billingClient.launchBillingFlow( + sku: skuDetails.sku, + accountId: accountId, + obfuscatedProfileId: profileId, + oldSku: null, + purchaseToken: dummyOldPurchase.purchaseToken), + throwsAssertionError); }); test( @@ -219,19 +257,25 @@ void main() { value: buildBillingResultMap(expectedBillingResult), ); final SkuDetailsWrapper skuDetails = dummySkuDetails; - final String accountId = "hashedAccountId"; + final String accountId = 'hashedAccountId'; + final String profileId = 'hashedProfileId'; expect( await billingClient.launchBillingFlow( sku: skuDetails.sku, accountId: accountId, - oldSku: dummyOldPurchase.sku), + obfuscatedProfileId: profileId, + oldSku: dummyOldPurchase.sku, + purchaseToken: dummyOldPurchase.purchaseToken), equals(expectedBillingResult)); Map arguments = stubPlatform.previousCallMatching(launchMethodName).arguments; expect(arguments['sku'], equals(skuDetails.sku)); expect(arguments['accountId'], equals(accountId)); expect(arguments['oldSku'], equals(dummyOldPurchase.sku)); + expect( + arguments['purchaseToken'], equals(dummyOldPurchase.purchaseToken)); + expect(arguments['obfuscatedProfileId'], equals(profileId)); }); test( @@ -246,21 +290,27 @@ void main() { value: buildBillingResultMap(expectedBillingResult), ); final SkuDetailsWrapper skuDetails = dummySkuDetails; - final String accountId = "hashedAccountId"; + final String accountId = 'hashedAccountId'; + final String profileId = 'hashedProfileId'; final prorationMode = ProrationMode.immediateAndChargeProratedPrice; expect( await billingClient.launchBillingFlow( sku: skuDetails.sku, accountId: accountId, + obfuscatedProfileId: profileId, oldSku: dummyOldPurchase.sku, - prorationMode: prorationMode), + prorationMode: prorationMode, + purchaseToken: dummyOldPurchase.purchaseToken), equals(expectedBillingResult)); Map arguments = stubPlatform.previousCallMatching(launchMethodName).arguments; expect(arguments['sku'], equals(skuDetails.sku)); expect(arguments['accountId'], equals(accountId)); expect(arguments['oldSku'], equals(dummyOldPurchase.sku)); + expect(arguments['obfuscatedProfileId'], equals(profileId)); + expect( + arguments['purchaseToken'], equals(dummyOldPurchase.purchaseToken)); expect(arguments['prorationMode'], ProrationModeConverter().toJson(prorationMode)); }); @@ -440,8 +490,8 @@ void main() { name: consumeMethodName, value: buildBillingResultMap(expectedBillingResult)); - final BillingResultWrapper billingResult = await billingClient - .consumeAsync('dummy token', developerPayload: 'dummy payload'); + final BillingResultWrapper billingResult = + await billingClient.consumeAsync('dummy token'); expect(billingResult, equals(expectedBillingResult)); }); @@ -451,8 +501,8 @@ void main() { name: consumeMethodName, value: null, ); - final BillingResultWrapper billingResult = await billingClient - .consumeAsync('dummy token', developerPayload: 'dummy payload'); + final BillingResultWrapper billingResult = + await billingClient.consumeAsync('dummy token'); expect( billingResult, @@ -475,8 +525,7 @@ void main() { value: buildBillingResultMap(expectedBillingResult)); final BillingResultWrapper billingResult = - await billingClient.acknowledgePurchase('dummy token', - developerPayload: 'dummy payload'); + await billingClient.acknowledgePurchase('dummy token'); expect(billingResult, equals(expectedBillingResult)); }); @@ -486,8 +535,7 @@ void main() { value: null, ); final BillingResultWrapper billingResult = - await billingClient.acknowledgePurchase('dummy token', - developerPayload: 'dummy payload'); + await billingClient.acknowledgePurchase('dummy token'); expect( billingResult, diff --git a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart index 13715eeb9fc0..7a7b7fb86364 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart @@ -12,7 +12,7 @@ final SkuDetailsWrapper dummySkuDetails = SkuDetailsWrapper( freeTrialPeriod: 'freeTrialPeriod', introductoryPrice: 'introductoryPrice', introductoryPriceMicros: 'introductoryPriceMicros', - introductoryPriceCycles: 'introductoryPriceCycles', + introductoryPriceCycles: 1, introductoryPricePeriod: 'introductoryPricePeriod', price: 'price', priceAmountMicros: 1000, @@ -21,7 +21,6 @@ final SkuDetailsWrapper dummySkuDetails = SkuDetailsWrapper( subscriptionPeriod: 'subscriptionPeriod', title: 'title', type: SkuType.inapp, - isRewarded: true, originalPrice: 'originalPrice', originalPriceAmountMicros: 1000, ); @@ -144,7 +143,6 @@ Map buildSkuMap(SkuDetailsWrapper original) { 'subscriptionPeriod': original.subscriptionPeriod, 'title': original.title, 'type': original.type.toString().substring(8), - 'isRewarded': original.isRewarded, 'originalPrice': original.originalPrice, 'originalPriceAmountMicros': original.originalPriceAmountMicros, }; diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart index 79c2ee436c5c..5a265b8de907 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart @@ -632,9 +632,8 @@ void main() { purchaseDetails.status = PurchaseStatus.purchased; if (purchaseDetails.pendingCompletePurchase) { final BillingResultWrapper billingResultWrapper = - await GooglePlayConnection.instance.completePurchase( - purchaseDetails, - developerPayload: 'dummy payload'); + await GooglePlayConnection.instance + .completePurchase(purchaseDetails); expect(billingResultWrapper, equals(expectedBillingResult)); completer.complete(billingResultWrapper); } From 96ea724a099d896f3643f98138864877210c2e42 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Mon, 1 Mar 2021 18:15:51 -0800 Subject: [PATCH 293/924] Move plugin tool tests over (#3606) --- .cirrus.yml | 20 +- script/tool/pubspec.yaml | 5 + script/tool/test/analyze_command_test.dart | 93 ++++ .../test/build_examples_command_test.dart | 470 ++++++++++++++++ script/tool/test/common_test.dart | 100 ++++ .../test/drive_examples_command_test.dart | 505 ++++++++++++++++++ script/tool/test/firebase_test_lab_test.dart | 256 +++++++++ .../tool/test/lint_podspecs_command_test.dart | 202 +++++++ script/tool/test/list_command_test.dart | 198 +++++++ script/tool/test/mocks.dart | 33 ++ .../test/publish_plugin_command_test.dart | 378 +++++++++++++ script/tool/test/test_command_test.dart | 154 ++++++ script/tool/test/util.dart | 291 ++++++++++ script/tool/test/version_check_test.dart | 319 +++++++++++ script/tool/test/xctest_command_test.dart | 358 +++++++++++++ 15 files changed, 3367 insertions(+), 15 deletions(-) create mode 100644 script/tool/test/analyze_command_test.dart create mode 100644 script/tool/test/build_examples_command_test.dart create mode 100644 script/tool/test/common_test.dart create mode 100644 script/tool/test/drive_examples_command_test.dart create mode 100644 script/tool/test/firebase_test_lab_test.dart create mode 100644 script/tool/test/lint_podspecs_command_test.dart create mode 100644 script/tool/test/list_command_test.dart create mode 100644 script/tool/test/mocks.dart create mode 100644 script/tool/test/publish_plugin_command_test.dart create mode 100644 script/tool/test/test_command_test.dart create mode 100644 script/tool/test/util.dart create mode 100644 script/tool/test/version_check_test.dart create mode 100644 script/tool/test/xctest_command_test.dart diff --git a/.cirrus.yml b/.cirrus.yml index 5a25b773ea33..118802b74810 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -16,10 +16,12 @@ task: - flutter channel master - flutter upgrade - git fetch origin master - submodules_script: - - git submodule init - - git submodule update matrix: + - name: plugin_tools_tests + script: + - cd script/tool + - pub get + - CIRRUS_BUILD_ID=null pub run test - name: publishable script: - flutter channel master @@ -132,9 +134,6 @@ task: - flutter channel master - flutter upgrade - git fetch origin master - submodules_script: - - git submodule init - - git submodule update matrix: - name: build-linux+drive-examples install_script: @@ -161,9 +160,6 @@ task: - flutter channel master - flutter upgrade - git fetch origin master - submodules_script: - - git submodule init - - git submodule update create_simulator_script: - xcrun simctl list - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-3 | xargs xcrun simctl boot @@ -222,9 +218,6 @@ task: - flutter channel master - flutter upgrade - git fetch origin master - submodules_script: - - git submodule init - - git submodule update create_simulator_script: - xcrun simctl list - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot @@ -254,9 +247,6 @@ task: - flutter channel master - flutter upgrade - git fetch origin master - submodules_script: - - git submodule init - - git submodule update matrix: - name: build_all_plugins_app script: diff --git a/script/tool/pubspec.yaml b/script/tool/pubspec.yaml index d9fce4ad26a7..e47123959005 100644 --- a/script/tool/pubspec.yaml +++ b/script/tool/pubspec.yaml @@ -21,5 +21,10 @@ dependencies: http_multi_server: ^2.2.0 collection: 1.14.13 +dev_dependencies: + matcher: ^0.12.6 + mockito: ^4.1.1 + pedantic: 1.8.0 + environment: sdk: ">=2.3.0 <3.0.0" diff --git a/script/tool/test/analyze_command_test.dart b/script/tool/test/analyze_command_test.dart new file mode 100644 index 000000000000..9e7a42bbb680 --- /dev/null +++ b/script/tool/test/analyze_command_test.dart @@ -0,0 +1,93 @@ +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:flutter_plugin_tools/src/analyze_command.dart'; +import 'package:flutter_plugin_tools/src/common.dart'; +import 'package:test/test.dart'; + +import 'mocks.dart'; +import 'util.dart'; + +void main() { + RecordingProcessRunner processRunner; + CommandRunner runner; + + setUp(() { + initializeFakePackages(); + processRunner = RecordingProcessRunner(); + final AnalyzeCommand analyzeCommand = AnalyzeCommand( + mockPackagesDir, mockFileSystem, + processRunner: processRunner); + + runner = CommandRunner('analyze_command', 'Test for analyze_command'); + runner.addCommand(analyzeCommand); + }); + + tearDown(() { + mockPackagesDir.deleteSync(recursive: true); + }); + + test('analyzes all packages', () async { + final Directory plugin1Dir = await createFakePlugin('a'); + final Directory plugin2Dir = await createFakePlugin('b'); + + final MockProcess mockProcess = MockProcess(); + mockProcess.exitCodeCompleter.complete(0); + processRunner.processToReturn = mockProcess; + await runner.run(['analyze']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('pub', ['global', 'activate', 'tuneup'], + mockPackagesDir.path), + ProcessCall('flutter', ['packages', 'get'], plugin1Dir.path), + ProcessCall('flutter', ['packages', 'get'], plugin2Dir.path), + ProcessCall('pub', ['global', 'run', 'tuneup', 'check'], + plugin1Dir.path), + ProcessCall('pub', ['global', 'run', 'tuneup', 'check'], + plugin2Dir.path), + ])); + }); + + group('verifies analysis settings', () { + test('fails analysis_options.yaml', () async { + await createFakePlugin('foo', withExtraFiles: >[ + ['analysis_options.yaml'] + ]); + + await expectLater(() => runner.run(['analyze']), + throwsA(const TypeMatcher())); + }); + + test('fails .analysis_options', () async { + await createFakePlugin('foo', withExtraFiles: >[ + ['.analysis_options'] + ]); + + await expectLater(() => runner.run(['analyze']), + throwsA(const TypeMatcher())); + }); + + test('takes an allow list', () async { + final Directory pluginDir = + await createFakePlugin('foo', withExtraFiles: >[ + ['analysis_options.yaml'] + ]); + + final MockProcess mockProcess = MockProcess(); + mockProcess.exitCodeCompleter.complete(0); + processRunner.processToReturn = mockProcess; + await runner.run(['analyze', '--custom-analysis', 'foo']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('pub', ['global', 'activate', 'tuneup'], + mockPackagesDir.path), + ProcessCall('flutter', ['packages', 'get'], pluginDir.path), + ProcessCall('pub', ['global', 'run', 'tuneup', 'check'], + pluginDir.path), + ])); + }); + }); +} diff --git a/script/tool/test/build_examples_command_test.dart b/script/tool/test/build_examples_command_test.dart new file mode 100644 index 000000000000..eaf5049dcc02 --- /dev/null +++ b/script/tool/test/build_examples_command_test.dart @@ -0,0 +1,470 @@ +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:flutter_plugin_tools/src/build_examples_command.dart'; +import 'package:path/path.dart' as p; +import 'package:platform/platform.dart'; +import 'package:test/test.dart'; + +import 'util.dart'; + +void main() { + group('test build_example_command', () { + CommandRunner runner; + RecordingProcessRunner processRunner; + final String flutterCommand = + LocalPlatform().isWindows ? 'flutter.bat' : 'flutter'; + + setUp(() { + initializeFakePackages(); + processRunner = RecordingProcessRunner(); + final BuildExamplesCommand command = BuildExamplesCommand( + mockPackagesDir, mockFileSystem, + processRunner: processRunner); + + runner = CommandRunner( + 'build_examples_command', 'Test for build_example_command'); + runner.addCommand(command); + cleanupPackages(); + }); + + test('building for iOS when plugin is not set up for iOS results in no-op', + () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isLinuxPlugin: false); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint( + runner, ['build-examples', '--ipa', '--no-macos']); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING IPA for $packageName', + 'iOS is not supported by this plugin', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running build-examples --macos with no macos + // implementation is a no-op. + expect(processRunner.recordedCalls, orderedEquals([])); + cleanupPackages(); + }); + + test('building for ios', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isIosPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--ipa', + '--no-macos', + '--enable-experiment=exp1' + ]); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING IPA for $packageName', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + [ + 'build', + 'ios', + '--no-codesign', + '--enable-experiment=exp1' + ], + pluginExampleDirectory.path), + ])); + cleanupPackages(); + }); + + test( + 'building for Linux when plugin is not set up for Linux results in no-op', + () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isLinuxPlugin: false); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint( + runner, ['build-examples', '--no-ipa', '--linux']); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING Linux for $packageName', + 'Linux is not supported by this plugin', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running build-examples --linux with no + // Linux implementation is a no-op. + expect(processRunner.recordedCalls, orderedEquals([])); + cleanupPackages(); + }); + + test('building for Linux', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isLinuxPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint( + runner, ['build-examples', '--no-ipa', '--linux']); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING Linux for $packageName', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(flutterCommand, ['build', 'linux'], + pluginExampleDirectory.path), + ])); + cleanupPackages(); + }); + + test('building for macos with no implementation results in no-op', + () async { + createFakePlugin('plugin', withExtraFiles: >[ + ['example', 'test'], + ]); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint( + runner, ['build-examples', '--no-ipa', '--macos']); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING macOS for $packageName', + '\macOS is not supported by this plugin', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running build-examples --macos with no macos + // implementation is a no-op. + expect(processRunner.recordedCalls, orderedEquals([])); + cleanupPackages(); + }); + test('building for macos', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ['example', 'macos', 'macos.swift'], + ], + isMacOsPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint( + runner, ['build-examples', '--no-ipa', '--macos']); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING macOS for $packageName', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(flutterCommand, ['pub', 'get'], + pluginExampleDirectory.path), + ProcessCall(flutterCommand, ['build', 'macos'], + pluginExampleDirectory.path), + ])); + cleanupPackages(); + }); + + test( + 'building for Windows when plugin is not set up for Windows results in no-op', + () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isWindowsPlugin: false); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint( + runner, ['build-examples', '--no-ipa', '--windows']); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING Windows for $packageName', + 'Windows is not supported by this plugin', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running build-examples --macos with no macos + // implementation is a no-op. + expect(processRunner.recordedCalls, orderedEquals([])); + cleanupPackages(); + }); + + test('building for windows', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isWindowsPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint( + runner, ['build-examples', '--no-ipa', '--windows']); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING Windows for $packageName', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(flutterCommand, ['build', 'windows'], + pluginExampleDirectory.path), + ])); + cleanupPackages(); + }); + + test( + 'building for Android when plugin is not set up for Android results in no-op', + () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isLinuxPlugin: false); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint( + runner, ['build-examples', '--apk', '--no-ipa']); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING APK for $packageName', + 'Android is not supported by this plugin', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running build-examples --macos with no macos + // implementation is a no-op. + expect(processRunner.recordedCalls, orderedEquals([])); + cleanupPackages(); + }); + + test('building for android', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isAndroidPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'build-examples', + '--apk', + '--no-ipa', + '--no-macos', + ]); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING APK for $packageName', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(flutterCommand, ['build', 'apk'], + pluginExampleDirectory.path), + ])); + cleanupPackages(); + }); + + test('enable-experiment flag for Android', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isAndroidPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + await runCapturingPrint(runner, [ + 'build-examples', + '--apk', + '--no-ipa', + '--no-macos', + '--enable-experiment=exp1' + ]); + + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + ['build', 'apk', '--enable-experiment=exp1'], + pluginExampleDirectory.path), + ])); + cleanupPackages(); + }); + + test('enable-experiment flag for ios', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isIosPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + await runCapturingPrint(runner, [ + 'build-examples', + '--ipa', + '--no-macos', + '--enable-experiment=exp1' + ]); + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + [ + 'build', + 'ios', + '--no-codesign', + '--enable-experiment=exp1' + ], + pluginExampleDirectory.path), + ])); + cleanupPackages(); + }); + }); +} diff --git a/script/tool/test/common_test.dart b/script/tool/test/common_test.dart new file mode 100644 index 000000000000..b3504c2358d9 --- /dev/null +++ b/script/tool/test/common_test.dart @@ -0,0 +1,100 @@ +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:flutter_plugin_tools/src/common.dart'; +import 'package:test/test.dart'; + +import 'util.dart'; + +void main() { + RecordingProcessRunner processRunner; + CommandRunner runner; + List plugins; + + setUp(() { + initializeFakePackages(); + processRunner = RecordingProcessRunner(); + plugins = []; + final SamplePluginCommand samplePluginCommand = SamplePluginCommand( + plugins, + mockPackagesDir, + mockFileSystem, + processRunner: processRunner, + ); + runner = + CommandRunner('common_command', 'Test for common functionality'); + runner.addCommand(samplePluginCommand); + }); + + tearDown(() { + mockPackagesDir.deleteSync(recursive: true); + }); + + test('all plugins from file system', () async { + final Directory plugin1 = createFakePlugin('plugin1'); + final Directory plugin2 = createFakePlugin('plugin2'); + await runner.run(['sample']); + expect(plugins, unorderedEquals([plugin1.path, plugin2.path])); + }); + + test('exclude plugins when plugins flag is specified', () async { + createFakePlugin('plugin1'); + final Directory plugin2 = createFakePlugin('plugin2'); + await runner.run( + ['sample', '--plugins=plugin1,plugin2', '--exclude=plugin1']); + expect(plugins, unorderedEquals([plugin2.path])); + }); + + test('exclude plugins when plugins flag isn\'t specified', () async { + createFakePlugin('plugin1'); + createFakePlugin('plugin2'); + await runner.run(['sample', '--exclude=plugin1,plugin2']); + expect(plugins, unorderedEquals([])); + }); + + test('exclude federated plugins when plugins flag is specified', () async { + createFakePlugin('plugin1', parentDirectoryName: 'federated'); + final Directory plugin2 = createFakePlugin('plugin2'); + await runner.run([ + 'sample', + '--plugins=federated/plugin1,plugin2', + '--exclude=federated/plugin1' + ]); + expect(plugins, unorderedEquals([plugin2.path])); + }); + + test('exclude entire federated plugins when plugins flag is specified', + () async { + createFakePlugin('plugin1', parentDirectoryName: 'federated'); + final Directory plugin2 = createFakePlugin('plugin2'); + await runner.run([ + 'sample', + '--plugins=federated/plugin1,plugin2', + '--exclude=federated' + ]); + expect(plugins, unorderedEquals([plugin2.path])); + }); +} + +class SamplePluginCommand extends PluginCommand { + SamplePluginCommand( + this.plugins_, + Directory packagesDir, + FileSystem fileSystem, { + ProcessRunner processRunner = const ProcessRunner(), + }) : super(packagesDir, fileSystem, processRunner: processRunner); + + List plugins_; + + @override + final String name = 'sample'; + + @override + final String description = 'sample command'; + + @override + Future run() async { + await for (Directory package in getPlugins()) { + this.plugins_.add(package.path); + } + } +} diff --git a/script/tool/test/drive_examples_command_test.dart b/script/tool/test/drive_examples_command_test.dart new file mode 100644 index 000000000000..f4bdd95c1664 --- /dev/null +++ b/script/tool/test/drive_examples_command_test.dart @@ -0,0 +1,505 @@ +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:flutter_plugin_tools/src/common.dart'; +import 'package:flutter_plugin_tools/src/drive_examples_command.dart'; +import 'package:path/path.dart' as p; +import 'package:platform/platform.dart'; +import 'package:test/test.dart'; + +import 'util.dart'; + +void main() { + group('test drive_example_command', () { + CommandRunner runner; + RecordingProcessRunner processRunner; + final String flutterCommand = + LocalPlatform().isWindows ? 'flutter.bat' : 'flutter'; + setUp(() { + initializeFakePackages(); + processRunner = RecordingProcessRunner(); + final DriveExamplesCommand command = DriveExamplesCommand( + mockPackagesDir, mockFileSystem, + processRunner: processRunner); + + runner = CommandRunner( + 'drive_examples_command', 'Test for drive_example_command'); + runner.addCommand(command); + }); + + tearDown(() { + cleanupPackages(); + }); + + test('driving under folder "test"', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test', 'plugin.dart'], + ], + isIosPlugin: true, + isAndroidPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + String deviceTestPath = p.join('test', 'plugin.dart'); + String driverTestPath = p.join('test_driver', 'plugin_test.dart'); + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + [ + 'drive', + '--driver', + driverTestPath, + '--target', + deviceTestPath + ], + pluginExampleDirectory.path), + ])); + }); + + test('driving under folder "test_driver"', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test_driver', 'plugin.dart'], + ], + isAndroidPlugin: true, + isIosPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + String deviceTestPath = p.join('test_driver', 'plugin.dart'); + String driverTestPath = p.join('test_driver', 'plugin_test.dart'); + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + [ + 'drive', + '--driver', + driverTestPath, + '--target', + deviceTestPath + ], + pluginExampleDirectory.path), + ])); + }); + + test('driving under folder "test_driver" when test files are missing"', + () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ], + isAndroidPlugin: true, + isIosPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + await expectLater( + () => runCapturingPrint(runner, ['drive-examples']), + throwsA(const TypeMatcher())); + }); + + test( + 'driving under folder "test_driver" when targets are under "integration_test"', + () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'integration_test.dart'], + ['example', 'integration_test', 'bar_test.dart'], + ['example', 'integration_test', 'foo_test.dart'], + ['example', 'integration_test', 'ignore_me.dart'], + ], + isAndroidPlugin: true, + isIosPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + String driverTestPath = p.join('test_driver', 'integration_test.dart'); + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + [ + 'drive', + '--driver', + driverTestPath, + '--target', + p.join('integration_test', 'bar_test.dart'), + ], + pluginExampleDirectory.path), + ProcessCall( + flutterCommand, + [ + 'drive', + '--driver', + driverTestPath, + '--target', + p.join('integration_test', 'foo_test.dart'), + ], + pluginExampleDirectory.path), + ])); + }); + + test('driving when plugin does not support Linux is a no-op', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test_driver', 'plugin.dart'], + ], + isMacOsPlugin: false); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--linux', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running drive-examples --linux on a non-Linux + // plugin is a no-op. + expect(processRunner.recordedCalls, []); + }); + + test('driving on a Linux plugin', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test_driver', 'plugin.dart'], + ], + isLinuxPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--linux', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + String deviceTestPath = p.join('test_driver', 'plugin.dart'); + String driverTestPath = p.join('test_driver', 'plugin_test.dart'); + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + [ + 'drive', + '-d', + 'linux', + '--driver', + driverTestPath, + '--target', + deviceTestPath + ], + pluginExampleDirectory.path), + ])); + }); + + test('driving when plugin does not suppport macOS is a no-op', () async { + createFakePlugin('plugin', withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test_driver', 'plugin.dart'], + ]); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--macos', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running drive-examples --macos with no macos + // implementation is a no-op. + expect(processRunner.recordedCalls, []); + }); + test('driving on a macOS plugin', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test_driver', 'plugin.dart'], + ['example', 'macos', 'macos.swift'], + ], + isMacOsPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--macos', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + String deviceTestPath = p.join('test_driver', 'plugin.dart'); + String driverTestPath = p.join('test_driver', 'plugin_test.dart'); + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + [ + 'drive', + '-d', + 'macos', + '--driver', + driverTestPath, + '--target', + deviceTestPath + ], + pluginExampleDirectory.path), + ])); + }); + + test('driving when plugin does not suppport windows is a no-op', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test_driver', 'plugin.dart'], + ], + isMacOsPlugin: false); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--windows', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running drive-examples --windows on a non-windows + // plugin is a no-op. + expect(processRunner.recordedCalls, []); + }); + + test('driving on a Windows plugin', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test_driver', 'plugin.dart'], + ], + isWindowsPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--windows', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + String deviceTestPath = p.join('test_driver', 'plugin.dart'); + String driverTestPath = p.join('test_driver', 'plugin_test.dart'); + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + [ + 'drive', + '-d', + 'windows', + '--driver', + driverTestPath, + '--target', + deviceTestPath + ], + pluginExampleDirectory.path), + ])); + }); + + test('driving when plugin does not support mobile is no-op', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test_driver', 'plugin.dart'], + ], + isMacOsPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running drive-examples --macos with no macos + // implementation is a no-op. + expect(processRunner.recordedCalls, []); + }); + + test('enable-experiment flag', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test', 'plugin.dart'], + ], + isIosPlugin: true, + isAndroidPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + await runCapturingPrint(runner, [ + 'drive-examples', + '--enable-experiment=exp1', + ]); + + String deviceTestPath = p.join('test', 'plugin.dart'); + String driverTestPath = p.join('test_driver', 'plugin_test.dart'); + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + [ + 'drive', + '--enable-experiment=exp1', + '--driver', + driverTestPath, + '--target', + deviceTestPath + ], + pluginExampleDirectory.path), + ])); + }); + }); +} diff --git a/script/tool/test/firebase_test_lab_test.dart b/script/tool/test/firebase_test_lab_test.dart new file mode 100644 index 000000000000..97b977619d57 --- /dev/null +++ b/script/tool/test/firebase_test_lab_test.dart @@ -0,0 +1,256 @@ +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:flutter_plugin_tools/src/common.dart'; +import 'package:flutter_plugin_tools/src/firebase_test_lab_command.dart'; +import 'package:test/test.dart'; + +import 'mocks.dart'; +import 'util.dart'; + +void main() { + group('$FirebaseTestLabCommand', () { + final List printedMessages = []; + CommandRunner runner; + RecordingProcessRunner processRunner; + + setUp(() { + initializeFakePackages(); + processRunner = RecordingProcessRunner(); + final FirebaseTestLabCommand command = FirebaseTestLabCommand( + mockPackagesDir, mockFileSystem, + processRunner: processRunner, + print: (Object message) => printedMessages.add(message.toString())); + + runner = CommandRunner( + 'firebase_test_lab_command', 'Test for $FirebaseTestLabCommand'); + runner.addCommand(command); + }); + + tearDown(() { + printedMessages.clear(); + }); + + test('retries gcloud set', () async { + final MockProcess mockProcess = MockProcess(); + mockProcess.exitCodeCompleter.complete(1); + processRunner.processToReturn = mockProcess; + createFakePlugin('plugin', withExtraFiles: >[ + ['lib/test/should_not_run_e2e.dart'], + ['example', 'test_driver', 'plugin_e2e.dart'], + ['example', 'test_driver', 'plugin_e2e_test.dart'], + ['example', 'android', 'gradlew'], + ['example', 'should_not_run_e2e.dart'], + [ + 'example', + 'android', + 'app', + 'src', + 'androidTest', + 'MainActivityTest.java' + ], + ]); + await expectLater( + () => runCapturingPrint(runner, ['firebase-test-lab']), + throwsA(const TypeMatcher())); + expect( + printedMessages, + contains( + "\nWarning: gcloud config set returned a non-zero exit code. Continuing anyway.")); + }); + + test('runs e2e tests', () async { + createFakePlugin('plugin', withExtraFiles: >[ + ['test', 'plugin_test.dart'], + ['test', 'plugin_e2e.dart'], + ['should_not_run_e2e.dart'], + ['lib/test/should_not_run_e2e.dart'], + ['example', 'test', 'plugin_e2e.dart'], + ['example', 'test_driver', 'plugin_e2e.dart'], + ['example', 'test_driver', 'plugin_e2e_test.dart'], + ['example', 'integration_test', 'foo_test.dart'], + ['example', 'integration_test', 'should_not_run.dart'], + ['example', 'android', 'gradlew'], + ['example', 'should_not_run_e2e.dart'], + [ + 'example', + 'android', + 'app', + 'src', + 'androidTest', + 'MainActivityTest.java' + ], + ]); + + final List output = await runCapturingPrint(runner, [ + 'firebase-test-lab', + '--device', + 'model=flame,version=29', + '--device', + 'model=seoul,version=26', + '--test-run-id', + 'testRunId', + ]); + + expect( + printedMessages, + orderedEquals([ + '\nRUNNING FIREBASE TEST LAB TESTS for plugin', + '\nFirebase project configured.', + '\n\n', + 'All Firebase Test Lab tests successful!', + ]), + ); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + 'gcloud', + 'auth activate-service-account --key-file=${Platform.environment['HOME']}/gcloud-service-key.json' + .split(' '), + null), + ProcessCall( + 'gcloud', 'config set project flutter-infra'.split(' '), null), + ProcessCall( + '/packages/plugin/example/android/gradlew', + 'app:assembleAndroidTest -Pverbose=true'.split(' '), + '/packages/plugin/example/android'), + ProcessCall( + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/test/plugin_e2e.dart' + .split(' '), + '/packages/plugin/example/android'), + ProcessCall( + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 5m --results-bucket=gs://flutter_firebase_testlab --results-dir=plugins_android_test/plugin/null/testRunId/0/ --device model=flame,version=29 --device model=seoul,version=26' + .split(' '), + '/packages/plugin/example'), + ProcessCall( + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/test_driver/plugin_e2e.dart' + .split(' '), + '/packages/plugin/example/android'), + ProcessCall( + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 5m --results-bucket=gs://flutter_firebase_testlab --results-dir=plugins_android_test/plugin/null/testRunId/1/ --device model=flame,version=29 --device model=seoul,version=26' + .split(' '), + '/packages/plugin/example'), + ProcessCall( + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/test/plugin_e2e.dart' + .split(' '), + '/packages/plugin/example/android'), + ProcessCall( + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 5m --results-bucket=gs://flutter_firebase_testlab --results-dir=plugins_android_test/plugin/null/testRunId/2/ --device model=flame,version=29 --device model=seoul,version=26' + .split(' '), + '/packages/plugin/example'), + ProcessCall( + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/integration_test/foo_test.dart' + .split(' '), + '/packages/plugin/example/android'), + ProcessCall( + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 5m --results-bucket=gs://flutter_firebase_testlab --results-dir=plugins_android_test/plugin/null/testRunId/3/ --device model=flame,version=29 --device model=seoul,version=26' + .split(' '), + '/packages/plugin/example'), + ]), + ); + }); + + test('experimental flag', () async { + createFakePlugin('plugin', withExtraFiles: >[ + ['test', 'plugin_test.dart'], + ['test', 'plugin_e2e.dart'], + ['should_not_run_e2e.dart'], + ['lib/test/should_not_run_e2e.dart'], + ['example', 'test', 'plugin_e2e.dart'], + ['example', 'test_driver', 'plugin_e2e.dart'], + ['example', 'test_driver', 'plugin_e2e_test.dart'], + ['example', 'integration_test', 'foo_test.dart'], + ['example', 'integration_test', 'should_not_run.dart'], + ['example', 'android', 'gradlew'], + ['example', 'should_not_run_e2e.dart'], + [ + 'example', + 'android', + 'app', + 'src', + 'androidTest', + 'MainActivityTest.java' + ], + ]); + + await runCapturingPrint(runner, [ + 'firebase-test-lab', + '--device', + 'model=flame,version=29', + '--test-run-id', + 'testRunId', + '--enable-experiment=exp1', + ]); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + 'gcloud', + 'auth activate-service-account --key-file=${Platform.environment['HOME']}/gcloud-service-key.json' + .split(' '), + null), + ProcessCall( + 'gcloud', 'config set project flutter-infra'.split(' '), null), + ProcessCall( + '/packages/plugin/example/android/gradlew', + 'app:assembleAndroidTest -Pverbose=true -Pextra-front-end-options=--enable-experiment%3Dexp1 -Pextra-gen-snapshot-options=--enable-experiment%3Dexp1' + .split(' '), + '/packages/plugin/example/android'), + ProcessCall( + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/test/plugin_e2e.dart -Pextra-front-end-options=--enable-experiment%3Dexp1 -Pextra-gen-snapshot-options=--enable-experiment%3Dexp1' + .split(' '), + '/packages/plugin/example/android'), + ProcessCall( + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 5m --results-bucket=gs://flutter_firebase_testlab --results-dir=plugins_android_test/plugin/null/testRunId/0/ --device model=flame,version=29' + .split(' '), + '/packages/plugin/example'), + ProcessCall( + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/test_driver/plugin_e2e.dart -Pextra-front-end-options=--enable-experiment%3Dexp1 -Pextra-gen-snapshot-options=--enable-experiment%3Dexp1' + .split(' '), + '/packages/plugin/example/android'), + ProcessCall( + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 5m --results-bucket=gs://flutter_firebase_testlab --results-dir=plugins_android_test/plugin/null/testRunId/1/ --device model=flame,version=29' + .split(' '), + '/packages/plugin/example'), + ProcessCall( + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/test/plugin_e2e.dart -Pextra-front-end-options=--enable-experiment%3Dexp1 -Pextra-gen-snapshot-options=--enable-experiment%3Dexp1' + .split(' '), + '/packages/plugin/example/android'), + ProcessCall( + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 5m --results-bucket=gs://flutter_firebase_testlab --results-dir=plugins_android_test/plugin/null/testRunId/2/ --device model=flame,version=29' + .split(' '), + '/packages/plugin/example'), + ProcessCall( + '/packages/plugin/example/android/gradlew', + 'app:assembleDebug -Pverbose=true -Ptarget=/packages/plugin/example/integration_test/foo_test.dart -Pextra-front-end-options=--enable-experiment%3Dexp1 -Pextra-gen-snapshot-options=--enable-experiment%3Dexp1' + .split(' '), + '/packages/plugin/example/android'), + ProcessCall( + 'gcloud', + 'firebase test android run --type instrumentation --app build/app/outputs/apk/debug/app-debug.apk --test build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk --timeout 5m --results-bucket=gs://flutter_firebase_testlab --results-dir=plugins_android_test/plugin/null/testRunId/3/ --device model=flame,version=29' + .split(' '), + '/packages/plugin/example'), + ]), + ); + + cleanupPackages(); + }); + }); +} diff --git a/script/tool/test/lint_podspecs_command_test.dart b/script/tool/test/lint_podspecs_command_test.dart new file mode 100644 index 000000000000..49d6ad4d8e20 --- /dev/null +++ b/script/tool/test/lint_podspecs_command_test.dart @@ -0,0 +1,202 @@ +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:flutter_plugin_tools/src/lint_podspecs_command.dart'; +import 'package:mockito/mockito.dart'; +import 'package:path/path.dart' as p; +import 'package:platform/platform.dart'; +import 'package:test/test.dart'; + +import 'mocks.dart'; +import 'util.dart'; + +void main() { + group('$LintPodspecsCommand', () { + CommandRunner runner; + MockPlatform mockPlatform; + final RecordingProcessRunner processRunner = RecordingProcessRunner(); + List printedMessages; + + setUp(() { + initializeFakePackages(); + + printedMessages = []; + mockPlatform = MockPlatform(); + when(mockPlatform.isMacOS).thenReturn(true); + final LintPodspecsCommand command = LintPodspecsCommand( + mockPackagesDir, + mockFileSystem, + processRunner: processRunner, + platform: mockPlatform, + print: (Object message) => printedMessages.add(message.toString()), + ); + + runner = + CommandRunner('podspec_test', 'Test for $LintPodspecsCommand'); + runner.addCommand(command); + final MockProcess mockLintProcess = MockProcess(); + mockLintProcess.exitCodeCompleter.complete(0); + processRunner.processToReturn = mockLintProcess; + processRunner.recordedCalls.clear(); + }); + + tearDown(() { + cleanupPackages(); + }); + + test('only runs on macOS', () async { + createFakePlugin('plugin1', withExtraFiles: >[ + ['plugin1.podspec'], + ]); + + when(mockPlatform.isMacOS).thenReturn(false); + await runner.run(['podspecs']); + + expect( + processRunner.recordedCalls, + equals([]), + ); + }); + + test('runs pod lib lint on a podspec', () async { + Directory plugin1Dir = + createFakePlugin('plugin1', withExtraFiles: >[ + ['ios', 'plugin1.podspec'], + ['bogus.dart'], // Ignore non-podspecs. + ]); + + processRunner.resultStdout = 'Foo'; + processRunner.resultStderr = 'Bar'; + + await runner.run(['podspecs']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('which', ['pod'], mockPackagesDir.path), + ProcessCall( + 'pod', + [ + 'lib', + 'lint', + p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'), + '--analyze', + '--use-libraries' + ], + mockPackagesDir.path), + ProcessCall( + 'pod', + [ + 'lib', + 'lint', + p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'), + '--analyze', + ], + mockPackagesDir.path), + ]), + ); + + expect( + printedMessages, contains('Linting and analyzing plugin1.podspec')); + expect(printedMessages, contains('Foo')); + expect(printedMessages, contains('Bar')); + }); + + test('skips podspecs with known issues', () async { + createFakePlugin('plugin1', withExtraFiles: >[ + ['plugin1.podspec'] + ]); + createFakePlugin('plugin2', withExtraFiles: >[ + ['plugin2.podspec'] + ]); + + await runner + .run(['podspecs', '--skip=plugin1', '--skip=plugin2']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('which', ['pod'], mockPackagesDir.path), + ]), + ); + }); + + test('skips analyzer for podspecs with known warnings', () async { + Directory plugin1Dir = + createFakePlugin('plugin1', withExtraFiles: >[ + ['plugin1.podspec'], + ]); + + await runner.run(['podspecs', '--no-analyze=plugin1']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('which', ['pod'], mockPackagesDir.path), + ProcessCall( + 'pod', + [ + 'lib', + 'lint', + p.join(plugin1Dir.path, 'plugin1.podspec'), + '--use-libraries' + ], + mockPackagesDir.path), + ProcessCall( + 'pod', + [ + 'lib', + 'lint', + p.join(plugin1Dir.path, 'plugin1.podspec'), + ], + mockPackagesDir.path), + ]), + ); + + expect(printedMessages, contains('Linting plugin1.podspec')); + }); + + test('allow warnings for podspecs with known warnings', () async { + Directory plugin1Dir = + createFakePlugin('plugin1', withExtraFiles: >[ + ['plugin1.podspec'], + ]); + + await runner.run(['podspecs', '--ignore-warnings=plugin1']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('which', ['pod'], mockPackagesDir.path), + ProcessCall( + 'pod', + [ + 'lib', + 'lint', + p.join(plugin1Dir.path, 'plugin1.podspec'), + '--allow-warnings', + '--analyze', + '--use-libraries' + ], + mockPackagesDir.path), + ProcessCall( + 'pod', + [ + 'lib', + 'lint', + p.join(plugin1Dir.path, 'plugin1.podspec'), + '--allow-warnings', + '--analyze', + ], + mockPackagesDir.path), + ]), + ); + + expect( + printedMessages, contains('Linting and analyzing plugin1.podspec')); + }); + }); +} + +class MockPlatform extends Mock implements Platform {} diff --git a/script/tool/test/list_command_test.dart b/script/tool/test/list_command_test.dart new file mode 100644 index 000000000000..478625283dd0 --- /dev/null +++ b/script/tool/test/list_command_test.dart @@ -0,0 +1,198 @@ +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:flutter_plugin_tools/src/list_command.dart'; +import 'package:test/test.dart'; + +import 'util.dart'; + +void main() { + group('$ListCommand', () { + CommandRunner runner; + + setUp(() { + initializeFakePackages(); + final ListCommand command = ListCommand(mockPackagesDir, mockFileSystem); + + runner = CommandRunner('list_test', 'Test for $ListCommand'); + runner.addCommand(command); + }); + + test('lists plugins', () async { + createFakePlugin('plugin1'); + createFakePlugin('plugin2'); + + final List plugins = + await runCapturingPrint(runner, ['list', '--type=plugin']); + + expect( + plugins, + orderedEquals([ + '/packages/plugin1', + '/packages/plugin2', + ]), + ); + + cleanupPackages(); + }); + + test('lists examples', () async { + createFakePlugin('plugin1', withSingleExample: true); + createFakePlugin('plugin2', + withExamples: ['example1', 'example2']); + createFakePlugin('plugin3'); + + final List examples = + await runCapturingPrint(runner, ['list', '--type=example']); + + expect( + examples, + orderedEquals([ + '/packages/plugin1/example', + '/packages/plugin2/example/example1', + '/packages/plugin2/example/example2', + ]), + ); + + cleanupPackages(); + }); + + test('lists packages', () async { + createFakePlugin('plugin1', withSingleExample: true); + createFakePlugin('plugin2', + withExamples: ['example1', 'example2']); + createFakePlugin('plugin3'); + + final List packages = + await runCapturingPrint(runner, ['list', '--type=package']); + + expect( + packages, + unorderedEquals([ + '/packages/plugin1', + '/packages/plugin1/example', + '/packages/plugin2', + '/packages/plugin2/example/example1', + '/packages/plugin2/example/example2', + '/packages/plugin3', + ]), + ); + + cleanupPackages(); + }); + + test('lists files', () async { + createFakePlugin('plugin1', withSingleExample: true); + createFakePlugin('plugin2', + withExamples: ['example1', 'example2']); + createFakePlugin('plugin3'); + + final List examples = + await runCapturingPrint(runner, ['list', '--type=file']); + + expect( + examples, + unorderedEquals([ + '/packages/plugin1/pubspec.yaml', + '/packages/plugin1/example/pubspec.yaml', + '/packages/plugin2/pubspec.yaml', + '/packages/plugin2/example/example1/pubspec.yaml', + '/packages/plugin2/example/example2/pubspec.yaml', + '/packages/plugin3/pubspec.yaml', + ]), + ); + + cleanupPackages(); + }); + + test('lists plugins using federated plugin layout', () async { + createFakePlugin('plugin1'); + + // Create a federated plugin by creating a directory under the packages + // directory with several packages underneath. + final Directory federatedPlugin = + mockPackagesDir.childDirectory('my_plugin')..createSync(); + final Directory clientLibrary = + federatedPlugin.childDirectory('my_plugin')..createSync(); + createFakePubspec(clientLibrary); + final Directory webLibrary = + federatedPlugin.childDirectory('my_plugin_web')..createSync(); + createFakePubspec(webLibrary); + final Directory macLibrary = + federatedPlugin.childDirectory('my_plugin_macos')..createSync(); + createFakePubspec(macLibrary); + + // Test without specifying `--type`. + final List plugins = + await runCapturingPrint(runner, ['list']); + + expect( + plugins, + unorderedEquals([ + '/packages/plugin1', + '/packages/my_plugin/my_plugin', + '/packages/my_plugin/my_plugin_web', + '/packages/my_plugin/my_plugin_macos', + ]), + ); + + cleanupPackages(); + }); + + test('can filter plugins with the --plugins argument', () async { + createFakePlugin('plugin1'); + + // Create a federated plugin by creating a directory under the packages + // directory with several packages underneath. + final Directory federatedPlugin = + mockPackagesDir.childDirectory('my_plugin')..createSync(); + final Directory clientLibrary = + federatedPlugin.childDirectory('my_plugin')..createSync(); + createFakePubspec(clientLibrary); + final Directory webLibrary = + federatedPlugin.childDirectory('my_plugin_web')..createSync(); + createFakePubspec(webLibrary); + final Directory macLibrary = + federatedPlugin.childDirectory('my_plugin_macos')..createSync(); + createFakePubspec(macLibrary); + + List plugins = await runCapturingPrint( + runner, ['list', '--plugins=plugin1']); + expect( + plugins, + unorderedEquals([ + '/packages/plugin1', + ]), + ); + + plugins = await runCapturingPrint( + runner, ['list', '--plugins=my_plugin']); + expect( + plugins, + unorderedEquals([ + '/packages/my_plugin/my_plugin', + '/packages/my_plugin/my_plugin_web', + '/packages/my_plugin/my_plugin_macos', + ]), + ); + + plugins = await runCapturingPrint( + runner, ['list', '--plugins=my_plugin/my_plugin_web']); + expect( + plugins, + unorderedEquals([ + '/packages/my_plugin/my_plugin_web', + ]), + ); + + plugins = await runCapturingPrint(runner, + ['list', '--plugins=my_plugin/my_plugin_web,plugin1']); + expect( + plugins, + unorderedEquals([ + '/packages/plugin1', + '/packages/my_plugin/my_plugin_web', + ]), + ); + }); + }); +} diff --git a/script/tool/test/mocks.dart b/script/tool/test/mocks.dart new file mode 100644 index 000000000000..3e17ff8efd32 --- /dev/null +++ b/script/tool/test/mocks.dart @@ -0,0 +1,33 @@ +import 'dart:async'; +import 'dart:io' as io; + +import 'package:file/file.dart'; +import 'package:mockito/mockito.dart'; + +class MockProcess extends Mock implements io.Process { + final Completer exitCodeCompleter = Completer(); + final StreamController> stdoutController = + StreamController>(); + final StreamController> stderrController = + StreamController>(); + final MockIOSink stdinMock = MockIOSink(); + + @override + Future get exitCode => exitCodeCompleter.future; + + @override + Stream> get stdout => stdoutController.stream; + + @override + Stream> get stderr => stderrController.stream; + + @override + IOSink get stdin => stdinMock; +} + +class MockIOSink extends Mock implements IOSink { + List lines = []; + + @override + void writeln([Object obj = ""]) => lines.add(obj); +} diff --git a/script/tool/test/publish_plugin_command_test.dart b/script/tool/test/publish_plugin_command_test.dart new file mode 100644 index 000000000000..ada4bf08fd72 --- /dev/null +++ b/script/tool/test/publish_plugin_command_test.dart @@ -0,0 +1,378 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io' as io; + +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:flutter_plugin_tools/src/publish_plugin_command.dart'; +import 'package:flutter_plugin_tools/src/common.dart'; +import 'package:git/git.dart'; +import 'package:matcher/matcher.dart'; +import 'package:mockito/mockito.dart'; +import 'package:test/test.dart'; + +import 'mocks.dart'; +import 'util.dart'; + +void main() { + const String testPluginName = 'foo'; + final List printedMessages = []; + + Directory parentDir; + Directory pluginDir; + GitDir gitDir; + TestProcessRunner processRunner; + CommandRunner commandRunner; + MockStdin mockStdin; + + setUp(() async { + // This test uses a local file system instead of an in memory one throughout + // so that git actually works. In setup we initialize a mono repo of plugins + // with one package and commit everything to Git. + parentDir = const LocalFileSystem() + .systemTempDirectory + .createTempSync('publish_plugin_command_test-'); + initializeFakePackages(parentDir: parentDir); + pluginDir = createFakePlugin(testPluginName, withSingleExample: false); + assert(pluginDir != null && pluginDir.existsSync()); + createFakePubspec(pluginDir, includeVersion: true); + io.Process.runSync('git', ['init'], + workingDirectory: mockPackagesDir.path); + gitDir = await GitDir.fromExisting(mockPackagesDir.path); + await gitDir.runCommand(['add', '-A']); + await gitDir.runCommand(['commit', '-m', 'Initial commit']); + processRunner = TestProcessRunner(); + mockStdin = MockStdin(); + commandRunner = CommandRunner('tester', '') + ..addCommand(PublishPluginCommand( + mockPackagesDir, const LocalFileSystem(), + processRunner: processRunner, + print: (Object message) => printedMessages.add(message.toString()), + stdinput: mockStdin)); + }); + + tearDown(() { + parentDir.deleteSync(recursive: true); + printedMessages.clear(); + }); + + group('Initial validation', () { + test('requires a package flag', () async { + await expectLater(() => commandRunner.run(['publish-plugin']), + throwsA(const TypeMatcher())); + + expect( + printedMessages.last, contains("Must specify a package to publish.")); + }); + + test('requires an existing flag', () async { + await expectLater( + () => commandRunner + .run(['publish-plugin', '--package', 'iamerror']), + throwsA(const TypeMatcher())); + + expect(printedMessages.last, contains('iamerror does not exist')); + }); + + test('refuses to proceed with dirty files', () async { + pluginDir.childFile('tmp').createSync(); + + await expectLater( + () => commandRunner + .run(['publish-plugin', '--package', testPluginName]), + throwsA(const TypeMatcher())); + + expect( + printedMessages.last, + contains( + "There are files in the package directory that haven't been saved in git.")); + }); + + test('fails immediately if the remote doesn\'t exist', () async { + await expectLater( + () => commandRunner + .run(['publish-plugin', '--package', testPluginName]), + throwsA(const TypeMatcher())); + + expect(processRunner.results.last.stderr, contains("No such remote")); + }); + + test("doesn't validate the remote if it's not pushing tags", () async { + // Immediately return 0 when running `pub publish`. + processRunner.mockPublishProcess.exitCodeCompleter.complete(0); + + await commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + '--no-push-tags', + '--no-tag-release' + ]); + + expect(printedMessages.last, 'Done!'); + }); + + test('can publish non-flutter package', () async { + createFakePubspec(pluginDir, includeVersion: true, isFlutter: false); + io.Process.runSync('git', ['init'], + workingDirectory: mockPackagesDir.path); + gitDir = await GitDir.fromExisting(mockPackagesDir.path); + await gitDir.runCommand(['add', '-A']); + await gitDir.runCommand(['commit', '-m', 'Initial commit']); + // Immediately return 0 when running `pub publish`. + processRunner.mockPublishProcess.exitCodeCompleter.complete(0); + await commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + '--no-push-tags', + '--no-tag-release' + ]); + expect(printedMessages.last, 'Done!'); + }); + }); + + group('Publishes package', () { + test('while showing all output from pub publish to the user', () async { + final Future publishCommand = commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + '--no-push-tags', + '--no-tag-release' + ]); + processRunner.mockPublishProcess.stdoutController.add(utf8.encode('Foo')); + processRunner.mockPublishProcess.stderrController.add(utf8.encode('Bar')); + processRunner.mockPublishProcess.exitCodeCompleter.complete(0); + + await publishCommand; + + expect(printedMessages, contains('Foo')); + expect(printedMessages, contains('Bar')); + }); + + test('forwards input from the user to `pub publish`', () async { + final Future publishCommand = commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + '--no-push-tags', + '--no-tag-release' + ]); + mockStdin.controller.add(utf8.encode('user input')); + processRunner.mockPublishProcess.exitCodeCompleter.complete(0); + + await publishCommand; + + expect(processRunner.mockPublishProcess.stdinMock.lines, + contains('user input')); + }); + + test('forwards --pub-publish-flags to pub publish', () async { + processRunner.mockPublishProcess.exitCodeCompleter.complete(0); + await commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + '--no-push-tags', + '--no-tag-release', + '--pub-publish-flags', + '--dry-run,--server=foo' + ]); + + expect(processRunner.mockPublishArgs.length, 4); + expect(processRunner.mockPublishArgs[0], 'pub'); + expect(processRunner.mockPublishArgs[1], 'publish'); + expect(processRunner.mockPublishArgs[2], '--dry-run'); + expect(processRunner.mockPublishArgs[3], '--server=foo'); + }); + + test('throws if pub publish fails', () async { + processRunner.mockPublishProcess.exitCodeCompleter.complete(128); + await expectLater( + () => commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + '--no-push-tags', + '--no-tag-release', + ]), + throwsA(const TypeMatcher())); + + expect(printedMessages, contains("Publish failed. Exiting.")); + }); + }); + + group('Tags release', () { + test('with the version and name from the pubspec.yaml', () async { + processRunner.mockPublishProcess.exitCodeCompleter.complete(0); + await commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + '--no-push-tags', + ]); + + final String tag = + (await gitDir.runCommand(['show-ref', 'fake_package-v0.0.1'])) + .stdout; + expect(tag, isNotEmpty); + }); + + test('only if publishing succeeded', () async { + processRunner.mockPublishProcess.exitCodeCompleter.complete(128); + await expectLater( + () => commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + '--no-push-tags', + ]), + throwsA(const TypeMatcher())); + + expect(printedMessages, contains("Publish failed. Exiting.")); + final String tag = (await gitDir.runCommand( + ['show-ref', 'fake_package-v0.0.1'], + throwOnError: false)) + .stdout; + expect(tag, isEmpty); + }); + }); + + group('Pushes tags', () { + setUp(() async { + await gitDir.runCommand( + ['remote', 'add', 'upstream', 'http://localhost:8000']); + }); + + test('requires user confirmation', () async { + processRunner.mockPublishProcess.exitCodeCompleter.complete(0); + mockStdin.readLineOutput = 'help'; + await expectLater( + () => commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + ]), + throwsA(const TypeMatcher())); + + expect(printedMessages, contains('Tag push canceled.')); + }); + + test('to upstream by default', () async { + await gitDir.runCommand(['tag', 'garbage']); + processRunner.mockPublishProcess.exitCodeCompleter.complete(0); + mockStdin.readLineOutput = 'y'; + await commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + ]); + + expect(processRunner.pushTagsArgs.isNotEmpty, isTrue); + expect(processRunner.pushTagsArgs[1], 'upstream'); + expect(processRunner.pushTagsArgs[2], 'fake_package-v0.0.1'); + expect(printedMessages.last, 'Done!'); + }); + + test('to different remotes based on a flag', () async { + await gitDir.runCommand( + ['remote', 'add', 'origin', 'http://localhost:8001']); + processRunner.mockPublishProcess.exitCodeCompleter.complete(0); + mockStdin.readLineOutput = 'y'; + await commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + '--remote', + 'origin', + ]); + + expect(processRunner.pushTagsArgs.isNotEmpty, isTrue); + expect(processRunner.pushTagsArgs[1], 'origin'); + expect(processRunner.pushTagsArgs[2], 'fake_package-v0.0.1'); + expect(printedMessages.last, 'Done!'); + }); + + test('only if tagging and pushing to remotes are both enabled', () async { + processRunner.mockPublishProcess.exitCodeCompleter.complete(0); + await commandRunner.run([ + 'publish-plugin', + '--package', + testPluginName, + '--no-tag-release', + ]); + + expect(processRunner.pushTagsArgs.isEmpty, isTrue); + expect(printedMessages.last, 'Done!'); + }); + }); +} + +class TestProcessRunner extends ProcessRunner { + final List results = []; + final MockProcess mockPublishProcess = MockProcess(); + final List mockPublishArgs = []; + final MockProcessResult mockPushTagsResult = MockProcessResult(); + final List pushTagsArgs = []; + + @override + Future runAndExitOnError( + String executable, + List args, { + Directory workingDir, + }) async { + // Don't ever really push tags. + if (executable == 'git' && args.isNotEmpty && args[0] == 'push') { + pushTagsArgs.addAll(args); + return mockPushTagsResult; + } + + final io.ProcessResult result = io.Process.runSync(executable, args, + workingDirectory: workingDir?.path); + results.add(result); + if (result.exitCode != 0) { + throw ToolExit(result.exitCode); + } + return result; + } + + @override + Future start(String executable, List args, + {Directory workingDirectory}) async { + /// Never actually publish anything. Start is always and only used for this + /// since it returns something we can route stdin through. + assert(executable == 'flutter' && + args.isNotEmpty && + args[0] == 'pub' && + args[1] == 'publish'); + mockPublishArgs.addAll(args); + return mockPublishProcess; + } +} + +class MockStdin extends Mock implements io.Stdin { + final StreamController> controller = StreamController>(); + String readLineOutput; + + @override + Stream transform(StreamTransformer streamTransformer) { + return controller.stream.transform(streamTransformer); + } + + @override + StreamSubscription> listen(void onData(List event), + {Function onError, void onDone(), bool cancelOnError}) { + return controller.stream.listen(onData, + onError: onError, onDone: onDone, cancelOnError: cancelOnError); + } + + @override + String readLineSync( + {Encoding encoding = io.systemEncoding, + bool retainNewlines = false}) => + readLineOutput; +} + +class MockProcessResult extends Mock implements io.ProcessResult {} diff --git a/script/tool/test/test_command_test.dart b/script/tool/test/test_command_test.dart new file mode 100644 index 000000000000..514e4c27190a --- /dev/null +++ b/script/tool/test/test_command_test.dart @@ -0,0 +1,154 @@ +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:flutter_plugin_tools/src/test_command.dart'; +import 'package:test/test.dart'; + +import 'util.dart'; + +void main() { + group('$TestCommand', () { + CommandRunner runner; + final RecordingProcessRunner processRunner = RecordingProcessRunner(); + + setUp(() { + initializeFakePackages(); + final TestCommand command = TestCommand(mockPackagesDir, mockFileSystem, + processRunner: processRunner); + + runner = CommandRunner('test_test', 'Test for $TestCommand'); + runner.addCommand(command); + }); + + tearDown(() { + cleanupPackages(); + processRunner.recordedCalls.clear(); + }); + + test('runs flutter test on each plugin', () async { + final Directory plugin1Dir = + createFakePlugin('plugin1', withExtraFiles: >[ + ['test', 'empty_test.dart'], + ]); + final Directory plugin2Dir = + createFakePlugin('plugin2', withExtraFiles: >[ + ['test', 'empty_test.dart'], + ]); + + await runner.run(['test']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', ['test', '--color'], plugin1Dir.path), + ProcessCall('flutter', ['test', '--color'], plugin2Dir.path), + ]), + ); + + cleanupPackages(); + }); + + test('skips testing plugins without test directory', () async { + createFakePlugin('plugin1'); + final Directory plugin2Dir = + createFakePlugin('plugin2', withExtraFiles: >[ + ['test', 'empty_test.dart'], + ]); + + await runner.run(['test']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', ['test', '--color'], plugin2Dir.path), + ]), + ); + + cleanupPackages(); + }); + + test('runs pub run test on non-Flutter packages', () async { + final Directory plugin1Dir = createFakePlugin('plugin1', + isFlutter: true, + withExtraFiles: >[ + ['test', 'empty_test.dart'], + ]); + final Directory plugin2Dir = createFakePlugin('plugin2', + isFlutter: false, + withExtraFiles: >[ + ['test', 'empty_test.dart'], + ]); + + await runner.run(['test', '--enable-experiment=exp1']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + 'flutter', + ['test', '--color', '--enable-experiment=exp1'], + plugin1Dir.path), + ProcessCall('pub', ['get'], plugin2Dir.path), + ProcessCall( + 'pub', + ['run', '--enable-experiment=exp1', 'test'], + plugin2Dir.path), + ]), + ); + + cleanupPackages(); + }); + + test('runs on Chrome for web plugins', () async { + final Directory pluginDir = createFakePlugin( + 'plugin', + withExtraFiles: >[ + ['test', 'empty_test.dart'], + ], + isFlutter: true, + isWebPlugin: true, + ); + + await runner.run(['test']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', + ['test', '--color', '--platform=chrome'], pluginDir.path), + ]), + ); + }); + + test('enable-experiment flag', () async { + final Directory plugin1Dir = createFakePlugin('plugin1', + isFlutter: true, + withExtraFiles: >[ + ['test', 'empty_test.dart'], + ]); + final Directory plugin2Dir = createFakePlugin('plugin2', + isFlutter: false, + withExtraFiles: >[ + ['test', 'empty_test.dart'], + ]); + + await runner.run(['test', '--enable-experiment=exp1']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + 'flutter', + ['test', '--color', '--enable-experiment=exp1'], + plugin1Dir.path), + ProcessCall('pub', ['get'], plugin2Dir.path), + ProcessCall( + 'pub', + ['run', '--enable-experiment=exp1', 'test'], + plugin2Dir.path), + ]), + ); + + cleanupPackages(); + }); + }); +} diff --git a/script/tool/test/util.dart b/script/tool/test/util.dart new file mode 100644 index 000000000000..ec0000d13f34 --- /dev/null +++ b/script/tool/test/util.dart @@ -0,0 +1,291 @@ +import 'dart:async'; +import 'dart:io' as io; + +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:platform/platform.dart'; +import 'package:flutter_plugin_tools/src/common.dart'; +import 'package:quiver/collection.dart'; + +FileSystem mockFileSystem = MemoryFileSystem( + style: LocalPlatform().isWindows + ? FileSystemStyle.windows + : FileSystemStyle.posix); +Directory mockPackagesDir; + +/// Creates a mock packages directory in the mock file system. +/// +/// If [parentDir] is set the mock packages dir will be creates as a child of +/// it. If not [mockFileSystem] will be used instead. +void initializeFakePackages({Directory parentDir}) { + mockPackagesDir = + (parentDir ?? mockFileSystem.currentDirectory).childDirectory('packages'); + mockPackagesDir.createSync(); +} + +/// Creates a plugin package with the given [name] in [mockPackagesDir]. +Directory createFakePlugin( + String name, { + bool withSingleExample = false, + List withExamples = const [], + List> withExtraFiles = const >[], + bool isFlutter = true, + bool isAndroidPlugin = false, + bool isIosPlugin = false, + bool isWebPlugin = false, + bool isLinuxPlugin = false, + bool isMacOsPlugin = false, + bool isWindowsPlugin = false, + String parentDirectoryName = '', +}) { + assert(!(withSingleExample && withExamples.isNotEmpty), + 'cannot pass withSingleExample and withExamples simultaneously'); + + final Directory pluginDirectory = (parentDirectoryName != '') + ? mockPackagesDir.childDirectory(parentDirectoryName).childDirectory(name) + : mockPackagesDir.childDirectory(name); + pluginDirectory.createSync(recursive: true); + + createFakePubspec( + pluginDirectory, + name: name, + isFlutter: isFlutter, + isAndroidPlugin: isAndroidPlugin, + isIosPlugin: isIosPlugin, + isWebPlugin: isWebPlugin, + isLinuxPlugin: isLinuxPlugin, + isMacOsPlugin: isMacOsPlugin, + isWindowsPlugin: isWindowsPlugin, + ); + + if (withSingleExample) { + final Directory exampleDir = pluginDirectory.childDirectory('example') + ..createSync(); + createFakePubspec(exampleDir, + name: "${name}_example", isFlutter: isFlutter); + } else if (withExamples.isNotEmpty) { + final Directory exampleDir = pluginDirectory.childDirectory('example') + ..createSync(); + for (String example in withExamples) { + final Directory currentExample = exampleDir.childDirectory(example) + ..createSync(); + createFakePubspec(currentExample, name: example, isFlutter: isFlutter); + } + } + + for (List file in withExtraFiles) { + final List newFilePath = [pluginDirectory.path] + ..addAll(file); + final File newFile = + mockFileSystem.file(mockFileSystem.path.joinAll(newFilePath)); + newFile.createSync(recursive: true); + } + + return pluginDirectory; +} + +/// Creates a `pubspec.yaml` file with a flutter dependency. +void createFakePubspec( + Directory parent, { + String name = 'fake_package', + bool isFlutter = true, + bool includeVersion = false, + bool isAndroidPlugin = false, + bool isIosPlugin = false, + bool isWebPlugin = false, + bool isLinuxPlugin = false, + bool isMacOsPlugin = false, + bool isWindowsPlugin = false, +}) { + parent.childFile('pubspec.yaml').createSync(); + String yaml = ''' +name: $name +flutter: + plugin: + platforms: +'''; + if (isAndroidPlugin) { + yaml += ''' + android: + package: io.flutter.plugins.fake + pluginClass: FakePlugin +'''; + } + if (isIosPlugin) { + yaml += ''' + ios: + pluginClass: FLTFakePlugin +'''; + } + if (isWebPlugin) { + yaml += ''' + web: + pluginClass: FakePlugin + fileName: ${name}_web.dart +'''; + } + if (isLinuxPlugin) { + yaml += ''' + linux: + pluginClass: FakePlugin +'''; + } + if (isMacOsPlugin) { + yaml += ''' + macos: + pluginClass: FakePlugin +'''; + } + if (isWindowsPlugin) { + yaml += ''' + windows: + pluginClass: FakePlugin +'''; + } + if (isFlutter) { + yaml += ''' +dependencies: + flutter: + sdk: flutter +'''; + } + if (includeVersion) { + yaml += ''' +version: 0.0.1 +publish_to: none # Hardcoded safeguard to prevent this from somehow being published by a broken test. +'''; + } + parent.childFile('pubspec.yaml').writeAsStringSync(yaml); +} + +/// Cleans up the mock packages directory, making it an empty directory again. +void cleanupPackages() { + mockPackagesDir.listSync().forEach((FileSystemEntity entity) { + entity.deleteSync(recursive: true); + }); +} + +/// Run the command [runner] with the given [args] and return +/// what was printed. +Future> runCapturingPrint( + CommandRunner runner, List args) async { + final List prints = []; + final ZoneSpecification spec = ZoneSpecification( + print: (_, __, ___, String message) { + prints.add(message); + }, + ); + await Zone.current + .fork(specification: spec) + .run>(() => runner.run(args)); + + return prints; +} + +/// A mock [ProcessRunner] which records process calls. +class RecordingProcessRunner extends ProcessRunner { + io.Process processToReturn; + final List recordedCalls = []; + + /// Populate for [io.ProcessResult] to use a String [stdout] instead of a [List] of [int]. + String resultStdout; + + /// Populate for [io.ProcessResult] to use a String [stderr] instead of a [List] of [int]. + String resultStderr; + + @override + Future runAndStream( + String executable, + List args, { + Directory workingDir, + bool exitOnError = false, + }) async { + recordedCalls.add(ProcessCall(executable, args, workingDir?.path)); + return Future.value( + processToReturn == null ? 0 : await processToReturn.exitCode); + } + + /// Returns [io.ProcessResult] created from [processToReturn], [resultStdout], and [resultStderr]. + @override + Future run(String executable, List args, + {Directory workingDir, + bool exitOnError = false, + stdoutEncoding = io.systemEncoding, + stderrEncoding = io.systemEncoding}) async { + recordedCalls.add(ProcessCall(executable, args, workingDir?.path)); + io.ProcessResult result; + + if (processToReturn != null) { + result = io.ProcessResult( + processToReturn.pid, + await processToReturn.exitCode, + resultStdout ?? processToReturn.stdout, + resultStderr ?? processToReturn.stderr); + } + return Future.value(result); + } + + @override + Future runAndExitOnError( + String executable, + List args, { + Directory workingDir, + }) async { + recordedCalls.add(ProcessCall(executable, args, workingDir?.path)); + io.ProcessResult result; + if (processToReturn != null) { + result = io.ProcessResult( + processToReturn.pid, + await processToReturn.exitCode, + resultStdout ?? processToReturn.stdout, + resultStderr ?? processToReturn.stderr); + } + return Future.value(result); + } + + @override + Future start(String executable, List args, + {Directory workingDirectory}) async { + recordedCalls.add(ProcessCall(executable, args, workingDirectory?.path)); + return Future.value(processToReturn); + } +} + +/// A recorded process call. +class ProcessCall { + const ProcessCall(this.executable, this.args, this.workingDir); + + /// The executable that was called. + final String executable; + + /// The arguments passed to [executable] in the call. + final List args; + + /// The working directory this process was called from. + final String workingDir; + + @override + bool operator ==(dynamic other) { + if (other is! ProcessCall) { + return false; + } + final ProcessCall otherCall = other; + return executable == otherCall.executable && + listsEqual(args, otherCall.args) && + workingDir == otherCall.workingDir; + } + + @override + int get hashCode => + executable?.hashCode ?? + 0 ^ args?.hashCode ?? + 0 ^ workingDir?.hashCode ?? + 0; + + @override + String toString() { + final List command = [executable]..addAll(args); + return '"${command.join(' ')}" in $workingDir'; + } +} diff --git a/script/tool/test/version_check_test.dart b/script/tool/test/version_check_test.dart new file mode 100644 index 000000000000..b9ace3811bff --- /dev/null +++ b/script/tool/test/version_check_test.dart @@ -0,0 +1,319 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:git/git.dart'; +import 'package:mockito/mockito.dart'; +import "package:test/test.dart"; +import "package:flutter_plugin_tools/src/version_check_command.dart"; +import 'package:pub_semver/pub_semver.dart'; +import 'util.dart'; + +void testAllowedVersion( + String masterVersion, + String headVersion, { + bool allowed = true, + NextVersionType nextVersionType, +}) { + final Version master = Version.parse(masterVersion); + final Version head = Version.parse(headVersion); + final Map allowedVersions = + getAllowedNextVersions(master, head); + if (allowed) { + expect(allowedVersions, contains(head)); + if (nextVersionType != null) { + expect(allowedVersions[head], equals(nextVersionType)); + } + } else { + expect(allowedVersions, isNot(contains(head))); + } +} + +class MockGitDir extends Mock implements GitDir {} + +class MockProcessResult extends Mock implements ProcessResult {} + +void main() { + group('$VersionCheckCommand', () { + CommandRunner runner; + RecordingProcessRunner processRunner; + List> gitDirCommands; + String gitDiffResponse; + Map gitShowResponses; + + setUp(() { + gitDirCommands = >[]; + gitDiffResponse = ''; + gitShowResponses = {}; + final MockGitDir gitDir = MockGitDir(); + when(gitDir.runCommand(any)).thenAnswer((Invocation invocation) { + gitDirCommands.add(invocation.positionalArguments[0]); + final MockProcessResult mockProcessResult = MockProcessResult(); + if (invocation.positionalArguments[0][0] == 'diff') { + when(mockProcessResult.stdout).thenReturn(gitDiffResponse); + } else if (invocation.positionalArguments[0][0] == 'show') { + final String response = + gitShowResponses[invocation.positionalArguments[0][1]]; + when(mockProcessResult.stdout).thenReturn(response); + } + return Future.value(mockProcessResult); + }); + initializeFakePackages(); + processRunner = RecordingProcessRunner(); + final VersionCheckCommand command = VersionCheckCommand( + mockPackagesDir, mockFileSystem, + processRunner: processRunner, gitDir: gitDir); + + runner = CommandRunner( + 'version_check_command', 'Test for $VersionCheckCommand'); + runner.addCommand(command); + }); + + tearDown(() { + cleanupPackages(); + }); + + test('allows valid version', () async { + createFakePlugin('plugin'); + gitDiffResponse = "packages/plugin/pubspec.yaml"; + gitShowResponses = { + 'master:packages/plugin/pubspec.yaml': 'version: 1.0.0', + 'HEAD:packages/plugin/pubspec.yaml': 'version: 2.0.0', + }; + final List output = await runCapturingPrint( + runner, ['version-check', '--base_sha=master']); + + expect( + output, + orderedEquals([ + 'No version check errors found!', + ]), + ); + expect(gitDirCommands.length, equals(3)); + expect( + gitDirCommands[0].join(' '), equals('diff --name-only master HEAD')); + expect(gitDirCommands[1].join(' '), + equals('show master:packages/plugin/pubspec.yaml')); + expect(gitDirCommands[2].join(' '), + equals('show HEAD:packages/plugin/pubspec.yaml')); + }); + + test('denies invalid version', () async { + createFakePlugin('plugin'); + gitDiffResponse = "packages/plugin/pubspec.yaml"; + gitShowResponses = { + 'master:packages/plugin/pubspec.yaml': 'version: 0.0.1', + 'HEAD:packages/plugin/pubspec.yaml': 'version: 0.2.0', + }; + final Future> result = runCapturingPrint( + runner, ['version-check', '--base_sha=master']); + + await expectLater( + result, + throwsA(const TypeMatcher()), + ); + expect(gitDirCommands.length, equals(3)); + expect( + gitDirCommands[0].join(' '), equals('diff --name-only master HEAD')); + expect(gitDirCommands[1].join(' '), + equals('show master:packages/plugin/pubspec.yaml')); + expect(gitDirCommands[2].join(' '), + equals('show HEAD:packages/plugin/pubspec.yaml')); + }); + + test('gracefully handles missing pubspec.yaml', () async { + createFakePlugin('plugin'); + gitDiffResponse = "packages/plugin/pubspec.yaml"; + mockFileSystem.currentDirectory + .childDirectory('packages') + .childDirectory('plugin') + .childFile('pubspec.yaml') + .deleteSync(); + final List output = await runCapturingPrint( + runner, ['version-check', '--base_sha=master']); + + expect( + output, + orderedEquals([ + 'No version check errors found!', + ]), + ); + expect(gitDirCommands.length, equals(1)); + expect(gitDirCommands.first.join(' '), + equals('diff --name-only master HEAD')); + }); + + test('allows minor changes to platform interfaces', () async { + createFakePlugin('plugin_platform_interface'); + gitDiffResponse = "packages/plugin_platform_interface/pubspec.yaml"; + gitShowResponses = { + 'master:packages/plugin_platform_interface/pubspec.yaml': + 'version: 1.0.0', + 'HEAD:packages/plugin_platform_interface/pubspec.yaml': + 'version: 1.1.0', + }; + final List output = await runCapturingPrint( + runner, ['version-check', '--base_sha=master']); + expect( + output, + orderedEquals([ + 'No version check errors found!', + ]), + ); + expect(gitDirCommands.length, equals(3)); + expect( + gitDirCommands[0].join(' '), equals('diff --name-only master HEAD')); + expect( + gitDirCommands[1].join(' '), + equals( + 'show master:packages/plugin_platform_interface/pubspec.yaml')); + expect(gitDirCommands[2].join(' '), + equals('show HEAD:packages/plugin_platform_interface/pubspec.yaml')); + }); + + test('disallows breaking changes to platform interfaces', () async { + createFakePlugin('plugin_platform_interface'); + gitDiffResponse = "packages/plugin_platform_interface/pubspec.yaml"; + gitShowResponses = { + 'master:packages/plugin_platform_interface/pubspec.yaml': + 'version: 1.0.0', + 'HEAD:packages/plugin_platform_interface/pubspec.yaml': + 'version: 2.0.0', + }; + final Future> output = runCapturingPrint( + runner, ['version-check', '--base_sha=master']); + await expectLater( + output, + throwsA(const TypeMatcher()), + ); + expect(gitDirCommands.length, equals(3)); + expect( + gitDirCommands[0].join(' '), equals('diff --name-only master HEAD')); + expect( + gitDirCommands[1].join(' '), + equals( + 'show master:packages/plugin_platform_interface/pubspec.yaml')); + expect(gitDirCommands[2].join(' '), + equals('show HEAD:packages/plugin_platform_interface/pubspec.yaml')); + }); + }); + + group("Pre 1.0", () { + test("nextVersion allows patch version", () { + testAllowedVersion("0.12.0", "0.12.0+1", + nextVersionType: NextVersionType.PATCH); + testAllowedVersion("0.12.0+4", "0.12.0+5", + nextVersionType: NextVersionType.PATCH); + }); + + test("nextVersion does not allow jumping patch", () { + testAllowedVersion("0.12.0", "0.12.0+2", allowed: false); + testAllowedVersion("0.12.0+2", "0.12.0+4", allowed: false); + }); + + test("nextVersion does not allow going back", () { + testAllowedVersion("0.12.0", "0.11.0", allowed: false); + testAllowedVersion("0.12.0+2", "0.12.0+1", allowed: false); + testAllowedVersion("0.12.0+1", "0.12.0", allowed: false); + }); + + test("nextVersion allows minor version", () { + testAllowedVersion("0.12.0", "0.12.1", + nextVersionType: NextVersionType.MINOR); + testAllowedVersion("0.12.0+4", "0.12.1", + nextVersionType: NextVersionType.MINOR); + }); + + test("nextVersion does not allow jumping minor", () { + testAllowedVersion("0.12.0", "0.12.2", allowed: false); + testAllowedVersion("0.12.0+2", "0.12.3", allowed: false); + }); + }); + + group("Releasing 1.0", () { + test("nextVersion allows releasing 1.0", () { + testAllowedVersion("0.12.0", "1.0.0", + nextVersionType: NextVersionType.BREAKING_MAJOR); + testAllowedVersion("0.12.0+4", "1.0.0", + nextVersionType: NextVersionType.BREAKING_MAJOR); + }); + + test("nextVersion does not allow jumping major", () { + testAllowedVersion("0.12.0", "2.0.0", allowed: false); + testAllowedVersion("0.12.0+4", "2.0.0", allowed: false); + }); + + test("nextVersion does not allow un-releasing", () { + testAllowedVersion("1.0.0", "0.12.0+4", allowed: false); + testAllowedVersion("1.0.0", "0.12.0", allowed: false); + }); + }); + + group("Post 1.0", () { + test("nextVersion allows patch jumps", () { + testAllowedVersion("1.0.1", "1.0.2", + nextVersionType: NextVersionType.PATCH); + testAllowedVersion("1.0.0", "1.0.1", + nextVersionType: NextVersionType.PATCH); + }); + + test("nextVersion does not allow build jumps", () { + testAllowedVersion("1.0.1", "1.0.1+1", allowed: false); + testAllowedVersion("1.0.0+5", "1.0.0+6", allowed: false); + }); + + test("nextVersion does not allow skipping patches", () { + testAllowedVersion("1.0.1", "1.0.3", allowed: false); + testAllowedVersion("1.0.0", "1.0.6", allowed: false); + }); + + test("nextVersion allows minor version jumps", () { + testAllowedVersion("1.0.1", "1.1.0", + nextVersionType: NextVersionType.MINOR); + testAllowedVersion("1.0.0", "1.1.0", + nextVersionType: NextVersionType.MINOR); + }); + + test("nextVersion does not allow skipping minor versions", () { + testAllowedVersion("1.0.1", "1.2.0", allowed: false); + testAllowedVersion("1.1.0", "1.3.0", allowed: false); + }); + + test("nextVersion allows breaking changes", () { + testAllowedVersion("1.0.1", "2.0.0", + nextVersionType: NextVersionType.BREAKING_MAJOR); + testAllowedVersion("1.0.0", "2.0.0", + nextVersionType: NextVersionType.BREAKING_MAJOR); + }); + + test("nextVersion allows null safety pre prelease", () { + testAllowedVersion("1.0.1", "2.0.0-nullsafety", + nextVersionType: NextVersionType.MAJOR_NULLSAFETY_PRE_RELEASE); + testAllowedVersion("1.0.0", "2.0.0-nullsafety", + nextVersionType: NextVersionType.MAJOR_NULLSAFETY_PRE_RELEASE); + testAllowedVersion("1.0.0-nullsafety", "1.0.0-nullsafety.1", + nextVersionType: NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE); + testAllowedVersion("1.0.0-nullsafety.1", "1.0.0-nullsafety.2", + nextVersionType: NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE); + testAllowedVersion("0.1.0", "0.2.0-nullsafety", + nextVersionType: NextVersionType.MAJOR_NULLSAFETY_PRE_RELEASE); + testAllowedVersion("0.1.0-nullsafety", "0.1.0-nullsafety.1", + nextVersionType: NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE); + testAllowedVersion("0.1.0-nullsafety.1", "0.1.0-nullsafety.2", + nextVersionType: NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE); + testAllowedVersion("1.0.0", "1.1.0-nullsafety", + nextVersionType: NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE); + testAllowedVersion("1.1.0-nullsafety", "1.1.0-nullsafety.1", + nextVersionType: NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE); + testAllowedVersion("0.1.0", "0.1.1-nullsafety", + nextVersionType: NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE); + testAllowedVersion("0.1.1-nullsafety", "0.1.1-nullsafety.1", + nextVersionType: NextVersionType.MINOR_NULLSAFETY_PRE_RELEASE); + }); + + test("nextVersion does not allow skipping major versions", () { + testAllowedVersion("1.0.1", "3.0.0", allowed: false); + testAllowedVersion("1.1.0", "2.3.0", allowed: false); + }); + }); +} diff --git a/script/tool/test/xctest_command_test.dart b/script/tool/test/xctest_command_test.dart new file mode 100644 index 000000000000..007c2e12188c --- /dev/null +++ b/script/tool/test/xctest_command_test.dart @@ -0,0 +1,358 @@ +// 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:convert'; + +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:flutter_plugin_tools/src/xctest_command.dart'; +import 'package:test/test.dart'; +import 'package:flutter_plugin_tools/src/common.dart'; + +import 'mocks.dart'; +import 'util.dart'; + +final _kDeviceListMap = { + "runtimes": [ + { + "bundlePath": + "/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.0.simruntime", + "buildversion": "17A577", + "runtimeRoot": + "/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.0.simruntime/Contents/Resources/RuntimeRoot", + "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-13-0", + "version": "13.0", + "isAvailable": true, + "name": "iOS 13.0" + }, + { + "bundlePath": + "/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.4.simruntime", + "buildversion": "17L255", + "runtimeRoot": + "/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.4.simruntime/Contents/Resources/RuntimeRoot", + "identifier": "com.apple.CoreSimulator.SimRuntime.iOS-13-4", + "version": "13.4", + "isAvailable": true, + "name": "iOS 13.4" + }, + { + "bundlePath": + "/Applications/Xcode_11_7.app/Contents/Developer/Platforms/WatchOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/watchOS.simruntime", + "buildversion": "17T531", + "runtimeRoot": + "/Applications/Xcode_11_7.app/Contents/Developer/Platforms/WatchOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/watchOS.simruntime/Contents/Resources/RuntimeRoot", + "identifier": "com.apple.CoreSimulator.SimRuntime.watchOS-6-2", + "version": "6.2.1", + "isAvailable": true, + "name": "watchOS 6.2" + } + ], + "devices": { + "com.apple.CoreSimulator.SimRuntime.iOS-13-4": [ + { + "dataPath": + "/Users/xxx/Library/Developer/CoreSimulator/Devices/2706BBEB-1E01-403E-A8E9-70E8E5A24774/data", + "logPath": + "/Users/xxx/Library/Logs/CoreSimulator/2706BBEB-1E01-403E-A8E9-70E8E5A24774", + "udid": "2706BBEB-1E01-403E-A8E9-70E8E5A24774", + "isAvailable": true, + "deviceTypeIdentifier": + "com.apple.CoreSimulator.SimDeviceType.iPhone-8", + "state": "Shutdown", + "name": "iPhone 8" + }, + { + "dataPath": + "/Users/xxx/Library/Developer/CoreSimulator/Devices/1E76A0FD-38AC-4537-A989-EA639D7D012A/data", + "logPath": + "/Users/xxx/Library/Logs/CoreSimulator/1E76A0FD-38AC-4537-A989-EA639D7D012A", + "udid": "1E76A0FD-38AC-4537-A989-EA639D7D012A", + "isAvailable": true, + "deviceTypeIdentifier": + "com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus", + "state": "Shutdown", + "name": "iPhone 8 Plus" + } + ] + } +}; + +void main() { + const String _kDestination = '--ios-destination'; + const String _kTarget = '--target'; + const String _kSkip = '--skip'; + + group('test xctest_command', () { + CommandRunner runner; + RecordingProcessRunner processRunner; + + setUp(() { + initializeFakePackages(); + processRunner = RecordingProcessRunner(); + final XCTestCommand command = XCTestCommand( + mockPackagesDir, mockFileSystem, + processRunner: processRunner); + + runner = CommandRunner('xctest_command', 'Test for xctest_command'); + runner.addCommand(command); + cleanupPackages(); + }); + + test('Not specifying --target throws', () async { + await expectLater( + () => runner.run(['xctest', _kDestination, 'a_destination']), + throwsA(const TypeMatcher())); + }); + + test('skip if ios is not supported', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isIosPlugin: false); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final MockProcess mockProcess = MockProcess(); + mockProcess.exitCodeCompleter.complete(0); + processRunner.processToReturn = mockProcess; + final List output = await runCapturingPrint(runner, [ + 'xctest', + _kTarget, + 'foo_scheme', + _kDestination, + 'foo_destination' + ]); + expect(output, contains('iOS is not supported by this plugin.')); + expect(processRunner.recordedCalls, orderedEquals([])); + + cleanupPackages(); + }); + + test('running with correct scheme and destination, did not find scheme', + () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isIosPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final MockProcess mockProcess = MockProcess(); + mockProcess.exitCodeCompleter.complete(0); + processRunner.processToReturn = mockProcess; + processRunner.resultStdout = '{"project":{"targets":["bar_scheme"]}}'; + + await expectLater(() async { + final List output = await runCapturingPrint(runner, [ + 'xctest', + _kTarget, + 'foo_scheme', + _kDestination, + 'foo_destination' + ]); + expect(output, + contains('foo_scheme not configured for plugin, test failed.')); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', ['simctl', 'list', '--json'], null), + ProcessCall( + 'xcodebuild', + [ + '-project', + 'ios/Runner.xcodeproj', + '-list', + '-json' + ], + pluginExampleDirectory.path), + ])); + }, throwsA(const TypeMatcher())); + cleanupPackages(); + }); + + test('running with correct scheme and destination, found scheme', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isIosPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final MockProcess mockProcess = MockProcess(); + mockProcess.exitCodeCompleter.complete(0); + processRunner.processToReturn = mockProcess; + processRunner.resultStdout = + '{"project":{"targets":["bar_scheme", "foo_scheme"]}}'; + List output = await runCapturingPrint(runner, [ + 'xctest', + _kTarget, + 'foo_scheme', + _kDestination, + 'foo_destination' + ]); + + expect(output, contains('Successfully ran xctest for plugin')); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + 'xcodebuild', + ['-project', 'ios/Runner.xcodeproj', '-list', '-json'], + pluginExampleDirectory.path), + ProcessCall( + 'xcodebuild', + [ + 'test', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'foo_scheme', + '-destination', + 'foo_destination', + 'CODE_SIGN_IDENTITY=""', + 'CODE_SIGNING_REQUIRED=NO' + ], + pluginExampleDirectory.path), + ])); + + cleanupPackages(); + }); + + test('running with correct scheme and destination, skip 1 plugin', + () async { + createFakePlugin('plugin1', + withExtraFiles: >[ + ['example', 'test'], + ], + isIosPlugin: true); + createFakePlugin('plugin2', + withExtraFiles: >[ + ['example', 'test'], + ], + isIosPlugin: true); + + final Directory pluginExampleDirectory1 = + mockPackagesDir.childDirectory('plugin1').childDirectory('example'); + createFakePubspec(pluginExampleDirectory1, isFlutter: true); + final Directory pluginExampleDirectory2 = + mockPackagesDir.childDirectory('plugin2').childDirectory('example'); + createFakePubspec(pluginExampleDirectory2, isFlutter: true); + + final MockProcess mockProcess = MockProcess(); + mockProcess.exitCodeCompleter.complete(0); + processRunner.processToReturn = mockProcess; + processRunner.resultStdout = + '{"project":{"targets":["bar_scheme", "foo_scheme"]}}'; + List output = await runCapturingPrint(runner, [ + 'xctest', + _kTarget, + 'foo_scheme', + _kDestination, + 'foo_destination', + _kSkip, + 'plugin1' + ]); + + expect(output, contains('plugin1 was skipped with the --skip flag.')); + expect(output, contains('Successfully ran xctest for plugin2')); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + 'xcodebuild', + ['-project', 'ios/Runner.xcodeproj', '-list', '-json'], + pluginExampleDirectory2.path), + ProcessCall( + 'xcodebuild', + [ + 'test', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'foo_scheme', + '-destination', + 'foo_destination', + 'CODE_SIGN_IDENTITY=""', + 'CODE_SIGNING_REQUIRED=NO' + ], + pluginExampleDirectory2.path), + ])); + + cleanupPackages(); + }); + + test('Not specifying --ios-destination assigns an available simulator', + () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ], + isIosPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final MockProcess mockProcess = MockProcess(); + mockProcess.exitCodeCompleter.complete(0); + processRunner.processToReturn = mockProcess; + final Map schemeCommandResult = { + "project": { + "targets": ["bar_scheme", "foo_scheme"] + } + }; + // For simplicity of the test, we combine all the mock results into a single mock result, each internal command + // will get this result and they should still be able to parse them correctly. + processRunner.resultStdout = + jsonEncode(schemeCommandResult..addAll(_kDeviceListMap)); + await runner.run([ + 'xctest', + _kTarget, + 'foo_scheme', + ]); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('xcrun', ['simctl', 'list', '--json'], null), + ProcessCall( + 'xcodebuild', + ['-project', 'ios/Runner.xcodeproj', '-list', '-json'], + pluginExampleDirectory.path), + ProcessCall( + 'xcodebuild', + [ + 'test', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'foo_scheme', + '-destination', + 'id=1E76A0FD-38AC-4537-A989-EA639D7D012A', + 'CODE_SIGN_IDENTITY=""', + 'CODE_SIGNING_REQUIRED=NO' + ], + pluginExampleDirectory.path), + ])); + + cleanupPackages(); + }); + }); +} From 976a7fbc3de77b8fd16e7bffbb3c6f2c13ba8b95 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 1 Mar 2021 19:24:10 -0800 Subject: [PATCH 294/924] [in_app_purchase] fix plugin version (#3654) --- packages/in_app_purchase/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 6175e8cbf1dc..3d121fd51e5e 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.4.1 +version: 0.5.0 dependencies: flutter: From a6cbf671e3463953b7ade113537cbe043dec4a0e Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 2 Mar 2021 15:11:31 +0100 Subject: [PATCH 295/924] [camera] Stable release for null safety. (#3641) Stable NNBD release for the camera package. With this PR I also migrated the example App to sound null safe. --- packages/camera/camera/CHANGELOG.md | 15 +- .../example/integration_test/camera_test.dart | 7 + packages/camera/camera/example/lib/main.dart | 282 +++++++++++------- packages/camera/camera/example/pubspec.yaml | 14 +- .../example/test_driver/integration_test.dart | 7 + packages/camera/camera/pubspec.yaml | 19 +- 6 files changed, 212 insertions(+), 132 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 079aa1685bd5..f1d771496dde 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,18 +1,9 @@ -## 0.8.0-nullsafety.3 - -* Updates the example code listed in the [README.md](README.md), so it runs without errors when you simply copy/ paste it into a Flutter App. - -## 0.8.0-nullsafety.2 +## 0.8.0 +* Stable null safety release. * Solved delay when using the zoom feature on iOS. - -## 0.8.0-nullsafety.1 - * Added a timeout to the pre-capture sequence on Android to prevent crashes when the camera cannot get a focus. - -## 0.8.0-nullsafety - -* Migrated to null safety. +* Updates the example code listed in the [README.md](README.md), so it runs without errors when you simply copy/ paste it into a Flutter App. ## 0.7.0+4 diff --git a/packages/camera/camera/example/integration_test/camera_test.dart b/packages/camera/camera/example/integration_test/camera_test.dart index c2e73e0f1563..4ff624c7d989 100644 --- a/packages/camera/camera/example/integration_test/camera_test.dart +++ b/packages/camera/camera/example/integration_test/camera_test.dart @@ -1,3 +1,10 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// TODO(mvanbeusekom): Remove this once flutter_driver supports null safety. +// https://github.com/flutter/flutter/issues/71379 +// @dart = 2.9 import 'dart:async'; import 'dart:io'; import 'dart:ui'; diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 6244aa5a8e37..5eebc9a379ca 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -27,32 +27,38 @@ IconData getCameraLensIcon(CameraLensDirection direction) { return Icons.camera_front; case CameraLensDirection.external: return Icons.camera; + default: + throw ArgumentError('Unknown lens direction'); } - throw ArgumentError('Unknown lens direction'); } -void logError(String code, String message) => +void logError(String code, String? message) { + if (message != null) { print('Error: $code\nError Message: $message'); + } else { + print('Error: $code'); + } +} class _CameraExampleHomeState extends State with WidgetsBindingObserver, TickerProviderStateMixin { - CameraController controller; - XFile imageFile; - XFile videoFile; - VideoPlayerController videoController; - VoidCallback videoPlayerListener; + CameraController? controller; + XFile? imageFile; + XFile? videoFile; + VideoPlayerController? videoController; + VoidCallback? videoPlayerListener; bool enableAudio = true; double _minAvailableExposureOffset = 0.0; double _maxAvailableExposureOffset = 0.0; double _currentExposureOffset = 0.0; - AnimationController _flashModeControlRowAnimationController; - Animation _flashModeControlRowAnimation; - AnimationController _exposureModeControlRowAnimationController; - Animation _exposureModeControlRowAnimation; - AnimationController _focusModeControlRowAnimationController; - Animation _focusModeControlRowAnimation; - double _minAvailableZoom; - double _maxAvailableZoom; + late AnimationController _flashModeControlRowAnimationController; + late Animation _flashModeControlRowAnimation; + late AnimationController _exposureModeControlRowAnimationController; + late Animation _exposureModeControlRowAnimation; + late AnimationController _focusModeControlRowAnimationController; + late Animation _focusModeControlRowAnimation; + double _minAvailableZoom = 1.0; + double _maxAvailableZoom = 1.0; double _currentScale = 1.0; double _baseScale = 1.0; @@ -62,7 +68,8 @@ class _CameraExampleHomeState extends State @override void initState() { super.initState(); - WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance?.addObserver(this); + _flashModeControlRowAnimationController = AnimationController( duration: const Duration(milliseconds: 300), vsync: this, @@ -91,7 +98,7 @@ class _CameraExampleHomeState extends State @override void dispose() { - WidgetsBinding.instance.removeObserver(this); + WidgetsBinding.instance?.removeObserver(this); _flashModeControlRowAnimationController.dispose(); _exposureModeControlRowAnimationController.dispose(); super.dispose(); @@ -99,16 +106,17 @@ class _CameraExampleHomeState extends State @override void didChangeAppLifecycleState(AppLifecycleState state) { + final CameraController? cameraController = controller; + // App state changed before we got the chance to initialize. - if (controller == null || !controller.value.isInitialized) { + if (cameraController == null || !cameraController.value.isInitialized) { return; } + if (state == AppLifecycleState.inactive) { - controller?.dispose(); + cameraController.dispose(); } else if (state == AppLifecycleState.resumed) { - if (controller != null) { - onNewCameraSelected(controller.description); - } + onNewCameraSelected(cameraController.description); } } @@ -134,9 +142,10 @@ class _CameraExampleHomeState extends State decoration: BoxDecoration( color: Colors.black, border: Border.all( - color: controller != null && controller.value.isRecordingVideo - ? Colors.redAccent - : Colors.grey, + color: + controller != null && controller!.value.isRecordingVideo + ? Colors.redAccent + : Colors.grey, width: 3.0, ), ), @@ -161,7 +170,9 @@ class _CameraExampleHomeState extends State /// Display the preview from the camera (or a message if the preview is not available). Widget _cameraPreviewWidget() { - if (controller == null || !controller.value.isInitialized) { + final CameraController? cameraController = controller; + + if (cameraController == null || !cameraController.value.isInitialized) { return const Text( 'Tap a camera', style: TextStyle( @@ -175,7 +186,7 @@ class _CameraExampleHomeState extends State onPointerDown: (_) => _pointers++, onPointerUp: (_) => _pointers--, child: CameraPreview( - controller, + controller!, child: LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { return GestureDetector( @@ -196,37 +207,40 @@ class _CameraExampleHomeState extends State Future _handleScaleUpdate(ScaleUpdateDetails details) async { // When there are not exactly two fingers on screen don't scale - if (_pointers != 2) { + if (controller == null || _pointers != 2) { return; } _currentScale = (_baseScale * details.scale) .clamp(_minAvailableZoom, _maxAvailableZoom); - await controller.setZoomLevel(_currentScale); + await controller!.setZoomLevel(_currentScale); } /// Display the thumbnail of the captured image or video. Widget _thumbnailWidget() { + final VideoPlayerController? localVideoController = videoController; + return Expanded( child: Align( alignment: Alignment.centerRight, child: Row( mainAxisSize: MainAxisSize.min, children: [ - videoController == null && imageFile == null + localVideoController == null && imageFile == null ? Container() : SizedBox( - child: (videoController == null) - ? Image.file(File(imageFile.path)) + child: (localVideoController == null) + ? Image.file(File(imageFile!.path)) : Container( child: Center( child: AspectRatio( aspectRatio: - videoController.value.size != null - ? videoController.value.aspectRatio + localVideoController.value.size != null + ? localVideoController + .value.aspectRatio : 1.0, - child: VideoPlayer(videoController)), + child: VideoPlayer(localVideoController)), ), decoration: BoxDecoration( border: Border.all(color: Colors.pink)), @@ -270,7 +284,7 @@ class _CameraExampleHomeState extends State onPressed: controller != null ? onAudioModeButtonPressed : null, ), IconButton( - icon: Icon(controller?.value?.isCaptureOrientationLocked ?? false + icon: Icon(controller?.value.isCaptureOrientationLocked ?? false ? Icons.screen_lock_rotation : Icons.screen_rotation), color: Colors.blue, @@ -297,7 +311,7 @@ class _CameraExampleHomeState extends State children: [ IconButton( icon: Icon(Icons.flash_off), - color: controller?.value?.flashMode == FlashMode.off + color: controller?.value.flashMode == FlashMode.off ? Colors.orange : Colors.blue, onPressed: controller != null @@ -306,7 +320,7 @@ class _CameraExampleHomeState extends State ), IconButton( icon: Icon(Icons.flash_auto), - color: controller?.value?.flashMode == FlashMode.auto + color: controller?.value.flashMode == FlashMode.auto ? Colors.orange : Colors.blue, onPressed: controller != null @@ -315,7 +329,7 @@ class _CameraExampleHomeState extends State ), IconButton( icon: Icon(Icons.flash_on), - color: controller?.value?.flashMode == FlashMode.always + color: controller?.value.flashMode == FlashMode.always ? Colors.orange : Colors.blue, onPressed: controller != null @@ -324,7 +338,7 @@ class _CameraExampleHomeState extends State ), IconButton( icon: Icon(Icons.highlight), - color: controller?.value?.flashMode == FlashMode.torch + color: controller?.value.flashMode == FlashMode.torch ? Colors.orange : Colors.blue, onPressed: controller != null @@ -339,12 +353,12 @@ class _CameraExampleHomeState extends State Widget _exposureModeControlRowWidget() { final ButtonStyle styleAuto = TextButton.styleFrom( - primary: controller?.value?.exposureMode == ExposureMode.auto + primary: controller?.value.exposureMode == ExposureMode.auto ? Colors.orange : Colors.blue, ); final ButtonStyle styleLocked = TextButton.styleFrom( - primary: controller?.value?.exposureMode == ExposureMode.locked + primary: controller?.value.exposureMode == ExposureMode.locked ? Colors.orange : Colors.blue, ); @@ -371,8 +385,10 @@ class _CameraExampleHomeState extends State onSetExposureModeButtonPressed(ExposureMode.auto) : null, onLongPress: () { - if (controller != null) controller.setExposurePoint(null); - showInSnackBar('Resetting exposure point'); + if (controller != null) { + controller!.setExposurePoint(null); + showInSnackBar('Resetting exposure point'); + } }, ), TextButton( @@ -415,12 +431,12 @@ class _CameraExampleHomeState extends State Widget _focusModeControlRowWidget() { final ButtonStyle styleAuto = TextButton.styleFrom( - primary: controller?.value?.focusMode == FocusMode.auto + primary: controller?.value.focusMode == FocusMode.auto ? Colors.orange : Colors.blue, ); final ButtonStyle styleLocked = TextButton.styleFrom( - primary: controller?.value?.focusMode == FocusMode.locked + primary: controller?.value.focusMode == FocusMode.locked ? Colors.orange : Colors.blue, ); @@ -446,7 +462,7 @@ class _CameraExampleHomeState extends State ? () => onSetFocusModeButtonPressed(FocusMode.auto) : null, onLongPress: () { - if (controller != null) controller.setFocusPoint(null); + if (controller != null) controller!.setFocusPoint(null); showInSnackBar('Resetting focus point'); }, ), @@ -468,6 +484,8 @@ class _CameraExampleHomeState extends State /// Display the control bar with buttons to take pictures and record videos. Widget _captureControlRowWidget() { + final CameraController? cameraController = controller; + return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisSize: MainAxisSize.max, @@ -475,40 +493,41 @@ class _CameraExampleHomeState extends State IconButton( icon: const Icon(Icons.camera_alt), color: Colors.blue, - onPressed: controller != null && - controller.value.isInitialized && - !controller.value.isRecordingVideo + onPressed: cameraController != null && + cameraController.value.isInitialized && + !cameraController.value.isRecordingVideo ? onTakePictureButtonPressed : null, ), IconButton( icon: const Icon(Icons.videocam), color: Colors.blue, - onPressed: controller != null && - controller.value.isInitialized && - !controller.value.isRecordingVideo + onPressed: cameraController != null && + cameraController.value.isInitialized && + !cameraController.value.isRecordingVideo ? onVideoRecordButtonPressed : null, ), IconButton( - icon: controller != null && controller.value.isRecordingPaused + icon: cameraController != null && + cameraController.value.isRecordingPaused ? Icon(Icons.play_arrow) : Icon(Icons.pause), color: Colors.blue, - onPressed: controller != null && - controller.value.isInitialized && - controller.value.isRecordingVideo - ? (controller != null && controller.value.isRecordingPaused + onPressed: cameraController != null && + cameraController.value.isInitialized && + cameraController.value.isRecordingVideo + ? (cameraController.value.isRecordingPaused) ? onResumeButtonPressed - : onPauseButtonPressed) + : onPauseButtonPressed : null, ), IconButton( icon: const Icon(Icons.stop), color: Colors.red, - onPressed: controller != null && - controller.value.isInitialized && - controller.value.isRecordingVideo + onPressed: cameraController != null && + cameraController.value.isInitialized && + cameraController.value.isRecordingVideo ? onStopButtonPressed : null, ) @@ -520,6 +539,14 @@ class _CameraExampleHomeState extends State Widget _cameraTogglesRowWidget() { final List toggles = []; + final onChanged = (CameraDescription? description) { + if (description == null) { + return; + } + + onNewCameraSelected(description); + }; + if (cameras.isEmpty) { return const Text('No camera found'); } else { @@ -531,9 +558,10 @@ class _CameraExampleHomeState extends State title: Icon(getCameraLensIcon(cameraDescription.lensDirection)), groupValue: controller?.description, value: cameraDescription, - onChanged: controller != null && controller.value.isRecordingVideo - ? null - : onNewCameraSelected, + onChanged: + controller != null && controller!.value.isRecordingVideo + ? null + : onChanged, ), ), ); @@ -547,48 +575,60 @@ class _CameraExampleHomeState extends State void showInSnackBar(String message) { // ignore: deprecated_member_use - _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message))); + _scaffoldKey.currentState?.showSnackBar(SnackBar(content: Text(message))); } void onViewFinderTap(TapDownDetails details, BoxConstraints constraints) { + if (controller == null) { + return; + } + + final CameraController cameraController = controller!; + final offset = Offset( details.localPosition.dx / constraints.maxWidth, details.localPosition.dy / constraints.maxHeight, ); - controller.setExposurePoint(offset); - controller.setFocusPoint(offset); + cameraController.setExposurePoint(offset); + cameraController.setFocusPoint(offset); } void onNewCameraSelected(CameraDescription cameraDescription) async { if (controller != null) { - await controller.dispose(); + await controller!.dispose(); } - controller = CameraController( + final CameraController cameraController = CameraController( cameraDescription, ResolutionPreset.medium, enableAudio: enableAudio, imageFormatGroup: ImageFormatGroup.jpeg, ); + controller = cameraController; // If the controller is updated then update the UI. - controller.addListener(() { + cameraController.addListener(() { if (mounted) setState(() {}); - if (controller.value.hasError) { - showInSnackBar('Camera error ${controller.value.errorDescription}'); + if (cameraController.value.hasError) { + showInSnackBar( + 'Camera error ${cameraController.value.errorDescription}'); } }); try { - await controller.initialize(); + await cameraController.initialize(); await Future.wait([ - controller + cameraController .getMinExposureOffset() .then((value) => _minAvailableExposureOffset = value), - controller + cameraController .getMaxExposureOffset() .then((value) => _maxAvailableExposureOffset = value), - controller.getMaxZoomLevel().then((value) => _maxAvailableZoom = value), - controller.getMinZoomLevel().then((value) => _minAvailableZoom = value), + cameraController + .getMaxZoomLevel() + .then((value) => _maxAvailableZoom = value), + cameraController + .getMinZoomLevel() + .then((value) => _minAvailableZoom = value), ]); } on CameraException catch (e) { _showCameraException(e); @@ -600,7 +640,7 @@ class _CameraExampleHomeState extends State } void onTakePictureButtonPressed() { - takePicture().then((XFile file) { + takePicture().then((XFile? file) { if (mounted) { setState(() { imageFile = file; @@ -645,19 +685,20 @@ class _CameraExampleHomeState extends State void onAudioModeButtonPressed() { enableAudio = !enableAudio; if (controller != null) { - onNewCameraSelected(controller.description); + onNewCameraSelected(controller!.description); } } void onCaptureOrientationLockButtonPressed() async { if (controller != null) { - if (controller.value.isCaptureOrientationLocked) { - await controller.unlockCaptureOrientation(); + final CameraController cameraController = controller!; + if (cameraController.value.isCaptureOrientationLocked) { + await cameraController.unlockCaptureOrientation(); showInSnackBar('Capture orientation unlocked'); } else { - await controller.lockCaptureOrientation(); + await cameraController.lockCaptureOrientation(); showInSnackBar( - 'Capture orientation locked to ${controller.value.lockedCaptureOrientation.toString().split('.').last}'); + 'Capture orientation locked to ${cameraController.value.lockedCaptureOrientation.toString().split('.').last}'); } } } @@ -715,31 +756,35 @@ class _CameraExampleHomeState extends State } Future startVideoRecording() async { - if (!controller.value.isInitialized) { + final CameraController? cameraController = controller; + + if (cameraController == null || !cameraController.value.isInitialized) { showInSnackBar('Error: select a camera first.'); return; } - if (controller.value.isRecordingVideo) { + if (cameraController.value.isRecordingVideo) { // A recording is already started, do nothing. return; } try { - await controller.startVideoRecording(); + await cameraController.startVideoRecording(); } on CameraException catch (e) { _showCameraException(e); return; } } - Future stopVideoRecording() async { - if (!controller.value.isRecordingVideo) { + Future stopVideoRecording() async { + final CameraController? cameraController = controller; + + if (cameraController == null || !cameraController.value.isRecordingVideo) { return null; } try { - return controller.stopVideoRecording(); + return cameraController.stopVideoRecording(); } on CameraException catch (e) { _showCameraException(e); return null; @@ -747,12 +792,14 @@ class _CameraExampleHomeState extends State } Future pauseVideoRecording() async { - if (!controller.value.isRecordingVideo) { + final CameraController? cameraController = controller; + + if (cameraController == null || !cameraController.value.isRecordingVideo) { return null; } try { - await controller.pauseVideoRecording(); + await cameraController.pauseVideoRecording(); } on CameraException catch (e) { _showCameraException(e); rethrow; @@ -760,12 +807,14 @@ class _CameraExampleHomeState extends State } Future resumeVideoRecording() async { - if (!controller.value.isRecordingVideo) { + final CameraController? cameraController = controller; + + if (cameraController == null || !cameraController.value.isRecordingVideo) { return null; } try { - await controller.resumeVideoRecording(); + await cameraController.resumeVideoRecording(); } on CameraException catch (e) { _showCameraException(e); rethrow; @@ -773,8 +822,12 @@ class _CameraExampleHomeState extends State } Future setFlashMode(FlashMode mode) async { + if (controller == null) { + return; + } + try { - await controller.setFlashMode(mode); + await controller!.setFlashMode(mode); } on CameraException catch (e) { _showCameraException(e); rethrow; @@ -782,8 +835,12 @@ class _CameraExampleHomeState extends State } Future setExposureMode(ExposureMode mode) async { + if (controller == null) { + return; + } + try { - await controller.setExposureMode(mode); + await controller!.setExposureMode(mode); } on CameraException catch (e) { _showCameraException(e); rethrow; @@ -791,11 +848,15 @@ class _CameraExampleHomeState extends State } Future setExposureOffset(double offset) async { + if (controller == null) { + return; + } + setState(() { _currentExposureOffset = offset; }); try { - offset = await controller.setExposureOffset(offset); + offset = await controller!.setExposureOffset(offset); } on CameraException catch (e) { _showCameraException(e); rethrow; @@ -803,8 +864,12 @@ class _CameraExampleHomeState extends State } Future setFocusMode(FocusMode mode) async { + if (controller == null) { + return; + } + try { - await controller.setFocusMode(mode); + await controller!.setFocusMode(mode); } on CameraException catch (e) { _showCameraException(e); rethrow; @@ -812,16 +877,20 @@ class _CameraExampleHomeState extends State } Future _startVideoPlayer() async { + if (videoFile == null) { + return; + } + final VideoPlayerController vController = - VideoPlayerController.file(File(videoFile.path)); + VideoPlayerController.file(File(videoFile!.path)); videoPlayerListener = () { - if (videoController != null && videoController.value.size != null) { + if (videoController != null && videoController!.value.size != null) { // Refreshing the state to update video player with the correct ratio. if (mounted) setState(() {}); - videoController.removeListener(videoPlayerListener); + videoController!.removeListener(videoPlayerListener!); } }; - vController.addListener(videoPlayerListener); + vController.addListener(videoPlayerListener!); await vController.setLooping(true); await vController.initialize(); await videoController?.dispose(); @@ -834,19 +903,20 @@ class _CameraExampleHomeState extends State await vController.play(); } - Future takePicture() async { - if (!controller.value.isInitialized) { + Future takePicture() async { + final CameraController? cameraController = controller; + if (cameraController == null || !cameraController.value.isInitialized) { showInSnackBar('Error: select a camera first.'); return null; } - if (controller.value.isTakingPicture) { + if (cameraController.value.isTakingPicture) { // A capture is already pending, do nothing. return null; } try { - XFile file = await controller.takePicture(); + XFile file = await cameraController.takePicture(); return file; } on CameraException catch (e) { _showCameraException(e); diff --git a/packages/camera/camera/example/pubspec.yaml b/packages/camera/camera/example/pubspec.yaml index 2a45fd69194c..b3ef8e497dc1 100644 --- a/packages/camera/camera/example/pubspec.yaml +++ b/packages/camera/camera/example/pubspec.yaml @@ -9,23 +9,23 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - path_provider: ^0.5.0 + path_provider: ^2.0.0 flutter: sdk: flutter - video_player: ^0.10.0 - integration_test: - path: ../../../integration_test + video_player: ^2.0.0 dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter - pedantic: ^1.8.0 + integration_test: + path: ../../../integration_test + pedantic: ^1.10.0 flutter: uses-material-design: true environment: - sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.9.1+hotfix.4" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.22.0" diff --git a/packages/camera/camera/example/test_driver/integration_test.dart b/packages/camera/camera/example/test_driver/integration_test.dart index 1e6e3ba7941f..160b48f8f72f 100644 --- a/packages/camera/camera/example/test_driver/integration_test.dart +++ b/packages/camera/camera/example/test_driver/integration_test.dart @@ -1,3 +1,10 @@ +// Copyright 2019, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// TODO(mvanbeusekom): Remove this once flutter_driver supports null safety. +// https://github.com/flutter/flutter/issues/71379 +// @dart = 2.9 import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 2d620505def2..53f9b3b40ad1 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,26 +2,31 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.8.0-nullsafety.3 +version: 0.8.0 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: flutter: sdk: flutter - camera_platform_interface: ^2.0.0-nullsafety + camera_platform_interface: ^2.0.0 pedantic: ^1.10.0 - quiver: ^3.0.0-nullsafety.3 + quiver: ^3.0.0 dev_dependencies: - video_player: ^2.0.0-nullsafety.7 + video_player: ^2.0.0 flutter_test: sdk: flutter flutter_driver: sdk: flutter - mockito: ^5.0.0-nullsafety.5 - plugin_platform_interface: ^1.1.0-nullsafety.2 + + # TODO(mvanbeusekom): Update to stable 5.0.0 release when dependency conflict + # with flutter_driver has been resolved: + # Because mockito >=5.0.0 depends on analyzer ^1.0.0 which depends on crypto ^3.0.0 + # every version of flutter_driver from sdk depends on crypto 2.1.5. + mockito: ^5.0.0-nullsafety.7 + plugin_platform_interface: ^2.0.0 flutter: plugin: @@ -33,5 +38,5 @@ flutter: pluginClass: CameraPlugin environment: - sdk: '>=2.12.0-0 <3.0.0' + sdk: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.22.0" From 72feefd6df283ac4ff97421218ccc1e694f9fbb8 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 2 Mar 2021 11:14:04 -0800 Subject: [PATCH 296/924] [connectivity_for_web] Migration to null-safety. (#3652) --- .../connectivity_for_web/CHANGELOG.md | 5 ++ .../connectivity_for_web/example/README.md | 21 +++++++ .../network_information_test.dart} | 56 ++++++++++--------- .../src/connectivity_mocks.dart | 56 +++++++++++++++++++ .../example/lib/main.dart | 25 +++++++++ .../connectivity_for_web/example/pubspec.yaml | 21 +++++++ .../connectivity_for_web/example/run_test.sh | 18 ++++++ .../test_driver/integration_driver.dart | 7 +++ .../{test => example}/web/index.html | 0 .../src/dart_html_connectivity_plugin.dart | 12 ++-- ...k_information_api_connectivity_plugin.dart | 16 +++--- .../lib/src/utils/connectivity_result.dart | 6 +- .../connectivity_for_web/pubspec.yaml | 13 ++--- .../connectivity_for_web/test/.gitignore | 8 --- .../connectivity_for_web/test/README.md | 5 ++ .../test/lib/src/connectivity_mocks.dart | 25 --------- .../connectivity_for_web/test/pubspec.yaml | 25 --------- .../test/tests_exist_elsewhere_test.dart | 10 ++++ 18 files changed, 219 insertions(+), 110 deletions(-) create mode 100644 packages/connectivity/connectivity_for_web/example/README.md rename packages/connectivity/connectivity_for_web/{test/lib/main.dart => example/integration_test/network_information_test.dart} (57%) create mode 100644 packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart create mode 100644 packages/connectivity/connectivity_for_web/example/lib/main.dart create mode 100644 packages/connectivity/connectivity_for_web/example/pubspec.yaml create mode 100755 packages/connectivity/connectivity_for_web/example/run_test.sh create mode 100644 packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart rename packages/connectivity/connectivity_for_web/{test => example}/web/index.html (100%) delete mode 100644 packages/connectivity/connectivity_for_web/test/.gitignore create mode 100644 packages/connectivity/connectivity_for_web/test/README.md delete mode 100644 packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart delete mode 100644 packages/connectivity/connectivity_for_web/test/pubspec.yaml create mode 100644 packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart diff --git a/packages/connectivity/connectivity_for_web/CHANGELOG.md b/packages/connectivity/connectivity_for_web/CHANGELOG.md index f6d83dd3e0cc..ccd689760b84 100644 --- a/packages/connectivity/connectivity_for_web/CHANGELOG.md +++ b/packages/connectivity/connectivity_for_web/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.4.0 + +* Migrate to null-safety +* Run tests using flutter driver + ## 0.3.1+4 * Remove unused `test` dependency. diff --git a/packages/connectivity/connectivity_for_web/example/README.md b/packages/connectivity/connectivity_for_web/example/README.md new file mode 100644 index 000000000000..0ec01e025570 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/README.md @@ -0,0 +1,21 @@ +# Testing + +This package utilizes the `integration_test` package to run its tests in a web browser. + +See [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests) for more info. + +## Running the tests + +Make sure you have updated to the latest Flutter master. + +1. Check what version of Chrome is running on the machine you're running tests on. + +2. Download and install driver for that version from here: + * + +3. Start the driver using `chromedriver --port=4444` + +4. Run tests: `flutter drive -d web-server --browser-name=chrome --driver=test_driver/integration_driver.dart --target=integration_test/TEST_NAME.dart`, or (in Linux): + + * Single: `./run_test.sh integration_test/TEST_NAME.dart` + * All: `./run_test.sh` diff --git a/packages/connectivity/connectivity_for_web/test/lib/main.dart b/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart similarity index 57% rename from packages/connectivity/connectivity_for_web/test/lib/main.dart rename to packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart index e3473532553e..f8e8059e7dba 100644 --- a/packages/connectivity/connectivity_for_web/test/lib/main.dart +++ b/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart @@ -1,9 +1,7 @@ -import 'package:integration_test/integration_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:connectivity_for_web/src/network_information_api_connectivity_plugin.dart'; - -import 'package:mockito/mockito.dart'; +import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; import 'src/connectivity_mocks.dart'; @@ -12,66 +10,70 @@ void main() { group('checkConnectivity', () { void testCheckConnectivity({ - String type, - String effectiveType, - num downlink = 10, - num rtt = 50, - ConnectivityResult expected, + String? type, + String? effectiveType, + num? downlink = 10, + int? rtt = 50, + required ConnectivityResult expected, }) { - final connection = MockNetworkInformation(); - when(connection.type).thenReturn(type); - when(connection.effectiveType).thenReturn(effectiveType); - when(connection.downlink).thenReturn(downlink); - when(connection.rtt).thenReturn(downlink); + final connection = FakeNetworkInformation( + type: type, + effectiveType: effectiveType, + downlink: downlink, + rtt: rtt, + ); NetworkInformationApiConnectivityPlugin plugin = NetworkInformationApiConnectivityPlugin.withConnection(connection); expect(plugin.checkConnectivity(), completion(equals(expected))); } - test('0 downlink and rtt -> none', () { + testWidgets('0 downlink and rtt -> none', (WidgetTester tester) async { testCheckConnectivity( effectiveType: '4g', downlink: 0, rtt: 0, expected: ConnectivityResult.none); }); - test('slow-2g -> mobile', () { + testWidgets('slow-2g -> mobile', (WidgetTester tester) async { testCheckConnectivity( effectiveType: 'slow-2g', expected: ConnectivityResult.mobile); }); - test('2g -> mobile', () { + testWidgets('2g -> mobile', (WidgetTester tester) async { testCheckConnectivity( effectiveType: '2g', expected: ConnectivityResult.mobile); }); - test('3g -> mobile', () { + testWidgets('3g -> mobile', (WidgetTester tester) async { testCheckConnectivity( effectiveType: '3g', expected: ConnectivityResult.mobile); }); - test('4g -> wifi', () { + testWidgets('4g -> wifi', (WidgetTester tester) async { testCheckConnectivity( effectiveType: '4g', expected: ConnectivityResult.wifi); }); }); group('get onConnectivityChanged', () { - test('puts change events in a Stream', () async { - final connection = MockNetworkInformation(); + testWidgets('puts change events in a Stream', (WidgetTester tester) async { + final connection = FakeNetworkInformation(); NetworkInformationApiConnectivityPlugin plugin = NetworkInformationApiConnectivityPlugin.withConnection(connection); - Stream results = plugin.onConnectivityChanged; + // The onConnectivityChanged stream is infinite, so we only .take(2) so the test completes. + // We need to do .toList() now, because otherwise the Stream won't be actually listened to, + // and we'll miss the calls to mockChangeValue below. + final results = plugin.onConnectivityChanged.take(2).toList(); // Fake a disconnect-reconnect await connection.mockChangeValue(downlink: 0, rtt: 0); await connection.mockChangeValue( downlink: 10, rtt: 50, effectiveType: '4g'); - // The stream of results is infinite, so we need to .take(2) for this test to complete. + // Expect to see the disconnect-reconnect in the resulting stream. expect( - results.take(2).toList(), - completion( - equals([ConnectivityResult.none, ConnectivityResult.wifi]))); + results, + completion([ConnectivityResult.none, ConnectivityResult.wifi]), + ); }); }); } diff --git a/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart b/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart new file mode 100644 index 000000000000..fc795595e3f3 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart @@ -0,0 +1,56 @@ +import 'dart:async'; +import 'dart:html'; +import 'dart:js_util' show getProperty; + +import 'package:flutter_test/flutter_test.dart'; + +/// A Fake implementation of the NetworkInformation API that allows +/// for external modification of its values. +/// +/// Note that the DOM API works by internally mutating and broadcasting +/// 'change' events. +class FakeNetworkInformation extends Fake implements NetworkInformation { + String? _type; + String? _effectiveType; + num? _downlink; + int? _rtt; + + @override + String? get type => _type; + + @override + String? get effectiveType => _effectiveType; + + @override + num? get downlink => _downlink; + + @override + int? get rtt => _rtt; + + FakeNetworkInformation({ + String? type, + String? effectiveType, + num? downlink, + int? rtt, + }) : this._type = type, + this._effectiveType = effectiveType, + this._downlink = downlink, + this._rtt = rtt; + + /// Changes the desired values, and triggers the change event listener. + Future mockChangeValue({ + String? type, + String? effectiveType, + num? downlink, + int? rtt, + }) async { + this._type = type; + this._effectiveType = effectiveType; + this._downlink = downlink; + this._rtt = rtt; + + // This is set by the onConnectivityChanged getter... + final Function onchange = getProperty(this, 'onchange') as Function; + onchange(Event('change')); + } +} diff --git a/packages/connectivity/connectivity_for_web/example/lib/main.dart b/packages/connectivity/connectivity_for_web/example/lib/main.dart new file mode 100644 index 000000000000..e1a38dcdcd46 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/lib/main.dart @@ -0,0 +1,25 @@ +// Copyright 2013 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/material.dart'; + +void main() { + runApp(MyApp()); +} + +/// App for testing +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + Widget build(BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: Text('Testing... Look at the console output for results!'), + ); + } +} diff --git a/packages/connectivity/connectivity_for_web/example/pubspec.yaml b/packages/connectivity/connectivity_for_web/example/pubspec.yaml new file mode 100644 index 000000000000..54289bc648ec --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/pubspec.yaml @@ -0,0 +1,21 @@ +name: connectivity_for_web_integration_tests +publish_to: none + +dependencies: + connectivity_for_web: + path: ../ + flutter: + sdk: flutter + +dev_dependencies: + js: ^0.6.3 + flutter_test: + sdk: flutter + flutter_driver: + sdk: flutter + integration_test: + sdk: flutter + +environment: + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.27.0-0" # For integration_test from sdk diff --git a/packages/connectivity/connectivity_for_web/example/run_test.sh b/packages/connectivity/connectivity_for_web/example/run_test.sh new file mode 100755 index 000000000000..8e6f149358c9 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/run_test.sh @@ -0,0 +1,18 @@ +#!/usr/bin/bash +if pgrep -lf chromedriver > /dev/null; then + echo "chromedriver is running." + + if [ $# -eq 0 ]; then + echo "No target specified, running all tests..." + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target='{}' + else + echo "Running test target: $1..." + set -x + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target=$1 + fi + + else + echo "chromedriver is not running." + echo "Please, check the README.md for instructions on how to use run_test.sh" +fi + diff --git a/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart b/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart new file mode 100644 index 000000000000..64e2248a4f9b --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart @@ -0,0 +1,7 @@ +// Copyright 2019 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 'package:integration_test/integration_test_driver.dart'; + +Future main() async => integrationDriver(); diff --git a/packages/connectivity/connectivity_for_web/test/web/index.html b/packages/connectivity/connectivity_for_web/example/web/index.html similarity index 100% rename from packages/connectivity/connectivity_for_web/test/web/index.html rename to packages/connectivity/connectivity_for_web/example/web/index.html diff --git a/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart index 5caa5679d6ad..950d26804371 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart @@ -9,26 +9,26 @@ class DartHtmlConnectivityPlugin extends ConnectivityPlugin { /// Checks the connection status of the device. @override Future checkConnectivity() async { - return html.window.navigator.onLine + return html.window.navigator.onLine ?? false ? ConnectivityResult.wifi : ConnectivityResult.none; } - StreamController _connectivityResult; + StreamController? _connectivityResult; /// Returns a Stream of ConnectivityResults changes. @override Stream get onConnectivityChanged { if (_connectivityResult == null) { - _connectivityResult = StreamController(); + _connectivityResult = StreamController.broadcast(); // Fallback to dart:html window.onOnline / window.onOffline html.window.onOnline.listen((event) { - _connectivityResult.add(ConnectivityResult.wifi); + _connectivityResult!.add(ConnectivityResult.wifi); }); html.window.onOffline.listen((event) { - _connectivityResult.add(ConnectivityResult.none); + _connectivityResult!.add(ConnectivityResult.none); }); } - return _connectivityResult.stream; + return _connectivityResult!.stream; } } diff --git a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart index 99bac2ab8d30..800be2ef238f 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:html' as html show window, NetworkInformation; -import 'dart:js'; -import 'dart:js_util'; +import 'dart:js' show allowInterop; +import 'dart:js_util' show setProperty; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:connectivity_for_web/connectivity_for_web.dart'; @@ -18,7 +18,7 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { /// The constructor of the plugin. NetworkInformationApiConnectivityPlugin() - : this.withConnection(html.window.navigator.connection); + : this.withConnection(html.window.navigator.connection!); /// Creates the plugin, with an override of the NetworkInformation object. @visibleForTesting @@ -32,8 +32,8 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { return networkInformationToConnectivityResult(_networkInformation); } - StreamController _connectivityResultStreamController; - Stream _connectivityResultStream; + StreamController? _connectivityResultStreamController; + late Stream _connectivityResultStream; /// Returns a Stream of ConnectivityResults changes. @override @@ -41,8 +41,10 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { if (_connectivityResultStreamController == null) { _connectivityResultStreamController = StreamController(); + + // Directly write the 'onchange' function on the networkInformation object. setProperty(_networkInformation, 'onchange', allowInterop((_) { - _connectivityResultStreamController + _connectivityResultStreamController! .add(networkInformationToConnectivityResult(_networkInformation)); })); // TODO: Implement the above with _networkInformation.onChange: @@ -54,7 +56,7 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { // onChange Stream upon hot restart. // https://github.com/dart-lang/sdk/issues/42679 _connectivityResultStream = - _connectivityResultStreamController.stream.asBroadcastStream(); + _connectivityResultStreamController!.stream.asBroadcastStream(); } return _connectivityResultStream; } diff --git a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart index efefd8d52440..e7eb8969231a 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart @@ -3,7 +3,7 @@ import 'package:connectivity_platform_interface/connectivity_platform_interface. /// Converts an incoming NetworkInformation object into the correct ConnectivityResult. ConnectivityResult networkInformationToConnectivityResult( - html.NetworkInformation info, + html.NetworkInformation? info, ) { if (info == null) { return ConnectivityResult.none; @@ -12,10 +12,10 @@ ConnectivityResult networkInformationToConnectivityResult( return ConnectivityResult.none; } if (info.effectiveType != null) { - return _effectiveTypeToConnectivityResult(info.effectiveType); + return _effectiveTypeToConnectivityResult(info.effectiveType!); } if (info.type != null) { - return _typeToConnectivityResult(info.type); + return _typeToConnectivityResult(info.type!); } return ConnectivityResult.none; } diff --git a/packages/connectivity/connectivity_for_web/pubspec.yaml b/packages/connectivity/connectivity_for_web/pubspec.yaml index 3622b15709b6..5c673e83b44a 100644 --- a/packages/connectivity/connectivity_for_web/pubspec.yaml +++ b/packages/connectivity/connectivity_for_web/pubspec.yaml @@ -1,7 +1,7 @@ name: connectivity_for_web description: An implementation for the web platform of the Flutter `connectivity` plugin. This uses the NetworkInformation Web API, with a fallback to Navigator.onLine. -version: 0.3.1+4 repository: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_for_web +version: 0.4.0 flutter: plugin: @@ -11,21 +11,16 @@ flutter: fileName: connectivity_for_web.dart dependencies: - connectivity_platform_interface: ^1.0.3 + connectivity_platform_interface: ^2.0.0 flutter_web_plugins: sdk: flutter flutter: sdk: flutter dev_dependencies: - flutter_driver: - sdk: flutter flutter_test: sdk: flutter - integration_test: - path: ../../integration_test - mockito: ^4.1.1 environment: - sdk: ">=2.6.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/connectivity/connectivity_for_web/test/.gitignore b/packages/connectivity/connectivity_for_web/test/.gitignore deleted file mode 100644 index d7dee828a6b9..000000000000 --- a/packages/connectivity/connectivity_for_web/test/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.DS_Store -.dart_tool/ - -.packages -.pub/ - -build/ -lib/generated_plugin_registrant.dart diff --git a/packages/connectivity/connectivity_for_web/test/README.md b/packages/connectivity/connectivity_for_web/test/README.md new file mode 100644 index 000000000000..7c5b4ad682ba --- /dev/null +++ b/packages/connectivity/connectivity_for_web/test/README.md @@ -0,0 +1,5 @@ +## test + +This package uses integration tests for testing. + +See `example/README.md` for more info. diff --git a/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart b/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart deleted file mode 100644 index 7b82b512065b..000000000000 --- a/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:html'; - -import 'package:mockito/mockito.dart'; - -/// A Mock implementation of the NetworkInformation API that allows -/// for external modification of its values. -class MockNetworkInformation extends Mock implements NetworkInformation { - /// The callback that will fire after the network information values change. - Function onchange; - - /// Changes the desired values, and triggers the change event listener. - void mockChangeValue({ - String type, - String effectiveType, - num downlink, - num rtt, - }) async { - when(this.type).thenAnswer((_) => type); - when(this.effectiveType).thenAnswer((_) => effectiveType); - when(this.downlink).thenAnswer((_) => downlink); - when(this.rtt).thenAnswer((_) => rtt); - - onchange(Event('change')); - } -} diff --git a/packages/connectivity/connectivity_for_web/test/pubspec.yaml b/packages/connectivity/connectivity_for_web/test/pubspec.yaml deleted file mode 100644 index 512b7df8c26e..000000000000 --- a/packages/connectivity/connectivity_for_web/test/pubspec.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: connectivity_web_example -description: Example web app for the connectivity plugin -homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_web - -dependencies: - connectivity_for_web: - path: ../ - js: ^0.6.1+1 - flutter_web_plugins: - sdk: flutter - flutter: - sdk: flutter - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - integration_test: - path: ../../../integration_test - mockito: ^4.1.1 - -environment: - sdk: ">=2.6.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4" diff --git a/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart b/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart new file mode 100644 index 000000000000..334f52186d9d --- /dev/null +++ b/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart @@ -0,0 +1,10 @@ +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Tell the user where to find the real tests', () { + print('---'); + print('This package uses integration_test for its tests.'); + print('See `example/README.md` for more info.'); + print('---'); + }); +} From 84648904cb3a2e1040ede68ebbd71525574da626 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 2 Mar 2021 13:09:04 -0800 Subject: [PATCH 297/924] [share] Migrate unit tests to null-safety. (#3660) --- packages/share/CHANGELOG.md | 4 ++ packages/share/pubspec.yaml | 4 +- packages/share/test/share_test.dart | 89 ++++++++++++++++++----------- 3 files changed, 61 insertions(+), 36 deletions(-) diff --git a/packages/share/CHANGELOG.md b/packages/share/CHANGELOG.md index 20afdea9f054..87e941c7afd7 100644 --- a/packages/share/CHANGELOG.md +++ b/packages/share/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Migrate unit tests to sound null safety. + ## 2.0.0 * Migrate to null safety. diff --git a/packages/share/pubspec.yaml b/packages/share/pubspec.yaml index e8a116799433..dd82fb4926bf 100644 --- a/packages/share/pubspec.yaml +++ b/packages/share/pubspec.yaml @@ -2,7 +2,7 @@ name: share description: Flutter plugin for sharing content via the platform share UI, using the ACTION_SEND intent on Android and UIActivityViewController on iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/share -version: 2.0.0 +version: 2.0.1 flutter: plugin: @@ -20,8 +20,6 @@ dependencies: sdk: flutter dev_dependencies: - test: ^1.16.3 - mockito: ^5.0.0-nullsafety.7 flutter_test: sdk: flutter integration_test: diff --git a/packages/share/test/share_test.dart b/packages/share/test/share_test.dart index d00867b19452..7e72fc4dc012 100644 --- a/packages/share/test/share_test.dart +++ b/packages/share/test/share_test.dart @@ -2,38 +2,33 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:io'; import 'dart:ui'; -import 'package:flutter_test/flutter_test.dart' show TestWidgetsFlutterBinding; -import 'package:mockito/mockito.dart'; -import 'package:share/share.dart'; -import 'package:test/test.dart'; - import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:share/share.dart'; void main() { - TestWidgetsFlutterBinding.ensureInitialized(); + TestWidgetsFlutterBinding.ensureInitialized(); // Required for MethodChannels - MockMethodChannel mockChannel; + late FakeMethodChannel fakeChannel; setUp(() { - mockChannel = MockMethodChannel(); - // Re-pipe to mockito for easier verifies. + fakeChannel = FakeMethodChannel(); + // Re-pipe to our fake to verify invocations. Share.channel.setMockMethodCallHandler((MethodCall call) async { // The explicit type can be void as the only method call has a return type of void. - await mockChannel.invokeMethod(call.method, call.arguments); + await fakeChannel.invokeMethod(call.method, call.arguments); }); }); test('sharing empty fails', () { expect( () => Share.share(''), - throwsA(const TypeMatcher()), + throwsA(isA()), ); - verifyZeroInteractions(mockChannel); + expect(fakeChannel.invocation, isNull); }); test('sharing origin sets the right params', () async { @@ -42,22 +37,28 @@ void main() { subject: 'some subject to share', sharePositionOrigin: const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), ); - verify(mockChannel.invokeMethod('share', { - 'text': 'some text to share', - 'subject': 'some subject to share', - 'originX': 1.0, - 'originY': 2.0, - 'originWidth': 3.0, - 'originHeight': 4.0, - })); + + expect( + fakeChannel.invocation, + equals({ + 'share': { + 'text': 'some text to share', + 'subject': 'some subject to share', + 'originX': 1.0, + 'originY': 2.0, + 'originWidth': 3.0, + 'originHeight': 4.0, + } + }), + ); }); test('sharing empty file fails', () { expect( () => Share.shareFiles(['']), - throwsA(const TypeMatcher()), + throwsA(isA()), ); - verifyZeroInteractions(mockChannel); + expect(fakeChannel.invocation, isNull); }); test('sharing file sets correct mimeType', () async { @@ -65,11 +66,18 @@ void main() { final File file = File(path); try { file.createSync(); + await Share.shareFiles([path]); - verify(mockChannel.invokeMethod('shareFiles', { - 'paths': [path], - 'mimeTypes': ['image/png'], - })); + + expect( + fakeChannel.invocation, + equals({ + 'shareFiles': { + 'paths': [path], + 'mimeTypes': ['image/png'], + } + }), + ); } finally { file.deleteSync(); } @@ -80,15 +88,30 @@ void main() { final File file = File(path); try { file.createSync(); + await Share.shareFiles([path], mimeTypes: ['*/*']); - verify(mockChannel.invokeMethod('shareFiles', { - 'paths': [file.path], - 'mimeTypes': ['*/*'], - })); + + expect( + fakeChannel.invocation, + equals({ + 'shareFiles': { + 'paths': [file.path], + 'mimeTypes': ['*/*'], + } + }), + ); } finally { file.deleteSync(); } }); } -class MockMethodChannel extends Mock implements MethodChannel {} +class FakeMethodChannel extends Fake implements MethodChannel { + Map? invocation; + + @override + Future invokeMethod(String method, [dynamic arguments]) async { + this.invocation = {method: arguments}; + return null; + } +} From b90e42b9a4c373b7f86beec6606ded7fac9874cb Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 2 Mar 2021 14:00:43 -0800 Subject: [PATCH 298/924] [url_launcher] Migrate unit tests to NNBD (#3657) Replaces the problematic Mockito mock with a manual mock that handles null and non-null types correctly. Removes the unit test of the example app, since it's not adding any actual coverage. --- .../test/url_launcher_example_test.dart | 52 --- .../url_launcher/url_launcher/pubspec.yaml | 2 +- .../url_launcher/test/link_test.dart | 108 +++--- .../test/mock_url_launcher_platform.dart | 93 ++++++ .../url_launcher/test/url_launcher_test.dart | 309 ++++++++++-------- 5 files changed, 314 insertions(+), 250 deletions(-) delete mode 100644 packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart create mode 100644 packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart diff --git a/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart b/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.dart deleted file mode 100644 index a890be7f65f1..000000000000 --- a/packages/url_launcher/url_launcher/example/test/url_launcher_example_test.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. - -// TODO(egarciad): Remove once mockito is migrated to null safety. -// @dart = 2.9 - -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter/material.dart'; -import 'package:mockito/mockito.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; -import 'package:url_launcher_example/main.dart'; - -void main() { - final MockUrlLauncher mock = MockUrlLauncher(); - UrlLauncherPlatform.instance = mock; - - testWidgets('Can open URLs', (WidgetTester tester) async { - await tester.pumpWidget(MyApp()); - const String defaultUrl = 'https://www.cylog.org/headers/'; - when(mock.canLaunch(defaultUrl)).thenAnswer((_) => Future.value(true)); - const Map defaultHeaders = { - 'my_header_key': 'my_header_value' - }; - verifyNever(mock.launch(defaultUrl, - useSafariVC: false, - useWebView: false, - enableDomStorage: false, - enableJavaScript: false, - universalLinksOnly: false, - headers: defaultHeaders)); - - Finder browserlaunchBtn = - find.widgetWithText(ElevatedButton, 'Launch in browser'); - expect(browserlaunchBtn, findsOneWidget); - await tester.tap(browserlaunchBtn); - - verify(mock.launch(defaultUrl, - useSafariVC: false, - useWebView: false, - enableDomStorage: false, - enableJavaScript: false, - universalLinksOnly: false, - headers: defaultHeaders)) - .called(1); - }); -} - -class MockUrlLauncher extends Mock - with MockPlatformInterfaceMixin - implements UrlLauncherPlatform {} diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index f337c8bed525..7a4d1820fb1f 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -39,7 +39,7 @@ dev_dependencies: flutter_test: sdk: flutter test: ^1.16.3 - mockito: ^5.0.0-nullsafety.7 + mockito: ^5.0.0 plugin_platform_interface: ^2.0.0 pedantic: ^1.10.0 diff --git a/packages/url_launcher/url_launcher/test/link_test.dart b/packages/url_launcher/url_launcher/test/link_test.dart index 46903aadaede..8da5111f5733 100644 --- a/packages/url_launcher/url_launcher/test/link_test.dart +++ b/packages/url_launcher/url_launcher/test/link_test.dart @@ -2,26 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(egarciad): Remove once Mockito has been migrated to null safety. -// @dart = 2.9 - import 'dart:ui'; + import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:flutter/services.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:url_launcher/link.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; +import 'mock_url_launcher_platform.dart'; + final MethodCodec _codec = const JSONMethodCodec(); void main() { - final MockUrlLauncher mock = MockUrlLauncher(); - UrlLauncherPlatform.instance = mock; + late MockUrlLauncher mock; - PlatformMessageCallback realOnPlatformMessage; + PlatformMessageCallback? realOnPlatformMessage; setUp(() { + mock = MockUrlLauncher(); + UrlLauncherPlatform.instance = mock; realOnPlatformMessage = window.onPlatformMessage; }); tearDown(() { @@ -31,11 +31,11 @@ void main() { group('$Link', () { testWidgets('handles null uri correctly', (WidgetTester tester) async { bool isBuilt = false; - FollowLink followLink; + FollowLink? followLink; final Link link = Link( uri: null, - builder: (BuildContext context, FollowLink followLink2) { + builder: (BuildContext context, FollowLink? followLink2) { isBuilt = true; followLink = followLink2; return Container(); @@ -50,66 +50,62 @@ void main() { testWidgets('calls url_launcher for external URLs with blank target', (WidgetTester tester) async { - FollowLink followLink; + FollowLink? followLink; await tester.pumpWidget(Link( uri: Uri.parse('http://example.com/foobar'), target: LinkTarget.blank, - builder: (BuildContext context, FollowLink followLink2) { + builder: (BuildContext context, FollowLink? followLink2) { followLink = followLink2; return Container(); }, )); - when(mock.canLaunch('http://example.com/foobar')) - .thenAnswer((realInvocation) => Future.value(true)); - clearInteractions(mock); - await followLink(); - - verifyInOrder([ - mock.canLaunch('http://example.com/foobar'), - mock.launch( - 'http://example.com/foobar', + mock + ..setLaunchExpectations( + url: 'http://example.com/foobar', useSafariVC: false, useWebView: false, universalLinksOnly: false, enableJavaScript: false, enableDomStorage: false, headers: {}, + webOnlyWindowName: null, ) - ]); + ..setResponse(true); + await followLink!(); + expect(mock.canLaunchCalled, isTrue); + expect(mock.launchCalled, isTrue); }); testWidgets('calls url_launcher for external URLs with self target', (WidgetTester tester) async { - FollowLink followLink; + FollowLink? followLink; await tester.pumpWidget(Link( uri: Uri.parse('http://example.com/foobar'), target: LinkTarget.self, - builder: (BuildContext context, FollowLink followLink2) { + builder: (BuildContext context, FollowLink? followLink2) { followLink = followLink2; return Container(); }, )); - when(mock.canLaunch('http://example.com/foobar')) - .thenAnswer((realInvocation) => Future.value(true)); - clearInteractions(mock); - await followLink(); - - verifyInOrder([ - mock.canLaunch('http://example.com/foobar'), - mock.launch( - 'http://example.com/foobar', + mock + ..setLaunchExpectations( + url: 'http://example.com/foobar', useSafariVC: true, useWebView: true, universalLinksOnly: false, enableJavaScript: false, enableDomStorage: false, headers: {}, + webOnlyWindowName: null, ) - ]); + ..setResponse(true); + await followLink!(); + expect(mock.canLaunchCalled, isTrue); + expect(mock.launchCalled, isTrue); }); testWidgets('sends navigation platform messages for internal route names', @@ -125,21 +121,21 @@ void main() { final List frameworkCalls = []; window.onPlatformMessage = ( String name, - ByteData data, - PlatformMessageResponseCallback callback, + ByteData? data, + PlatformMessageResponseCallback? callback, ) { frameworkCalls.add(_codec.decodeMethodCall(data)); - realOnPlatformMessage(name, data, callback); + realOnPlatformMessage!(name, data, callback); }; final Uri uri = Uri.parse('/foo/bar'); - FollowLink followLink; + FollowLink? followLink; await tester.pumpWidget(MaterialApp( routes: { '/': (BuildContext context) => Link( uri: uri, - builder: (BuildContext context, FollowLink followLink2) { + builder: (BuildContext context, FollowLink? followLink2) { followLink = followLink2; return Container(); }, @@ -150,11 +146,11 @@ void main() { engineCalls.clear(); frameworkCalls.clear(); - clearInteractions(mock); - await followLink(); + await followLink!(); // Shouldn't use url_launcher when uri is an internal route name. - verifyZeroInteractions(mock); + expect(mock.canLaunchCalled, isFalse); + expect(mock.launchCalled, isFalse); // A message should've been sent to the engine (by the Navigator, not by // the Link widget). @@ -191,19 +187,19 @@ void main() { final List frameworkCalls = []; window.onPlatformMessage = ( String name, - ByteData data, - PlatformMessageResponseCallback callback, + ByteData? data, + PlatformMessageResponseCallback? callback, ) { frameworkCalls.add(_codec.decodeMethodCall(data)); - realOnPlatformMessage(name, data, callback); + realOnPlatformMessage!(name, data, callback); }; final Uri uri = Uri.parse('/foo/bar'); - FollowLink followLink; + FollowLink? followLink; final Link link = Link( uri: uri, - builder: (BuildContext context, FollowLink followLink2) { + builder: (BuildContext context, FollowLink? followLink2) { followLink = followLink2; return Container(); }, @@ -217,11 +213,11 @@ void main() { engineCalls.clear(); frameworkCalls.clear(); - clearInteractions(mock); - await followLink(); + await followLink!(); // Shouldn't use url_launcher when uri is an internal route name. - verifyZeroInteractions(mock); + expect(mock.canLaunchCalled, isFalse); + expect(mock.launchCalled, isFalse); // Sends route information update to the engine. expect(engineCalls, hasLength(1)); @@ -249,10 +245,6 @@ void main() { }); } -class MockUrlLauncher extends Mock - with MockPlatformInterfaceMixin - implements UrlLauncherPlatform {} - class MockRouteInformationParser extends Mock implements RouteInformationParser { @override @@ -261,8 +253,8 @@ class MockRouteInformationParser extends Mock } } -class MockRouterDelegate extends Mock implements RouterDelegate { - MockRouterDelegate({@required this.builder}); +class MockRouterDelegate extends Mock implements RouterDelegate { + MockRouterDelegate({required this.builder}); final WidgetBuilder builder; @@ -270,4 +262,10 @@ class MockRouterDelegate extends Mock implements RouterDelegate { Widget build(BuildContext context) { return builder(context); } + + @override + Future setInitialRoutePath(Object configuration) async {} + + @override + Future setNewRoutePath(Object configuration) async {} } diff --git a/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart b/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart new file mode 100644 index 000000000000..87ae99e81024 --- /dev/null +++ b/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart @@ -0,0 +1,93 @@ +// 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 'package:flutter_test/flutter_test.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:url_launcher_platform_interface/link.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; + +class MockUrlLauncher extends Fake + with MockPlatformInterfaceMixin + implements UrlLauncherPlatform { + String? url; + bool? useSafariVC; + bool? useWebView; + bool? enableJavaScript; + bool? enableDomStorage; + bool? universalLinksOnly; + Map? headers; + String? webOnlyWindowName; + + bool? response; + + bool closeWebViewCalled = false; + bool canLaunchCalled = false; + bool launchCalled = false; + + void setCanLaunchExpectations(String url) { + this.url = url; + } + + void setLaunchExpectations({ + required String url, + required bool? useSafariVC, + required bool useWebView, + required bool enableJavaScript, + required bool enableDomStorage, + required bool universalLinksOnly, + required Map headers, + required String? webOnlyWindowName, + }) { + this.url = url; + this.useSafariVC = useSafariVC; + this.useWebView = useWebView; + this.enableJavaScript = enableJavaScript; + this.enableDomStorage = enableDomStorage; + this.universalLinksOnly = universalLinksOnly; + this.headers = headers; + this.webOnlyWindowName = webOnlyWindowName; + } + + void setResponse(bool response) { + this.response = response; + } + + @override + LinkDelegate? get linkDelegate => null; + + @override + Future canLaunch(String url) async { + expect(url, this.url); + canLaunchCalled = true; + return response!; + } + + @override + Future launch( + String url, { + required bool useSafariVC, + required bool useWebView, + required bool enableJavaScript, + required bool enableDomStorage, + required bool universalLinksOnly, + required Map headers, + String? webOnlyWindowName, + }) async { + expect(url, this.url); + expect(useSafariVC, this.useSafariVC); + expect(useWebView, this.useWebView); + expect(enableJavaScript, this.enableJavaScript); + expect(enableDomStorage, this.enableDomStorage); + expect(universalLinksOnly, this.universalLinksOnly); + expect(headers, this.headers); + expect(webOnlyWindowName, this.webOnlyWindowName); + launchCalled = true; + return response!; + } + + @override + Future closeWebView() async { + closeWebViewCalled = true; + } +} diff --git a/packages/url_launcher/url_launcher/test/url_launcher_test.dart b/packages/url_launcher/url_launcher/test/url_launcher_test.dart index bb3fd2ad92b5..9fb16019a543 100644 --- a/packages/url_launcher/url_launcher/test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/test/url_launcher_test.dart @@ -2,32 +2,31 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(mvanbeusekom): Remove once Mockito is migrated to null safety. -// @dart = 2.9 - import 'dart:async'; import 'dart:ui'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; import 'package:flutter/foundation.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; import 'package:flutter/services.dart' show PlatformException; +import 'mock_url_launcher_platform.dart'; + void main() { final MockUrlLauncher mock = MockUrlLauncher(); UrlLauncherPlatform.instance = mock; test('closeWebView default behavior', () async { await closeWebView(); - verify(mock.closeWebView()); + expect(mock.closeWebViewCalled, isTrue); }); group('canLaunch', () { test('returns true', () async { - when(mock.canLaunch('foo')).thenAnswer((_) => Future.value(true)); + mock + ..setCanLaunchExpectations('foo') + ..setResponse(true); final bool result = await canLaunch('foo'); @@ -35,7 +34,9 @@ void main() { }); test('returns false', () async { - when(mock.canLaunch('foo')).thenAnswer((_) => Future.value(false)); + mock + ..setCanLaunchExpectations('foo') + ..setResponse(false); final bool result = await canLaunch('foo'); @@ -44,146 +45,145 @@ void main() { }); group('launch', () { test('default behavior', () async { - await launch('http://flutter.dev/'); - expect( - verify(mock.launch( - captureAny, - useSafariVC: captureAnyNamed('useSafariVC'), - useWebView: captureAnyNamed('useWebView'), - enableJavaScript: captureAnyNamed('enableJavaScript'), - enableDomStorage: captureAnyNamed('enableDomStorage'), - universalLinksOnly: captureAnyNamed('universalLinksOnly'), - headers: captureAnyNamed('headers'), - )).captured, - [ - 'http://flutter.dev/', - true, - false, - false, - false, - false, - {}, - ], - ); + mock + ..setLaunchExpectations( + url: 'http://flutter.dev/', + useSafariVC: true, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, + webOnlyWindowName: null, + ) + ..setResponse(true); + expect(await launch('http://flutter.dev/'), isTrue); }); test('with headers', () async { - await launch( - 'http://flutter.dev/', - headers: {'key': 'value'}, - ); + mock + ..setLaunchExpectations( + url: 'http://flutter.dev/', + useSafariVC: true, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {'key': 'value'}, + webOnlyWindowName: null, + ) + ..setResponse(true); expect( - verify(mock.launch( - any, - useSafariVC: anyNamed('useSafariVC'), - useWebView: anyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: captureAnyNamed('headers'), - )).captured.single, - {'key': 'value'}, - ); + await launch( + 'http://flutter.dev/', + headers: {'key': 'value'}, + ), + isTrue); }); test('force SafariVC', () async { - await launch('http://flutter.dev/', forceSafariVC: true); - expect( - verify(mock.launch( - any, - useSafariVC: captureAnyNamed('useSafariVC'), - useWebView: anyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured.single, - true, - ); + mock + ..setLaunchExpectations( + url: 'http://flutter.dev/', + useSafariVC: true, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, + webOnlyWindowName: null, + ) + ..setResponse(true); + expect(await launch('http://flutter.dev/', forceSafariVC: true), isTrue); }); test('universal links only', () async { - await launch('http://flutter.dev/', - forceSafariVC: false, universalLinksOnly: true); + mock + ..setLaunchExpectations( + url: 'http://flutter.dev/', + useSafariVC: false, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: true, + headers: {}, + webOnlyWindowName: null, + ) + ..setResponse(true); expect( - verify(mock.launch( - any, - useSafariVC: captureAnyNamed('useSafariVC'), - useWebView: anyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: captureAnyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured, - [false, true], - ); + await launch('http://flutter.dev/', + forceSafariVC: false, universalLinksOnly: true), + isTrue); }); test('force WebView', () async { - await launch('http://flutter.dev/', forceWebView: true); - expect( - verify(mock.launch( - any, - useSafariVC: anyNamed('useSafariVC'), - useWebView: captureAnyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured.single, - true, - ); + mock + ..setLaunchExpectations( + url: 'http://flutter.dev/', + useSafariVC: true, + useWebView: true, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, + webOnlyWindowName: null, + ) + ..setResponse(true); + expect(await launch('http://flutter.dev/', forceWebView: true), isTrue); }); test('force WebView enable javascript', () async { - await launch('http://flutter.dev/', - forceWebView: true, enableJavaScript: true); + mock + ..setLaunchExpectations( + url: 'http://flutter.dev/', + useSafariVC: true, + useWebView: true, + enableJavaScript: true, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, + webOnlyWindowName: null, + ) + ..setResponse(true); expect( - verify(mock.launch( - any, - useSafariVC: anyNamed('useSafariVC'), - useWebView: captureAnyNamed('useWebView'), - enableJavaScript: captureAnyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured, - [true, true], - ); + await launch('http://flutter.dev/', + forceWebView: true, enableJavaScript: true), + isTrue); }); test('force WebView enable DOM storage', () async { - await launch('http://flutter.dev/', - forceWebView: true, enableDomStorage: true); + mock + ..setLaunchExpectations( + url: 'http://flutter.dev/', + useSafariVC: true, + useWebView: true, + enableJavaScript: false, + enableDomStorage: true, + universalLinksOnly: false, + headers: {}, + webOnlyWindowName: null, + ) + ..setResponse(true); expect( - verify(mock.launch( - any, - useSafariVC: anyNamed('useSafariVC'), - useWebView: captureAnyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: captureAnyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured, - [true, true], - ); + await launch('http://flutter.dev/', + forceWebView: true, enableDomStorage: true), + isTrue); }); test('force SafariVC to false', () async { - await launch('http://flutter.dev/', forceSafariVC: false); - expect( - // ignore: missing_required_param - verify(mock.launch( - any, - useSafariVC: captureAnyNamed('useSafariVC'), - useWebView: anyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )).captured.single, - false, - ); + mock + ..setLaunchExpectations( + url: 'http://flutter.dev/', + useSafariVC: false, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, + webOnlyWindowName: null, + ) + ..setResponse(true); + expect(await launch('http://flutter.dev/', forceSafariVC: false), isTrue); }); test('cannot launch a non-web in webview', () async { @@ -192,19 +192,20 @@ void main() { }); test('send e-mail', () async { - await launch('mailto:gmail-noreply@google.com?subject=Hello'); - expect( - verify(await mock.launch( - any, - useSafariVC: anyNamed('useSafariVC'), - useWebView: anyNamed('useWebView'), - enableJavaScript: anyNamed('enableJavaScript'), - enableDomStorage: anyNamed('enableDomStorage'), - universalLinksOnly: anyNamed('universalLinksOnly'), - headers: anyNamed('headers'), - )), - isInstanceOf(), - ); + mock + ..setLaunchExpectations( + url: 'mailto:gmail-noreply@google.com?subject=Hello', + useSafariVC: false, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, + webOnlyWindowName: null, + ) + ..setResponse(true); + expect(await launch('mailto:gmail-noreply@google.com?subject=Hello'), + isTrue); }); test('cannot send e-mail with forceSafariVC: true', () async { @@ -224,8 +225,22 @@ void main() { }); test('controls system UI when changing statusBarBrightness', () async { + mock + ..setLaunchExpectations( + url: 'http://flutter.dev/', + useSafariVC: true, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, + webOnlyWindowName: null, + ) + ..setResponse(true); + final TestWidgetsFlutterBinding binding = - TestWidgetsFlutterBinding.ensureInitialized(); + TestWidgetsFlutterBinding.ensureInitialized() + as TestWidgetsFlutterBinding; debugDefaultTargetPlatformOverride = TargetPlatform.iOS; binding.renderView.automaticSystemUiAdjustment = true; final Future launchResult = @@ -239,8 +254,22 @@ void main() { }); test('sets automaticSystemUiAdjustment to not be null', () async { + mock + ..setLaunchExpectations( + url: 'http://flutter.dev/', + useSafariVC: true, + useWebView: false, + enableJavaScript: false, + enableDomStorage: false, + universalLinksOnly: false, + headers: {}, + webOnlyWindowName: null, + ) + ..setResponse(true); + final TestWidgetsFlutterBinding binding = - TestWidgetsFlutterBinding.ensureInitialized(); + TestWidgetsFlutterBinding.ensureInitialized() + as TestWidgetsFlutterBinding; debugDefaultTargetPlatformOverride = TargetPlatform.android; expect(binding.renderView.automaticSystemUiAdjustment, true); final Future launchResult = @@ -254,7 +283,3 @@ void main() { }); }); } - -class MockUrlLauncher extends Mock - with MockPlatformInterfaceMixin - implements UrlLauncherPlatform {} From beef9a8b9b49ecbfee7bc6a2d8633e62985c28fb Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 2 Mar 2021 14:04:04 -0800 Subject: [PATCH 299/924] [android_intent] move unit test to nullsafety (#3659) --- packages/android_intent/pubspec.yaml | 3 +- .../test/android_intent_test.dart | 14 ++-- .../test/android_intent_test.mocks.dart | 64 +++++++++++++++++++ 3 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 packages/android_intent/test/android_intent_test.mocks.dart diff --git a/packages/android_intent/pubspec.yaml b/packages/android_intent/pubspec.yaml index e02c7a270344..8a80370a78a3 100644 --- a/packages/android_intent/pubspec.yaml +++ b/packages/android_intent/pubspec.yaml @@ -17,10 +17,11 @@ dependencies: meta: ^1.3.0 dev_dependencies: test: ^1.16.3 - mockito: ^5.0.0-nullsafety.7 + mockito: ^5.0.0 flutter_test: sdk: flutter pedantic: ^1.10.0 + build_runner: ^1.11.1 environment: sdk: ">=2.12.0-259.9.beta <3.0.0" diff --git a/packages/android_intent/test/android_intent_test.dart b/packages/android_intent/test/android_intent_test.dart index ad0eae3b662d..95ff345395cf 100644 --- a/packages/android_intent/test/android_intent_test.dart +++ b/packages/android_intent/test/android_intent_test.dart @@ -2,23 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'package:android_intent/flag.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:android_intent/android_intent.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:platform/platform.dart'; +import 'android_intent_test.mocks.dart'; + +@GenerateMocks([MethodChannel]) void main() { - AndroidIntent androidIntent; - MockMethodChannel mockChannel; + late AndroidIntent androidIntent; + late MockMethodChannel mockChannel; setUp(() { mockChannel = MockMethodChannel(); when(mockChannel.invokeMethod('canResolveActivity', any)) .thenAnswer((realInvocation) async => true); + when(mockChannel.invokeMethod('launch', any)) + .thenAnswer((realInvocation) async => {}); }); group('AndroidIntent', () { @@ -178,5 +182,3 @@ void main() { }); }); } - -class MockMethodChannel extends Mock implements MethodChannel {} diff --git a/packages/android_intent/test/android_intent_test.mocks.dart b/packages/android_intent/test/android_intent_test.mocks.dart new file mode 100644 index 000000000000..fed1624ad069 --- /dev/null +++ b/packages/android_intent/test/android_intent_test.mocks.dart @@ -0,0 +1,64 @@ +// Mocks generated by Mockito 5.0.0 from annotations +// in android_intent/test/android_intent_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i5; + +import 'package:flutter/src/services/binary_messenger.dart' as _i3; +import 'package:flutter/src/services/message_codec.dart' as _i2; +import 'package:flutter/src/services/platform_channel.dart' as _i4; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: comment_references +// ignore_for_file: unnecessary_parenthesis + +class _FakeMethodCodec extends _i1.Fake implements _i2.MethodCodec {} + +class _FakeBinaryMessenger extends _i1.Fake implements _i3.BinaryMessenger {} + +/// A class which mocks [MethodChannel]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMethodChannel extends _i1.Mock implements _i4.MethodChannel { + MockMethodChannel() { + _i1.throwOnMissingStub(this); + } + + @override + String get name => + (super.noSuchMethod(Invocation.getter(#name), returnValue: '') as String); + @override + _i2.MethodCodec get codec => (super.noSuchMethod(Invocation.getter(#codec), + returnValue: _FakeMethodCodec()) as _i2.MethodCodec); + @override + _i3.BinaryMessenger get binaryMessenger => + (super.noSuchMethod(Invocation.getter(#binaryMessenger), + returnValue: _FakeBinaryMessenger()) as _i3.BinaryMessenger); + @override + _i5.Future invokeMethod(String? method, [dynamic arguments]) => + (super.noSuchMethod(Invocation.method(#invokeMethod, [method, arguments]), + returnValue: Future.value(null)) as _i5.Future); + @override + _i5.Future?> invokeListMethod(String? method, + [dynamic arguments]) => + (super.noSuchMethod( + Invocation.method(#invokeListMethod, [method, arguments]), + returnValue: Future.value([])) as _i5.Future?>); + @override + _i5.Future?> invokeMapMethod(String? method, + [dynamic arguments]) => + (super.noSuchMethod( + Invocation.method(#invokeMapMethod, [method, arguments]), + returnValue: Future.value({})) as _i5.Future?>); + @override + bool checkMethodCallHandler( + _i5.Future Function(_i2.MethodCall)? handler) => + (super.noSuchMethod(Invocation.method(#checkMethodCallHandler, [handler]), + returnValue: false) as bool); + @override + bool checkMockMethodCallHandler( + _i5.Future Function(_i2.MethodCall)? handler) => + (super.noSuchMethod( + Invocation.method(#checkMockMethodCallHandler, [handler]), + returnValue: false) as bool); +} From 4738c8384d3d3dfd68eb2f8b67a296f7a35b8320 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 2 Mar 2021 14:09:02 -0800 Subject: [PATCH 300/924] remove unused plugin (#3661) --- .../integration_test/example/pubspec.yaml | 2 -- .../integration_test_macos/CHANGELOG.md | 11 -------- .../integration_test_macos/LICENSE | 25 ------------------- .../macos/Assets/.gitkeep | 0 .../macos/Classes/IntegrationTestPlugin.swift | 22 ---------------- .../macos/integration_test_macos.podspec | 21 ---------------- .../integration_test_macos/pubspec.yaml | 21 ---------------- 7 files changed, 102 deletions(-) delete mode 100644 packages/integration_test/integration_test_macos/CHANGELOG.md delete mode 100644 packages/integration_test/integration_test_macos/LICENSE delete mode 100644 packages/integration_test/integration_test_macos/macos/Assets/.gitkeep delete mode 100644 packages/integration_test/integration_test_macos/macos/Classes/IntegrationTestPlugin.swift delete mode 100644 packages/integration_test/integration_test_macos/macos/integration_test_macos.podspec delete mode 100644 packages/integration_test/integration_test_macos/pubspec.yaml diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 5ad8be4a818e..558d5f7bc1a1 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -24,8 +24,6 @@ dev_dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - integration_test_macos: - path: ../integration_test_macos test: any pedantic: ^1.8.0 diff --git a/packages/integration_test/integration_test_macos/CHANGELOG.md b/packages/integration_test/integration_test_macos/CHANGELOG.md deleted file mode 100644 index ab4bac1a3f3f..000000000000 --- a/packages/integration_test/integration_test_macos/CHANGELOG.md +++ /dev/null @@ -1,11 +0,0 @@ -## 0.0.2 - -* Renames package to integration_test_macos. - -## 0.0.1+1 - -* Remove Android folder from `e2e_macos`. - -## 0.0.1 - -* Initial release diff --git a/packages/integration_test/integration_test_macos/LICENSE b/packages/integration_test/integration_test_macos/LICENSE deleted file mode 100644 index 507569823f1b..000000000000 --- a/packages/integration_test/integration_test_macos/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright 2019 The Chromium Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/integration_test/integration_test_macos/macos/Assets/.gitkeep b/packages/integration_test/integration_test_macos/macos/Assets/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/packages/integration_test/integration_test_macos/macos/Classes/IntegrationTestPlugin.swift b/packages/integration_test/integration_test_macos/macos/Classes/IntegrationTestPlugin.swift deleted file mode 100644 index b4eb5fc410d5..000000000000 --- a/packages/integration_test/integration_test_macos/macos/Classes/IntegrationTestPlugin.swift +++ /dev/null @@ -1,22 +0,0 @@ -import FlutterMacOS - -public class IntegrationTestPlugin: NSObject, FlutterPlugin { - - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel( - name: "plugins.flutter.io/integration_test", - binaryMessenger: registrar.messenger) - - let instance = IntegrationTestPlugin() - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "allTestsFinished": - result(nil) - default: - result(FlutterMethodNotImplemented) - } - } -} diff --git a/packages/integration_test/integration_test_macos/macos/integration_test_macos.podspec b/packages/integration_test/integration_test_macos/macos/integration_test_macos.podspec deleted file mode 100644 index 74bf66321319..000000000000 --- a/packages/integration_test/integration_test_macos/macos/integration_test_macos.podspec +++ /dev/null @@ -1,21 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'IntegrationTestMacOS' - s.version = '0.0.1' - s.summary = 'Adapter for integration tests.' - s.description = <<-DESC -Runs tests that use the flutter_test API as integration tests on macOS. - DESC - s.homepage = 'https://github.com/flutter/plugins/tree/master/packages/integration_test/integration_test_macos' - s.license = { :type => 'BSD', :file => '../LICENSE' } - s.author = { 'Flutter Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/integration_test' } - s.source_files = 'Classes/**/*' - s.dependency 'FlutterMacOS' - - s.platform = :osx, '10.11' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } -end - diff --git a/packages/integration_test/integration_test_macos/pubspec.yaml b/packages/integration_test/integration_test_macos/pubspec.yaml deleted file mode 100644 index 46510e32b94a..000000000000 --- a/packages/integration_test/integration_test_macos/pubspec.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: integration_test_macos -description: Desktop implementation of integration_test plugin -version: 0.0.1+1 -author: Flutter Team -homepage: https://github.com/flutter/plugins/tree/master/packages/integration_test/integration_test_macos - -flutter: - plugin: - platforms: - macos: - pluginClass: IntegrationTestPlugin - -environment: - sdk: ">=2.1.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - -dev_dependencies: - pedantic: ^1.8.0 From 1e3a82316e0389409e60f0197ef49290192a9dcc Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 2 Mar 2021 14:50:39 -0800 Subject: [PATCH 301/924] [device_info] Enable NNBD for unit test (#3658) Removes the opt-out now that the underlying issue is fixed --- .../test/method_channel_device_info_test.dart | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart index 03ff4b53cda9..b257109fe2f6 100644 --- a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart +++ b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(cyanglaz): Remove once https://github.com/flutter/flutter/issues/59879 is fixed. -// @dart = 2.9 - import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:device_info_platform_interface/device_info_platform_interface.dart'; @@ -14,7 +11,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); group("$MethodChannelDeviceInfo", () { - MethodChannelDeviceInfo methodChannelDeviceInfo; + late MethodChannelDeviceInfo methodChannelDeviceInfo; setUp(() async { methodChannelDeviceInfo = MethodChannelDeviceInfo(); @@ -162,7 +159,7 @@ void main() { group( "$MethodChannelDeviceInfo handles null value in the map returned from method channel", () { - MethodChannelDeviceInfo methodChannelDeviceInfo; + late MethodChannelDeviceInfo methodChannelDeviceInfo; setUp(() async { methodChannelDeviceInfo = MethodChannelDeviceInfo(); @@ -261,7 +258,7 @@ void main() { }); group("$MethodChannelDeviceInfo handles method channel returns null", () { - MethodChannelDeviceInfo methodChannelDeviceInfo; + late MethodChannelDeviceInfo methodChannelDeviceInfo; setUp(() async { methodChannelDeviceInfo = MethodChannelDeviceInfo(); @@ -329,7 +326,7 @@ void main() { }); group("$MethodChannelDeviceInfo android handles null values in list", () { - MethodChannelDeviceInfo methodChannelDeviceInfo; + late MethodChannelDeviceInfo methodChannelDeviceInfo; setUp(() async { methodChannelDeviceInfo = MethodChannelDeviceInfo(); @@ -339,9 +336,9 @@ void main() { switch (methodCall.method) { case 'getAndroidDeviceInfo': return ({ - "supported32BitAbis": ["x86", null], - "supported64BitAbis": ["x86_64", null], - "supportedAbis": ["x86_64", "x86", null], + "supported32BitAbis": ["x86"], + "supported64BitAbis": ["x86_64"], + "supportedAbis": ["x86_64", "x86"], "systemFeatures": [ "android.hardware.sensor.proximity", "android.software.adoptable_storage", @@ -349,7 +346,6 @@ void main() { "android.hardware.faketouch", "android.software.backup", "android.hardware.touchscreen", - null ], }); default: From 9509b7a623a11c4611f83607324b0a231f0493ca Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Tue, 2 Mar 2021 17:48:26 -0800 Subject: [PATCH 302/924] [webview_flutter] Run CocoaPods iOS tests in RunnerUITests target (#3664) --- .cirrus.yml | 2 +- .gitignore | 1 + packages/webview_flutter/CHANGELOG.md | 4 ++ packages/webview_flutter/example/ios/Podfile | 45 +++++++++++++ .../ios/Runner.xcodeproj/project.pbxproj | 64 +++++++++++-------- .../xcshareddata/xcschemes/Runner.xcscheme | 4 +- .../xcschemes/RunnerUITests.xcscheme | 52 +++++++++++++++ .../Info.plist | 0 .../ios/webview_flutter.podspec | 2 +- packages/webview_flutter/pubspec.yaml | 2 +- 10 files changed, 145 insertions(+), 31 deletions(-) create mode 100644 packages/webview_flutter/example/ios/Podfile create mode 100644 packages/webview_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme rename packages/webview_flutter/example/ios/{webview_flutter_exampleTests => RunnerUITests}/Info.plist (100%) diff --git a/.cirrus.yml b/.cirrus.yml index 118802b74810..d7aebddb92cf 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -179,7 +179,7 @@ task: - name: build-ipas+drive-examples env: PATH: $PATH:/usr/local/bin - PLUGINS_TO_SKIP_XCTESTS: "battery/battery,camera/camera,connectivity/connectivity,device_info/device_info,espresso,google_maps_flutter/google_maps_flutter,google_sign_in/google_sign_in,in_app_purchase,integration_test,ios_platform_images,local_auth,package_info,path_provider/path_provider,sensors,shared_preferences/shared_preferences,url_launcher/url_launcher,video_player/video_player,webview_flutter,wifi_info_flutter/wifi_info_flutter" + PLUGINS_TO_SKIP_XCTESTS: "battery/battery,camera/camera,connectivity/connectivity,device_info/device_info,espresso,google_maps_flutter/google_maps_flutter,google_sign_in/google_sign_in,in_app_purchase,integration_test,ios_platform_images,local_auth,package_info,path_provider/path_provider,sensors,shared_preferences/shared_preferences,url_launcher/url_launcher,video_player/video_player,wifi_info_flutter/wifi_info_flutter" matrix: PLUGIN_SHARDING: "--shardIndex 0 --shardCount 4" PLUGIN_SHARDING: "--shardIndex 1 --shardCount 4" diff --git a/.gitignore b/.gitignore index 3582a15fae57..823f9031d960 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ Pods/ .symlinks/ **/Flutter/App.framework/ **/Flutter/ephemeral/ +**/Flutter/Flutter.podspec **/Flutter/Flutter.framework/ **/Flutter/Generated.xcconfig **/Flutter/flutter_assets/ diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index fb448d245127..139f120f12b2 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Run CocoaPods iOS tests in RunnerUITests target + ## 2.0.0 * Migration to null-safety. diff --git a/packages/webview_flutter/example/ios/Podfile b/packages/webview_flutter/example/ios/Podfile new file mode 100644 index 000000000000..ce7f8a5df02b --- /dev/null +++ b/packages/webview_flutter/example/ios/Podfile @@ -0,0 +1,45 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + + target 'RunnerUITests' do + inherit! :search_paths + + # Matches test_spec dependency. + pod 'OCMock', '3.5' + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj index 33e9d9745bba..d651613f32dc 100644 --- a/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 9D26F6F82D91F92CC095EBA9 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B845D8FBDE0AAD6BE1A0386 /* libPods-Runner.a */; }; + EE189BB43C38EE5DE05135A7 /* libPods-RunnerUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0EBE6A98F0F7B17A8E813670 /* libPods-RunnerUITests.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -43,12 +44,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 06E410020C7D35382771541C /* Pods-RunnerUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerUITests/Pods-RunnerUITests.release.xcconfig"; sourceTree = ""; }; + 0EBE6A98F0F7B17A8E813670 /* libPods-RunnerUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 127772EEA7782174BE0D74B5 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 686B4BF82548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLTWKNavigationDelegateTests.m; path = ../../../ios/Tests/FLTWKNavigationDelegateTests.m; sourceTree = ""; }; - 68BDCAE923C3F7CB00D9C032 /* webview_flutter_exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = webview_flutter_exampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 68BDCAE923C3F7CB00D9C032 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68BDCAED23C3F7CB00D9C032 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 68BDCAF523C3F97800D9C032 /* FLTWebViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLTWebViewTests.m; path = ../../../ios/Tests/FLTWebViewTests.m; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -64,6 +67,7 @@ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C475C484BD510DD9CB2E403C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + DA434001E038D9F8CFB0EDEC /* Pods-RunnerUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerUITests/Pods-RunnerUITests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -71,6 +75,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + EE189BB43C38EE5DE05135A7 /* libPods-RunnerUITests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -85,14 +90,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 68BDCAEA23C3F7CB00D9C032 /* webview_flutter_exampleTests */ = { + 68BDCAEA23C3F7CB00D9C032 /* RunnerUITests */ = { isa = PBXGroup; children = ( 686B4BF82548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m */, 68BDCAF523C3F97800D9C032 /* FLTWebViewTests.m */, 68BDCAED23C3F7CB00D9C032 /* Info.plist */, ); - path = webview_flutter_exampleTests; + path = RunnerUITests; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { @@ -111,7 +116,7 @@ children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, - 68BDCAEA23C3F7CB00D9C032 /* webview_flutter_exampleTests */, + 68BDCAEA23C3F7CB00D9C032 /* RunnerUITests */, 97C146EF1CF9000F007C117D /* Products */, C6FFB52F5C2B8A41A7E39DE2 /* Pods */, B6736FC417BDCCDA377E779D /* Frameworks */, @@ -122,7 +127,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, - 68BDCAE923C3F7CB00D9C032 /* webview_flutter_exampleTests.xctest */, + 68BDCAE923C3F7CB00D9C032 /* RunnerUITests.xctest */, ); name = Products; sourceTree = ""; @@ -155,6 +160,7 @@ isa = PBXGroup; children = ( 8B845D8FBDE0AAD6BE1A0386 /* libPods-Runner.a */, + 0EBE6A98F0F7B17A8E813670 /* libPods-RunnerUITests.a */, ); name = Frameworks; sourceTree = ""; @@ -164,6 +170,8 @@ children = ( 127772EEA7782174BE0D74B5 /* Pods-Runner.debug.xcconfig */, C475C484BD510DD9CB2E403C /* Pods-Runner.release.xcconfig */, + DA434001E038D9F8CFB0EDEC /* Pods-RunnerUITests.debug.xcconfig */, + 06E410020C7D35382771541C /* Pods-RunnerUITests.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -171,10 +179,11 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 68BDCAE823C3F7CB00D9C032 /* webview_flutter_exampleTests */ = { + 68BDCAE823C3F7CB00D9C032 /* RunnerUITests */ = { isa = PBXNativeTarget; - buildConfigurationList = 68BDCAF223C3F7CB00D9C032 /* Build configuration list for PBXNativeTarget "webview_flutter_exampleTests" */; + buildConfigurationList = 68BDCAF223C3F7CB00D9C032 /* Build configuration list for PBXNativeTarget "RunnerUITests" */; buildPhases = ( + 53FD4CBDD9756D74B5A3B4C1 /* [CP] Check Pods Manifest.lock */, 68BDCAE523C3F7CB00D9C032 /* Sources */, 68BDCAE623C3F7CB00D9C032 /* Frameworks */, 68BDCAE723C3F7CB00D9C032 /* Resources */, @@ -184,9 +193,9 @@ dependencies = ( 68BDCAEF23C3F7CB00D9C032 /* PBXTargetDependency */, ); - name = webview_flutter_exampleTests; + name = RunnerUITests; productName = webview_flutter_exampleTests; - productReference = 68BDCAE923C3F7CB00D9C032 /* webview_flutter_exampleTests.xctest */; + productReference = 68BDCAE923C3F7CB00D9C032 /* RunnerUITests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 97C146ED1CF9000F007C117D /* Runner */ = { @@ -200,7 +209,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - A1F14D6FD37A3C5047F5A5AD /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -243,7 +251,7 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, - 68BDCAE823C3F7CB00D9C032 /* webview_flutter_exampleTests */, + 68BDCAE823C3F7CB00D9C032 /* RunnerUITests */, ); }; /* End PBXProject section */ @@ -284,37 +292,41 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin\n"; }; - 9740EEB61CF901F6004384FC /* Run Script */ = { + 53FD4CBDD9756D74B5A3B4C1 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( ); - name = "Run Script"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerUITests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; - A1F14D6FD37A3C5047F5A5AD /* [CP] Embed Pods Frameworks */ = { + 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../Flutter/Flutter.framework", ); - name = "[CP] Embed Pods Frameworks"; + name = "Run Script"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; B71376B4FB8384EF9D5F3F84 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; @@ -388,7 +400,7 @@ /* Begin XCBuildConfiguration section */ 68BDCAF023C3F7CB00D9C032 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + baseConfigurationReference = DA434001E038D9F8CFB0EDEC /* Pods-RunnerUITests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -398,7 +410,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = webview_flutter_exampleTests/Info.plist; + INFOPLIST_FILE = RunnerUITests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; @@ -412,7 +424,7 @@ }; 68BDCAF123C3F7CB00D9C032 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + baseConfigurationReference = 06E410020C7D35382771541C /* Pods-RunnerUITests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -422,7 +434,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = webview_flutter_exampleTests/Info.plist; + INFOPLIST_FILE = RunnerUITests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_FAST_MATH = YES; @@ -590,7 +602,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 68BDCAF223C3F7CB00D9C032 /* Build configuration list for PBXNativeTarget "webview_flutter_exampleTests" */ = { + 68BDCAF223C3F7CB00D9C032 /* Build configuration list for PBXNativeTarget "RunnerUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( 68BDCAF023C3F7CB00D9C032 /* Debug */, diff --git a/packages/webview_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/webview_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 7bcb47d19031..bcb1de689917 100644 --- a/packages/webview_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/webview_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -42,8 +42,8 @@ diff --git a/packages/webview_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme b/packages/webview_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme new file mode 100644 index 000000000000..917be4f45bfa --- /dev/null +++ b/packages/webview_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/webview_flutter/example/ios/webview_flutter_exampleTests/Info.plist b/packages/webview_flutter/example/ios/RunnerUITests/Info.plist similarity index 100% rename from packages/webview_flutter/example/ios/webview_flutter_exampleTests/Info.plist rename to packages/webview_flutter/example/ios/RunnerUITests/Info.plist diff --git a/packages/webview_flutter/ios/webview_flutter.podspec b/packages/webview_flutter/ios/webview_flutter.podspec index 469195ae6449..066dfaacbfb9 100644 --- a/packages/webview_flutter/ios/webview_flutter.podspec +++ b/packages/webview_flutter/ios/webview_flutter.podspec @@ -19,7 +19,7 @@ Downloaded by pub (not CocoaPods). s.dependency 'Flutter' s.platform = :ios, '8.0' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } s.test_spec 'Tests' do |test_spec| test_spec.source_files = 'Tests/**/*' diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index bae19fd8b726..0640386c517d 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter -version: 2.0.0 +version: 2.0.1 environment: sdk: ">=2.12.0-259.9.beta <3.0.0" From 2eba00a05cc147cd89f48657d881edf21cd406db Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Tue, 2 Mar 2021 17:48:43 -0800 Subject: [PATCH 303/924] [image_picker] Run CocoaPods iOS tests in RunnerUITests target (#3663) --- .../image_picker/image_picker/CHANGELOG.md | 4 + .../image_picker/example/ios/Podfile | 42 +++++ .../ios/Runner.xcodeproj/project.pbxproj | 175 +++--------------- .../contents.xcworkspacedata | 5 +- .../xcshareddata/xcschemes/Runner.xcscheme | 6 +- .../xcschemes/RunnerUITests.xcscheme | 52 ++++++ .../image_picker/ios/image_picker.podspec | 2 +- .../image_picker/image_picker/pubspec.yaml | 2 +- 8 files changed, 133 insertions(+), 155 deletions(-) create mode 100644 packages/image_picker/image_picker/example/ios/Podfile create mode 100644 packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 4673c01f506e..7be13a574a77 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.2 + +* Run CocoaPods iOS tests in RunnerUITests target + ## 0.7.1 * Update platform_plugin_interface version requirement. diff --git a/packages/image_picker/image_picker/example/ios/Podfile b/packages/image_picker/image_picker/example/ios/Podfile new file mode 100644 index 000000000000..48f7bbc93cb5 --- /dev/null +++ b/packages/image_picker/image_picker/example/ios/Podfile @@ -0,0 +1,42 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + + target 'RunnerUITests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj index be3d55f406bf..492dd014ce6d 100644 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj @@ -28,13 +28,6 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 6800491C2280D368006DD6AB /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 97C146E61CF9000F007C117D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 97C146ED1CF9000F007C117D; - remoteInfo = Runner; - }; 6801C83B2555D726009DAF8D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 97C146E61CF9000F007C117D /* Project object */; @@ -58,12 +51,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 15BE72415096DFE5D077E563 /* Pods-RunnerUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerUITests/Pods-RunnerUITests.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 515A7EC9B4C971C01E672CF8 /* Pods-RunnerUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerUITests/Pods-RunnerUITests.release.xcconfig"; sourceTree = ""; }; 5A9D31B91557877A0E8EF3E7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 5C9512FF1EC38BD300040975 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 5C9513001EC38BD300040975 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 680049172280D368006DD6AB /* image_picker_exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = image_picker_exampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 6800491B2280D368006DD6AB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 680049252280D736006DD6AB /* MetaDataUtilTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MetaDataUtilTests.m; path = ../../../ios/Tests/MetaDataUtilTests.m; sourceTree = ""; }; 680049352280F2B8006DD6AB /* pngImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = pngImage.png; sourceTree = ""; }; 680049362280F2B8006DD6AB /* jpgImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = jpgImage.jpg; sourceTree = ""; }; @@ -86,23 +79,18 @@ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9FC8F0E8229FA49E00C8D58F /* gifImage.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = gifImage.gif; sourceTree = ""; }; 9FC8F0ED229FB90B00C8D58F /* ImageUtilTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ImageUtilTests.m; path = ../../../ios/Tests/ImageUtilTests.m; sourceTree = ""; }; + A908FAEEA2A9B26D903C09C5 /* libPods-RunnerUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; EC32F6993F4529982D9519F1 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; F78AF3172342D9D7008449C7 /* ImagePickerTestImages.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ImagePickerTestImages.h; path = ../../../ios/Tests/ImagePickerTestImages.h; sourceTree = ""; }; F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ImagePickerTestImages.m; path = ../../../ios/Tests/ImagePickerTestImages.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 680049142280D368006DD6AB /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 6801C8332555D726009DAF8D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F10E2DB84567A50A8721C9C7 /* libPods-RunnerUITests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -117,20 +105,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 680049182280D368006DD6AB /* image_picker_exampleTests */ = { - isa = PBXGroup; - children = ( - 6800491B2280D368006DD6AB /* Info.plist */, - 9FC8F0ED229FB90B00C8D58F /* ImageUtilTests.m */, - 680049252280D736006DD6AB /* MetaDataUtilTests.m */, - 68F4B463228B3AB500C25614 /* PhotoAssetUtilTests.m */, - F78AF3172342D9D7008449C7 /* ImagePickerTestImages.h */, - F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */, - 68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */, - ); - path = image_picker_exampleTests; - sourceTree = ""; - }; 680049282280E33D006DD6AB /* TestImages */ = { isa = PBXGroup; children = ( @@ -145,6 +119,12 @@ isa = PBXGroup; children = ( 6801C8382555D726009DAF8D /* ImagePickerFromGalleryUITests.m */, + 9FC8F0ED229FB90B00C8D58F /* ImageUtilTests.m */, + 680049252280D736006DD6AB /* MetaDataUtilTests.m */, + 68F4B463228B3AB500C25614 /* PhotoAssetUtilTests.m */, + F78AF3172342D9D7008449C7 /* ImagePickerTestImages.h */, + F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */, + 68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */, 6801C83A2555D726009DAF8D /* Info.plist */, ); path = RunnerUITests; @@ -155,6 +135,8 @@ children = ( 6801632E632668F4349764C9 /* Pods-Runner.debug.xcconfig */, 5A9D31B91557877A0E8EF3E7 /* Pods-Runner.release.xcconfig */, + 15BE72415096DFE5D077E563 /* Pods-RunnerUITests.debug.xcconfig */, + 515A7EC9B4C971C01E672CF8 /* Pods-RunnerUITests.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -176,7 +158,6 @@ 680049282280E33D006DD6AB /* TestImages */, 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, - 680049182280D368006DD6AB /* image_picker_exampleTests */, 6801C8372555D726009DAF8D /* RunnerUITests */, 97C146EF1CF9000F007C117D /* Products */, 840012C8B5EDBCF56B0E4AC1 /* Pods */, @@ -188,7 +169,6 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, - 680049172280D368006DD6AB /* image_picker_exampleTests.xctest */, 6801C8362555D726009DAF8D /* RunnerUITests.xctest */, ); name = Products; @@ -222,6 +202,7 @@ isa = PBXGroup; children = ( EC32F6993F4529982D9519F1 /* libPods-Runner.a */, + A908FAEEA2A9B26D903C09C5 /* libPods-RunnerUITests.a */, ); name = Frameworks; sourceTree = ""; @@ -229,28 +210,11 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 680049162280D368006DD6AB /* image_picker_exampleTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 6800491E2280D368006DD6AB /* Build configuration list for PBXNativeTarget "image_picker_exampleTests" */; - buildPhases = ( - 680049132280D368006DD6AB /* Sources */, - 680049142280D368006DD6AB /* Frameworks */, - 680049152280D368006DD6AB /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 6800491D2280D368006DD6AB /* PBXTargetDependency */, - ); - name = image_picker_exampleTests; - productName = image_picker_exampleTests; - productReference = 680049172280D368006DD6AB /* image_picker_exampleTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; 6801C8352555D726009DAF8D /* RunnerUITests */ = { isa = PBXNativeTarget; buildConfigurationList = 6801C83F2555D726009DAF8D /* Build configuration list for PBXNativeTarget "RunnerUITests" */; buildPhases = ( + 4F8C1F500AF4DCAB62651A1E /* [CP] Check Pods Manifest.lock */, 6801C8322555D726009DAF8D /* Sources */, 6801C8332555D726009DAF8D /* Frameworks */, 6801C8342555D726009DAF8D /* Resources */, @@ -275,7 +239,6 @@ 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, - 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, ); buildRules = ( @@ -297,11 +260,6 @@ LastUpgradeCheck = 1100; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { - 680049162280D368006DD6AB = { - CreatedOnToolsVersion = 10.2.1; - ProvisioningStyle = Automatic; - TestTargetID = 97C146ED1CF9000F007C117D; - }; 6801C8352555D726009DAF8D = { CreatedOnToolsVersion = 11.7; ProvisioningStyle = Automatic; @@ -331,31 +289,22 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, - 680049162280D368006DD6AB /* image_picker_exampleTests */, 6801C8352555D726009DAF8D /* RunnerUITests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 680049152280D368006DD6AB /* Resources */ = { + 6801C8342555D726009DAF8D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 680049272280D79A006DD6AB /* Assets.xcassets in Resources */, 9FC8F0EC229FA68500C8D58F /* gifImage.gif in Resources */, 680049382280F2B9006DD6AB /* pngImage.png in Resources */, 680049392280F2B9006DD6AB /* jpgImage.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 6801C8342555D726009DAF8D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -384,22 +333,26 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { + 4F8C1F500AF4DCAB62651A1E /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../Flutter/Flutter.framework", + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( ); - name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + "$(DERIVED_FILE_DIR)/Pods-RunnerUITests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { @@ -437,10 +390,11 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 680049132280D368006DD6AB /* Sources */ = { + 6801C8322555D726009DAF8D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 6801C8392555D726009DAF8D /* ImagePickerFromGalleryUITests.m in Sources */, 9FC8F0EE229FB90B00C8D58F /* ImageUtilTests.m in Sources */, F78AF3192342D9D7008449C7 /* ImagePickerTestImages.m in Sources */, 680049262280D736006DD6AB /* MetaDataUtilTests.m in Sources */, @@ -449,14 +403,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 6801C8322555D726009DAF8D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 6801C8392555D726009DAF8D /* ImagePickerFromGalleryUITests.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -470,11 +416,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 6800491D2280D368006DD6AB /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 97C146ED1CF9000F007C117D /* Runner */; - targetProxy = 6800491C2280D368006DD6AB /* PBXContainerItemProxy */; - }; 6801C83C2555D726009DAF8D /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 97C146ED1CF9000F007C117D /* Runner */; @@ -502,59 +443,9 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 6800491F2280D368006DD6AB /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - INFOPLIST_FILE = image_picker_exampleTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.google.transformTest.image-picker-exampleTests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; - }; - name = Debug; - }; - 680049202280D368006DD6AB /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - INFOPLIST_FILE = image_picker_exampleTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.google.transformTest.image-picker-exampleTests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; - }; - name = Release; - }; 6801C83D2555D726009DAF8D /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -579,6 +470,7 @@ }; 6801C83E2555D726009DAF8D /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -753,15 +645,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 6800491E2280D368006DD6AB /* Build configuration list for PBXNativeTarget "image_picker_exampleTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6800491F2280D368006DD6AB /* Debug */, - 680049202280D368006DD6AB /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 6801C83F2555D726009DAF8D /* Build configuration list for PBXNativeTarget "RunnerUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 21a3cc14c74e..919434a6254f 100755 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,9 +2,6 @@ - - + location = "self:"> diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 7a9aea57bd9d..641cb8ccafa4 100755 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -41,9 +41,9 @@ skipped = "NO"> diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme new file mode 100644 index 000000000000..1a97d9638346 --- /dev/null +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/image_picker/image_picker/ios/image_picker.podspec b/packages/image_picker/image_picker/ios/image_picker.podspec index 5c13cef272dd..f0c8aa47e1b2 100644 --- a/packages/image_picker/image_picker/ios/image_picker.podspec +++ b/packages/image_picker/image_picker/ios/image_picker.podspec @@ -18,7 +18,7 @@ Downloaded by pub (not CocoaPods). s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' s.platform = :ios, '8.0' - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } s.test_spec 'Tests' do |test_spec| test_spec.source_files = 'Tests/**/*' diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index fb351b3ece75..562528466861 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.7.1 +version: 0.7.2 flutter: plugin: From 65768856ba965f024cfd45638dd6bb49ceae0fa5 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 2 Mar 2021 18:59:04 -0800 Subject: [PATCH 304/924] [google_maps_flutter_web] update min flutter sdk version to 1.20.0 (#3662) --- .../google_maps_flutter/google_maps_flutter_web/CHANGELOG.md | 2 +- .../google_maps_flutter/google_maps_flutter_web/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index f5e289cb19ae..4277d7b02769 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.1.2 -* Add support for Custom Tiles. +* Update min Flutter SDK to 1.20.0. ## 0.1.1 diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index 83ac0fbdde5f..595ca20db78d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -33,4 +33,4 @@ dev_dependencies: environment: sdk: ">=2.3.0 <3.0.0" - flutter: ">=1.10.0" + flutter: ">=1.20.0" From 60d85fdcb24c4b7c3f350073e931077cbf3de30d Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Tue, 2 Mar 2021 19:27:48 -0800 Subject: [PATCH 305/924] Run static analyzer during xctest (#3667) --- .cirrus.yml | 4 +- CONTRIBUTING.md | 2 +- .../tool/lib/src/lint_podspecs_command.dart | 25 +-- script/tool/lib/src/xctest_command.dart | 104 +++++-------- .../tool/test/lint_podspecs_command_test.dart | 43 +----- script/tool/test/xctest_command_test.dart | 145 ++---------------- 6 files changed, 64 insertions(+), 259 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index d7aebddb92cf..ff8cc0ca3ad7 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -179,7 +179,7 @@ task: - name: build-ipas+drive-examples env: PATH: $PATH:/usr/local/bin - PLUGINS_TO_SKIP_XCTESTS: "battery/battery,camera/camera,connectivity/connectivity,device_info/device_info,espresso,google_maps_flutter/google_maps_flutter,google_sign_in/google_sign_in,in_app_purchase,integration_test,ios_platform_images,local_auth,package_info,path_provider/path_provider,sensors,shared_preferences/shared_preferences,url_launcher/url_launcher,video_player/video_player,wifi_info_flutter/wifi_info_flutter" + PLUGINS_TO_SKIP_XCTESTS: "integration_test" matrix: PLUGIN_SHARDING: "--shardIndex 0 --shardCount 4" PLUGIN_SHARDING: "--shardIndex 1 --shardCount 4" @@ -197,7 +197,7 @@ task: - flutter channel $CHANNEL - flutter upgrade - ./script/incremental_build.sh build-examples --ipa - - ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=14.3" + - ./script/incremental_build.sh xctest --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=latest" # `drive-examples` contains integration tests, which changes the UI of the application. # This UI change sometimes affects `xctest`. # So we run `drive-examples` after `xctest`, changing the order will result ci failure. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c4abd0cb516..5a8a9ec5522f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,7 @@ If XCUITests has not been set up for the plugin, follow these steps to set it up 1. Open /example/ios/Runner.xcworkspace using XCode. 1. Create a new "UI Testing Bundle". 1. In the target options window, populate details as following, then click on "Finish". - * In the "product name" field, type in "RunnerUITests" (this is the test target name our CI looks for.). + * In the "product name" field, type in "RunnerUITests". * In the "Team" field, select "None". * In the Organization Name field, type in "Flutter". This should usually be pre-populated. * In the organization identifer field, type in "com.google". This should usually be pre-populated. diff --git a/script/tool/lib/src/lint_podspecs_command.dart b/script/tool/lib/src/lint_podspecs_command.dart index 68fd4b61dd66..b10031162fee 100644 --- a/script/tool/lib/src/lint_podspecs_command.dart +++ b/script/tool/lib/src/lint_podspecs_command.dart @@ -14,8 +14,7 @@ import 'common.dart'; typedef void Print(Object object); -/// Lint the CocoaPod podspecs, run the static analyzer on iOS/macOS plugin -/// platform code, and run unit tests. +/// Lint the CocoaPod podspecs and run unit tests. /// /// See https://guides.cocoapods.org/terminal/commands.html#pod_lib_lint. class LintPodspecsCommand extends PluginCommand { @@ -35,10 +34,6 @@ class LintPodspecsCommand extends PluginCommand { help: 'Do not pass --allow-warnings flag to "pod lib lint" for podspecs with this basename (example: plugins with known warnings)', valueHelp: 'podspec_file_name'); - argParser.addMultiOption('no-analyze', - help: - 'Do not pass --analyze flag to "pod lib lint" for podspecs with this basename (example: plugins with known analyzer warnings)', - valueHelp: 'podspec_file_name'); } @override @@ -102,25 +97,17 @@ class LintPodspecsCommand extends PluginCommand { Future _lintPodspec(File podspec) async { // Do not run the static analyzer on plugins with known analyzer issues. final String podspecPath = podspec.path; - final bool runAnalyzer = !argResults['no-analyze'] - .contains(p.basenameWithoutExtension(podspecPath)); final String podspecBasename = p.basename(podspecPath); - if (runAnalyzer) { - _print('Linting and analyzing $podspecBasename'); - } else { - _print('Linting $podspecBasename'); - } + _print('Linting $podspecBasename'); // Lint plugin as framework (use_frameworks!). - final ProcessResult frameworkResult = await _runPodLint(podspecPath, - runAnalyzer: runAnalyzer, libraryLint: true); + final ProcessResult frameworkResult = await _runPodLint(podspecPath, libraryLint: true); _print(frameworkResult.stdout); _print(frameworkResult.stderr); // Lint plugin as library. - final ProcessResult libraryResult = await _runPodLint(podspecPath, - runAnalyzer: runAnalyzer, libraryLint: false); + final ProcessResult libraryResult = await _runPodLint(podspecPath, libraryLint: false); _print(libraryResult.stdout); _print(libraryResult.stderr); @@ -128,7 +115,7 @@ class LintPodspecsCommand extends PluginCommand { } Future _runPodLint(String podspecPath, - {bool runAnalyzer, bool libraryLint}) async { + {bool libraryLint}) async { final bool allowWarnings = argResults['ignore-warnings'] .contains(p.basenameWithoutExtension(podspecPath)); final List arguments = [ @@ -136,10 +123,10 @@ class LintPodspecsCommand extends PluginCommand { 'lint', podspecPath, if (allowWarnings) '--allow-warnings', - if (runAnalyzer) '--analyze', if (libraryLint) '--use-libraries' ]; + _print('Running "pod ${arguments.join(' ')}"'); return processRunner.run('pod', arguments, workingDir: packagesDir, stdoutEncoding: utf8, stderrEncoding: utf8); } diff --git a/script/tool/lib/src/xctest_command.dart b/script/tool/lib/src/xctest_command.dart index d90b7a8fbfea..a4d03360b292 100644 --- a/script/tool/lib/src/xctest_command.dart +++ b/script/tool/lib/src/xctest_command.dart @@ -12,17 +12,15 @@ import 'package:path/path.dart' as p; import 'common.dart'; const String _kiOSDestination = 'ios-destination'; -const String _kTarget = 'target'; const String _kSkip = 'skip'; const String _kXcodeBuildCommand = 'xcodebuild'; const String _kXCRunCommand = 'xcrun'; const String _kFoundNoSimulatorsMessage = 'Cannot find any available simulators, tests failed'; -/// The command to run iOS' XCTests in plugins, this should work for both XCUnitTest and XCUITest targets. -/// The tests target have to be added to the xcode project of the example app. Usually at "example/ios/Runner.xcodeproj". -/// The command takes a "-target" argument which has to match the target of the test target. -/// For information on how to add test target in an xcode project, see https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/UnitTesting.html +/// The command to run iOS XCTests in plugins, this should work for both XCUnitTest and XCUITest targets. +/// The tests target have to be added to the xcode project of the example app. Usually at "example/ios/Runner.xcworkspace". +/// The static analyzer is also run. class XCTestCommand extends PluginCommand { XCTestCommand( Directory packagesDir, @@ -36,10 +34,6 @@ class XCTestCommand extends PluginCommand { 'this is passed to the `-destination` argument in xcodebuild command.\n' 'See https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT for details on how to specify the destination.', ); - argParser.addOption(_kTarget, - help: 'The test target.\n' - 'This is the xcode project test target. This is passed to the `-scheme` argument in the xcodebuild command. \n' - 'See https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT for details on how to specify the scheme'); argParser.addMultiOption(_kSkip, help: 'Plugins to skip while running this command. \n'); } @@ -49,17 +43,10 @@ class XCTestCommand extends PluginCommand { @override final String description = 'Runs the xctests in the iOS example apps.\n\n' - 'This command requires "flutter" to be in your path.'; + 'This command requires "flutter" and "xcrun" to be in your path.'; @override Future run() async { - if (argResults[_kTarget] == null) { - // TODO(cyanglaz): Automatically find all the available testing schemes if this argument is not specified. - // https://github.com/flutter/flutter/issues/68419 - print('--$_kTarget must be specified'); - throw ToolExit(1); - } - String destination = argResults[_kiOSDestination]; if (destination == null) { String simulatorId = await _findAvailableIphoneSimulator(); @@ -72,7 +59,6 @@ class XCTestCommand extends PluginCommand { checkSharding(); - final String target = argResults[_kTarget]; final List skipped = argResults[_kSkip]; List failingPackages = []; @@ -92,57 +78,14 @@ class XCTestCommand extends PluginCommand { continue; } for (Directory example in getExamplesForPlugin(plugin)) { - // Look for the test scheme in the example app. - print('Look for target named: $_kTarget ...'); - final List findSchemeArgs = [ - '-project', - 'ios/Runner.xcodeproj', - '-list', - '-json' - ]; - final String completeFindSchemeCommand = - '$_kXcodeBuildCommand ${findSchemeArgs.join(' ')}'; - print(completeFindSchemeCommand); - final io.ProcessResult xcodeprojListResult = await processRunner - .run(_kXcodeBuildCommand, findSchemeArgs, workingDir: example); - if (xcodeprojListResult.exitCode != 0) { - print('Error occurred while running "$completeFindSchemeCommand":\n' - '${xcodeprojListResult.stderr}'); - failingPackages.add(packageName); - print('\n\n'); - continue; - } - - final String xcodeprojListOutput = xcodeprojListResult.stdout; - Map xcodeprojListOutputJson = - jsonDecode(xcodeprojListOutput); - if (!xcodeprojListOutputJson['project']['targets'].contains(target)) { - failingPackages.add(packageName); - print('$target not configured for $packageName, test failed.'); - print( - 'Please check the scheme for the test target if it matches the name $target.\n' - 'If this plugin does not have an XCTest target, use the $_kSkip flag in the $name command to skip the plugin.'); - print('\n\n'); - continue; + // Running tests and static analyzer. + print('Running tests and analyzer for $packageName ...'); + int exitCode = await _runTests(true, destination, example); + // 66 = there is no test target (this fails fast). Try again with just the analyzer. + if (exitCode == 66) { + print('Tests not found for $packageName, running analyzer only...'); + exitCode = await _runTests(false, destination, example); } - // Found the scheme, running tests - print('Running XCTests:$target for $packageName ...'); - final List xctestArgs = [ - 'test', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - target, - '-destination', - destination, - 'CODE_SIGN_IDENTITY=""', - 'CODE_SIGNING_REQUIRED=NO' - ]; - final String completeTestCommand = - '$_kXcodeBuildCommand ${xctestArgs.join(' ')}'; - print(completeTestCommand); - final int exitCode = await processRunner - .runAndStream(_kXcodeBuildCommand, xctestArgs, workingDir: example); if (exitCode == 0) { print('Successfully ran xctest for $packageName'); } else { @@ -164,6 +107,31 @@ class XCTestCommand extends PluginCommand { } } + Future _runTests(bool runTests, String destination, Directory example) { + final List xctestArgs = [ + _kXcodeBuildCommand, + if (runTests) + 'test', + 'analyze', + '-workspace', + 'ios/Runner.xcworkspace', + '-configuration', + 'Debug', + '-scheme', + 'Runner', + '-destination', + destination, + 'CODE_SIGN_IDENTITY=""', + 'CODE_SIGNING_REQUIRED=NO', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ]; + final String completeTestCommand = + '$_kXCRunCommand ${xctestArgs.join(' ')}'; + print(completeTestCommand); + return processRunner + .runAndStream(_kXCRunCommand, xctestArgs, workingDir: example, exitOnError: false); + } + Future _findAvailableIphoneSimulator() async { // Find the first available destination if not specified. final List findSimulatorsArguments = [ diff --git a/script/tool/test/lint_podspecs_command_test.dart b/script/tool/test/lint_podspecs_command_test.dart index 49d6ad4d8e20..1014dcd170be 100644 --- a/script/tool/test/lint_podspecs_command_test.dart +++ b/script/tool/test/lint_podspecs_command_test.dart @@ -81,7 +81,6 @@ void main() { 'lib', 'lint', p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'), - '--analyze', '--use-libraries' ], mockPackagesDir.path), @@ -91,14 +90,13 @@ void main() { 'lib', 'lint', p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'), - '--analyze', ], mockPackagesDir.path), ]), ); expect( - printedMessages, contains('Linting and analyzing plugin1.podspec')); + printedMessages, contains('Linting plugin1.podspec')); expect(printedMessages, contains('Foo')); expect(printedMessages, contains('Bar')); }); @@ -122,41 +120,6 @@ void main() { ); }); - test('skips analyzer for podspecs with known warnings', () async { - Directory plugin1Dir = - createFakePlugin('plugin1', withExtraFiles: >[ - ['plugin1.podspec'], - ]); - - await runner.run(['podspecs', '--no-analyze=plugin1']); - - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('which', ['pod'], mockPackagesDir.path), - ProcessCall( - 'pod', - [ - 'lib', - 'lint', - p.join(plugin1Dir.path, 'plugin1.podspec'), - '--use-libraries' - ], - mockPackagesDir.path), - ProcessCall( - 'pod', - [ - 'lib', - 'lint', - p.join(plugin1Dir.path, 'plugin1.podspec'), - ], - mockPackagesDir.path), - ]), - ); - - expect(printedMessages, contains('Linting plugin1.podspec')); - }); - test('allow warnings for podspecs with known warnings', () async { Directory plugin1Dir = createFakePlugin('plugin1', withExtraFiles: >[ @@ -176,7 +139,6 @@ void main() { 'lint', p.join(plugin1Dir.path, 'plugin1.podspec'), '--allow-warnings', - '--analyze', '--use-libraries' ], mockPackagesDir.path), @@ -187,14 +149,13 @@ void main() { 'lint', p.join(plugin1Dir.path, 'plugin1.podspec'), '--allow-warnings', - '--analyze', ], mockPackagesDir.path), ]), ); expect( - printedMessages, contains('Linting and analyzing plugin1.podspec')); + printedMessages, contains('Linting plugin1.podspec')); }); }); } diff --git a/script/tool/test/xctest_command_test.dart b/script/tool/test/xctest_command_test.dart index 007c2e12188c..2b75ccde4210 100644 --- a/script/tool/test/xctest_command_test.dart +++ b/script/tool/test/xctest_command_test.dart @@ -8,7 +8,6 @@ import 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:flutter_plugin_tools/src/xctest_command.dart'; import 'package:test/test.dart'; -import 'package:flutter_plugin_tools/src/common.dart'; import 'mocks.dart'; import 'util.dart'; @@ -81,7 +80,6 @@ final _kDeviceListMap = { void main() { const String _kDestination = '--ios-destination'; - const String _kTarget = '--target'; const String _kSkip = '--skip'; group('test xctest_command', () { @@ -100,12 +98,6 @@ void main() { cleanupPackages(); }); - test('Not specifying --target throws', () async { - await expectLater( - () => runner.run(['xctest', _kDestination, 'a_destination']), - throwsA(const TypeMatcher())); - }); - test('skip if ios is not supported', () async { createFakePlugin('plugin', withExtraFiles: >[ @@ -123,8 +115,6 @@ void main() { processRunner.processToReturn = mockProcess; final List output = await runCapturingPrint(runner, [ 'xctest', - _kTarget, - 'foo_scheme', _kDestination, 'foo_destination' ]); @@ -134,106 +124,7 @@ void main() { cleanupPackages(); }); - test('running with correct scheme and destination, did not find scheme', - () async { - createFakePlugin('plugin', - withExtraFiles: >[ - ['example', 'test'], - ], - isIosPlugin: true); - - final Directory pluginExampleDirectory = - mockPackagesDir.childDirectory('plugin').childDirectory('example'); - - createFakePubspec(pluginExampleDirectory, isFlutter: true); - - final MockProcess mockProcess = MockProcess(); - mockProcess.exitCodeCompleter.complete(0); - processRunner.processToReturn = mockProcess; - processRunner.resultStdout = '{"project":{"targets":["bar_scheme"]}}'; - - await expectLater(() async { - final List output = await runCapturingPrint(runner, [ - 'xctest', - _kTarget, - 'foo_scheme', - _kDestination, - 'foo_destination' - ]); - expect(output, - contains('foo_scheme not configured for plugin, test failed.')); - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('xcrun', ['simctl', 'list', '--json'], null), - ProcessCall( - 'xcodebuild', - [ - '-project', - 'ios/Runner.xcodeproj', - '-list', - '-json' - ], - pluginExampleDirectory.path), - ])); - }, throwsA(const TypeMatcher())); - cleanupPackages(); - }); - - test('running with correct scheme and destination, found scheme', () async { - createFakePlugin('plugin', - withExtraFiles: >[ - ['example', 'test'], - ], - isIosPlugin: true); - - final Directory pluginExampleDirectory = - mockPackagesDir.childDirectory('plugin').childDirectory('example'); - - createFakePubspec(pluginExampleDirectory, isFlutter: true); - - final MockProcess mockProcess = MockProcess(); - mockProcess.exitCodeCompleter.complete(0); - processRunner.processToReturn = mockProcess; - processRunner.resultStdout = - '{"project":{"targets":["bar_scheme", "foo_scheme"]}}'; - List output = await runCapturingPrint(runner, [ - 'xctest', - _kTarget, - 'foo_scheme', - _kDestination, - 'foo_destination' - ]); - - expect(output, contains('Successfully ran xctest for plugin')); - - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcodebuild', - ['-project', 'ios/Runner.xcodeproj', '-list', '-json'], - pluginExampleDirectory.path), - ProcessCall( - 'xcodebuild', - [ - 'test', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'foo_scheme', - '-destination', - 'foo_destination', - 'CODE_SIGN_IDENTITY=""', - 'CODE_SIGNING_REQUIRED=NO' - ], - pluginExampleDirectory.path), - ])); - - cleanupPackages(); - }); - - test('running with correct scheme and destination, skip 1 plugin', + test('running with correct destination, skip 1 plugin', () async { createFakePlugin('plugin1', withExtraFiles: >[ @@ -260,8 +151,6 @@ void main() { '{"project":{"targets":["bar_scheme", "foo_scheme"]}}'; List output = await runCapturingPrint(runner, [ 'xctest', - _kTarget, - 'foo_scheme', _kDestination, 'foo_destination', _kSkip, @@ -275,21 +164,22 @@ void main() { processRunner.recordedCalls, orderedEquals([ ProcessCall( - 'xcodebuild', - ['-project', 'ios/Runner.xcodeproj', '-list', '-json'], - pluginExampleDirectory2.path), - ProcessCall( - 'xcodebuild', + 'xcrun', [ + 'xcodebuild', 'test', + 'analyze', '-workspace', 'ios/Runner.xcworkspace', + '-configuration', + 'Debug', '-scheme', - 'foo_scheme', + 'Runner', '-destination', 'foo_destination', 'CODE_SIGN_IDENTITY=""', - 'CODE_SIGNING_REQUIRED=NO' + 'CODE_SIGNING_REQUIRED=NO', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', ], pluginExampleDirectory2.path), ])); @@ -324,8 +214,6 @@ void main() { jsonEncode(schemeCommandResult..addAll(_kDeviceListMap)); await runner.run([ 'xctest', - _kTarget, - 'foo_scheme', ]); expect( @@ -333,21 +221,22 @@ void main() { orderedEquals([ ProcessCall('xcrun', ['simctl', 'list', '--json'], null), ProcessCall( - 'xcodebuild', - ['-project', 'ios/Runner.xcodeproj', '-list', '-json'], - pluginExampleDirectory.path), - ProcessCall( - 'xcodebuild', + 'xcrun', [ + 'xcodebuild', 'test', + 'analyze', '-workspace', 'ios/Runner.xcworkspace', + '-configuration', + 'Debug', '-scheme', - 'foo_scheme', + 'Runner', '-destination', 'id=1E76A0FD-38AC-4537-A989-EA639D7D012A', 'CODE_SIGN_IDENTITY=""', - 'CODE_SIGNING_REQUIRED=NO' + 'CODE_SIGNING_REQUIRED=NO', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', ], pluginExampleDirectory.path), ])); From 025c8c199b3a0aad7c886b1288b94cf4bddf4de2 Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Wed, 3 Mar 2021 10:56:12 -0800 Subject: [PATCH 306/924] Adopt Xcode 12 for podspec lints (#3653) --- .cirrus.yml | 20 ------------------- .../tool/lib/src/lint_podspecs_command.dart | 1 + .../tool/test/lint_podspecs_command_test.dart | 4 ++++ 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index ff8cc0ca3ad7..924cb63492a0 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -202,26 +202,6 @@ task: # This UI change sometimes affects `xctest`. # So we run `drive-examples` after `xctest`, changing the order will result ci failure. - ./script/incremental_build.sh drive-examples --ios - -task: - # Xcode 11 task - # TODO(cyanglaz): merge Xcode 11 task to Xcode 12 task when all the matrix can be run in Xcode 12. - # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins - only_if: $CIRRUS_TAG == '' - use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' - osx_instance: - image: catalina-xcode-11.3.1-flutter - upgrade_script: - - sudo gem install cocoapods - - flutter channel stable - - flutter upgrade - - flutter channel master - - flutter upgrade - - git fetch origin master - create_simulator_script: - - xcrun simctl list - - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot - matrix: - name: lint_darwin_plugins env: matrix: diff --git a/script/tool/lib/src/lint_podspecs_command.dart b/script/tool/lib/src/lint_podspecs_command.dart index b10031162fee..749d67ee5f16 100644 --- a/script/tool/lib/src/lint_podspecs_command.dart +++ b/script/tool/lib/src/lint_podspecs_command.dart @@ -122,6 +122,7 @@ class LintPodspecsCommand extends PluginCommand { 'lib', 'lint', podspecPath, + '--configuration=Debug', // Release targets unsupported arm64 simulators. Use Debug to only build against targeted x86_64 simulator devices. if (allowWarnings) '--allow-warnings', if (libraryLint) '--use-libraries' ]; diff --git a/script/tool/test/lint_podspecs_command_test.dart b/script/tool/test/lint_podspecs_command_test.dart index 1014dcd170be..e0411d5cffd1 100644 --- a/script/tool/test/lint_podspecs_command_test.dart +++ b/script/tool/test/lint_podspecs_command_test.dart @@ -81,6 +81,7 @@ void main() { 'lib', 'lint', p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'), + '--configuration=Debug', '--use-libraries' ], mockPackagesDir.path), @@ -90,6 +91,7 @@ void main() { 'lib', 'lint', p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'), + '--configuration=Debug', ], mockPackagesDir.path), ]), @@ -138,6 +140,7 @@ void main() { 'lib', 'lint', p.join(plugin1Dir.path, 'plugin1.podspec'), + '--configuration=Debug', '--allow-warnings', '--use-libraries' ], @@ -148,6 +151,7 @@ void main() { 'lib', 'lint', p.join(plugin1Dir.path, 'plugin1.podspec'), + '--configuration=Debug', '--allow-warnings', ], mockPackagesDir.path), From bc2514ebd824adb1c85709e53bc57235af7b5212 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Wed, 3 Mar 2021 15:07:07 -0800 Subject: [PATCH 307/924] [google_maps_flutter_web] Make google_maps_flutter_web work with latest plugins (#3673) Co-authored-by: David Iglesias Teixeira --- .../google_maps_flutter_web/CHANGELOG.md | 7 + .../lib/src/convert.dart | 167 ++---------------- .../lib/src/google_maps_controller.dart | 61 ++++--- .../lib/src/google_maps_flutter_web.dart | 54 ++++-- .../google_maps_flutter_web/pubspec.yaml | 16 +- .../google_maps_controller_integration.dart | 154 ++++++++-------- .../google_maps_plugin_integration.dart | 49 +++-- script/nnbd_plugins.sh | 4 +- 8 files changed, 224 insertions(+), 288 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 4277d7b02769..826f1ea53023 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.2.0 + +* Make this plugin compatible with the rest of null-safe plugins. +* Noop tile overlays methods, so they don't crash on web. + +**NOTE**: This plugin is **not** null-safe yet! + ## 0.1.2 * Update min Flutter SDK to 1.20.0. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index 95f481a9bdc5..5212679fb5fe 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -11,8 +11,6 @@ final _nullLatLngBounds = LatLngBounds( ); // Defaults taken from the Google Maps Platform SDK documentation. -final _defaultStrokeColor = Colors.black.value; -final _defaultFillColor = Colors.transparent.value; final _defaultCssColor = '#000000'; final _defaultCssOpacity = 0.0; @@ -59,41 +57,39 @@ double _getCssOpacity(Color color) { // buildingsEnabled seems to not have an equivalent in web // padding seems to behave differently in web than mobile. You can't move UI elements in web. gmaps.MapOptions _rawOptionsToGmapsOptions(Map rawOptions) { - Map optionsUpdate = rawOptions['options'] ?? {}; - gmaps.MapOptions options = gmaps.MapOptions(); - if (_mapTypeToMapTypeId.containsKey(optionsUpdate['mapType'])) { - options.mapTypeId = _mapTypeToMapTypeId[optionsUpdate['mapType']]; + if (_mapTypeToMapTypeId.containsKey(rawOptions['mapType'])) { + options.mapTypeId = _mapTypeToMapTypeId[rawOptions['mapType']]; } - if (optionsUpdate['minMaxZoomPreference'] != null) { + if (rawOptions['minMaxZoomPreference'] != null) { options - ..minZoom = optionsUpdate['minMaxZoomPreference'][0] - ..maxZoom = optionsUpdate['minMaxZoomPreference'][1]; + ..minZoom = rawOptions['minMaxZoomPreference'][0] + ..maxZoom = rawOptions['minMaxZoomPreference'][1]; } - if (optionsUpdate['cameraTargetBounds'] != null) { + if (rawOptions['cameraTargetBounds'] != null) { // Needs gmaps.MapOptions.restriction and gmaps.MapRestriction // see: https://developers.google.com/maps/documentation/javascript/reference/map#MapOptions.restriction } - if (optionsUpdate['zoomControlsEnabled'] != null) { - options.zoomControl = optionsUpdate['zoomControlsEnabled']; + if (rawOptions['zoomControlsEnabled'] != null) { + options.zoomControl = rawOptions['zoomControlsEnabled']; } - if (optionsUpdate['styles'] != null) { - options.styles = optionsUpdate['styles']; + if (rawOptions['styles'] != null) { + options.styles = rawOptions['styles']; } - if (optionsUpdate['scrollGesturesEnabled'] == false || - optionsUpdate['zoomGesturesEnabled'] == false) { + if (rawOptions['scrollGesturesEnabled'] == false || + rawOptions['zoomGesturesEnabled'] == false) { options.gestureHandling = 'none'; } else { options.gestureHandling = 'auto'; } - // These don't have any optionUpdate entry, but they seem to be off in the native maps. + // These don't have any rawOptions entry, but they seem to be off in the native maps. options.mapTypeControl = false; options.fullscreenControl = false; options.streetViewControl = false; @@ -102,26 +98,21 @@ gmaps.MapOptions _rawOptionsToGmapsOptions(Map rawOptions) { } gmaps.MapOptions _applyInitialPosition( - Map rawOptions, + CameraPosition initialPosition, gmaps.MapOptions options, ) { // Adjust the initial position, if passed... - Map initialPosition = rawOptions['initialCameraPosition']; if (initialPosition != null) { - final position = CameraPosition.fromMap(initialPosition); - options.zoom = position.zoom; - options.center = - gmaps.LatLng(position.target.latitude, position.target.longitude); + options.zoom = initialPosition.zoom; + options.center = gmaps.LatLng( + initialPosition.target.latitude, initialPosition.target.longitude); } return options; } // Extracts the status of the traffic layer from the rawOptions map. bool _isTrafficLayerEnabled(Map rawOptions) { - if (rawOptions['options'] == null) { - return false; - } - return rawOptions['options']['trafficEnabled'] ?? false; + return rawOptions['trafficEnabled'] ?? false; } // Coverts the incoming JSON object into a List of MapTypeStyler objects. @@ -257,126 +248,6 @@ CameraPosition _gmViewportToCameraPosition(gmaps.GMap map) { ); } -Set _rawOptionsToInitialMarkers(Map rawOptions) { - final List> list = rawOptions['markersToAdd']; - Set markers = {}; - markers.addAll(list?.map((rawMarker) { - Offset offset; - LatLng position; - InfoWindow infoWindow; - BitmapDescriptor icon; - if (rawMarker['anchor'] != null) { - offset = Offset((rawMarker['anchor'][0]), (rawMarker['anchor'][1])); - } - if (rawMarker['position'] != null) { - position = LatLng.fromJson(rawMarker['position']); - } - if (rawMarker['infoWindow'] != null) { - final String title = rawMarker['infoWindow']['title']; - final String snippet = rawMarker['infoWindow']['snippet']; - if (title != null || snippet != null) { - infoWindow = InfoWindow( - title: title ?? '', - snippet: snippet ?? '', - ); - } - } - if (rawMarker['icon'] != null) { - icon = BitmapDescriptor.fromJson(rawMarker['icon']); - } - return Marker( - markerId: MarkerId(rawMarker['markerId']), - alpha: rawMarker['alpha'], - anchor: offset, - consumeTapEvents: rawMarker['consumeTapEvents'], - draggable: rawMarker['draggable'], - flat: rawMarker['flat'], - icon: icon, - infoWindow: infoWindow, - position: position ?? _nullLatLng, - rotation: rawMarker['rotation'], - visible: rawMarker['visible'], - zIndex: rawMarker['zIndex'], - ); - }) ?? - []); - return markers; -} - -Set _rawOptionsToInitialCircles(Map rawOptions) { - final List> list = rawOptions['circlesToAdd']; - Set circles = {}; - circles.addAll(list?.map((rawCircle) { - LatLng center; - if (rawCircle['center'] != null) { - center = LatLng.fromJson(rawCircle['center']); - } - return Circle( - circleId: CircleId(rawCircle['circleId']), - consumeTapEvents: rawCircle['consumeTapEvents'], - fillColor: Color(rawCircle['fillColor'] ?? _defaultFillColor), - center: center ?? _nullLatLng, - radius: rawCircle['radius'], - strokeColor: Color(rawCircle['strokeColor'] ?? _defaultStrokeColor), - strokeWidth: rawCircle['strokeWidth'], - visible: rawCircle['visible'], - zIndex: rawCircle['zIndex'], - ); - }) ?? - []); - return circles; -} - -// Unsupported on the web: endCap, jointType, patterns and startCap. -Set _rawOptionsToInitialPolylines(Map rawOptions) { - final List> list = rawOptions['polylinesToAdd']; - Set polylines = {}; - polylines.addAll(list?.map((rawPolyline) { - return Polyline( - polylineId: PolylineId(rawPolyline['polylineId']), - consumeTapEvents: rawPolyline['consumeTapEvents'], - color: Color(rawPolyline['color'] ?? _defaultStrokeColor), - geodesic: rawPolyline['geodesic'], - visible: rawPolyline['visible'], - zIndex: rawPolyline['zIndex'], - width: rawPolyline['width'], - points: rawPolyline['points'] - ?.map((rawPoint) => LatLng.fromJson(rawPoint)) - ?.toList(), - ); - }) ?? - []); - return polylines; -} - -Set _rawOptionsToInitialPolygons(Map rawOptions) { - final List> list = rawOptions['polygonsToAdd']; - Set polygons = {}; - - polygons.addAll(list?.map((rawPolygon) { - return Polygon( - polygonId: PolygonId(rawPolygon['polygonId']), - consumeTapEvents: rawPolygon['consumeTapEvents'], - fillColor: Color(rawPolygon['fillColor'] ?? _defaultFillColor), - geodesic: rawPolygon['geodesic'], - strokeColor: Color(rawPolygon['strokeColor'] ?? _defaultStrokeColor), - strokeWidth: rawPolygon['strokeWidth'], - visible: rawPolygon['visible'], - zIndex: rawPolygon['zIndex'], - points: rawPolygon['points'] - ?.map((rawPoint) => LatLng.fromJson(rawPoint)) - ?.toList(), - holes: rawPolygon['holes'] - ?.map>((List hole) => hole - ?.map((rawPoint) => LatLng.fromJson(rawPoint)) - ?.toList()) - ?.toList(), - ); - }) ?? - []); - return polygons; -} - // Convert plugin objects to gmaps.Options objects // TODO: Move to their appropriate objects, maybe make these copy constructors: // Marker.fromMarker(anotherMarker, moreOptions); @@ -550,7 +421,7 @@ gmaps.PolylineOptions _polylineOptionsFromPolyline( // Translates a [CameraUpdate] into operations on a [gmaps.GMap]. void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { - final json = update.toJson(); + final json = update.toJson() as List; switch (json[0]) { case 'newCameraPosition': map.heading = json[1]['bearing']; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart index 8195473ee6ba..a119f2aab9f2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart @@ -14,11 +14,14 @@ class GoogleMapController { // The internal ID of the map. Used to broadcast events, DOM IDs and everything where a unique ID is needed. final int _mapId; + final CameraPosition _initialCameraPosition; + final Set _markers; + final Set _polygons; + final Set _polylines; + final Set _circles; // The raw options passed by the user, before converting to gmaps. // Caching this allows us to re-create the map faithfully when needed. - Map _rawOptions = { - 'options': {}, - }; + Map _rawMapOptions = {}; // Creates the 'viewType' for the _widget String _getViewType(int mapId) => 'plugins.flutter.io/google_maps_$mapId'; @@ -68,10 +71,23 @@ class GoogleMapController { GoogleMapController({ @required int mapId, @required StreamController streamController, - @required Map rawOptions, - }) : this._mapId = mapId, - this._streamController = streamController, - this._rawOptions = rawOptions { + @required CameraPosition initialCameraPosition, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set> gestureRecognizers = + const >{}, + Map mapOptions = const {}, + }) : _mapId = mapId, + _streamController = streamController, + _initialCameraPosition = initialCameraPosition, + _markers = markers, + _polygons = polygons, + _polylines = polylines, + _circles = circles, + _rawMapOptions = mapOptions { _circlesController = CirclesController(stream: this._streamController); _polygonsController = PolygonsController(stream: this._streamController); _polylinesController = PolylinesController(stream: this._streamController); @@ -121,9 +137,9 @@ class GoogleMapController { /// Failure to call this method would result in the GMap not rendering at all, /// and most of the public methods on this class no-op'ing. void init() { - var options = _rawOptionsToGmapsOptions(_rawOptions); + var options = _rawOptionsToGmapsOptions(_rawMapOptions); // Initial position can only to be set here! - options = _applyInitialPosition(_rawOptions, options); + options = _applyInitialPosition(_initialCameraPosition, options); // Create the map... _googleMap = _createMap(_div, options); @@ -132,13 +148,13 @@ class GoogleMapController { _attachGeometryControllers(_googleMap); _renderInitialGeometry( - markers: _rawOptionsToInitialMarkers(_rawOptions), - circles: _rawOptionsToInitialCircles(_rawOptions), - polygons: _rawOptionsToInitialPolygons(_rawOptions), - polylines: _rawOptionsToInitialPolylines(_rawOptions), + markers: _markers, + circles: _circles, + polygons: _polygons, + polylines: _polylines, ); - _setTrafficLayer(_googleMap, _isTrafficLayerEnabled(_rawOptions)); + _setTrafficLayer(_googleMap, _isTrafficLayerEnabled(_rawMapOptions)); } // Funnels map gmap events into the plugin's stream controller. @@ -196,20 +212,15 @@ class GoogleMapController { _polylinesController.addPolylines(polylines); } - // Merges new options coming from the plugin into the `key` entry of the _rawOptions map. + // Merges new options coming from the plugin into the _rawMapOptions map. // - // By default: `key` is 'options'. - // - // Returns the updated _rawOptions object. - Map _mergeRawOptions( - Map newOptions, { - String key = 'options', - }) { - _rawOptions[key] = { - ...(_rawOptions[key] ?? {}), + // Returns the updated _rawMapOptions object. + Map _mergeRawOptions(Map newOptions) { + _rawMapOptions = { + ..._rawMapOptions, ...newOptions, }; - return _rawOptions; + return _rawMapOptions; } /// Updates the map options from a `Map`. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart index cf549e8e375e..cb2a8aa238f9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart @@ -86,6 +86,22 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { _map(mapId).updateCircles(circleUpdates); } + @override + Future updateTileOverlays({ + @required Set newTileOverlays, + @required int mapId, + }) async { + return; // Noop for now! + } + + @override + Future clearTileCache( + TileOverlayId tileOverlayId, { + @required int mapId, + }) async { + return; // Noop for now! + } + /// Applies the given `cameraUpdate` to the current viewport (with animation). @override Future animateCamera( @@ -260,31 +276,43 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Widget buildView( - Map creationParams, - Set> gestureRecognizers, - PlatformViewCreatedCallback onPlatformViewCreated) { - int mapId = creationParams.remove('_webOnlyMapCreationId'); - - assert(mapId != null, + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + @required CameraPosition initialCameraPosition, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set> gestureRecognizers = + const >{}, + Map mapOptions = const {}, + }) { + assert(creationId != null, 'buildView needs a `_webOnlyMapCreationId` in its creationParams to prevent widget reloads in web.'); - // Bail fast if we've already rendered this mapId... - if (_mapById[mapId]?.widget != null) { - return _mapById[mapId].widget; + // Bail fast if we've already rendered this map ID... + if (_mapById[creationId]?.widget != null) { + return _mapById[creationId].widget; } final StreamController controller = StreamController.broadcast(); final mapController = GoogleMapController( - mapId: mapId, + initialCameraPosition: initialCameraPosition, + mapId: creationId, streamController: controller, - rawOptions: creationParams, + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + mapOptions: mapOptions, ); - _mapById[mapId] = mapController; + _mapById[creationId] = mapController; - onPlatformViewCreated.call(mapId); + onPlatformViewCreated.call(creationId); return mapController.widget; } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index 595ca20db78d..20d078284742 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.1.2 +version: 0.2.0 flutter: plugin: @@ -15,19 +15,19 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - meta: ^1.1.7 - google_maps_flutter_platform_interface: ^1.1.0 + meta: ^1.3.0 + google_maps_flutter_platform_interface: ^2.0.1 google_maps: ^3.4.5 - stream_transform: ^1.2.0 - sanitize_html: ^1.4.1 + stream_transform: ^2.0.0 + sanitize_html: ^2.0.0 dev_dependencies: flutter_test: sdk: flutter - http: ^0.12.2 - url_launcher: ^5.2.5 + http: ^0.13.0 + url_launcher: ^6.0.2 pedantic: ^1.8.0 - mockito: ^4.1.1 + mockito: ^5.0.0 integration_test: path: ../../integration_test diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart index 302057f0ea57..0eca5b82d922 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart @@ -50,11 +50,24 @@ void main() { StreamController stream; // Creates a controller with the default mapId and stream controller, and any `options` needed. - GoogleMapController _createController({Map options}) { + GoogleMapController _createController({ + CameraPosition initialCameraPosition = + const CameraPosition(target: LatLng(0, 0)), + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Map options, + }) { return GoogleMapController( mapId: mapId, streamController: stream, - rawOptions: options ?? {}); + initialCameraPosition: initialCameraPosition, + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + mapOptions: options ?? {}); } setUp(() { @@ -143,58 +156,45 @@ void main() { }); testWidgets('renders initial geometry', (WidgetTester tester) async { - controller = _createController(options: { - 'circlesToAdd': [ - {'circleId': 'circle-1'} - ], - 'markersToAdd': [ - { - 'markerId': 'marker-1', - 'infoWindow': { - 'title': 'title for test', - 'snippet': 'snippet for test', - }, - }, - ], - 'polygonsToAdd': [ - { - 'polygonId': 'polygon-1', - 'points': [ - [43.355114, -5.851333], - [43.354797, -5.851860], - [43.354469, -5.851318], - [43.354762, -5.850824], - ], - }, - { - 'polygonId': 'polygon-2-with-holes', - 'points': [ - [43.355114, -5.851333], - [43.354797, -5.851860], - [43.354469, -5.851318], - [43.354762, -5.850824], - ], - 'holes': [ - [ - [41.354797, -6.851860], - [41.354469, -6.851318], - [41.354762, -6.850824], - ] + controller = _createController(circles: { + Circle(circleId: CircleId('circle-1')) + }, markers: { + Marker( + markerId: MarkerId('marker-1'), + infoWindow: InfoWindow( + title: 'title for test', snippet: 'snippet for test')) + }, polygons: { + Polygon(polygonId: PolygonId('polygon-1'), points: [ + LatLng(43.355114, -5.851333), + LatLng(43.354797, -5.851860), + LatLng(43.354469, -5.851318), + LatLng(43.354762, -5.850824), + ]), + Polygon( + polygonId: PolygonId('polygon-2-with-holes'), + points: [ + LatLng(43.355114, -5.851333), + LatLng(43.354797, -5.851860), + LatLng(43.354469, -5.851318), + LatLng(43.354762, -5.850824), + ], + holes: [ + [ + LatLng(41.354797, -6.851860), + LatLng(41.354469, -6.851318), + LatLng(41.354762, -6.850824), ] - }, - ], - 'polylinesToAdd': [ - { - 'polylineId': 'polyline-1', - 'points': [ - [43.355114, -5.851333], - [43.354797, -5.851860], - [43.354469, -5.851318], - [43.354762, -5.850824], - ], - }, - ], + ], + ), + }, polylines: { + Polyline(polylineId: PolylineId('polyline-1'), points: [ + LatLng(43.355114, -5.851333), + LatLng(43.354797, -5.851860), + LatLng(43.354469, -5.851318), + LatLng(43.354762, -5.850824), + ]) }); + controller.debugSetOverrides( circles: circles, markers: markers, @@ -226,14 +226,10 @@ void main() { testWidgets('empty infoWindow does not create InfoWindow instance.', (WidgetTester tester) async { - controller = _createController(options: { - 'markersToAdd': [ - { - 'markerId': 'marker-1', - 'infoWindow': {}, - }, - ], + controller = _createController(markers: { + Marker(markerId: MarkerId('marker-1'), infoWindow: null), }); + controller.debugSetOverrides( markers: markers, ); @@ -253,10 +249,8 @@ void main() { }); testWidgets('translates initial options', (WidgetTester tester) async { controller = _createController(options: { - 'options': { - 'mapType': 2, - 'zoomControlsEnabled': true, - } + 'mapType': 2, + 'zoomControlsEnabled': true, }); controller.debugSetOverrides(createMap: (_, options) { capturedOptions = options; @@ -276,9 +270,7 @@ void main() { testWidgets('disables gestureHandling with scrollGesturesEnabled false', (WidgetTester tester) async { controller = _createController(options: { - 'options': { - 'scrollGesturesEnabled': false, - } + 'scrollGesturesEnabled': false, }); controller.debugSetOverrides(createMap: (_, options) { capturedOptions = options; @@ -296,9 +288,7 @@ void main() { testWidgets('disables gestureHandling with zoomGesturesEnabled false', (WidgetTester tester) async { controller = _createController(options: { - 'options': { - 'zoomGesturesEnabled': false, - } + 'zoomGesturesEnabled': false, }); controller.debugSetOverrides(createMap: (_, options) { capturedOptions = options; @@ -315,7 +305,10 @@ void main() { testWidgets('does not set initial position if absent', (WidgetTester tester) async { - controller = _createController(); + controller = _createController( + initialCameraPosition: null, + ); + controller.debugSetOverrides(createMap: (_, options) { capturedOptions = options; return map; @@ -330,14 +323,15 @@ void main() { testWidgets('sets initial position when passed', (WidgetTester tester) async { - controller = _createController(options: { - 'initialCameraPosition': { - 'target': [43.308, -5.6910], - 'zoom': 12, - 'bearing': 0, - 'tilt': 0, - } - }); + controller = _createController( + initialCameraPosition: CameraPosition( + target: LatLng(43.308, -5.6910), + zoom: 12, + bearing: 0, + tilt: 0, + ), + ); + controller.debugSetOverrides(createMap: (_, options) { capturedOptions = options; return map; @@ -361,9 +355,7 @@ void main() { testWidgets('initializes with traffic layer', (WidgetTester tester) async { controller = _createController(options: { - 'options': { - 'trafficEnabled': true, - } + 'trafficEnabled': true, }); controller.debugSetOverrides(createMap: (_, __) => map); controller.init(); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart index 6276d26753a4..f0cae1dcdaf6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart @@ -70,11 +70,16 @@ void main() { group('buildView', () { final testMapId = 33930; + final initialCameraPosition = CameraPosition(target: LatLng(0, 0)); testWidgets('throws without _webOnlyMapCreationId', (WidgetTester tester) async { expect( - () => plugin.buildView({}, null, onPlatformViewCreated), + () => plugin.buildView( + null, + onPlatformViewCreated, + initialCameraPosition: initialCameraPosition, + ), throwsAssertionError, reason: '_webOnlyMapCreationId is mandatory to prevent unnecessary reloads in web.', @@ -87,9 +92,11 @@ void main() { final Map cache = {}; plugin.debugSetMapById(cache); - final HtmlElementView widget = plugin.buildView({ - '_webOnlyMapCreationId': testMapId, - }, null, onPlatformViewCreated); + final HtmlElementView widget = plugin.buildView( + testMapId, + onPlatformViewCreated, + initialCameraPosition: initialCameraPosition, + ); expect( widget.viewType, @@ -116,9 +123,11 @@ void main() { when(controller.widget).thenReturn(expected); plugin.debugSetMapById({testMapId: controller}); - final widget = plugin.buildView({ - '_webOnlyMapCreationId': testMapId, - }, null, onPlatformViewCreated); + final widget = plugin.buildView( + testMapId, + onPlatformViewCreated, + initialCameraPosition: initialCameraPosition, + ); expect(widget, equals(expected)); expect( @@ -159,6 +168,24 @@ void main() { }); }); + group('Noop methods:', () { + int mapId = 0; + setUp(() { + plugin.debugSetMapById({mapId: controller}); + }); + // Options + testWidgets('updateTileOverlays', (WidgetTester tester) async { + final update = + plugin.updateTileOverlays(mapId: mapId, newTileOverlays: {}); + expect(update, completion(null)); + }); + testWidgets('updateTileOverlays', (WidgetTester tester) async { + final update = + plugin.clearTileCache(TileOverlayId('any'), mapId: mapId); + expect(update, completion(null)); + }); + }); + // These methods only pass-through values from the plugin to the controller // so we verify them all together here... group('Pass-through methods:', () { @@ -176,28 +203,28 @@ void main() { }); // Geometry testWidgets('updateMarkers', (WidgetTester tester) async { - final expectedUpdates = MarkerUpdates.from(null, null); + final expectedUpdates = MarkerUpdates.from({}, {}); await plugin.updateMarkers(expectedUpdates, mapId: mapId); verify(controller.updateMarkers(expectedUpdates)); }); testWidgets('updatePolygons', (WidgetTester tester) async { - final expectedUpdates = PolygonUpdates.from(null, null); + final expectedUpdates = PolygonUpdates.from({}, {}); await plugin.updatePolygons(expectedUpdates, mapId: mapId); verify(controller.updatePolygons(expectedUpdates)); }); testWidgets('updatePolylines', (WidgetTester tester) async { - final expectedUpdates = PolylineUpdates.from(null, null); + final expectedUpdates = PolylineUpdates.from({}, {}); await plugin.updatePolylines(expectedUpdates, mapId: mapId); verify(controller.updatePolylines(expectedUpdates)); }); testWidgets('updateCircles', (WidgetTester tester) async { - final expectedUpdates = CircleUpdates.from(null, null); + final expectedUpdates = CircleUpdates.from({}, {}); await plugin.updateCircles(expectedUpdates, mapId: mapId); diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh index fb5f8eac44e9..5681775cdb3f 100644 --- a/script/nnbd_plugins.sh +++ b/script/nnbd_plugins.sh @@ -34,6 +34,7 @@ readonly NNBD_PLUGINS_LIST=( "webview_flutter" "wifi_info_flutter" "in_app_purchase" + "google_maps_flutter_web" # Not yet migrated, but compatible with others ) # This list contains the list of plugins that have *not* been @@ -41,8 +42,7 @@ readonly NNBD_PLUGINS_LIST=( # building the all plugins app. This list should be kept empty. readonly NON_NNBD_PLUGINS_LIST=( - "extension_google_sign_in_as_googleapis_auth" - "google_maps_flutter_web" # Not yet migrated. + "extension_google_sign_in_as_googleapis_auth" # Some deps are still clashing ) export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}") From 8ab62c5b0c99b87b3aa4f745f3dfda09c20128b6 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Wed, 3 Mar 2021 18:21:16 -0800 Subject: [PATCH 308/924] [google_maps_flutter_web] Move integration tests to example. (#3675) This PR moves the integration tests of this package to conform with the latest best practices for web plugins. --- .../google_maps_flutter_web/CHANGELOG.md | 5 +++++ .../google_maps_flutter_web/example/README.md | 21 +++++++++++++++++++ .../google_maps_controller_test.dart} | 0 .../google_maps_plugin_test.dart} | 0 .../integration_test/marker_test.dart} | 0 .../integration_test/markers_test.dart} | 2 +- .../resources/icon_image_base64.dart | 0 .../integration_test/shape_test.dart} | 0 .../integration_test/shapes_test.dart} | 0 .../{test => example}/lib/main.dart | 0 .../{test => example}/pubspec.yaml | 16 +++++++------- .../{test/run_test => example/run_test.sh} | 5 +++-- .../test_driver/integration_driver.dart} | 0 .../{test => example}/web/index.html | 0 .../google_maps_flutter_web/pubspec.yaml | 9 ++------ .../google_maps_flutter_web/test/README.md | 18 +++------------- .../google_maps_plugin_integration_test.dart | 7 ------- .../test_driver/marker_integration_test.dart | 7 ------- .../test_driver/markers_integration_test.dart | 7 ------- .../test_driver/shape_integration_test.dart | 7 ------- .../test_driver/shapes_integration_test.dart | 7 ------- .../test/tests_exist_elsewhere_test.dart | 10 +++++++++ 22 files changed, 53 insertions(+), 68 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/example/README.md rename packages/google_maps_flutter/google_maps_flutter_web/{test/test_driver/google_maps_controller_integration.dart => example/integration_test/google_maps_controller_test.dart} (100%) rename packages/google_maps_flutter/google_maps_flutter_web/{test/test_driver/google_maps_plugin_integration.dart => example/integration_test/google_maps_plugin_test.dart} (100%) rename packages/google_maps_flutter/google_maps_flutter_web/{test/test_driver/marker_integration.dart => example/integration_test/marker_test.dart} (100%) rename packages/google_maps_flutter/google_maps_flutter_web/{test/test_driver/markers_integration.dart => example/integration_test/markers_test.dart} (99%) rename packages/google_maps_flutter/google_maps_flutter_web/{test/test_driver => example/integration_test}/resources/icon_image_base64.dart (100%) rename packages/google_maps_flutter/google_maps_flutter_web/{test/test_driver/shape_integration.dart => example/integration_test/shape_test.dart} (100%) rename packages/google_maps_flutter/google_maps_flutter_web/{test/test_driver/shapes_integration.dart => example/integration_test/shapes_test.dart} (100%) rename packages/google_maps_flutter/google_maps_flutter_web/{test => example}/lib/main.dart (100%) rename packages/google_maps_flutter/google_maps_flutter_web/{test => example}/pubspec.yaml (52%) rename packages/google_maps_flutter/google_maps_flutter_web/{test/run_test => example/run_test.sh} (51%) rename packages/google_maps_flutter/google_maps_flutter_web/{test/test_driver/google_maps_controller_integration_test.dart => example/test_driver/integration_driver.dart} (100%) rename packages/google_maps_flutter/google_maps_flutter_web/{test => example}/web/index.html (100%) delete mode 100644 packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration_test.dart delete mode 100644 packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/marker_integration_test.dart delete mode 100644 packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration_test.dart delete mode 100644 packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shape_integration_test.dart delete mode 100644 packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 826f1ea53023..29e9287a14fb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.2.1 + +* Move integration tests to `example`. +* Tweak pubspec dependencies for main package. + ## 0.2.0 * Make this plugin compatible with the rest of null-safe plugins. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/README.md b/packages/google_maps_flutter/google_maps_flutter_web/example/README.md new file mode 100644 index 000000000000..0ec01e025570 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/README.md @@ -0,0 +1,21 @@ +# Testing + +This package utilizes the `integration_test` package to run its tests in a web browser. + +See [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests) for more info. + +## Running the tests + +Make sure you have updated to the latest Flutter master. + +1. Check what version of Chrome is running on the machine you're running tests on. + +2. Download and install driver for that version from here: + * + +3. Start the driver using `chromedriver --port=4444` + +4. Run tests: `flutter drive -d web-server --browser-name=chrome --driver=test_driver/integration_driver.dart --target=integration_test/TEST_NAME.dart`, or (in Linux): + + * Single: `./run_test.sh integration_test/TEST_NAME.dart` + * All: `./run_test.sh` diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart rename to packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart rename to packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/marker_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/marker_integration.dart rename to packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart similarity index 99% rename from packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart rename to packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart index 9c3ed8ea3860..71cf41522d67 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart @@ -164,7 +164,7 @@ void main() { startsWith('blob:')); final blobUrl = controller.markers[MarkerId('1')].marker.icon.url; - final response = await http.get(blobUrl); + final response = await http.get(Uri.parse(blobUrl)); expect(response.bodyBytes, bytes, reason: diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/resources/icon_image_base64.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/resources/icon_image_base64.dart similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/resources/icon_image_base64.dart rename to packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/resources/icon_image_base64.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shape_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shape_integration.dart rename to packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration.dart rename to packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/lib/main.dart similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_web/test/lib/main.dart rename to packages/google_maps_flutter/google_maps_flutter_web/example/lib/main.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml similarity index 52% rename from packages/google_maps_flutter/google_maps_flutter_web/test/pubspec.yaml rename to packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml index 008cc0350430..96da8ab90d82 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml @@ -1,23 +1,23 @@ -name: regular_integration_tests +name: google_maps_flutter_web_integration_tests publish_to: none environment: - sdk: ">=2.2.2 <3.0.0" + sdk: ">=2.2.2 <3.0.0" # Bump this to 2.12 when migrating to nnbd. + flutter: ">=1.27.0-0" # For integration_test from sdk dependencies: + google_maps_flutter_web: + path: ../ flutter: sdk: flutter dev_dependencies: google_maps: ^3.4.4 + http: ^0.13.0 + mockito: ^5.0.0 flutter_driver: sdk: flutter flutter_test: sdk: flutter - http: ^0.12.2 - mockito: ^4.1.1 - google_maps_flutter_web: - path: ../ integration_test: - path: ../../../integration_test - + sdk: flutter diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/run_test b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh similarity index 51% rename from packages/google_maps_flutter/google_maps_flutter_web/test/run_test rename to packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh index 74a8526a0fa3..8e6f149358c9 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/run_test +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh @@ -4,14 +4,15 @@ if pgrep -lf chromedriver > /dev/null; then if [ $# -eq 0 ]; then echo "No target specified, running all tests..." - find test_driver/ -iname *_integration.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --target='{}' + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target='{}' else echo "Running test target: $1..." set -x - flutter drive -d web-server --web-port=7357 --browser-name=chrome --target=$1 + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target=$1 fi else echo "chromedriver is not running." + echo "Please, check the README.md for instructions on how to use run_test.sh" fi diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration_test.dart rename to packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/web/index.html b/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_web/test/web/index.html rename to packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index 20d078284742..22df1b24afe0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.2.0 +version: 0.2.1 flutter: plugin: @@ -24,12 +24,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - http: ^0.13.0 - url_launcher: ^6.0.2 - pedantic: ^1.8.0 - mockito: ^5.0.0 - integration_test: - path: ../../integration_test + pedantic: ^1.10.0 environment: sdk: ">=2.3.0 <3.0.0" diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/README.md b/packages/google_maps_flutter/google_maps_flutter_web/test/README.md index 7c48d024ba57..7c5b4ad682ba 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/README.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/README.md @@ -1,17 +1,5 @@ -# Running browser_tests +## test -Make sure you have updated to the latest Flutter master. +This package uses integration tests for testing. -1. Check what version of Chrome is running on the machine you're running tests on. - -2. Download and install driver for that version from here: - * - -3. Start the driver using `chromedriver --port=4444` - -4. Change into the `test` directory of your clone. - -5. Run tests: `flutter drive -d web-server --browser-name=chrome --target=test_driver/TEST_NAME_integration.dart`, or (in Linux): - - * Single: `./run_test test_driver/TEST_NAME_integration.dart` - * All: `./run_test` +See `example/README.md` for more info. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration_test.dart deleted file mode 100644 index 39444c0daa24..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration_test.dart +++ /dev/null @@ -1,7 +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 'package:integration_test/integration_test_driver.dart'; - -Future main() async => integrationDriver(); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/marker_integration_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/marker_integration_test.dart deleted file mode 100644 index 39444c0daa24..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/marker_integration_test.dart +++ /dev/null @@ -1,7 +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 'package:integration_test/integration_test_driver.dart'; - -Future main() async => integrationDriver(); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration_test.dart deleted file mode 100644 index 39444c0daa24..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration_test.dart +++ /dev/null @@ -1,7 +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 'package:integration_test/integration_test_driver.dart'; - -Future main() async => integrationDriver(); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shape_integration_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shape_integration_test.dart deleted file mode 100644 index 39444c0daa24..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shape_integration_test.dart +++ /dev/null @@ -1,7 +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 'package:integration_test/integration_test_driver.dart'; - -Future main() async => integrationDriver(); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration_test.dart deleted file mode 100644 index 39444c0daa24..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/shapes_integration_test.dart +++ /dev/null @@ -1,7 +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 'package:integration_test/integration_test_driver.dart'; - -Future main() async => integrationDriver(); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart new file mode 100644 index 000000000000..334f52186d9d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart @@ -0,0 +1,10 @@ +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Tell the user where to find the real tests', () { + print('---'); + print('This package uses integration_test for its tests.'); + print('See `example/README.md` for more info.'); + print('---'); + }); +} From 2518218fade2207cb39e72e5bc29d549665f3386 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Thu, 4 Mar 2021 23:34:04 +0530 Subject: [PATCH 309/924] [image_picker] fix flutter/flutter#71927 (#3676) --- .../ios/RunnerUITests/ImagePickerFromGalleryUITests.m | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m index e30fabd2d071..8be41dc63587 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m @@ -120,17 +120,6 @@ - (void)launchPickerAndCancel { elementMatchingPredicate:[NSPredicate predicateWithFormat:@"label == %@", @"You have not yet picked an image."]]; - if (![imageNotPickedText waitForExistenceWithTimeout:kElementWaitingTime]) { - // Before https://github.com/flutter/engine/pull/22811 the label's a11y type was otherElements. - // TODO(cyanglaz): Remove this after - // https://github.com/flutter/flutter/commit/057e8230743ec96f33b73948ccd6b80081e3615e rolled to - // stable. - // https://github.com/flutter/flutter/issues/71927 - imageNotPickedText = [self.app.otherElements - elementMatchingPredicate:[NSPredicate - predicateWithFormat:@"label == %@", - @"You have not yet picked an image."]]; - } if (![imageNotPickedText waitForExistenceWithTimeout:kElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); XCTFail(@"Failed due to not able to find imageNotPickedText with %@ seconds", From 47c380a9bbc78bae8b18a849183cab0e21a703f4 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 4 Mar 2021 13:59:21 -0800 Subject: [PATCH 310/924] Update CI config for Flutter 2 (#3674) Includes cleanup to simplify our setup. Major changes: - Eliminate the NNBD plugin filtering for stable. - Remove the temporarily-added beta branch testing. - Enable Linux, macOS, and web on stable (Windows is LUCI-based) - Combine the two different macOS matrix configurations now that they are the same. - Combine the two different Linux matrix configurations by using a single Dockerfile (which now also includes clang-format) - The web integration smoke test temporarily still uses the old Dockerfile, now renamed, because the driver installer script doesn't support Chrome 89 yet. - Move most of the Linux tasks to lower-CPU machines to allow more tasks to run in parallel without hitting the community limit. - Reorder the tasks slightly and give them comments to identify platform groupings - Enabled web "build all plugins together" and "build all examples" tests --- .ci/Dockerfile | 16 +- ...e-LinuxDesktop => Dockerfile-LegacyChrome} | 20 +- .cirrus.yml | 208 ++++++++++-------- .../ios/Classes/WifiInfoFlutterPlugin.m | 4 +- script/build_all_plugins_app.sh | 22 +- script/incremental_build.sh | 6 - script/nnbd_plugins.sh | 49 ----- .../tool/lib/src/build_examples_command.dart | 51 +++-- script/tool/lib/src/format_command.dart | 6 +- .../test/build_examples_command_test.dart | 74 ++++++- 10 files changed, 261 insertions(+), 195 deletions(-) rename .ci/{Dockerfile-LinuxDesktop => Dockerfile-LegacyChrome} (62%) delete mode 100644 script/nnbd_plugins.sh diff --git a/.ci/Dockerfile b/.ci/Dockerfile index 13ac087498d1..14000e2032ed 100644 --- a/.ci/Dockerfile +++ b/.ci/Dockerfile @@ -6,7 +6,7 @@ RUN sudo apt-get install -y --no-install-recommends gnupg # Add repo for gcloud sdk and install it RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | \ - sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list + sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \ sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - @@ -23,7 +23,21 @@ RUN yes | sdkmanager \ RUN yes | sdkmanager --licenses +# Install formatter. +RUN sudo apt-get install -y clang-format + +# Install xvfb to allow running headless +RUN sudo apt-get install -y xvfb libegl1-mesa +# Install Linux desktop build tool requirements. +RUN sudo apt-get install -y clang cmake ninja-build file pkg-config +# Install necessary libraries. +RUN sudo apt-get install -y libgtk-3-dev libblkid-dev liblzma-dev + # Add repo for Google Chrome and install it RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - RUN echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee /etc/apt/sources.list.d/google-chrome.list RUN sudo apt-get update && sudo apt-get install -y --no-install-recommends google-chrome-stable + +# Make Chrome the default so http: has a handler for url_launcher tests. +RUN sudo apt-get install -y xdg-utils +RUN xdg-settings set default-web-browser google-chrome.desktop diff --git a/.ci/Dockerfile-LinuxDesktop b/.ci/Dockerfile-LegacyChrome similarity index 62% rename from .ci/Dockerfile-LinuxDesktop rename to .ci/Dockerfile-LegacyChrome index 63e4516e26fc..13ac087498d1 100644 --- a/.ci/Dockerfile-LinuxDesktop +++ b/.ci/Dockerfile-LegacyChrome @@ -6,7 +6,7 @@ RUN sudo apt-get install -y --no-install-recommends gnupg # Add repo for gcloud sdk and install it RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | \ - sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list + sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \ sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - @@ -15,17 +15,15 @@ RUN sudo apt-get update && sudo apt-get install -y google-cloud-sdk && \ gcloud config set core/disable_usage_reporting true && \ gcloud config set component_manager/disable_update_check true -# Install xvfb to allow running headless -RUN sudo apt-get install -y xvfb libegl1-mesa -# Install Linux desktop build tool requirements. -RUN sudo apt-get install -y clang cmake ninja-build file pkg-config -# Install necessary libraries. -RUN sudo apt-get install -y libgtk-3-dev +RUN yes | sdkmanager \ + "platforms;android-27" \ + "build-tools;27.0.3" \ + "extras;google;m2repository" \ + "extras;android;m2repository" -# Add repo for Google Chrome and install it, for url_launcher tests. +RUN yes | sdkmanager --licenses + +# Add repo for Google Chrome and install it RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - RUN echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee /etc/apt/sources.list.d/google-chrome.list RUN sudo apt-get update && sudo apt-get install -y --no-install-recommends google-chrome-stable -# Make it the default so http: has a handler. -RUN sudo apt-get install -y xdg-utils -RUN xdg-settings set default-web-browser google-chrome.desktop diff --git a/.cirrus.yml b/.cirrus.yml index 924cb63492a0..ea27c88b97e0 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,22 +1,23 @@ +# Light-workload tasks. +# These use default machines, with fewer CPUs, to reduce pressure on the +# concurrency limits. task: # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins only_if: $CIRRUS_TAG == '' use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' container: dockerfile: .ci/Dockerfile - cpu: 8 - memory: 16G env: INTEGRATION_TEST_PATH: "./packages/integration_test" upgrade_script: - flutter channel stable - flutter upgrade - - flutter channel beta - - flutter upgrade - flutter channel master - flutter upgrade + - flutter config --enable-linux-desktop - git fetch origin master matrix: + ### Platform-agnostic tasks ### - name: plugin_tools_tests script: - cd script/tool @@ -27,48 +28,91 @@ task: - flutter channel master - ./script/check_publish.sh - name: format - install_script: - - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - - sudo apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main" - - sudo apt-get update - - sudo apt-get install -y --allow-unauthenticated clang-format-7 - format_script: ./script/incremental_build.sh format --travis --clang-format=clang-format-7 + format_script: ./script/incremental_build.sh format --fail-on-change - name: test env: matrix: CHANNEL: "master" - CHANNEL: "beta" CHANNEL: "stable" test_script: - # TODO(jackson): Allow web plugins once supported on stable - # https://github.com/flutter/flutter/issues/42864 - - if [[ "$CHANNEL" -eq "stable" ]]; then find . | grep _web$ | xargs rm -rf; fi - flutter channel $CHANNEL - ./script/incremental_build.sh test - name: analyze env: matrix: CHANNEL: "master" - CHANNEL: "beta" CHANNEL: "stable" - script: ./script/incremental_build.sh analyze + script: + - flutter channel $CHANNEL + - ./script/incremental_build.sh analyze + ### Android tasks ### - name: build_all_plugins_apk env: matrix: CHANNEL: "master" - CHANNEL: "beta" CHANNEL: "stable" script: - # TODO(jackson): Allow web plugins once supported on stable - # https://github.com/flutter/flutter/issues/42864 - - if [[ "$CHANNEL" -eq "stable" ]]; then find . | grep _web$ | xargs rm -rf; fi - flutter channel $CHANNEL - ./script/build_all_plugins_app.sh apk + ### Web tasks ### + - name: build_all_plugins_web + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" + script: + - flutter channel $CHANNEL + - ./script/build_all_plugins_app.sh web + - name: build-web-examples + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" + build_script: + - flutter channel $CHANNEL + - ./script/incremental_build.sh build-examples --web + # TODO: Add driving examples (and move to heavy-workload group). + ### Linux desktop tasks ### + - name: build_all_plugins_linux + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" + script: + - flutter channel $CHANNEL + - ./script/build_all_plugins_app.sh linux + +# Legacy Dockerfile configuration for web integration tests. +# https://github.com/flutter/web_installers doesn't yet support the current +# stable version of Chrome, so newly-generated Docker images don't work. +# TODO: Merge this task into the "Web tasks" section of the "Light-workload +# tasks" block above once web_installers has been updated to support Chrome 89 +# (which is what the current image generated from .ci/Dockerfile has). +task: + # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins + only_if: $CIRRUS_TAG == '' + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' + container: + dockerfile: .ci/Dockerfile-LegacyChrome + env: + INTEGRATION_TEST_PATH: "./packages/integration_test" + upgrade_script: + - flutter channel stable + - flutter upgrade + - flutter channel master + - flutter upgrade + - flutter config --enable-linux-desktop + - git fetch origin master + matrix: - name: integration_web_smoke_test + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" # Tests integration example test in web. only_if: "changesInclude('.cirrus.yml', 'packages/integration_test/**') || $CIRRUS_PR == ''" install_script: - - flutter config --enable-web + - flutter channel $CHANNEL - git clone https://github.com/flutter/web_installers.git - cd web_installers/packages/web_drivers/ - pub get @@ -77,6 +121,29 @@ task: test_script: - cd $INTEGRATION_TEST_PATH/example/ - flutter drive -v --driver=test_driver/integration_test.dart --target=integration_test/example_test.dart -d web-server --release --browser-name=chrome + +# Heavy-workload tasks. +# These use machines with more CPUs and memory, so will reduce parallelization +# for non-credit runs. +task: + # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins + only_if: $CIRRUS_TAG == '' + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' + container: + dockerfile: .ci/Dockerfile + cpu: 8 + memory: 16G + env: + INTEGRATION_TEST_PATH: "./packages/integration_test" + upgrade_script: + - flutter channel stable + - flutter upgrade + - flutter channel master + - flutter upgrade + - flutter config --enable-linux-desktop + - git fetch origin master + matrix: + ### Android tasks ### - name: build-apks+java-test+firebase-test-lab env: matrix: @@ -86,14 +153,10 @@ task: PLUGIN_SHARDING: "--shardIndex 3 --shardCount 4" matrix: CHANNEL: "master" - CHANNEL: "beta" CHANNEL: "stable" MAPS_API_KEY: ENCRYPTED[596a9f6bca436694625ac50851dc5da6b4d34cba8025f7db5bc9465142e8cd44e15f69e3507787753accebfc4910d550] GCLOUD_FIREBASE_TESTLAB_KEY: ENCRYPTED[07586610af1fdfc894e5969f70ef2458341b9b7e9c3b7c4225a663b4a48732b7208a4d91c3b7d45305a6b55fa2a37fc4] script: - # TODO(jackson): Allow web plugins once supported on stable - # https://github.com/flutter/flutter/issues/42864 - - if [[ "$CHANNEL" -eq "stable" ]]; then find . | grep _web$ | xargs rm -rf; fi - flutter channel $CHANNEL # Unsetting CIRRUS_CHANGE_MESSAGE and CIRRUS_COMMIT_MESSAGE as they # might include non-ASCII characters which makes Gradle crash. @@ -115,32 +178,14 @@ task: - fi - export CIRRUS_CHANGE_MESSAGE=`cat /tmp/cirrus_change_message.txt` - export CIRRUS_COMMIT_MESSAGE=`cat /tmp/cirrus_commit_message.txt` - -task: - # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins - only_if: $CIRRUS_TAG == '' - use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' - container: - dockerfile: .ci/Dockerfile-LinuxDesktop - cpu: 8 - memory: 16G - env: - INTEGRATION_TEST_PATH: "./packages/integration_test" - upgrade_script: - - flutter channel stable - - flutter upgrade - - flutter channel beta - - flutter upgrade - - flutter channel master - - flutter upgrade - - git fetch origin master - matrix: + ### Linux desktop tasks ### - name: build-linux+drive-examples - install_script: - - flutter config --enable-linux-desktop + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" build_script: - # TODO(stuartmorgan): Include stable once Linux is supported on stable. - - flutter channel master + - flutter channel $CHANNEL - ./script/incremental_build.sh build-examples --linux - xvfb-run ./script/incremental_build.sh drive-examples --linux @@ -148,32 +193,40 @@ task: # Xcode 12 task # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins only_if: $CIRRUS_TAG == '' - use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' osx_instance: image: big-sur-xcode-12.3 upgrade_script: - sudo gem install cocoapods - flutter channel stable - flutter upgrade - - flutter channel beta - - flutter upgrade - flutter channel master - flutter upgrade + - flutter config --enable-macos-desktop - git fetch origin master create_simulator_script: - xcrun simctl list - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-3 | xargs xcrun simctl boot matrix: + ### Platform-agnostic tasks ### + - name: lint_darwin_plugins + env: + matrix: + PLUGIN_SHARDING: "--shardIndex 0 --shardCount 2" + PLUGIN_SHARDING: "--shardIndex 1 --shardCount 2" + script: + # TODO(jmagman): Lint macOS podspecs but skip any that fail library validation. + - find . -name "*.podspec" | xargs grep -l "osx" | xargs rm + # Skip the dummy podspecs used to placate the tool. + - find . -name "*_web*.podspec" -o -name "*_mac*.podspec" | xargs rm + - ./script/incremental_build.sh podspecs + ### iOS tasks ### - name: build_all_plugins_ipa env: matrix: CHANNEL: "master" - CHANNEL: "beta" CHANNEL: "stable" script: - # TODO(jackson): Allow web plugins once supported on stable - # https://github.com/flutter/flutter/issues/42864 - - if [[ "$CHANNEL" -eq "stable" ]]; then find . | grep _web$ | xargs rm -rf; fi - flutter channel $CHANNEL - ./script/build_all_plugins_app.sh ios --no-codesign - name: build-ipas+drive-examples @@ -187,55 +240,32 @@ task: PLUGIN_SHARDING: "--shardIndex 3 --shardCount 4" matrix: CHANNEL: "master" - CHANNEL: "beta" CHANNEL: "stable" SIMCTL_CHILD_MAPS_API_KEY: ENCRYPTED[596a9f6bca436694625ac50851dc5da6b4d34cba8025f7db5bc9465142e8cd44e15f69e3507787753accebfc4910d550] build_script: - # TODO(jackson): Allow web plugins once supported on stable - # https://github.com/flutter/flutter/issues/42864 - - if [[ "$CHANNEL" -eq "stable" ]]; then find . | grep _web$ | xargs rm -rf; fi - flutter channel $CHANNEL - - flutter upgrade - ./script/incremental_build.sh build-examples --ipa - ./script/incremental_build.sh xctest --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=latest" # `drive-examples` contains integration tests, which changes the UI of the application. # This UI change sometimes affects `xctest`. # So we run `drive-examples` after `xctest`, changing the order will result ci failure. - ./script/incremental_build.sh drive-examples --ios - - name: lint_darwin_plugins + ### macOS desktop tasks ### + - name: build_all_plugins_macos env: matrix: - PLUGIN_SHARDING: "--shardIndex 0 --shardCount 2" - PLUGIN_SHARDING: "--shardIndex 1 --shardCount 2" - script: - # TODO(jmagman): Lint macOS podspecs but skip any that fail library validation. - - find . -name "*.podspec" | xargs grep -l "osx" | xargs rm - # Skip the dummy podspecs used to placate the tool. - - find . -name "*_web*.podspec" -o -name "*_mac*.podspec" | xargs rm - - ./script/incremental_build.sh podspecs - -task: - # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins - only_if: $CIRRUS_TAG == '' - use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' - osx_instance: - image: big-sur-xcode-12.3 - setup_script: - - flutter config --enable-macos-desktop - upgrade_script: - - sudo gem install cocoapods - - flutter channel master - - flutter upgrade - - git fetch origin master - matrix: - - name: build_all_plugins_app + CHANNEL: "master" + CHANNEL: "stable" script: - - flutter channel master + - flutter channel $CHANNEL - ./script/build_all_plugins_app.sh macos - - name: build-apps+drive-examples + - name: build-macos+drive-examples env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" PATH: $PATH:/usr/local/bin build_script: - - flutter channel master + - flutter channel $CHANNEL - ./script/incremental_build.sh build-examples --macos --no-ipa - ./script/incremental_build.sh drive-examples --macos diff --git a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m index 3abdbeef5744..f0811dd92ef6 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m +++ b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m @@ -119,7 +119,9 @@ - (NSString*)convertCLAuthorizationStatusToString:(CLAuthorizationStatus)status case kCLAuthorizationStatusAuthorizedWhenInUse: { return @"authorizedWhenInUse"; } - default: { return @"unknown"; } + default: { + return @"unknown"; + } } } diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 0cd6f4888e79..f6b1c166069f 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -14,7 +14,6 @@ readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null && pwd)" readonly REPO_DIR="$(dirname "$SCRIPT_DIR")" source "$SCRIPT_DIR/common.sh" -source "$SCRIPT_DIR/nnbd_plugins.sh" check_changed_packages > /dev/null @@ -26,22 +25,14 @@ check_changed_packages > /dev/null # updating multiple plugins for a breaking change in a common dependency in # cases where using a relaxed version constraint isn't possible. readonly EXCLUDED_PLUGINS_LIST=( - # "file_selector" # currently out of sync with camera - # "flutter_plugin_android_lifecycle" - # "image_picker" - # "local_auth" # flutter_plugin_android_lifecycle conflict "plugin_platform_interface" # This should never be a direct app dependency. + "extension_google_sign_in_as_googleapis_auth" # Transitive dependency issues + # with integration_test. ) # Comma-separated string of the list above readonly EXCLUDED=$(IFS=, ; echo "${EXCLUDED_PLUGINS_LIST[*]}") ALL_EXCLUDED=($EXCLUDED) -# Exclude nnbd plugins from stable, and conflicting plugins otherwise. -if [ "$CHANNEL" == "stable" ]; then - ALL_EXCLUDED=("$EXCLUDED,$EXCLUDED_PLUGINS_FROM_STABLE") -else - ALL_EXCLUDED=("$EXCLUDED,$EXCLUDED_PLUGINS_FOR_NNBD") -fi echo "Excluding the following plugins: $ALL_EXCLUDED" @@ -53,7 +44,14 @@ function error() { failures=0 -for version in "debug" "release"; do +BUILD_MODES=("debug" "release") +# Web doesn't support --debug for builds. +if [[ "$1" == "web" ]]; then + BUILD_MODES=("release") +fi + +for version in "${BUILD_MODES[@]}"; do + echo "Building $version..." (cd $REPO_DIR/all_plugins && flutter build $@ --$version) if [ $? -eq 0 ]; then diff --git a/script/incremental_build.sh b/script/incremental_build.sh index bc41ebd3c70d..826229bced60 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -5,15 +5,9 @@ readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" readonly REPO_DIR="$(dirname "$SCRIPT_DIR")" source "$SCRIPT_DIR/common.sh" -source "$SCRIPT_DIR/nnbd_plugins.sh" # Plugins that are excluded from this task. ALL_EXCLUDED=("") -# Exclude nnbd plugins from stable. -if [ "$CHANNEL" == "stable" ]; then - ALL_EXCLUDED=($EXCLUDED_PLUGINS_FROM_STABLE) - echo "Excluding the following plugins because stable does not yet support NNBD: $ALL_EXCLUDED" -fi # Plugins that deliberately use their own analysis_options.yaml. # diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh deleted file mode 100644 index 5681775cdb3f..000000000000 --- a/script/nnbd_plugins.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -# This script contains the list of plugins migrated to nnbd -# that should be excluded from testing on Flutter stable until -# null-safe is available on stable. - -readonly NNBD_PLUGINS_LIST=( - "android_alarm_manager" - "android_intent" - "battery" - "camera" - "camera_platform_interface" - "connectivity" - "cross_file" - "device_info" - "espresso" - "file_selector" - "flutter_plugin_android_lifecycle" - "flutter_webview" - "google_maps_flutter" - "google_sign_in" - "image_picker" - "ios_platform_images" - "local_auth" - "path_provider" - "package_info" - "plugin_platform_interface" - "quick_actions" - "sensors" - "share" - "shared_preferences" - "url_launcher" - "video_player" - "webview_flutter" - "wifi_info_flutter" - "in_app_purchase" - "google_maps_flutter_web" # Not yet migrated, but compatible with others -) - -# This list contains the list of plugins that have *not* been -# migrated to nnbd, and conflict with those that have when -# building the all plugins app. This list should be kept empty. - -readonly NON_NNBD_PLUGINS_LIST=( - "extension_google_sign_in_as_googleapis_auth" # Some deps are still clashing -) - -export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}") -export EXCLUDED_PLUGINS_FOR_NNBD=$(IFS=, ; echo "${NON_NNBD_PLUGINS_LIST[*]}") diff --git a/script/tool/lib/src/build_examples_command.dart b/script/tool/lib/src/build_examples_command.dart index 53da9086abaa..bb140bd429c6 100644 --- a/script/tool/lib/src/build_examples_command.dart +++ b/script/tool/lib/src/build_examples_command.dart @@ -19,6 +19,7 @@ class BuildExamplesCommand extends PluginCommand { }) : super(packagesDir, fileSystem, processRunner: processRunner) { argParser.addFlag(kLinux, defaultsTo: false); argParser.addFlag(kMacos, defaultsTo: false); + argParser.addFlag(kWeb, defaultsTo: false); argParser.addFlag(kWindows, defaultsTo: false); argParser.addFlag(kIpa, defaultsTo: io.Platform.isMacOS); argParser.addFlag(kApk); @@ -43,10 +44,10 @@ class BuildExamplesCommand extends PluginCommand { !argResults[kApk] && !argResults[kLinux] && !argResults[kMacos] && + !argResults[kWeb] && !argResults[kWindows]) { - print( - 'None of --linux, --macos, --windows, --apk nor --ipa were specified, ' - 'so not building anything.'); + print('None of --linux, --macos, --web, --windows, --apk, or --ipa were ' + 'specified, so not building anything.'); return; } final String flutterCommand = @@ -84,33 +85,43 @@ class BuildExamplesCommand extends PluginCommand { if (argResults[kMacos]) { print('\nBUILDING macOS for $packageName'); if (isMacOsPlugin(plugin, fileSystem)) { - // TODO(https://github.com/flutter/flutter/issues/46236): - // Builing macos without running flutter pub get first results - // in an error. int exitCode = await processRunner.runAndStream( - flutterCommand, ['pub', 'get'], + flutterCommand, + [ + 'build', + kMacos, + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + ], workingDir: example); if (exitCode != 0) { failingPackages.add('$packageName (macos)'); - } else { - exitCode = await processRunner.runAndStream( - flutterCommand, - [ - 'build', - kMacos, - if (enableExperiment.isNotEmpty) - '--enable-experiment=$enableExperiment', - ], - workingDir: example); - if (exitCode != 0) { - failingPackages.add('$packageName (macos)'); - } } } else { print('macOS is not supported by this plugin'); } } + if (argResults[kWeb]) { + print('\nBUILDING web for $packageName'); + if (isWebPlugin(plugin, fileSystem)) { + int buildExitCode = await processRunner.runAndStream( + flutterCommand, + [ + 'build', + kWeb, + if (enableExperiment.isNotEmpty) + '--enable-experiment=$enableExperiment', + ], + workingDir: example); + if (buildExitCode != 0) { + failingPackages.add('$packageName (web)'); + } + } else { + print('Web is not supported by this plugin'); + } + } + if (argResults[kWindows]) { print('\nBUILDING Windows for $packageName'); if (isWindowsPlugin(plugin, fileSystem)) { diff --git a/script/tool/lib/src/format_command.dart b/script/tool/lib/src/format_command.dart index ec326b96c1f9..e1c14e04cfec 100644 --- a/script/tool/lib/src/format_command.dart +++ b/script/tool/lib/src/format_command.dart @@ -22,10 +22,10 @@ class FormatCommand extends PluginCommand { FileSystem fileSystem, { ProcessRunner processRunner = const ProcessRunner(), }) : super(packagesDir, fileSystem, processRunner: processRunner) { - argParser.addFlag('travis', hide: true); + argParser.addFlag('fail-on-change', hide: true); argParser.addOption('clang-format', defaultsTo: 'clang-format', - help: 'Path to executable of clang-format v5.'); + help: 'Path to executable of clang-format.'); } @override @@ -46,7 +46,7 @@ class FormatCommand extends PluginCommand { await _formatJava(googleFormatterPath); await _formatCppAndObjectiveC(); - if (argResults['travis']) { + if (argResults['fail-on-change']) { final bool modified = await _didModifyAnything(); if (modified) { throw ToolExit(1); diff --git a/script/tool/test/build_examples_command_test.dart b/script/tool/test/build_examples_command_test.dart index eaf5049dcc02..65417525d710 100644 --- a/script/tool/test/build_examples_command_test.dart +++ b/script/tool/test/build_examples_command_test.dart @@ -201,7 +201,7 @@ void main() { output, orderedEquals([ '\nBUILDING macOS for $packageName', - '\macOS is not supported by this plugin', + 'macOS is not supported by this plugin', '\n\n', 'All builds successful!', ]), @@ -213,6 +213,7 @@ void main() { expect(processRunner.recordedCalls, orderedEquals([])); cleanupPackages(); }); + test('building for macos', () async { createFakePlugin('plugin', withExtraFiles: >[ @@ -244,14 +245,81 @@ void main() { expect( processRunner.recordedCalls, orderedEquals([ - ProcessCall(flutterCommand, ['pub', 'get'], - pluginExampleDirectory.path), ProcessCall(flutterCommand, ['build', 'macos'], pluginExampleDirectory.path), ])); cleanupPackages(); }); + test('building for web with no implementation results in no-op', () async { + createFakePlugin('plugin', withExtraFiles: >[ + ['example', 'test'], + ]); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint( + runner, ['build-examples', '--no-ipa', '--web']); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING web for $packageName', + 'Web is not supported by this plugin', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running build-examples --macos with no macos + // implementation is a no-op. + expect(processRunner.recordedCalls, orderedEquals([])); + cleanupPackages(); + }); + + test('building for web', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test'], + ['example', 'web', 'index.html'], + ], + isWebPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint( + runner, ['build-examples', '--no-ipa', '--web']); + final String packageName = + p.relative(pluginExampleDirectory.path, from: mockPackagesDir.path); + + expect( + output, + orderedEquals([ + '\nBUILDING web for $packageName', + '\n\n', + 'All builds successful!', + ]), + ); + + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall(flutterCommand, ['build', 'web'], + pluginExampleDirectory.path), + ])); + cleanupPackages(); + }); + test( 'building for Windows when plugin is not set up for Windows results in no-op', () async { From eb86dfcf69a3f75b8ca7c9a13684d06c98179a01 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Thu, 4 Mar 2021 18:25:46 -0800 Subject: [PATCH 311/924] [google_maps_flutter_web] Downgrade mockito in example app. (#3679) --- .../google_maps_flutter_web/example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml index 96da8ab90d82..9f942d654caa 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dev_dependencies: google_maps: ^3.4.4 http: ^0.13.0 - mockito: ^5.0.0 + mockito: ^4.1.4 # Update to ^5.0.0 as soon as this migrates to null-safety flutter_driver: sdk: flutter flutter_test: From b709f7e4994aa48d2be815d07a1da0d66180c86e Mon Sep 17 00:00:00 2001 From: Anton Borries Date: Fri, 5 Mar 2021 03:39:05 +0100 Subject: [PATCH 312/924] [in_app_purchase] presentCodeRedemptionSheet (#3274) --- packages/in_app_purchase/CHANGELOG.md | 4 ++++ .../ios/Classes/FIAPaymentQueueHandler.h | 1 + .../ios/Classes/FIAPaymentQueueHandler.m | 8 ++++++++ .../ios/Classes/InAppPurchasePlugin.m | 8 ++++++++ .../ios/Tests/InAppPurchasePluginTest.m | 16 ++++++++++++++++ .../in_app_purchase/app_store_connection.dart | 5 +++++ .../in_app_purchase/google_play_connection.dart | 6 ++++++ .../in_app_purchase_connection.dart | 6 ++++++ .../sk_payment_queue_wrapper.dart | 11 +++++++++++ packages/in_app_purchase/pubspec.yaml | 2 +- .../app_store_connection_test.dart | 7 +++++++ .../google_play_connection_test.dart | 7 +++++++ .../sk_methodchannel_apis_test.dart | 15 +++++++++++++++ 13 files changed, 95 insertions(+), 1 deletion(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index 535295a2f8af..84a65f4159f3 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.1 + +* [iOS] Introduce `SKPaymentQueueWrapper.presentCodeRedemptionSheet` + ## 0.5.0 * Migrate to Google Billing Library 3.0 diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h index 54898d170304..a27855230adb 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h +++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h @@ -29,6 +29,7 @@ typedef void (^UpdatedDownloads)(NSArray *downloads); // Can throw exceptions if the transaction type is purchasing, should always used in a @try block. - (void)finishTransaction:(nonnull SKPaymentTransaction *)transaction; - (void)restoreTransactions:(nullable NSString *)applicationName; +- (void)presentCodeRedemptionSheet; - (NSArray *)getUnfinishedTransactions; // This method needs to be called before any other methods. diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m index ecbd237c90ce..8d179aee7ba8 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m +++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m @@ -66,6 +66,14 @@ - (void)restoreTransactions:(nullable NSString *)applicationName { } } +- (void)presentCodeRedemptionSheet { + if (@available(iOS 14, *)) { + [self.queue presentCodeRedemptionSheet]; + } else { + NSLog(@"presentCodeRedemptionSheet is only available on iOS 14 or newer"); + } +} + #pragma mark - observing // Sent when the transaction array has changed (additions or state changes). Client should check diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m index 9b44ad766a98..e9b6bb9b8490 100644 --- a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m +++ b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m @@ -93,6 +93,9 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result [self finishTransaction:call result:result]; } else if ([@"-[InAppPurchasePlugin restoreTransactions:result:]" isEqualToString:call.method]) { [self restoreTransactions:call result:result]; + } else if ([@"-[InAppPurchasePlugin presentCodeRedemptionSheet:result:]" + isEqualToString:call.method]) { + [self presentCodeRedemptionSheet:call result:result]; } else if ([@"-[InAppPurchasePlugin retrieveReceiptData:result:]" isEqualToString:call.method]) { [self retrieveReceiptData:call result:result]; } else if ([@"-[InAppPurchasePlugin refreshReceipt:result:]" isEqualToString:call.method]) { @@ -246,6 +249,11 @@ - (void)restoreTransactions:(FlutterMethodCall *)call result:(FlutterResult)resu result(nil); } +- (void)presentCodeRedemptionSheet:(FlutterMethodCall *)call result:(FlutterResult)result { + [self.paymentQueueHandler presentCodeRedemptionSheet]; + result(nil); +} + - (void)retrieveReceiptData:(FlutterMethodCall *)call result:(FlutterResult)result { FlutterError *error = nil; NSString *receiptData = [self.receiptManager retrieveReceiptWithError:&error]; diff --git a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m index 4025e9270fa9..31e0f255034d 100644 --- a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m +++ b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m @@ -250,6 +250,22 @@ - (void)testRefreshReceiptRequest { XCTAssertTrue(result); } +- (void)testPresentCodeRedemptionSheet { + XCTestExpectation* expectation = + [self expectationWithDescription:@"expect successfully present Code Redemption Sheet"]; + FlutterMethodCall* call = [FlutterMethodCall + methodCallWithMethodName:@"-[InAppPurchasePlugin presentCodeRedemptionSheet:result:]" + arguments:nil]; + __block BOOL callbackInvoked = NO; + [self.plugin handleMethodCall:call + result:^(id r) { + callbackInvoked = YES; + [expectation fulfill]; + }]; + [self waitForExpectations:@[ expectation ] timeout:5]; + XCTAssertTrue(callbackInvoked); +} + - (void)testGetPendingTransactions { XCTestExpectation* expectation = [self expectationWithDescription:@"expect success"]; FlutterMethodCall* call = diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index 79a4a61fb328..e437e7f99cfc 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -201,6 +201,11 @@ class AppStoreConnection implements InAppPurchaseConnection { ); return productDetailsResponse; } + + @override + Future presentCodeRedemptionSheet() { + return _skPaymentQueueWrapper.presentCodeRedemptionSheet(); + } } class _TransactionObserver implements SKTransactionObserverWrapper { diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart index c45512ed353f..83435d23d395 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart @@ -179,6 +179,12 @@ class GooglePlayConnection 'The method only works on iOS.'); } + @override + Future presentCodeRedemptionSheet() async { + throw UnsupportedError( + 'The method only works on iOS.'); + } + /// Resets the connection instance. /// /// The next call to [instance] will create a new instance. Should only be diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart index aac5eae93e55..751bab62803c 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart @@ -239,6 +239,12 @@ abstract class InAppPurchaseConnection { /// Throws an [UnsupportedError] on Android. Future refreshPurchaseVerificationData(); + /// (App Store only) present Code Redemption Sheet. + /// Available on devices running iOS 14 and iPadOS 14 and later. + /// + /// Throws an [UnsupportedError] on Android. + Future presentCodeRedemptionSheet(); + /// The [InAppPurchaseConnection] implemented for this platform. /// /// Throws an [UnsupportedError] when accessed on a platform other than diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart index d56fbd00c6fe..f17166fbc969 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart @@ -137,6 +137,17 @@ class SKPaymentQueueWrapper { applicationUserName); } + /// Present Code Redemption Sheet + /// + /// Use this to allow Users to enter and redeem Codes + /// + /// This method triggers [`-[SKPayment + /// presentCodeRedemptionSheet]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/3566726-presentcoderedemptionsheet?language=objc) + Future presentCodeRedemptionSheet() async { + await channel.invokeMethod( + '-[InAppPurchasePlugin presentCodeRedemptionSheet:result:]'); + } + // Triage a method channel call from the platform and triggers the correct observer method. Future _handleObserverCallbacks(MethodCall call) async { assert(_observer != null, diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 3d121fd51e5e..c7582f91d8c2 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.5.0 +version: 0.5.1 dependencies: flutter: diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index bfcab085e26a..a6f9b07a59b3 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -300,6 +300,13 @@ void main() { throwsUnsupportedError); }); }); + + group('present code redemption sheet', () { + test('null', () async { + expect( + await AppStoreConnection.instance.presentCodeRedemptionSheet(), null); + }); + }); } class FakeIOSPlatform { diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart index 5a265b8de907..6630b4e1734a 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart @@ -238,6 +238,13 @@ void main() { }); }); + group('present code redemption sheet', () { + test('should throw on android', () { + expect(GooglePlayConnection.instance.presentCodeRedemptionSheet(), + throwsUnsupportedError); + }); + }); + group('make payment', () { final String launchMethodName = 'BillingClient#launchBillingFlow(Activity, BillingFlowParams)'; diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart index d41a1269d6c9..8df380bc223b 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart @@ -133,6 +133,15 @@ void main() { expect(fakeIOSPlatform.applicationNameHasTransactionRestored, 'aUserID'); }); }); + + group('Code Redemption Sheet', () { + test('presentCodeRedemptionSheet should not throw', () async { + expect(fakeIOSPlatform.presentCodeRedemption, false); + await SKPaymentQueueWrapper().presentCodeRedemptionSheet(); + expect(fakeIOSPlatform.presentCodeRedemption, true); + fakeIOSPlatform.presentCodeRedemption = false; + }); + }); } class FakeIOSPlatform { @@ -153,6 +162,9 @@ class FakeIOSPlatform { List> transactionsFinished = []; String applicationNameHasTransactionRestored = ''; + // present Code Redemption + bool presentCodeRedemption = false; + Future onMethodCall(MethodCall call) { switch (call.method) { // request makers @@ -193,6 +205,9 @@ class FakeIOSPlatform { case '-[InAppPurchasePlugin restoreTransactions:result:]': applicationNameHasTransactionRestored = call.arguments; return Future.sync(() {}); + case '-[InAppPurchasePlugin presentCodeRedemptionSheet:result:]': + presentCodeRedemption = true; + return Future.sync(() {}); } return Future.sync(() {}); } From fc1b17ea3728768c590272a28f1d23691562505e Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Fri, 5 Mar 2021 15:26:44 -0800 Subject: [PATCH 313/924] Bring HTML inputs into view automatically (#3655) --- packages/webview_flutter/CHANGELOG.md | 5 + .../webviewflutter/FlutterWebView.java | 30 ++++- .../webview_flutter_test.dart | 124 +++++++++++++++++- .../lib/src/webview_method_channel.dart | 5 +- .../webview_flutter/lib/webview_flutter.dart | 3 + packages/webview_flutter/pubspec.yaml | 2 +- 6 files changed, 153 insertions(+), 16 deletions(-) diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 139f120f12b2..6d2b4bb26815 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.2 + +* Fixes bug where text fields are hidden behind the keyboard +when hybrid composition is used [flutter/issues/75667](https://github.com/flutter/flutter/issues/75667). + ## 2.0.1 * Run CocoaPods iOS tests in RunnerUITests target diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java index 4578c7e0d1fe..022f1c3597e7 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java @@ -29,7 +29,7 @@ public class FlutterWebView implements PlatformView, MethodCallHandler { private static final String JS_CHANNEL_NAMES_FIELD = "javascriptChannelNames"; - private final InputAwareWebView webView; + private final WebView webView; private final MethodChannel methodChannel; private final FlutterWebViewClient flutterWebViewClient; private final Handler platformThreadHandler; @@ -92,7 +92,13 @@ public void onProgressChanged(WebView view, int progress) { DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); displayListenerProxy.onPreWebViewInitialization(displayManager); - webView = new InputAwareWebView(context, containerView); + + Boolean usesHybridComposition = (Boolean) params.get("usesHybridComposition"); + webView = + (usesHybridComposition) + ? new WebView(context) + : new InputAwareWebView(context, containerView); + displayListenerProxy.onPostWebViewInitialization(displayManager); platformThreadHandler = new Handler(context.getMainLooper()); @@ -140,7 +146,9 @@ public View getView() { // of Flutter but used as an override anyway wherever it's actually defined. // TODO(mklim): Add the @Override annotation once flutter/engine#9727 rolls to stable. public void onInputConnectionUnlocked() { - webView.unlockInputConnection(); + if (webView instanceof InputAwareWebView) { + ((InputAwareWebView) webView).unlockInputConnection(); + } } // @Override @@ -150,7 +158,9 @@ public void onInputConnectionUnlocked() { // of Flutter but used as an override anyway wherever it's actually defined. // TODO(mklim): Add the @Override annotation once flutter/engine#9727 rolls to stable. public void onInputConnectionLocked() { - webView.lockInputConnection(); + if (webView instanceof InputAwareWebView) { + ((InputAwareWebView) webView).lockInputConnection(); + } } // @Override @@ -160,7 +170,9 @@ public void onInputConnectionLocked() { // of Flutter but used as an override anyway wherever it's actually defined. // TODO(mklim): Add the @Override annotation once stable passes v1.10.9. public void onFlutterViewAttached(View flutterView) { - webView.setContainerView(flutterView); + if (webView instanceof InputAwareWebView) { + ((InputAwareWebView) webView).setContainerView(flutterView); + } } // @Override @@ -170,7 +182,9 @@ public void onFlutterViewAttached(View flutterView) { // of Flutter but used as an override anyway wherever it's actually defined. // TODO(mklim): Add the @Override annotation once stable passes v1.10.9. public void onFlutterViewDetached() { - webView.setContainerView(null); + if (webView instanceof InputAwareWebView) { + ((InputAwareWebView) webView).setContainerView(null); + } } @Override @@ -425,7 +439,9 @@ private void updateUserAgent(String userAgent) { @Override public void dispose() { methodChannel.setMethodCallHandler(null); - webView.dispose(); + if (webView instanceof InputAwareWebView) { + ((InputAwareWebView) webView).dispose(); + } webView.destroy(); } } diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index 50af77fe6c6e..d91ccc53b231 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -823,7 +823,7 @@ void main() { }); }); - group('$SurfaceAndroidWebView', () { + group('SurfaceAndroidWebView', () { setUpAll(() { WebView.platform = SurfaceAndroidWebView(); }); @@ -898,8 +898,113 @@ void main() { scrollPosY = await controller.getScrollY(); expect(X_SCROLL * 2, scrollPosX); expect(Y_SCROLL * 2, scrollPosY); - }); - }, skip: !Platform.isAndroid); + }, skip: !Platform.isAndroid); + + testWidgets('inputs are scrolled into view when focused', + (WidgetTester tester) async { + final String scrollTestPage = ''' + + + + + + +
+ + + + '''; + + final String scrollTestPageBase64 = + base64Encode(const Utf8Encoder().convert(scrollTestPage)); + + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + + await tester.runAsync(() async { + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: SizedBox( + width: 200, + height: 200, + child: WebView( + initialUrl: + 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + javascriptMode: JavascriptMode.unrestricted, + ), + ), + ), + ); + await Future.delayed(Duration(milliseconds: 20)); + await tester.pump(); + }); + + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + final String viewportRectJSON = await _evaluateJavascript( + controller, 'JSON.stringify(viewport.getBoundingClientRect())'); + final Map viewportRectRelativeToViewport = + jsonDecode(viewportRectJSON); + + // Check that the input is originally outside of the viewport. + + final String initialInputClientRectJSON = await _evaluateJavascript( + controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); + final Map initialInputClientRectRelativeToViewport = + jsonDecode(initialInputClientRectJSON); + + expect( + initialInputClientRectRelativeToViewport['bottom'] <= + viewportRectRelativeToViewport['bottom'], + isFalse); + + await controller.evaluateJavascript('inputEl.focus()'); + + // Check that focusing the input brought it into view. + + final String lastInputClientRectJSON = await _evaluateJavascript( + controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); + final Map lastInputClientRectRelativeToViewport = + jsonDecode(lastInputClientRectJSON); + + expect( + lastInputClientRectRelativeToViewport['top'] >= + viewportRectRelativeToViewport['top'], + isTrue); + expect( + lastInputClientRectRelativeToViewport['bottom'] <= + viewportRectRelativeToViewport['bottom'], + isTrue); + + expect( + lastInputClientRectRelativeToViewport['left'] >= + viewportRectRelativeToViewport['left'], + isTrue); + expect( + lastInputClientRectRelativeToViewport['right'] <= + viewportRectRelativeToViewport['right'], + isTrue); + }, skip: !Platform.isAndroid); + }); group('NavigationDelegate', () { final String blankPage = ""; @@ -966,7 +1071,8 @@ void main() { expect(error.failingUrl, isNull); } else if (Platform.isAndroid) { expect(error.errorType, isNotNull); - expect(error.failingUrl, 'https://www.notawebsite..com'); + expect(error.failingUrl.startsWith('https://www.notawebsite..com'), + isTrue); } }); @@ -1236,9 +1342,13 @@ String _webviewBool(bool value) { /// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests. Future _getUserAgent(WebViewController controller) async { + return _evaluateJavascript(controller, 'navigator.userAgent;'); +} + +Future _evaluateJavascript( + WebViewController controller, String js) async { if (defaultTargetPlatform == TargetPlatform.iOS) { - return await controller.evaluateJavascript('navigator.userAgent;'); + return await controller.evaluateJavascript(js); } - return jsonDecode( - await controller.evaluateJavascript('navigator.userAgent;')); + return jsonDecode(await controller.evaluateJavascript(js)); } diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart index ef1ed51835b8..e26604f74628 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -201,13 +201,16 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { /// This is used for the `creationParams` argument of the platform views created by /// [AndroidWebViewBuilder] and [CupertinoWebViewBuilder]. static Map creationParamsToMap( - CreationParams creationParams) { + CreationParams creationParams, { + bool usesHybridComposition = false, + }) { return { 'initialUrl': creationParams.initialUrl, 'settings': _webSettingsToMap(creationParams.webSettings), 'javascriptChannelNames': creationParams.javascriptChannelNames.toList(), 'userAgent': creationParams.userAgent, 'autoMediaPlaybackPolicy': creationParams.autoMediaPlaybackPolicy.index, + 'usesHybridComposition': usesHybridComposition, }; } } diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 7e4f3d6ac079..56315b6692a5 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -85,6 +86,7 @@ class SurfaceAndroidWebView extends AndroidWebView { Set>? gestureRecognizers, required WebViewPlatformCallbacksHandler webViewPlatformCallbacksHandler, }) { + assert(Platform.isAndroid); assert(webViewPlatformCallbacksHandler != null); return PlatformViewLink( viewType: 'plugins.flutter.io/webview', @@ -109,6 +111,7 @@ class SurfaceAndroidWebView extends AndroidWebView { layoutDirection: TextDirection.rtl, creationParams: MethodChannelWebViewPlatform.creationParamsToMap( creationParams, + usesHybridComposition: true, ), creationParamsCodec: const StandardMessageCodec(), ) diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 0640386c517d..6ee9e119bd3a 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter -version: 2.0.1 +version: 2.0.2 environment: sdk: ">=2.12.0-259.9.beta <3.0.0" From b3f750827bd22cad544667233dd1039770674439 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 5 Mar 2021 16:54:57 -0800 Subject: [PATCH 314/924] [ci] Disable analyze on stable for web plugins that contains null safety integration tests. (#3681) --- .cirrus.yml | 12 ++++++++++-- .../example/test_driver/test/integration_test.dart | 1 + .../example/pubspec.yaml | 4 ---- .../example/test_driver/test/integration_test.dart | 1 + 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index ea27c88b97e0..eac32d114269 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -37,13 +37,22 @@ task: test_script: - flutter channel $CHANNEL - ./script/incremental_build.sh test - - name: analyze + - name: analyze_master env: matrix: CHANNEL: "master" + script: + - flutter channel $CHANNEL + - ./script/incremental_build.sh analyze + ## TODO(cyanglaz): + ## Combing stable and master analyze jobs when integration test null safety is ready on flutter stable. + - name: analyze_stable + env: + matrix: CHANNEL: "stable" script: - flutter channel $CHANNEL + - find . -depth -type d -wholename '*_web/example' -exec rm -rf {} \; - ./script/incremental_build.sh analyze ### Android tasks ### - name: build_all_plugins_apk @@ -67,7 +76,6 @@ task: env: matrix: CHANNEL: "master" - CHANNEL: "stable" build_script: - flutter channel $CHANNEL - ./script/incremental_build.sh build-examples --web diff --git a/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart b/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart index c0cbdcab2fb6..425dac924e7c 100644 --- a/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart +++ b/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// @dart = 2.9 import 'dart:convert'; import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml index d3b428d190c9..c96ca065f081 100755 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml @@ -16,10 +16,6 @@ dependencies: dev_dependencies: pedantic: ^1.10.0 - integration_test: - path: ../../../integration_test - flutter_driver: - sdk: flutter flutter: uses-material-design: true diff --git a/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart b/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart index 7a2c21338786..0352d4aaeb2d 100644 --- a/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart +++ b/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// @dart = 2.9 import 'dart:async'; import 'dart:convert'; import 'dart:io'; From 26879dbd2f75f8f4f67ac8183aeefc394e6a1efa Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Fri, 5 Mar 2021 17:54:03 -0800 Subject: [PATCH 315/924] Import flutter_test for future compatibility (#3665) --- packages/camera/camera/test/utils/method_channel_mock.dart | 1 + .../test/utils/method_channel_mock.dart | 1 + .../app_store_connection_test.dart | 5 ++--- .../google_play_connection_test.dart | 3 +-- packages/sensors/test/sensors_test.dart | 3 +-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/camera/camera/test/utils/method_channel_mock.dart b/packages/camera/camera/test/utils/method_channel_mock.dart index fdbd9a18f29c..c667bed76e89 100644 --- a/packages/camera/camera/test/utils/method_channel_mock.dart +++ b/packages/camera/camera/test/utils/method_channel_mock.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; class MethodChannelMock { final Duration? delay; diff --git a/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart b/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart index fdbd9a18f29c..c667bed76e89 100644 --- a/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart +++ b/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; class MethodChannelMock { final Duration? delay; diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index a6f9b07a59b3..14383b96774d 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -6,9 +6,8 @@ import 'dart:async'; import 'dart:io'; import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart' show TestWidgetsFlutterBinding; +import 'package:flutter_test/flutter_test.dart'; import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart'; -import 'package:test/test.dart'; import 'package:in_app_purchase/src/channel.dart'; import 'package:in_app_purchase/src/in_app_purchase/app_store_connection.dart'; @@ -227,7 +226,7 @@ void main() { expect( () => AppStoreConnection.instance .buyConsumable(purchaseParam: purchaseParam, autoConsume: false), - throwsA(TypeMatcher())); + throwsA(isInstanceOf())); }); test('should get failed purchase status', () async { diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart index 6630b4e1734a..13582736f86f 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart @@ -5,9 +5,8 @@ import 'dart:async'; import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart' show TestWidgetsFlutterBinding; +import 'package:flutter_test/flutter_test.dart'; import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart'; -import 'package:test/test.dart'; import 'package:flutter/widgets.dart' as widgets; import 'package:in_app_purchase/billing_client_wrappers.dart'; diff --git a/packages/sensors/test/sensors_test.dart b/packages/sensors/test/sensors_test.dart index 93e0959befed..fe56c7e5a36f 100644 --- a/packages/sensors/test/sensors_test.dart +++ b/packages/sensors/test/sensors_test.dart @@ -5,9 +5,8 @@ import 'dart:typed_data'; import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart' show TestWidgetsFlutterBinding; +import 'package:flutter_test/flutter_test.dart'; import 'package:sensors/sensors.dart'; -import 'package:test/test.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); From e6156827a2b926cbe117f386524ded214625fa80 Mon Sep 17 00:00:00 2001 From: Guilherme Girotto Date: Sat, 6 Mar 2021 14:39:52 -0300 Subject: [PATCH 316/924] [google_sign_in] Updates google_sign_in_platform_interfaces adding parametrized `clientId` (#3686) --- .../google_sign_in_platform_interface/CHANGELOG.md | 4 ++++ .../lib/src/method_channel_google_sign_in.dart | 1 + .../google_sign_in_platform_interface/pubspec.yaml | 2 +- .../test/method_channel_google_sign_in_test.dart | 3 ++- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md b/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md index dd6c22fbef29..ee43db685339 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Updates `init` function in `MethodChannelGoogleSignIn` to parametrize `clientId` property. + ## 2.0.0 * Migrate to null-safety. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart index b36676e2376d..ea2426159e21 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart @@ -30,6 +30,7 @@ class MethodChannelGoogleSignIn extends GoogleSignInPlatform { 'signInOption': signInOption.toString(), 'scopes': scopes, 'hostedDomain': hostedDomain, + 'clientId': clientId, }); } diff --git a/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml b/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml index 56b4033dcb88..195bff28d992 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_sign_in plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in_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: 2.0.0 +version: 2.0.1 dependencies: flutter: diff --git a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart index 325f0c10a6ab..9447cd0edfc4 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart @@ -100,11 +100,12 @@ void main() { hostedDomain: 'example.com', scopes: ['two', 'scopes'], signInOption: SignInOption.games, - clientId: 'UNUSED!'); + clientId: 'fakeClientId'); }: isMethodCall('init', arguments: { 'hostedDomain': 'example.com', 'scopes': ['two', 'scopes'], 'signInOption': 'SignInOption.games', + 'clientId': 'fakeClientId', }), () { googleSignIn.getTokens( From 3acc0cf03051a2888b06753ebe7c4cc22ced191a Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 8 Mar 2021 10:20:38 -0800 Subject: [PATCH 317/924] [extension_google_sign_in_as_googleapis_auth] Update import (#3689) Replaces deprecated import with current version. --- .../lib/extension_google_sign_in_as_googleapis_auth.dart | 2 +- .../test/extension_google_sign_in_as_googleapis_auth_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart index 8c8ede5eee1a..b88be661fde4 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart @@ -6,7 +6,7 @@ import 'package:meta/meta.dart'; import 'package:google_sign_in/google_sign_in.dart'; -import 'package:googleapis_auth/auth.dart' as googleapis_auth; +import 'package:googleapis_auth/googleapis_auth.dart' as googleapis_auth; import 'package:http/http.dart' as http; /// Extension on [GoogleSignIn] that adds an `authenticatedClient` method. diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart index 508f366eacde..d747b3d19c63 100644 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart +++ b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart @@ -5,7 +5,7 @@ // https://developers.google.com/open-source/licenses/bsd import 'package:google_sign_in/google_sign_in.dart'; -import 'package:googleapis_auth/auth.dart' as auth; +import 'package:googleapis_auth/googleapis_auth.dart' as auth; import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:test/fake.dart'; From a2c855def90032cafbc67a007813a22053e53aa3 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 8 Mar 2021 12:17:52 -0800 Subject: [PATCH 318/924] [google_sign_in] fix test(#3690) --- .../test/google_sign_in_test.dart | 99 +++++-------------- 1 file changed, 24 insertions(+), 75 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart index 2a8d65e32ffd..79fa74ad1be1 100755 --- a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart @@ -64,11 +64,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signInSilently', arguments: null), ], ); @@ -80,11 +76,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signIn', arguments: null), ], ); @@ -94,11 +86,7 @@ void main() { await googleSignIn.signOut(); expect(googleSignIn.currentUser, isNull); expect(log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signOut', arguments: null), ]); }); @@ -109,11 +97,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('disconnect', arguments: null), ], ); @@ -126,11 +110,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('disconnect', arguments: null), ], ); @@ -140,11 +120,7 @@ void main() { final bool result = await googleSignIn.isSignedIn(); expect(result, isTrue); expect(log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('isSignedIn', arguments: null), ]); }); @@ -159,11 +135,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signInSilently', arguments: null), isMethodCall('signIn', arguments: null), ], @@ -187,11 +159,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signInSilently', arguments: null), ], ); @@ -204,11 +172,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signInSilently', arguments: null), isMethodCall('signIn', arguments: null), ], @@ -226,11 +190,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signInSilently', arguments: null), ], ); @@ -257,11 +217,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signOut', arguments: null), isMethodCall('signOut', arguments: null), isMethodCall('disconnect', arguments: null), @@ -282,11 +238,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signInSilently', arguments: null), isMethodCall('signOut', arguments: null), isMethodCall('signIn', arguments: null), @@ -333,11 +285,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signInSilently', arguments: null), ], ); @@ -352,11 +300,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.games', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(signInOption: 'SignInOption.games'), isMethodCall('signInSilently', arguments: null), ], ); @@ -391,11 +335,7 @@ void main() { expect( log, [ - isMethodCall('init', arguments: { - 'signInOption': 'SignInOption.standard', - 'scopes': [], - 'hostedDomain': null, - }), + _isSignInMethodCall(), isMethodCall('signIn', arguments: null), isMethodCall('requestScopes', arguments: { 'scopes': ['testScope'], @@ -447,3 +387,12 @@ void main() { }); }); } + +Matcher _isSignInMethodCall({String signInOption = 'SignInOption.standard'}) { + return isMethodCall('init', arguments: { + 'signInOption': signInOption, + 'scopes': [], + 'hostedDomain': null, + 'clientId': null, + }); +} From 728129a8ab7f132aa5dc298057fe98371e792714 Mon Sep 17 00:00:00 2001 From: zhenqiu1101 Date: Mon, 8 Mar 2021 12:29:04 -0800 Subject: [PATCH 319/924] [Video_Player] Remove the deprecated API reference. (#3669) --- packages/video_player/video_player/CHANGELOG.md | 4 ++++ .../java/io/flutter/plugins/videoplayer/VideoPlayer.java | 9 ++------- packages/video_player/video_player/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 57ba54e0a7bc..e5c30a0389e4 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 + +* Remove the deprecated API "exoPlayer.setAudioAttributes". + ## 2.0.0 * Migrate to null safety. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java index 65657509b49f..c3a31432e896 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java @@ -5,7 +5,6 @@ import android.content.Context; import android.net.Uri; -import android.os.Build; import android.view.Surface; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; @@ -222,12 +221,8 @@ void sendBufferingUpdate() { @SuppressWarnings("deprecation") private static void setAudioAttributes(SimpleExoPlayer exoPlayer, boolean isMixMode) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - exoPlayer.setAudioAttributes( - new AudioAttributes.Builder().setContentType(C.CONTENT_TYPE_MOVIE).build(), !isMixMode); - } else { - exoPlayer.setAudioStreamType(C.STREAM_TYPE_MUSIC); - } + exoPlayer.setAudioAttributes( + new AudioAttributes.Builder().setContentType(C.CONTENT_TYPE_MOVIE).build(), !isMixMode); } void play() { diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index fedc46c721b1..3c6a34c7f78c 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -version: 2.0.0 +version: 2.0.1 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: From d44d155fa501c6bd5ea5c6d79e13cdeaa4274c70 Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Mon, 8 Mar 2021 18:05:00 -0800 Subject: [PATCH 320/924] Skip pod lint tests (#3692) --- script/tool/lib/src/lint_podspecs_command.dart | 1 + script/tool/test/lint_podspecs_command_test.dart | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/script/tool/lib/src/lint_podspecs_command.dart b/script/tool/lib/src/lint_podspecs_command.dart index 749d67ee5f16..13de64415e9e 100644 --- a/script/tool/lib/src/lint_podspecs_command.dart +++ b/script/tool/lib/src/lint_podspecs_command.dart @@ -123,6 +123,7 @@ class LintPodspecsCommand extends PluginCommand { 'lint', podspecPath, '--configuration=Debug', // Release targets unsupported arm64 simulators. Use Debug to only build against targeted x86_64 simulator devices. + '--skip-tests', if (allowWarnings) '--allow-warnings', if (libraryLint) '--use-libraries' ]; diff --git a/script/tool/test/lint_podspecs_command_test.dart b/script/tool/test/lint_podspecs_command_test.dart index e0411d5cffd1..1c59d2d7e55a 100644 --- a/script/tool/test/lint_podspecs_command_test.dart +++ b/script/tool/test/lint_podspecs_command_test.dart @@ -82,6 +82,7 @@ void main() { 'lint', p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'), '--configuration=Debug', + '--skip-tests', '--use-libraries' ], mockPackagesDir.path), @@ -92,6 +93,7 @@ void main() { 'lint', p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'), '--configuration=Debug', + '--skip-tests', ], mockPackagesDir.path), ]), @@ -141,6 +143,7 @@ void main() { 'lint', p.join(plugin1Dir.path, 'plugin1.podspec'), '--configuration=Debug', + '--skip-tests', '--allow-warnings', '--use-libraries' ], @@ -152,6 +155,7 @@ void main() { 'lint', p.join(plugin1Dir.path, 'plugin1.podspec'), '--configuration=Debug', + '--skip-tests', '--allow-warnings', ], mockPackagesDir.path), From 8f6d3d161e061d8e295056a592b194f5a1a2bae5 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Tue, 9 Mar 2021 17:45:01 -0800 Subject: [PATCH 321/924] [extension_google_sign_in_as_googleapis_auth] Deleted. (#3694) The package now lives in flutter/packages. --- .../.gitignore | 75 --- .../.metadata | 10 - .../CHANGELOG.md | 24 - .../LICENSE | 25 - .../README.md | 46 -- .../example/README.md | 8 - .../example/android/app/build.gradle | 64 --- .../example/android/app/google-services.json | 246 --------- .../gradle/wrapper/gradle-wrapper.properties | 5 - .../android/app/src/main/AndroidManifest.xml | 25 - .../main/java/io/flutter/plugins/.gitignore | 1 - .../EmbeddingV1Activity.java | 19 - .../EmbeddingV1ActivityTest.java | 18 - .../FlutterActivityTest.java | 17 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values/strings.xml | 4 - .../example/android/build.gradle | 29 - .../example/android/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.properties | 5 - .../example/android/settings.gradle | 15 - .../ios/Flutter/AppFrameworkInfo.plist | 30 -- .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../ios/GoogleSignInPluginTest/Info.plist | 22 - .../ios/Runner.xcodeproj/project.pbxproj | 502 ------------------ .../contents.xcworkspacedata | 10 - .../xcshareddata/xcschemes/Runner.xcscheme | 87 --- .../contents.xcworkspacedata | 10 - .../example/ios/Runner/AppDelegate.h | 10 - .../example/ios/Runner/AppDelegate.m | 17 - .../AppIcon.appiconset/Contents.json | 116 ---- .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../Runner/Base.lproj/LaunchScreen.storyboard | 27 - .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../ios/Runner/GoogleService-Info.plist | 44 -- .../example/ios/Runner/Info.plist | 62 --- .../example/ios/Runner/main.m | 13 - .../example/lib/main.dart | 150 ------ .../example/pubspec.yaml | 25 - .../example/web/index.html | 11 - ...ion_google_sign_in_as_googleapis_auth.dart | 41 -- .../pubspec.yaml | 28 - ...oogle_sign_in_as_googleapis_auth_test.dart | 54 -- script/build_all_plugins_app.sh | 2 - 61 files changed, 1931 deletions(-) delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.gitignore delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.metadata delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/LICENSE delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/README.md delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/build.gradle delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/google-services.json delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/AndroidManifest.xml delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/values/strings.xml delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/build.gradle delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle.properties delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle/wrapper/gradle-wrapper.properties delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/settings.gradle delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Debug.xcconfig delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/GoogleSignInPluginTest/Info.plist delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.h delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.m delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/GoogleService-Info.plist delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Info.plist delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/main.m delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart delete mode 100755 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/web/index.html delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml delete mode 100644 packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.gitignore b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.gitignore deleted file mode 100644 index bb431f0d5b47..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.gitignore +++ /dev/null @@ -1,75 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Flutter.podspec -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.metadata b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.metadata deleted file mode 100644 index 2c91cc0fc35a..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 5e3e5a2a1a977c34b22f3709109fd237b5cab9c6 - channel: master - -project_type: package diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md deleted file mode 100644 index 5e29f340599b..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/CHANGELOG.md +++ /dev/null @@ -1,24 +0,0 @@ -## 2.0.0 - -* Migrate to null safety. -* Fixes the requested scopes to use the `GoogleSignIn` instance's `scopes`. - -## 1.0.4 - -* Update the example app: remove the deprecated `RaisedButton` and `FlatButton` widgets. - -## 1.0.3 - -* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 1.0.2 - -* Update Flutter SDK constraint. - -## 1.0.1 - -* Update android compileSdkVersion to 29. - -## 1.0.0 - -* First published version. diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/LICENSE b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/LICENSE deleted file mode 100644 index b707cc8221fb..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright 2020 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/README.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/README.md deleted file mode 100644 index 78ddb4bdc91b..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# extension_google_sign_in_as_googleapis_auth - -A bridge package between Flutter's [`google_sign_in` plugin](https://pub.dev/packages/google_sign_in) and Dart's [`googleapis` package](https://pub.dev/packages/googleapis), that is able to create [`googleapis_auth`-like `AuthClient` instances](https://pub.dev/documentation/googleapis_auth/latest/googleapis_auth.auth/AuthClient-class.html) directly from the `GoogleSignIn` plugin. - -## Usage - -This package is implemented as an [extension method](https://dart.dev/guides/language/extension-methods) on top of the `GoogleSignIn` plugin. - -In order to use it, you need to add a `dependency` to your `pubspec.yaml`. Then, wherever you're importing `package:google_sign_in/google_sign_in.dart`, add the following: - -```dart -... -import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; -... -``` - -From that moment on, your `GoogleSignIn` instance will have an additional `Future authenticatedClient()` method that you can call once your sign in is successful to retrieve an `AuthClient`. - -That object can then be used to create instances of `googleapis` API clients: - -```dart -... -final peopleApi = PeopleApi(await _googleSignIn.authenticatedClient()); -final response = await peopleApi.people.connections.list( - 'people/me', - personFields: 'names', -); -... -``` - -## Example - -This package contains a modified version of Flutter's Google Sign In example app that uses `package:googleapis`' API clients, instead of raw http requests. - -See it [here](https://github.com/flutter/plugins/blob/master/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart). - -The original code (and its license) can be seen [here](https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in/example/lib/main.dart). - -## Testing - -Run tests with `flutter test`. - -## Issues and feedback - -Please file [issues](https://github.com/flutter/flutter/issues/new) -to send feedback or report a bug. Thank you! diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md deleted file mode 100755 index a7ad235b71d5..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# extension_google_sign_in_example - -Demonstrates how to use the google_sign_in plugin with the `googleapis` package. - -## Getting Started - -For help getting started with Flutter, view our online -[documentation](https://flutter.dev/). diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/build.gradle b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/build.gradle deleted file mode 100755 index 2952c3b9c463..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/build.gradle +++ /dev/null @@ -1,64 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 29 - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - applicationId "io.flutter.plugins.googlesigninexample" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } - - testOptions { - unitTests.returnDefaultValues = true - } -} - -flutter { - source '../..' -} - -dependencies { - implementation 'com.google.android.gms:play-services-auth:16.0.1' - testImplementation'junit:junit:4.12' - testImplementation 'org.mockito:mockito-core:2.17.0' -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/google-services.json b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/google-services.json deleted file mode 100644 index efa524535553..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/google-services.json +++ /dev/null @@ -1,246 +0,0 @@ -{ - "project_info": { - "project_number": "479882132969", - "firebase_url": "https://my-flutter-proj.firebaseio.com", - "project_id": "my-flutter-proj", - "storage_bucket": "my-flutter-proj.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:479882132969:android:c73fd19ff7e2c0be", - "android_client_info": { - "package_name": "io.flutter.plugins.cameraexample" - } - }, - "oauth_client": [ - { - "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyCrZz9T0Pg0rDnpxfNuPBrOxGhXskfebXs" - } - ], - "services": { - "analytics_service": { - "status": 1 - }, - "appinvite_service": { - "status": 1, - "other_platform_oauth_client": [] - }, - "ads_service": { - "status": 2 - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:479882132969:android:632cdf3fc0a17139", - "android_client_info": { - "package_name": "io.flutter.plugins.firebasedynamiclinksexample" - } - }, - "oauth_client": [ - { - "client_id": "479882132969-32qusitiag53931ck80h121ajhlc5a7e.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "io.flutter.plugins.firebasedynamiclinksexample", - "certificate_hash": "e733b7a303250b63e06de6f7c9767c517d69cfa0" - } - }, - { - "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyCrZz9T0Pg0rDnpxfNuPBrOxGhXskfebXs" - } - ], - "services": { - "analytics_service": { - "status": 1 - }, - "appinvite_service": { - "status": 2, - "other_platform_oauth_client": [ - { - "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "479882132969-gjp4e63ogu2h6guttj2ie6t3f10ic7i8.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "io.flutter.plugins.firebaseMlVisionExample" - } - } - ] - }, - "ads_service": { - "status": 2 - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:479882132969:android:ae50362b4bc06086", - "android_client_info": { - "package_name": "io.flutter.plugins.firebasemlvisionexample" - } - }, - "oauth_client": [ - { - "client_id": "479882132969-9pp74fkgmtvt47t9rikc1p861v7n85tn.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "io.flutter.plugins.firebasemlvisionexample", - "certificate_hash": "e733b7a303250b63e06de6f7c9767c517d69cfa0" - } - }, - { - "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyCrZz9T0Pg0rDnpxfNuPBrOxGhXskfebXs" - } - ], - "services": { - "analytics_service": { - "status": 1 - }, - "appinvite_service": { - "status": 2, - "other_platform_oauth_client": [ - { - "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "479882132969-gjp4e63ogu2h6guttj2ie6t3f10ic7i8.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "io.flutter.plugins.firebaseMlVisionExample" - } - } - ] - }, - "ads_service": { - "status": 2 - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:479882132969:android:215a22700e1b466b", - "android_client_info": { - "package_name": "io.flutter.plugins.firebaseperformanceexample" - } - }, - "oauth_client": [ - { - "client_id": "479882132969-8h4kiv8m7ho4tvn6uuujsfcrf69unuf7.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "io.flutter.plugins.firebaseperformanceexample", - "certificate_hash": "e733b7a303250b63e06de6f7c9767c517d69cfa0" - } - }, - { - "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyCrZz9T0Pg0rDnpxfNuPBrOxGhXskfebXs" - } - ], - "services": { - "analytics_service": { - "status": 1 - }, - "appinvite_service": { - "status": 2, - "other_platform_oauth_client": [ - { - "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "479882132969-gjp4e63ogu2h6guttj2ie6t3f10ic7i8.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "io.flutter.plugins.firebaseMlVisionExample" - } - } - ] - }, - "ads_service": { - "status": 2 - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:479882132969:android:5e9f1f89e134dc86", - "android_client_info": { - "package_name": "io.flutter.plugins.googlesigninexample" - } - }, - "oauth_client": [ - { - "client_id": "479882132969-90ml692hkonp587sl0v0rurmnvkekgrg.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "io.flutter.plugins.googlesigninexample", - "certificate_hash": "e733b7a303250b63e06de6f7c9767c517d69cfa0" - } - }, - { - "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyCrZz9T0Pg0rDnpxfNuPBrOxGhXskfebXs" - } - ], - "services": { - "analytics_service": { - "status": 1 - }, - "appinvite_service": { - "status": 2, - "other_platform_oauth_client": [ - { - "client_id": "479882132969-0d20fkjtr1p8evfomfkf3vmi50uajml2.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "479882132969-gjp4e63ogu2h6guttj2ie6t3f10ic7i8.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "io.flutter.plugins.firebaseMlVisionExample" - } - } - ] - }, - "ads_service": { - "status": 2 - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 9a4163a4f5ee..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/AndroidManifest.xml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/AndroidManifest.xml deleted file mode 100755 index df80f829c1e7..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore deleted file mode 100755 index 9eb4563d2ae1..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/.gitignore +++ /dev/null @@ -1 +0,0 @@ -GeneratedPluginRegistrant.java diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java deleted file mode 100644 index 5ec19822734c..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java +++ /dev/null @@ -1,19 +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. - -package io.flutter.plugins.googlesigninexample; - -import android.os.Bundle; -import io.flutter.plugins.googlesignin.GoogleSignInPlugin; -import io.flutter.view.FlutterMain; - -@SuppressWarnings("deprecation") -public class EmbeddingV1Activity extends io.flutter.app.FlutterActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - FlutterMain.startInitialization(this); - super.onCreate(savedInstanceState); - GoogleSignInPlugin.registerWith(registrarFor("io.flutter.plugins.googlesignin")); - } -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java deleted file mode 100644 index 3e7250cea0ee..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 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. - -package io.flutter.plugins.googlesigninexample; - -import androidx.test.rule.ActivityTestRule; -import dev.flutter.plugins.integration_test.FlutterTestRunner; -import org.junit.Rule; -import org.junit.runner.RunWith; - -@RunWith(FlutterTestRunner.class) -@SuppressWarnings("deprecation") -public class EmbeddingV1ActivityTest { - @Rule - public ActivityTestRule rule = - new ActivityTestRule<>(EmbeddingV1Activity.class); -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java deleted file mode 100644 index f9aa77b30e5d..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2020 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. - -package io.flutter.plugins.googlesigninexample; - -import androidx.test.rule.ActivityTestRule; -import dev.flutter.plugins.integration_test.FlutterTestRunner; -import io.flutter.embedding.android.FlutterActivity; -import org.junit.Rule; -import org.junit.runner.RunWith; - -@RunWith(FlutterTestRunner.class) -public class FlutterActivityTest { - @Rule - public ActivityTestRule rule = new ActivityTestRule<>(FlutterActivity.class); -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100755 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100755 index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100755 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100755 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/values/strings.xml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/values/strings.xml deleted file mode 100644 index c7e28ffcedd1..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - YOUR_WEB_CLIENT_ID - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/build.gradle b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/build.gradle deleted file mode 100755 index 541636cc492a..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -buildscript { - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle.properties b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle.properties deleted file mode 100755 index 38c8d4544ff1..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 019065d1d650..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/settings.gradle b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/settings.gradle deleted file mode 100755 index 115da6cb4f4d..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withInputStream { stream -> plugins.load(stream) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/AppFrameworkInfo.plist b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100755 index 6c2de8086bcd..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - UIRequiredDeviceCapabilities - - arm64 - - MinimumOSVersion - 8.0 - - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Debug.xcconfig b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Debug.xcconfig deleted file mode 100755 index 9803018ca79d..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Generated.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Release.xcconfig b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Release.xcconfig deleted file mode 100755 index a4a8c604e13d..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Generated.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/GoogleSignInPluginTest/Info.plist b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/GoogleSignInPluginTest/Info.plist deleted file mode 100644 index 64d65ca49577..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/GoogleSignInPluginTest/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index faaaa58070bd..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,502 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 5C6F5A6E1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C6F5A6D1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m */; }; - 7A303C2E1E89D76400B1F19E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7A303C2D1E89D76400B1F19E /* GoogleService-Info.plist */; }; - 7ACDFB0E1E8944C400BE2D00 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7ACDFB0D1E8944C400BE2D00 /* AppFrameworkInfo.plist */; }; - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; - 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - C2FB9CBA01DB0A2DE5F31E12 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0263E28FA425D1CE928BDE15 /* libPods-Runner.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0263E28FA425D1CE928BDE15 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 5A76713E622F06379AEDEBFA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 5C6F5A6C1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 5C6F5A6D1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 7A303C2D1E89D76400B1F19E /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 7ACDFB0D1E8944C400BE2D00 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - F582639B44581540871D9BB0 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C2FB9CBA01DB0A2DE5F31E12 /* libPods-Runner.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { - isa = PBXGroup; - children = ( - 5A76713E622F06379AEDEBFA /* Pods-Runner.debug.xcconfig */, - F582639B44581540871D9BB0 /* Pods-Runner.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 7ACDFB0D1E8944C400BE2D00 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 840012C8B5EDBCF56B0E4AC1 /* Pods */, - CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 5C6F5A6C1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.h */, - 5C6F5A6D1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m */, - 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, - 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 7A303C2D1E89D76400B1F19E /* GoogleService-Info.plist */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 97C146F21CF9000F007C117D /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 0263E28FA425D1CE928BDE15 /* libPods-Runner.a */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */, - 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 7A303C2E1E89D76400B1F19E /* GoogleService-Info.plist in Resources */, - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 7ACDFB0E1E8944C400BE2D00 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin\n"; - }; - 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", - "${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle", - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../Flutter/Flutter.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - AB1344B0443C71CD721E1BB7 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, - 97C146F31CF9000F007C117D /* main.m in Sources */, - 5C6F5A6E1EC3B4CB008D64B5 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.googleSignInExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.googleSignInExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100755 index 21a3cc14c74e..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100755 index 3bb3697ef41c..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100755 index 21a3cc14c74e..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.h b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.h deleted file mode 100644 index d9e18e990f2e..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.h +++ /dev/null @@ -1,10 +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 -#import - -@interface AppDelegate : FlutterAppDelegate - -@end diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.m b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.m deleted file mode 100644 index f08675707182..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/AppDelegate.m +++ /dev/null @@ -1,17 +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. - -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -@end diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100755 index d22f10b2ab63..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100755 index 28c6bf03016f6c994b70f38d1b7346e5831b531f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 564 zcmV-40?Yl0P)Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100755 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100755 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100755 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100755 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100755 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100755 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 zcmVjJBgitF5mAp-i>4+KS_oR{|13AP->1TD4=w)g|)JHOx|a2Wk1Va z!k)vP$UcQ#mdj%wNQoaJ!w>jv_6&JPyutpQps?s5dmDQ>`%?Bvj>o<%kYG!YW6H-z zu`g$@mp`;qDR!51QaS}|ZToSuAGcJ7$2HF0z`ln4t!#Yg46>;vGG9N9{V@9z#}6v* zfP?}r6b{*-C*)(S>NECI_E~{QYzN5SXRmVnP<=gzP+_Sp(Aza_hKlZ{C1D&l*(7IKXxQC1Z9#6wx}YrGcn~g%;icdw>T0Rf^w0{ z$_wn1J+C0@!jCV<%Go5LA45e{5gY9PvZp8uM$=1}XDI+9m7!A95L>q>>oe0$nC->i zeexUIvq%Uk<-$>DiDb?!In)lAmtuMWxvWlk`2>4lNuhSsjAf2*2tjT`y;@d}($o)S zn(+W&hJ1p0xy@oxP%AM15->wPLp{H!k)BdBD$toBpJh+crWdsNV)qsHaqLg2_s|Ih z`8E9z{E3sA!}5aKu?T!#enD(wLw?IT?k-yWVHZ8Akz4k5(TZJN^zZgm&zM28sfTD2BYJ|Fde3Xzh;;S` z=GXTnY4Xc)8nYoz6&vF;P7{xRF-{|2Xs5>a5)@BrnQ}I(_x7Cgpx#5&Td^4Q9_FnQ zX5so*;#8-J8#c$OlA&JyPp$LKUhC~-e~Ij!L%uSMu!-VZG7Hx-L{m2DVR2i=GR(_% zCVD!4N`I)&Q5S`?P&fQZ=4#Dgt_v2-DzkT}K(9gF0L(owe-Id$Rc2qZVLqI_M_DyO z9@LC#U28_LU{;wGZ&))}0R2P4MhajKCd^K#D+JJ&JIXZ_p#@+7J9A&P<0kdRujtQ_ zOy>3=C$kgi6$0pW06KaLz!21oOryKM3ZUOWqppndxfH}QpgjEJ`j7Tzn5bk6K&@RA?vl##y z$?V~1E(!wB5rH`>3nc&@)|#<1dN2cMzzm=PGhQ|Yppne(C-Vlt450IXc`J4R0W@I7 zd1e5uW6juvO%ni(WX7BsKx3MLngO7rHO;^R5I~0^nE^9^E_eYLgiR9&KnJ)pBbfno zSVnW$0R+&6jOOsZ82}nJ126+c|%svPo;TeUku<2G7%?$oft zyaO;tVo}(W)VsTUhq^XmFi#2z%-W9a{7mXn{uzivYQ_d6b7VJG{77naW(vHt-uhnY zVN#d!JTqVh(7r-lhtXVU6o})aZbDt_;&wJVGl2FKYFBFpU-#9U)z#(A%=IVnqytR$SY-sO( z($oNE09{D^@OuYPz&w~?9>Fl5`g9u&ecFGhqX=^#fmR=we0CJw+5xna*@oHnkahk+ z9aWeE3v|An+O5%?4fA&$Fgu~H_YmqR!yIU!bFCk4!#pAj%(lI(A5n)n@Id#M)O9Yx zJU9oKy{sRAIV3=5>(s8n{8ryJ!;ho}%pn6hZKTKbqk=&m=f*UnK$zW3YQP*)pw$O* zIfLA^!-bmBl6%d_n$#tP8Zd_(XdA*z*WH|E_yILwjtI~;jK#v-6jMl^?<%Y%`gvpwv&cFb$||^v4D&V=aNy?NGo620jL3VZnA%s zH~I|qPzB~e(;p;b^gJr7Ure#7?8%F0m4vzzPy^^(q4q1OdthF}Fi*RmVZN1OwTsAP zn9CZP`FazX3^kG(KodIZ=Kty8DLTy--UKfa1$6XugS zk%6v$Kmxt6U!YMx0JQ)0qX*{CXwZZk$vEROidEc7=J-1;peNat!vS<3P-FT5po>iE z!l3R+<`#x|+_hw!HjQGV=8!q|76y8L7N8gP3$%0kfush|u0uU^?dKBaeRSBUpOZ0c z62;D&Mdn2}N}xHRFTRI?zRv=>=AjHgH}`2k4WK=#AHB)UFrR-J87GgX*x5fL^W2#d z=(%K8-oZfMO=i{aWRDg=FX}UubM4eotRDcn;OR#{3q=*?3mE3_oJ-~prjhxh%PgQT zyn)Qozaq0@o&|LEgS{Ind4Swsr;b`u185hZPOBLL<`d2%^Yp1?oL)=jnLi;Zo0ZDliTtQ^b5SmfIMe{T==zZkbvn$KTQGlbG8w}s@M3TZnde;1Am46P3juKb zl9GU&3F=q`>j!`?SyH#r@O59%@aMX^rx}Nxe<>NqpUp5=lX1ojGDIR*-D^SDuvCKF z?3$xG(gVUsBERef_YjPFl^rU9EtD{pt z0CXwpN7BN3!8>hajGaTVk-wl=9rxmfWtIhC{mheHgStLi^+Nz12a?4r(fz)?3A%at zMlvQmL<2-R)-@G1wJ0^zQK%mR=r4d{Y3fHp){nWXUL#|CqXl(+v+qDh>FkF9`eWrW zfr^D%LNfOcTNvtx0JXR35J0~Jpi2#P3Q&80w+nqNfc}&G0A~*)lGHKv=^FE+b(37|)zL;KLF>oiGfb(?&1 zV3XRu!Sw>@quKiab%g6jun#oZ%!>V#A%+lNc?q>6+VvyAn=kf_6z^(TZUa4Eelh{{ zqFX-#dY(EV@7l$NE&kv9u9BR8&Ojd#ZGJ6l8_BW}^r?DIS_rU2(XaGOK z225E@kH5Opf+CgD^{y29jD4gHbGf{1MD6ggQ&%>UG4WyPh5q_tb`{@_34B?xfSO*| zZv8!)q;^o-bz`MuxXk*G^}(6)ACb@=Lfs`Hxoh>`Y0NE8QRQ!*p|SH@{r8=%RKd4p z+#Ty^-0kb=-H-O`nAA3_6>2z(D=~Tbs(n8LHxD0`R0_ATFqp-SdY3(bZ3;VUM?J=O zKCNsxsgt@|&nKMC=*+ZqmLHhX1KHbAJs{nGVMs6~TiF%Q)P@>!koa$%oS zjXa=!5>P`vC-a}ln!uH1ooeI&v?=?v7?1n~P(wZ~0>xWxd_Aw;+}9#eULM7M8&E?Y zC-ZLhi3RoM92SXUb-5i-Lmt5_rfjE{6y^+24`y$1lywLyHO!)Boa7438K4#iLe?rh z2O~YGSgFUBH?og*6=r9rme=peP~ah`(8Zt7V)j5!V0KPFf_mebo3z95U8(up$-+EA^9dTRLq>Yl)YMBuch9%=e5B`Vnb>o zt03=kq;k2TgGe4|lGne&zJa~h(UGutjP_zr?a7~#b)@15XNA>Dj(m=gg2Q5V4-$)D|Q9}R#002ovPDHLkV1o7DH3k3x diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100755 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8 - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Base.lproj/Main.storyboard b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100755 index f3c28516fb38..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/GoogleService-Info.plist b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/GoogleService-Info.plist deleted file mode 100644 index 6042aab908af..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/GoogleService-Info.plist +++ /dev/null @@ -1,44 +0,0 @@ - - - - - AD_UNIT_ID_FOR_BANNER_TEST - ca-app-pub-3940256099942544/2934735716 - AD_UNIT_ID_FOR_INTERSTITIAL_TEST - ca-app-pub-3940256099942544/4411468910 - CLIENT_ID - 479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u - ANDROID_CLIENT_ID - 479882132969-jie8r1me6dsra60pal6ejaj8dgme3tg0.apps.googleusercontent.com - API_KEY - AIzaSyBECOwLTAN6PU4Aet1b2QLGIb3kRK8Xjew - GCM_SENDER_ID - 479882132969 - PLIST_VERSION - 1 - BUNDLE_ID - io.flutter.plugins.googleSignInExample - PROJECT_ID - my-flutter-proj - STORAGE_BUCKET - my-flutter-proj.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 1:479882132969:ios:2643f950e0a0da08 - DATABASE_URL - https://my-flutter-proj.firebaseio.com - SERVER_CLIENT_ID - YOUR_SERVER_CLIENT_ID - - \ No newline at end of file diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Info.plist b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Info.plist deleted file mode 100755 index e03ccfe55e37..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/Info.plist +++ /dev/null @@ -1,62 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - Google Sign-In Example - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - GoogleSignInExample - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLSchemes - - com.googleusercontent.apps.479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u - - - - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - arm64 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/main.m b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/main.m deleted file mode 100644 index bec320c0bee0..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/ios/Runner/main.m +++ /dev/null @@ -1,13 +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 -#import -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart deleted file mode 100755 index 0ec62a832648..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/lib/main.dart +++ /dev/null @@ -1,150 +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. - -// ignore_for_file: public_member_api_docs - -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:google_sign_in/google_sign_in.dart'; - -import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; -import 'package:googleapis/people/v1.dart'; - -GoogleSignIn _googleSignIn = GoogleSignIn( - scopes: [ - 'email', - 'https://www.googleapis.com/auth/contacts.readonly', - ], -); - -void main() { - runApp( - MaterialApp( - title: 'Google Sign In', - home: SignInDemo(), - ), - ); -} - -class SignInDemo extends StatefulWidget { - @override - State createState() => SignInDemoState(); -} - -class SignInDemoState extends State { - GoogleSignInAccount _currentUser; - String _contactText; - - @override - void initState() { - super.initState(); - _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account) { - setState(() { - _currentUser = account; - }); - if (_currentUser != null) { - _handleGetContact(); - } - }); - _googleSignIn.signInSilently(); - } - - Future _handleGetContact() async { - setState(() { - _contactText = 'Loading contact info...'; - }); - - final peopleApi = - PeopleServiceApi(await _googleSignIn.authenticatedClient()); - final response = await peopleApi.people.connections.list( - 'people/me', - personFields: 'names', - ); - - final firstNamedContactName = _pickFirstNamedContact(response.connections); - - setState(() { - if (firstNamedContactName != null) { - _contactText = 'I see you know $firstNamedContactName!'; - } else { - _contactText = 'No contacts to display.'; - } - }); - } - - String _pickFirstNamedContact(List connections) { - return connections - ?.firstWhere( - (person) => person.names != null, - orElse: () => null, - ) - ?.names - ?.firstWhere( - (name) => name.displayName != null, - orElse: () => null, - ) - ?.displayName; - } - - Future _handleSignIn() async { - try { - await _googleSignIn.signIn(); - } catch (error) { - print(error); - } - } - - Future _handleSignOut() => _googleSignIn.disconnect(); - - Widget _buildBody() { - if (_currentUser != null) { - return Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - ListTile( - leading: GoogleUserCircleAvatar( - identity: _currentUser, - ), - title: Text(_currentUser.displayName ?? ''), - subtitle: Text(_currentUser.email ?? ''), - ), - const Text('Signed in successfully.'), - Text(_contactText ?? ''), - ElevatedButton( - child: const Text('SIGN OUT'), - onPressed: _handleSignOut, - ), - ElevatedButton( - child: const Text('REFRESH'), - onPressed: _handleGetContact, - ), - ], - ); - } else { - return Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - const Text('You are not currently signed in.'), - ElevatedButton( - child: const Text('SIGN IN'), - onPressed: _handleSignIn, - ), - ], - ); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Google Sign In'), - ), - body: ConstrainedBox( - constraints: const BoxConstraints.expand(), - child: _buildBody(), - )); - } -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml deleted file mode 100755 index c96ca065f081..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/pubspec.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: extension_google_sign_in_example -description: Example of Google Sign-In plugin and googleapis. - -dependencies: - flutter: - sdk: flutter - google_sign_in: ^5.0.0 - extension_google_sign_in_as_googleapis_auth: - # When depending on this package from a real application you should use: - # extension_google_sign_in_as_googleapis_auth: ^x.y.z - # See https://dart.dev/tools/pub/dependencies#version-constraints - # The example app is bundled with the plugin so we use a path dependency on - # the parent directory to use the current plugin's version. - path: ../ - googleapis: ^1.0.0 - -dev_dependencies: - pedantic: ^1.10.0 - -flutter: - uses-material-design: true - -environment: - sdk: ">=2.0.0-dev.28.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4" diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/web/index.html b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/web/index.html deleted file mode 100644 index 42a7d93582ba..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/example/web/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - Google Sign-in Example - - - - - diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart deleted file mode 100644 index b88be661fde4..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/lib/extension_google_sign_in_as_googleapis_auth.dart +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2020 The Flutter Authors -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -import 'package:meta/meta.dart'; -import 'package:google_sign_in/google_sign_in.dart'; -import 'package:googleapis_auth/googleapis_auth.dart' as googleapis_auth; -import 'package:http/http.dart' as http; - -/// Extension on [GoogleSignIn] that adds an `authenticatedClient` method. -/// -/// This method can be used to retrieve an authenticated [googleapis_auth.AuthClient] -/// client that can be used with the rest of the `googleapis` libraries. -extension GoogleApisGoogleSignInAuth on GoogleSignIn { - /// Retrieve a `googleapis` authenticated client. - Future authenticatedClient({ - @visibleForTesting GoogleSignInAuthentication? debugAuthentication, - @visibleForTesting List? debugScopes, - }) async { - final GoogleSignInAuthentication? auth = - debugAuthentication ?? await currentUser?.authentication; - final String? oathTokenString = auth?.accessToken; - if (oathTokenString == null) { - return null; - } - final credentials = googleapis_auth.AccessCredentials( - googleapis_auth.AccessToken( - 'Bearer', - oathTokenString, - // We don't know when the token expires, so we assume "never" - DateTime.now().toUtc().add(Duration(days: 365)), - ), - null, // We don't have a refreshToken - debugScopes ?? this.scopes, - ); - - return googleapis_auth.authenticatedClient(http.Client(), credentials); - } -} diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml deleted file mode 100644 index 7d86b67196d0..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/pubspec.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2020 The Flutter Authors -# -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file or at -# https://developers.google.com/open-source/licenses/bsd - -name: extension_google_sign_in_as_googleapis_auth -description: A bridge package between google_sign_in and googleapis_auth, to create Authenticated Clients from google_sign_in user credentials. -version: 2.0.0 -homepage: https://github.com/flutter/plugins/google_sign_in/extension_google_sign_in_as_googleapis_auth - -dependencies: - flutter: - sdk: flutter - google_sign_in: ^5.0.0 - googleapis_auth: ^1.0.0 - meta: ^1.3.0 - http: ^0.13.0 - -dev_dependencies: - pedantic: ^1.10.0 - test: ^1.16.3 - flutter_test: - sdk: flutter - -environment: - sdk: ">=2.12.0-259.9.beta <3.0.0" - flutter: ">=1.12.13+hotfix.4" diff --git a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart b/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart deleted file mode 100644 index d747b3d19c63..000000000000 --- a/packages/google_sign_in/extension_google_sign_in_as_googleapis_auth/test/extension_google_sign_in_as_googleapis_auth_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2020 The Flutter Authors -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -import 'package:google_sign_in/google_sign_in.dart'; -import 'package:googleapis_auth/googleapis_auth.dart' as auth; -import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:test/fake.dart'; - -const SOME_FAKE_ACCESS_TOKEN = 'this-is-something-not-null'; -const DEBUG_FAKE_SCOPES = ['some-scope', 'another-scope']; -const SIGN_IN_FAKE_SCOPES = ['some-scope', 'another-scope']; - -class FakeGoogleSignIn extends Fake implements GoogleSignIn { - final List scopes = SIGN_IN_FAKE_SCOPES; -} - -class FakeGoogleSignInAuthentication extends Fake - implements GoogleSignInAuthentication { - final String accessToken = SOME_FAKE_ACCESS_TOKEN; -} - -void main() { - GoogleSignIn signIn = FakeGoogleSignIn(); - final authMock = FakeGoogleSignInAuthentication(); - - test('authenticatedClient returns an authenticated client', () async { - final client = await signIn.authenticatedClient( - debugAuthentication: authMock, - ); - expect(client, isA()); - }); - - test('authenticatedClient uses GoogleSignIn scopes by default', () async { - final client = (await signIn.authenticatedClient( - debugAuthentication: authMock, - ))!; - expect(client.credentials.accessToken.data, equals(SOME_FAKE_ACCESS_TOKEN)); - expect(client.credentials.scopes, equals(SIGN_IN_FAKE_SCOPES)); - }); - - test('authenticatedClient returned client contains the passed-in credentials', - () async { - final client = (await signIn.authenticatedClient( - debugAuthentication: authMock, - debugScopes: DEBUG_FAKE_SCOPES, - ))!; - expect(client.credentials.accessToken.data, equals(SOME_FAKE_ACCESS_TOKEN)); - expect(client.credentials.scopes, equals(DEBUG_FAKE_SCOPES)); - }); -} diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index f6b1c166069f..27726bd53426 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -26,8 +26,6 @@ check_changed_packages > /dev/null # cases where using a relaxed version constraint isn't possible. readonly EXCLUDED_PLUGINS_LIST=( "plugin_platform_interface" # This should never be a direct app dependency. - "extension_google_sign_in_as_googleapis_auth" # Transitive dependency issues - # with integration_test. ) # Comma-separated string of the list above readonly EXCLUDED=$(IFS=, ; echo "${EXCLUDED_PLUGINS_LIST[*]}") From 4dea720e3aa4c9a444f457a3fed17fee410b7e8b Mon Sep 17 00:00:00 2001 From: Konstantin Touev Date: Wed, 10 Mar 2021 19:10:09 +0200 Subject: [PATCH 322/924] [shared_preferences] Fix concurrent modification of the shared preferences on Android (#3684) Uses an actual queue, rather than a one-element handoff "queue", for the single-thread background processing of commits. --- .../shared_preferences/CHANGELOG.md | 4 ++++ .../sharedpreferences/MethodCallHandlerImpl.java | 4 ++-- .../integration_test/shared_preferences_test.dart | 13 +++++++++++++ .../shared_preferences/pubspec.yaml | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index 1516163b8807..b0899d57a3c5 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.4 + +* Fix a regression with simultaneous writes on Android. + ## 2.0.3 * Android: don't create additional Handler when method channel is called. diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java index 4f55d882005f..4486421e3959 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java @@ -23,7 +23,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; -import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -53,7 +53,7 @@ class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { MethodCallHandlerImpl(Context context) { preferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); executor = - new ThreadPoolExecutor(0, 1, 30L, TimeUnit.SECONDS, new SynchronousQueue()); + new ThreadPoolExecutor(0, 1, 30L, TimeUnit.SECONDS, new LinkedBlockingQueue()); handler = new Handler(Looper.getMainLooper()); } diff --git a/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart index 1caf695d9365..d36286a559b3 100644 --- a/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart @@ -91,5 +91,18 @@ void main() { expect(preferences.getDouble('double'), null); expect(preferences.getStringList('List'), null); }); + + testWidgets('simultaneous writes', (WidgetTester _) async { + final List> writes = >[]; + final int writeCount = 100; + for (int i = 1; i <= writeCount; i++) { + writes.add(preferences.setInt('int', i)); + } + List result = await Future.wait(writes, eagerError: true); + // All writes should succeed. + expect(result.where((element) => !element), isEmpty); + // The last write should win. + expect(preferences.getInt('int'), writeCount); + }); }); } diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 899266a4d6f0..b53bbfd93a38 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences description: Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences -version: 2.0.3 +version: 2.0.4 flutter: plugin: From 735e1a5208e1f8048fb7544dc288730533eae9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Wed, 10 Mar 2021 18:45:04 +0100 Subject: [PATCH 323/924] [image_picker] Implemented 2860 and added Unit Test to test functionality (#3685) --- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ .../io/flutter/plugins/imagepicker/FileUtils.java | 15 +++++++++++---- .../flutter/plugins/imagepicker/FileUtilTest.java | 9 +++++++++ packages/image_picker/image_picker/pubspec.yaml | 2 +- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 7be13a574a77..4f2a054f1520 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.2+1 + +* Android: fixes an issue where videos could be wrongly picked with `.jpg` extension. + ## 0.7.2 * Run CocoaPods iOS tests in RunnerUITests target diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java index 9ebf1fad826b..19e304ea9eee 100644 --- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java +++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java @@ -23,8 +23,10 @@ package io.flutter.plugins.imagepicker; +import android.content.ContentResolver; import android.content.Context; import android.net.Uri; +import android.webkit.MimeTypeMap; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -39,7 +41,7 @@ String getPathFromUri(final Context context, final Uri uri) { OutputStream outputStream = null; boolean success = false; try { - String extension = getImageExtension(uri); + String extension = getImageExtension(context, uri); inputStream = context.getContentResolver().openInputStream(uri); file = File.createTempFile("image_picker", extension, context.getCacheDir()); file.deleteOnExit(); @@ -67,13 +69,18 @@ String getPathFromUri(final Context context, final Uri uri) { } /** @return extension of image with dot, or default .jpg if it none. */ - private static String getImageExtension(Uri uriImage) { + private static String getImageExtension(Context context, Uri uriImage) { String extension = null; try { String imagePath = uriImage.getPath(); - if (imagePath != null && imagePath.lastIndexOf(".") != -1) { - extension = imagePath.substring(imagePath.lastIndexOf(".") + 1); + if (uriImage.getScheme().equals(ContentResolver.SCHEME_CONTENT)) { + final MimeTypeMap mime = MimeTypeMap.getSingleton(); + extension = mime.getExtensionFromMimeType(context.getContentResolver().getType(uriImage)); + } else { + extension = + MimeTypeMap.getFileExtensionFromUrl( + Uri.fromFile(new File(uriImage.getPath())).toString()); } } catch (Exception e) { extension = null; diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java index c9fa3381ebe5..bd705d2374e5 100644 --- a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java @@ -54,4 +54,13 @@ public void FileUtil_GetPathFromUri() throws IOException { String imageStream = new String(bytes, UTF_8); assertTrue(imageStream.equals("imageStream")); } + + @Test + public void FileUtil_getImageExtension() throws IOException { + Uri uri = Uri.parse("content://dummy/dummy.png"); + shadowContentResolver.registerInputStream( + uri, new ByteArrayInputStream("imageStream".getBytes(UTF_8))); + String path = fileUtils.getPathFromUri(context, uri); + assertTrue(path.endsWith(".jpg")); + } } diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 562528466861..9ea8e5ddcbd4 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.7.2 +version: 0.7.2+1 flutter: plugin: From d306f98fc13298bf2e0844a221bf699226700bd7 Mon Sep 17 00:00:00 2001 From: nt4f04uNd Date: Wed, 10 Mar 2021 22:45:02 +0300 Subject: [PATCH 324/924] [video_player] fixed misleading size and aspect ratio documentation (#3668) --- .../video_player/video_player/CHANGELOG.md | 4 ++++ .../lib/src/closed_caption_file.dart | 19 ++++++++++++------- .../video_player/lib/video_player.dart | 12 +++++++----- .../video_player/video_player/pubspec.yaml | 2 +- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index e5c30a0389e4..08a5e443149e 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.2 + +* Fix `VideoPlayerValue` size and aspect ratio documentation + ## 2.0.1 * Remove the deprecated API "exoPlayer.setAudioAttributes". diff --git a/packages/video_player/video_player/lib/src/closed_caption_file.dart b/packages/video_player/video_player/lib/src/closed_caption_file.dart index eae9bf5dfabf..64ab1f6ca651 100644 --- a/packages/video_player/video_player/lib/src/closed_caption_file.dart +++ b/packages/video_player/video_player/lib/src/closed_caption_file.dart @@ -31,11 +31,12 @@ class Caption { /// /// This is not recommended for direct use unless you are writing a parser for /// a new closed captioning file type. - const Caption( - {required this.number, - required this.start, - required this.end, - required this.text}); + const Caption({ + required this.number, + required this.start, + required this.end, + required this.text, + }); /// The number that this caption was assigned. final int number; @@ -52,8 +53,12 @@ class Caption { /// A no caption object. This is a caption with [start] and [end] durations of zero, /// and an empty [text] string. - static const Caption none = - Caption(number: 0, start: Duration.zero, end: Duration.zero, text: ''); + static const Caption none = Caption( + number: 0, + start: Duration.zero, + end: Duration.zero, + text: '', + ); @override String toString() { diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index 6a2af76fa547..96dd73d3adea 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -87,12 +87,10 @@ class VideoPlayerValue { /// A description of the error if present. /// - /// If [hasError] is false this is [null]. + /// If [hasError] is false this is `null`. final String? errorDescription; /// The [size] of the currently loaded video. - /// - /// Is null when [initialized] is false. final Size size; /// Indicates whether or not the video has been loaded and is ready to play. @@ -102,8 +100,12 @@ class VideoPlayerValue { /// [errorDescription] should have information about the problem. bool get hasError => errorDescription != null; - /// Returns [size.width] / [size.height] when size is non-null, or `1.0.` when - /// size is null or the aspect ratio would be less than or equal to 0.0. + /// Returns [size.width] / [size.height]. + /// + /// Will return `1.0` if: + /// * [isInitialized] is `false` + /// * [size.width], or [size.height] is equal to `0.0` + /// * aspect ratio would be less than or equal to `0.0` double get aspectRatio { if (!isInitialized || size.width == 0 || size.height == 0) { return 1.0; diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 3c6a34c7f78c..17442d7ec09a 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -version: 2.0.1 +version: 2.0.2 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: From 79dd06a1eb1d007844df812328a5414b0fe8db26 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Wed, 10 Mar 2021 12:51:12 -0800 Subject: [PATCH 325/924] Streamline CI setup, and reenable macOS credits (#3697) This makes a few improvements to CI throughput: - Moves the flutter channel+upgrade step into each step, rather then doing it for both channels in the setup step. This avoids pointlessly doing twice the work in every setup (downloading two channels, only one of which will be used) - Re-enables credits for macOS tasks. These were disabled in a recent chance since I was unifying configurations, but it turns out that without credits there is *no* parallelization of macOS tasks, which makes the end-to-end time very long. - Dials back the Linux VM requirements based on looking at the new CPU and memory usage graphs for runs: - No task was ever reaching 4 CPUs or 12 GB of memory, so use those values for heavy workload; this will double concurrency of the heavy-workload tasks and should have no impact on run length. - Linux build+drive was extremely low usage, so move it to the light workload group. --- .cirrus.yml | 123 ++++++++++++++++++---------------------------------- 1 file changed, 42 insertions(+), 81 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index eac32d114269..8d992d5cbbd1 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,21 +1,24 @@ -# Light-workload tasks. -# These use default machines, with fewer CPUs, to reduce pressure on the -# concurrency limits. -task: - # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins +root_task_template: &ROOT_TASK_TEMPLATE + # Don't run on release tags since it creates O(n^2) tasks where n is the + # number of plugins only_if: $CIRRUS_TAG == '' use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' - container: - dockerfile: .ci/Dockerfile env: INTEGRATION_TEST_PATH: "./packages/integration_test" - upgrade_script: - - flutter channel stable - - flutter upgrade - - flutter channel master + CHANNEL: "master" # Default to master when not explicitly set by a task. + setup_script: + - flutter channel $CHANNEL - flutter upgrade - - flutter config --enable-linux-desktop - - git fetch origin master + - git fetch origin master # To set FETCH_HEAD for "git merge-base" to work + + +# Light-workload Linux tasks. +# These use default machines, with fewer CPUs, to reduce pressure on the +# concurrency limits. +task: + << : *ROOT_TASK_TEMPLATE + container: + dockerfile: .ci/Dockerfile matrix: ### Platform-agnostic tasks ### - name: plugin_tools_tests @@ -25,7 +28,6 @@ task: - CIRRUS_BUILD_ID=null pub run test - name: publishable script: - - flutter channel master - ./script/check_publish.sh - name: format format_script: ./script/incremental_build.sh format --fail-on-change @@ -35,14 +37,12 @@ task: CHANNEL: "master" CHANNEL: "stable" test_script: - - flutter channel $CHANNEL - ./script/incremental_build.sh test - name: analyze_master env: matrix: CHANNEL: "master" script: - - flutter channel $CHANNEL - ./script/incremental_build.sh analyze ## TODO(cyanglaz): ## Combing stable and master analyze jobs when integration test null safety is ready on flutter stable. @@ -51,7 +51,6 @@ task: matrix: CHANNEL: "stable" script: - - flutter channel $CHANNEL - find . -depth -type d -wholename '*_web/example' -exec rm -rf {} \; - ./script/incremental_build.sh analyze ### Android tasks ### @@ -61,7 +60,6 @@ task: CHANNEL: "master" CHANNEL: "stable" script: - - flutter channel $CHANNEL - ./script/build_all_plugins_app.sh apk ### Web tasks ### - name: build_all_plugins_web @@ -70,14 +68,12 @@ task: CHANNEL: "master" CHANNEL: "stable" script: - - flutter channel $CHANNEL - ./script/build_all_plugins_app.sh web - name: build-web-examples env: matrix: CHANNEL: "master" build_script: - - flutter channel $CHANNEL - ./script/incremental_build.sh build-examples --web # TODO: Add driving examples (and move to heavy-workload group). ### Linux desktop tasks ### @@ -87,8 +83,17 @@ task: CHANNEL: "master" CHANNEL: "stable" script: - - flutter channel $CHANNEL + - flutter config --enable-linux-desktop - ./script/build_all_plugins_app.sh linux + - name: build-linux+drive-examples + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" + build_script: + - flutter config --enable-linux-desktop + - ./script/incremental_build.sh build-examples --linux + - xvfb-run ./script/incremental_build.sh drive-examples --linux # Legacy Dockerfile configuration for web integration tests. # https://github.com/flutter/web_installers doesn't yet support the current @@ -97,20 +102,9 @@ task: # tasks" block above once web_installers has been updated to support Chrome 89 # (which is what the current image generated from .ci/Dockerfile has). task: - # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins - only_if: $CIRRUS_TAG == '' - use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' + << : *ROOT_TASK_TEMPLATE container: dockerfile: .ci/Dockerfile-LegacyChrome - env: - INTEGRATION_TEST_PATH: "./packages/integration_test" - upgrade_script: - - flutter channel stable - - flutter upgrade - - flutter channel master - - flutter upgrade - - flutter config --enable-linux-desktop - - git fetch origin master matrix: - name: integration_web_smoke_test env: @@ -120,7 +114,6 @@ task: # Tests integration example test in web. only_if: "changesInclude('.cirrus.yml', 'packages/integration_test/**') || $CIRRUS_PR == ''" install_script: - - flutter channel $CHANNEL - git clone https://github.com/flutter/web_installers.git - cd web_installers/packages/web_drivers/ - pub get @@ -130,26 +123,15 @@ task: - cd $INTEGRATION_TEST_PATH/example/ - flutter drive -v --driver=test_driver/integration_test.dart --target=integration_test/example_test.dart -d web-server --release --browser-name=chrome -# Heavy-workload tasks. +# Heavy-workload Linux tasks. # These use machines with more CPUs and memory, so will reduce parallelization # for non-credit runs. task: - # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins - only_if: $CIRRUS_TAG == '' - use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' + << : *ROOT_TASK_TEMPLATE container: dockerfile: .ci/Dockerfile - cpu: 8 - memory: 16G - env: - INTEGRATION_TEST_PATH: "./packages/integration_test" - upgrade_script: - - flutter channel stable - - flutter upgrade - - flutter channel master - - flutter upgrade - - flutter config --enable-linux-desktop - - git fetch origin master + cpu: 4 + memory: 12G matrix: ### Android tasks ### - name: build-apks+java-test+firebase-test-lab @@ -165,7 +147,6 @@ task: MAPS_API_KEY: ENCRYPTED[596a9f6bca436694625ac50851dc5da6b4d34cba8025f7db5bc9465142e8cd44e15f69e3507787753accebfc4910d550] GCLOUD_FIREBASE_TESTLAB_KEY: ENCRYPTED[07586610af1fdfc894e5969f70ef2458341b9b7e9c3b7c4225a663b4a48732b7208a4d91c3b7d45305a6b55fa2a37fc4] script: - - flutter channel $CHANNEL # Unsetting CIRRUS_CHANGE_MESSAGE and CIRRUS_COMMIT_MESSAGE as they # might include non-ASCII characters which makes Gradle crash. # See: https://github.com/flutter/flutter/issues/24935 @@ -186,35 +167,16 @@ task: - fi - export CIRRUS_CHANGE_MESSAGE=`cat /tmp/cirrus_change_message.txt` - export CIRRUS_COMMIT_MESSAGE=`cat /tmp/cirrus_commit_message.txt` - ### Linux desktop tasks ### - - name: build-linux+drive-examples - env: - matrix: - CHANNEL: "master" - CHANNEL: "stable" - build_script: - - flutter channel $CHANNEL - - ./script/incremental_build.sh build-examples --linux - - xvfb-run ./script/incremental_build.sh drive-examples --linux +# macOS tasks. task: - # Xcode 12 task - # don't run on release tags since it creates O(n^2) tasks where n is the number of plugins - only_if: $CIRRUS_TAG == '' - use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' + << : *ROOT_TASK_TEMPLATE + # Only one macOS task can run in parallel without credits, so use them for + # PRs on macOS. + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' osx_instance: image: big-sur-xcode-12.3 - upgrade_script: - - sudo gem install cocoapods - - flutter channel stable - - flutter upgrade - - flutter channel master - - flutter upgrade - - flutter config --enable-macos-desktop - - git fetch origin master - create_simulator_script: - - xcrun simctl list - - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-3 | xargs xcrun simctl boot + cocoapod_install_script: sudo gem install cocoapods matrix: ### Platform-agnostic tasks ### - name: lint_darwin_plugins @@ -225,8 +187,6 @@ task: script: # TODO(jmagman): Lint macOS podspecs but skip any that fail library validation. - find . -name "*.podspec" | xargs grep -l "osx" | xargs rm - # Skip the dummy podspecs used to placate the tool. - - find . -name "*_web*.podspec" -o -name "*_mac*.podspec" | xargs rm - ./script/incremental_build.sh podspecs ### iOS tasks ### - name: build_all_plugins_ipa @@ -235,7 +195,6 @@ task: CHANNEL: "master" CHANNEL: "stable" script: - - flutter channel $CHANNEL - ./script/build_all_plugins_app.sh ios --no-codesign - name: build-ipas+drive-examples env: @@ -250,8 +209,10 @@ task: CHANNEL: "master" CHANNEL: "stable" SIMCTL_CHILD_MAPS_API_KEY: ENCRYPTED[596a9f6bca436694625ac50851dc5da6b4d34cba8025f7db5bc9465142e8cd44e15f69e3507787753accebfc4910d550] + create_simulator_script: + - xcrun simctl list + - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-3 | xargs xcrun simctl boot build_script: - - flutter channel $CHANNEL - ./script/incremental_build.sh build-examples --ipa - ./script/incremental_build.sh xctest --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=latest" # `drive-examples` contains integration tests, which changes the UI of the application. @@ -265,7 +226,7 @@ task: CHANNEL: "master" CHANNEL: "stable" script: - - flutter channel $CHANNEL + - flutter config --enable-macos-desktop - ./script/build_all_plugins_app.sh macos - name: build-macos+drive-examples env: @@ -274,6 +235,6 @@ task: CHANNEL: "stable" PATH: $PATH:/usr/local/bin build_script: - - flutter channel $CHANNEL + - flutter config --enable-macos-desktop - ./script/incremental_build.sh build-examples --macos --no-ipa - ./script/incremental_build.sh drive-examples --macos From 8feb2e78070fffbf53b752e1a548ff3a9e295b8a Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 10 Mar 2021 14:15:04 -0800 Subject: [PATCH 326/924] [tool] Improve check version ci so that it enforces the version in CHANGELOG and pubspec matches. (#3678) --- .cirrus.yml | 9 +- script/incremental_build.sh | 3 - script/tool/lib/src/common.dart | 143 ++++++++++- .../tool/lib/src/version_check_command.dart | 139 ++++++----- script/tool/test/common_test.dart | 227 +++++++++++++++++- script/tool/test/util.dart | 19 +- script/tool/test/version_check_test.dart | 160 +++++++++++- 7 files changed, 619 insertions(+), 81 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 8d992d5cbbd1..8f61fabc4f2a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -6,10 +6,13 @@ root_task_template: &ROOT_TASK_TEMPLATE env: INTEGRATION_TEST_PATH: "./packages/integration_test" CHANNEL: "master" # Default to master when not explicitly set by a task. + PLUGIN_TOOLS: "dart run ./script/tool/lib/src/main.dart" setup_script: - flutter channel $CHANNEL - flutter upgrade - git fetch origin master # To set FETCH_HEAD for "git merge-base" to work + - cd script/tool + - pub get # Light-workload Linux tasks. @@ -24,10 +27,14 @@ task: - name: plugin_tools_tests script: - cd script/tool - - pub get - CIRRUS_BUILD_ID=null pub run test - name: publishable script: + - if [[ "$CIRRUS_BRANCH" == "master" ]]; then + - $PLUGIN_TOOLS version-check + - else + - $PLUGIN_TOOLS version-check --run-on-changed-packages + - fi - ./script/check_publish.sh - name: format format_script: ./script/incremental_build.sh format --fail-on-change diff --git a/script/incremental_build.sh b/script/incremental_build.sh index 826229bced60..38a4d2d8edc7 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -49,8 +49,5 @@ else else echo running "${ACTIONS[@]}" (cd "$REPO_DIR" && plugin_tools "${ACTIONS[@]}" --plugins="$CHANGED_PACKAGES" --exclude="$ALL_EXCLUDED" ${PLUGIN_SHARDING[@]}) - echo "Running version check for changed packages" - # TODO(egarciad): Enable this check once in master. - # (cd "$REPO_DIR" && $PUB global run flutter_plugin_tools version-check --base_sha="$(get_branch_base_sha)") fi fi diff --git a/script/tool/lib/src/common.dart b/script/tool/lib/src/common.dart index 08622df281b4..ce4f37873b07 100644 --- a/script/tool/lib/src/common.dart +++ b/script/tool/lib/src/common.dart @@ -7,8 +7,12 @@ import 'dart:io' as io; import 'dart:math'; import 'package:args/command_runner.dart'; +import 'package:colorize/colorize.dart'; import 'package:file/file.dart'; +import 'package:git/git.dart'; +import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; +import 'package:pub_semver/pub_semver.dart'; import 'package:yaml/yaml.dart'; typedef void Print(Object object); @@ -140,6 +144,13 @@ bool isLinuxPlugin(FileSystemEntity entity, FileSystem fileSystem) { return pluginSupportsPlatform(kLinux, entity, fileSystem); } +/// Throws a [ToolExit] with `exitCode` and log the `errorMessage` in red. +void printErrorAndExit({@required String errorMessage, int exitCode = 1}) { + final Colorize redError = Colorize(errorMessage)..red(); + print(redError); + throw ToolExit(exitCode); +} + /// Error thrown when a command needs to exit with a non-zero exit code. class ToolExit extends Error { ToolExit(this.exitCode); @@ -152,6 +163,7 @@ abstract class PluginCommand extends Command { this.packagesDir, this.fileSystem, { this.processRunner = const ProcessRunner(), + this.gitDir, }) { argParser.addMultiOption( _pluginsArg, @@ -179,12 +191,23 @@ abstract class PluginCommand extends Command { help: 'Exclude packages from this command.', defaultsTo: [], ); + argParser.addFlag(_runOnChangedPackagesArg, + help: 'Run the command on changed packages/plugins.\n' + 'If the $_pluginsArg is specified, this flag is ignored.\n' + 'The packages excluded with $_excludeArg is also excluded even if changed.\n' + 'See $_kBaseSha if a custom base is needed to determine the diff.'); + argParser.addOption(_kBaseSha, + help: 'The base sha used to determine git diff. \n' + 'This is useful when $_runOnChangedPackagesArg is specified.\n' + 'If not specified, merge-base is used as base sha.'); } static const String _pluginsArg = 'plugins'; static const String _shardIndexArg = 'shardIndex'; static const String _shardCountArg = 'shardCount'; static const String _excludeArg = 'exclude'; + static const String _runOnChangedPackagesArg = 'run-on-changed-packages'; + static const String _kBaseSha = 'base-sha'; /// The directory containing the plugin packages. final Directory packagesDir; @@ -199,6 +222,11 @@ abstract class PluginCommand extends Command { /// This can be overridden for testing. final ProcessRunner processRunner; + /// The git directory to use. By default it uses the parent directory. + /// + /// This can be mocked for testing. + final GitDir gitDir; + int _shardIndex; int _shardCount; @@ -273,9 +301,13 @@ abstract class PluginCommand extends Command { /// "client library" package, which declares the API for the plugin, as /// well as one or more platform-specific implementations. Stream _getAllPlugins() async* { - final Set plugins = Set.from(argResults[_pluginsArg]); + Set plugins = Set.from(argResults[_pluginsArg]); final Set excludedPlugins = Set.from(argResults[_excludeArg]); + final bool runOnChangedPackages = argResults[_runOnChangedPackagesArg]; + if (plugins.isEmpty && runOnChangedPackages) { + plugins = await _getChangedPackages(); + } await for (FileSystemEntity entity in packagesDir.list(followLinks: false)) { @@ -363,6 +395,50 @@ abstract class PluginCommand extends Command { (FileSystemEntity entity) => isFlutterPackage(entity, fileSystem)) .cast(); } + + /// Retrieve an instance of [GitVersionFinder] based on `_kBaseSha` and [gitDir]. + /// + /// Throws tool exit if [gitDir] nor root directory is a git directory. + Future retrieveVersionFinder() async { + final String rootDir = packagesDir.parent.absolute.path; + String baseSha = argResults[_kBaseSha]; + + GitDir baseGitDir = gitDir; + if (baseGitDir == null) { + if (!await GitDir.isGitDir(rootDir)) { + printErrorAndExit( + errorMessage: '$rootDir is not a valid Git repository.', + exitCode: 2); + } + baseGitDir = await GitDir.fromExisting(rootDir); + } + + final GitVersionFinder gitVersionFinder = + GitVersionFinder(baseGitDir, baseSha); + return gitVersionFinder; + } + + Future> _getChangedPackages() async { + final GitVersionFinder gitVersionFinder = await retrieveVersionFinder(); + + final List allChangedFiles = + await gitVersionFinder.getChangedFiles(); + final Set packages = {}; + allChangedFiles.forEach((String path) { + final List pathComponents = path.split('/'); + final int packagesIndex = + pathComponents.indexWhere((String element) => element == 'packages'); + if (packagesIndex != -1) { + packages.add(pathComponents[packagesIndex + 1]); + } + }); + if (packages.isNotEmpty) { + final String changedPackages = packages.join(','); + print(changedPackages); + } + print('No changed packages.'); + return packages; + } } /// A class used to run processes. @@ -466,3 +542,68 @@ class ProcessRunner { return 'ERROR: Unable to execute "$executable ${args.join(' ')}"$workdir.'; } } + +/// Finding diffs based on `baseGitDir` and `baseSha`. +class GitVersionFinder { + /// Constructor + GitVersionFinder(this.baseGitDir, this.baseSha); + + /// The top level directory of the git repo. + /// + /// That is where the .git/ folder exists. + final GitDir baseGitDir; + + /// The base sha used to get diff. + final String baseSha; + + static bool _isPubspec(String file) { + return file.trim().endsWith('pubspec.yaml'); + } + + /// Get a list of all the pubspec.yaml file that is changed. + Future> getChangedPubSpecs() async { + return (await getChangedFiles()).where(_isPubspec).toList(); + } + + /// Get a list of all the changed files. + Future> getChangedFiles() async { + final String baseSha = await _getBaseSha(); + final io.ProcessResult changedFilesCommand = await baseGitDir + .runCommand(['diff', '--name-only', '$baseSha', 'HEAD']); + print('Determine diff with base sha: $baseSha'); + final String changedFilesStdout = changedFilesCommand.stdout.toString() ?? ''; + if (changedFilesStdout.isEmpty) { + return []; + } + final List changedFiles = changedFilesStdout + .split('\n') + ..removeWhere((element) => element.isEmpty); + return changedFiles.toList(); + } + + /// Get the package version specified in the pubspec file in `pubspecPath` and at the revision of `gitRef`. + Future getPackageVersion(String pubspecPath, String gitRef) async { + final io.ProcessResult gitShow = + await baseGitDir.runCommand(['show', '$gitRef:$pubspecPath']); + final String fileContent = gitShow.stdout; + final String versionString = loadYaml(fileContent)['version']; + return versionString == null ? null : Version.parse(versionString); + } + + Future _getBaseSha() async { + if (baseSha != null && baseSha.isNotEmpty) { + return baseSha; + } + + io.ProcessResult baseShaFromMergeBase = await baseGitDir.runCommand( + ['merge-base', '--fork-point', 'FETCH_HEAD', 'HEAD'], + throwOnError: false); + if (baseShaFromMergeBase == null || + baseShaFromMergeBase.stderr != null || + baseShaFromMergeBase.stdout == null) { + baseShaFromMergeBase = await baseGitDir + .runCommand(['merge-base', 'FETCH_HEAD', 'HEAD']); + } + return (baseShaFromMergeBase.stdout as String).trim(); + } +} diff --git a/script/tool/lib/src/version_check_command.dart b/script/tool/lib/src/version_check_command.dart index 2c6b92bbcb7a..111239f0399a 100644 --- a/script/tool/lib/src/version_check_command.dart +++ b/script/tool/lib/src/version_check_command.dart @@ -6,43 +6,14 @@ import 'dart:async'; import 'dart:io' as io; import 'package:meta/meta.dart'; -import 'package:colorize/colorize.dart'; import 'package:file/file.dart'; import 'package:git/git.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:pubspec_parse/pubspec_parse.dart'; -import 'package:yaml/yaml.dart'; import 'common.dart'; -const String _kBaseSha = 'base_sha'; - -class GitVersionFinder { - GitVersionFinder(this.baseGitDir, this.baseSha); - - final GitDir baseGitDir; - final String baseSha; - - static bool isPubspec(String file) { - return file.trim().endsWith('pubspec.yaml'); - } - - Future> getChangedPubSpecs() async { - final io.ProcessResult changedFilesCommand = await baseGitDir - .runCommand(['diff', '--name-only', '$baseSha', 'HEAD']); - final List changedFiles = - changedFilesCommand.stdout.toString().split('\n'); - return changedFiles.where(isPubspec).toList(); - } - - Future getPackageVersion(String pubspecPath, String gitRef) async { - final io.ProcessResult gitShow = - await baseGitDir.runCommand(['show', '$gitRef:$pubspecPath']); - final String fileContent = gitShow.stdout; - final String versionString = loadYaml(fileContent)['version']; - return versionString == null ? null : Version.parse(versionString); - } -} +const String _kBaseSha = 'base-sha'; enum NextVersionType { BREAKING_MAJOR, @@ -128,46 +99,28 @@ class VersionCheckCommand extends PluginCommand { Directory packagesDir, FileSystem fileSystem, { ProcessRunner processRunner = const ProcessRunner(), - this.gitDir, - }) : super(packagesDir, fileSystem, processRunner: processRunner) { - argParser.addOption(_kBaseSha); - } - - /// The git directory to use. By default it uses the parent directory. - /// - /// This can be mocked for testing. - final GitDir gitDir; + GitDir gitDir, + }) : super(packagesDir, fileSystem, + processRunner: processRunner, gitDir: gitDir); @override final String name = 'version-check'; @override final String description = - 'Checks if the versions of the plugins have been incremented per pub specification.\n\n' + 'Checks if the versions of the plugins have been incremented per pub specification.\n' + 'Also checks if the latest version in CHANGELOG matches the version in pubspec.\n\n' 'This command requires "pub" and "flutter" to be in your path.'; @override Future run() async { checkSharding(); - - final String rootDir = packagesDir.parent.absolute.path; - final String baseSha = argResults[_kBaseSha]; - - GitDir baseGitDir = gitDir; - if (baseGitDir == null) { - if (!await GitDir.isGitDir(rootDir)) { - print('$rootDir is not a valid Git repository.'); - throw ToolExit(2); - } - baseGitDir = await GitDir.fromExisting(rootDir); - } - - final GitVersionFinder gitVersionFinder = - GitVersionFinder(baseGitDir, baseSha); + final GitVersionFinder gitVersionFinder = await retrieveVersionFinder(); final List changedPubspecs = await gitVersionFinder.getChangedPubSpecs(); + final String baseSha = argResults[_kBaseSha]; for (final String pubspecPath in changedPubspecs) { try { final File pubspecFile = fileSystem.file(pubspecPath); @@ -194,9 +147,7 @@ class VersionCheckCommand extends PluginCommand { final String error = '$pubspecPath incorrectly updated version.\n' 'HEAD: $headVersion, master: $masterVersion.\n' 'Allowed versions: $allowedNextVersions'; - final Colorize redError = Colorize(error)..red(); - print(redError); - throw ToolExit(1); + printErrorAndExit(errorMessage: error); } bool isPlatformInterface = pubspec.name.endsWith("_platform_interface"); @@ -205,9 +156,7 @@ class VersionCheckCommand extends PluginCommand { NextVersionType.BREAKING_MAJOR) { final String error = '$pubspecPath breaking change detected.\n' 'Breaking changes to platform interfaces are strongly discouraged.\n'; - final Colorize redError = Colorize(error)..red(); - print(redError); - throw ToolExit(1); + printErrorAndExit(errorMessage: error); } } on io.ProcessException { print('Unable to find pubspec in master for $pubspecPath.' @@ -215,6 +164,74 @@ class VersionCheckCommand extends PluginCommand { } } + await for (Directory plugin in getPlugins()) { + await _checkVersionsMatch(plugin); + } + print('No version check errors found!'); } + + Future _checkVersionsMatch(Directory plugin) async { + // get version from pubspec + final String packageName = plugin.basename; + print('-----------------------------------------'); + print( + 'Checking the first version listed in CHANGELOG.MD matches the version in pubspec.yaml for $packageName.'); + + final Pubspec pubspec = _tryParsePubspec(plugin); + if (pubspec == null) { + final String error = 'Cannot parse version from pubspec.yaml'; + printErrorAndExit(errorMessage: error); + } + final Version fromPubspec = pubspec.version; + + // get first version from CHANGELOG + final File changelog = plugin.childFile('CHANGELOG.md'); + final List lines = changelog.readAsLinesSync(); + String firstLineWithText; + final Iterator iterator = lines.iterator; + while (iterator.moveNext()) { + if ((iterator.current as String).trim().isNotEmpty) { + firstLineWithText = iterator.current; + break; + } + } + // Remove all leading mark down syntax from the version line. + final String versionString = firstLineWithText.split(' ').last; + Version fromChangeLog = Version.parse(versionString); + if (fromChangeLog == null) { + final String error = + 'Cannot find version on the first line of ${plugin.path}/CHANGELOG.md'; + printErrorAndExit(errorMessage: error); + } + + if (fromPubspec != fromChangeLog) { + final String error = ''' +versions for $packageName in CHANGELOG.md and pubspec.yaml do not match. +The version in pubspec.yaml is $fromPubspec. +The first version listed in CHANGELOG.md is $fromChangeLog. +'''; + printErrorAndExit(errorMessage: error); + } + print('${packageName} passed version check'); + } + + Pubspec _tryParsePubspec(Directory package) { + final File pubspecFile = package.childFile('pubspec.yaml'); + + try { + Pubspec pubspec = Pubspec.parse(pubspecFile.readAsStringSync()); + if (pubspec == null) { + final String error = + 'Failed to parse `pubspec.yaml` at ${pubspecFile.path}'; + printErrorAndExit(errorMessage: error); + } + return pubspec; + } on Exception catch (exception) { + final String error = + 'Failed to parse `pubspec.yaml` at ${pubspecFile.path}: $exception}'; + printErrorAndExit(errorMessage: error); + } + return null; + } } diff --git a/script/tool/test/common_test.dart b/script/tool/test/common_test.dart index b3504c2358d9..0fb3ce74c373 100644 --- a/script/tool/test/common_test.dart +++ b/script/tool/test/common_test.dart @@ -1,6 +1,10 @@ +import 'dart:io'; + import 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:flutter_plugin_tools/src/common.dart'; +import 'package:git/git.dart'; +import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; import 'util.dart'; @@ -9,8 +13,21 @@ void main() { RecordingProcessRunner processRunner; CommandRunner runner; List plugins; + List> gitDirCommands; + String gitDiffResponse; setUp(() { + gitDirCommands = >[]; + gitDiffResponse = ''; + final MockGitDir gitDir = MockGitDir(); + when(gitDir.runCommand(any)).thenAnswer((Invocation invocation) { + gitDirCommands.add(invocation.positionalArguments[0]); + final MockProcessResult mockProcessResult = MockProcessResult(); + if (invocation.positionalArguments[0][0] == 'diff') { + when(mockProcessResult.stdout).thenReturn(gitDiffResponse); + } + return Future.value(mockProcessResult); + }); initializeFakePackages(); processRunner = RecordingProcessRunner(); plugins = []; @@ -19,6 +36,7 @@ void main() { mockPackagesDir, mockFileSystem, processRunner: processRunner, + gitDir: gitDir, ); runner = CommandRunner('common_command', 'Test for common functionality'); @@ -73,6 +91,207 @@ void main() { ]); expect(plugins, unorderedEquals([plugin2.path])); }); + + group('test run-on-changed-packages', () { + test('all plugins should be tested if there are no changes.', () async { + final Directory plugin1 = createFakePlugin('plugin1'); + final Directory plugin2 = createFakePlugin('plugin2'); + await runner.run( + ['sample', '--base-sha=master', '--run-on-changed-packages']); + + expect(plugins, unorderedEquals([plugin1.path, plugin2.path])); + }); + + test('all plugins should be tested if there are no plugin related changes.', + () async { + gitDiffResponse = ".cirrus"; + final Directory plugin1 = createFakePlugin('plugin1'); + final Directory plugin2 = createFakePlugin('plugin2'); + await runner.run( + ['sample', '--base-sha=master', '--run-on-changed-packages']); + + expect(plugins, unorderedEquals([plugin1.path, plugin2.path])); + }); + + test('Only changed plugin should be tested.', () async { + gitDiffResponse = "packages/plugin1/plugin1.dart"; + final Directory plugin1 = createFakePlugin('plugin1'); + createFakePlugin('plugin2'); + await runner.run( + ['sample', '--base-sha=master', '--run-on-changed-packages']); + + expect(plugins, unorderedEquals([plugin1.path])); + }); + + test('multiple files in one plugin should also test the plugin', () async { + gitDiffResponse = ''' +packages/plugin1/plugin1.dart +packages/plugin1/ios/plugin1.m +'''; + final Directory plugin1 = createFakePlugin('plugin1'); + createFakePlugin('plugin2'); + await runner.run( + ['sample', '--base-sha=master', '--run-on-changed-packages']); + + expect(plugins, unorderedEquals([plugin1.path])); + }); + + test('multiple plugins changed should test all the changed plugins', + () async { + gitDiffResponse = ''' +packages/plugin1/plugin1.dart +packages/plugin2/ios/plugin2.m +'''; + final Directory plugin1 = createFakePlugin('plugin1'); + final Directory plugin2 = createFakePlugin('plugin2'); + createFakePlugin('plugin3'); + await runner.run( + ['sample', '--base-sha=master', '--run-on-changed-packages']); + + expect(plugins, unorderedEquals([plugin1.path, plugin2.path])); + }); + + test( + 'multiple plugins inside the same plugin group changed should output the plugin group name', + () async { + gitDiffResponse = ''' +packages/plugin1/plugin1/plugin1.dart +packages/plugin1/plugin1_platform_interface/plugin1_platform_interface.dart +packages/plugin1/plugin1_web/plugin1_web.dart +'''; + final Directory plugin1 = + createFakePlugin('plugin1', parentDirectoryName: 'plugin1'); + createFakePlugin('plugin2'); + createFakePlugin('plugin3'); + await runner.run( + ['sample', '--base-sha=master', '--run-on-changed-packages']); + + expect(plugins, unorderedEquals([plugin1.path])); + }); + + test('--plugins flag overrides the behavior of --run-on-changed-packages', + () async { + gitDiffResponse = ''' +packages/plugin1/plugin1.dart +packages/plugin2/ios/plugin2.m +packages/plugin3/plugin3.dart +'''; + final Directory plugin1 = + createFakePlugin('plugin1', parentDirectoryName: 'plugin1'); + final Directory plugin2 = createFakePlugin('plugin2'); + createFakePlugin('plugin3'); + await runner.run([ + 'sample', + '--plugins=plugin1,plugin2', + '--base-sha=master', + '--run-on-changed-packages' + ]); + + expect(plugins, unorderedEquals([plugin1.path, plugin2.path])); + }); + + test('--exclude flag works with --run-on-changed-packages', () async { + gitDiffResponse = ''' +packages/plugin1/plugin1.dart +packages/plugin2/ios/plugin2.m +packages/plugin3/plugin3.dart +'''; + final Directory plugin1 = + createFakePlugin('plugin1', parentDirectoryName: 'plugin1'); + createFakePlugin('plugin2'); + createFakePlugin('plugin3'); + await runner.run([ + 'sample', + '--exclude=plugin2,plugin3', + '--base-sha=master', + '--run-on-changed-packages' + ]); + + expect(plugins, unorderedEquals([plugin1.path])); + }); + }); + + group('$GitVersionFinder', () { + List> gitDirCommands; + String gitDiffResponse; + String mergeBaseResponse; + MockGitDir gitDir; + + setUp(() { + gitDirCommands = >[]; + gitDiffResponse = ''; + gitDir = MockGitDir(); + when(gitDir.runCommand(any)).thenAnswer((Invocation invocation) { + gitDirCommands.add(invocation.positionalArguments[0]); + final MockProcessResult mockProcessResult = MockProcessResult(); + if (invocation.positionalArguments[0][0] == 'diff') { + when(mockProcessResult.stdout).thenReturn(gitDiffResponse); + } else if (invocation.positionalArguments[0][0] == 'merge-base') { + when(mockProcessResult.stdout).thenReturn(mergeBaseResponse); + } + return Future.value(mockProcessResult); + }); + initializeFakePackages(); + processRunner = RecordingProcessRunner(); + }); + + tearDown(() { + cleanupPackages(); + }); + + test('No git diff should result no files changed', () async { + final GitVersionFinder finder = GitVersionFinder(gitDir, 'some base sha'); + List changedFiles = await finder.getChangedFiles(); + + expect(changedFiles, isEmpty); + }); + + test('get correct files changed based on git diff', () async { + gitDiffResponse = ''' +file1/file1.cc +file2/file2.cc +'''; + final GitVersionFinder finder = GitVersionFinder(gitDir, 'some base sha'); + List changedFiles = await finder.getChangedFiles(); + + expect( + changedFiles, equals(['file1/file1.cc', 'file2/file2.cc'])); + }); + + test('get correct pubspec change based on git diff', () async { + gitDiffResponse = ''' +file1/pubspec.yaml +file2/file2.cc +'''; + final GitVersionFinder finder = GitVersionFinder(gitDir, 'some base sha'); + List changedFiles = await finder.getChangedPubSpecs(); + + expect(changedFiles, equals(['file1/pubspec.yaml'])); + }); + + test('use correct base sha if not specified', () async { + mergeBaseResponse = 'shaqwiueroaaidf12312jnadf123nd'; + gitDiffResponse = ''' +file1/pubspec.yaml +file2/file2.cc +'''; + final GitVersionFinder finder = GitVersionFinder(gitDir, null); + await finder.getChangedFiles(); + verify(gitDir + .runCommand(['diff', '--name-only', mergeBaseResponse, 'HEAD'])); + }); + + test('use correct base sha if specified', () async { + final String customBaseSha = 'aklsjdcaskf12312'; + gitDiffResponse = ''' +file1/pubspec.yaml +file2/file2.cc +'''; + final GitVersionFinder finder = GitVersionFinder(gitDir, customBaseSha); + await finder.getChangedFiles(); + verify(gitDir.runCommand(['diff', '--name-only', customBaseSha, 'HEAD'])); + }); + }); } class SamplePluginCommand extends PluginCommand { @@ -81,7 +300,9 @@ class SamplePluginCommand extends PluginCommand { Directory packagesDir, FileSystem fileSystem, { ProcessRunner processRunner = const ProcessRunner(), - }) : super(packagesDir, fileSystem, processRunner: processRunner); + GitDir gitDir, + }) : super(packagesDir, fileSystem, + processRunner: processRunner, gitDir: gitDir); List plugins_; @@ -98,3 +319,7 @@ class SamplePluginCommand extends PluginCommand { } } } + +class MockGitDir extends Mock implements GitDir {} + +class MockProcessResult extends Mock implements ProcessResult {} diff --git a/script/tool/test/util.dart b/script/tool/test/util.dart index ec0000d13f34..1538d9b554e8 100644 --- a/script/tool/test/util.dart +++ b/script/tool/test/util.dart @@ -37,6 +37,8 @@ Directory createFakePlugin( bool isLinuxPlugin = false, bool isMacOsPlugin = false, bool isWindowsPlugin = false, + bool includeChangeLog = false, + bool includeVersion = false, String parentDirectoryName = '', }) { assert(!(withSingleExample && withExamples.isNotEmpty), @@ -57,7 +59,14 @@ Directory createFakePlugin( isLinuxPlugin: isLinuxPlugin, isMacOsPlugin: isMacOsPlugin, isWindowsPlugin: isWindowsPlugin, + includeVersion: includeVersion, ); + if (includeChangeLog) { + createFakeCHANGELOG(pluginDirectory, ''' +## 0.0.1 + * Some changes. + '''); + } if (withSingleExample) { final Directory exampleDir = pluginDirectory.childDirectory('example') @@ -85,6 +94,11 @@ Directory createFakePlugin( return pluginDirectory; } +void createFakeCHANGELOG(Directory parent, String texts) { + parent.childFile('CHANGELOG.md').createSync(); + parent.childFile('CHANGELOG.md').writeAsStringSync(texts); +} + /// Creates a `pubspec.yaml` file with a flutter dependency. void createFakePubspec( Directory parent, { @@ -97,6 +111,7 @@ void createFakePubspec( bool isLinuxPlugin = false, bool isMacOsPlugin = false, bool isWindowsPlugin = false, + String version = '0.0.1', }) { parent.childFile('pubspec.yaml').createSync(); String yaml = ''' @@ -152,8 +167,8 @@ dependencies: } if (includeVersion) { yaml += ''' -version: 0.0.1 -publish_to: none # Hardcoded safeguard to prevent this from somehow being published by a broken test. +version: $version +publish_to: http://no_pub_server.com # Hardcoded safeguard to prevent this from somehow being published by a broken test. '''; } parent.childFile('pubspec.yaml').writeAsStringSync(yaml); diff --git a/script/tool/test/version_check_test.dart b/script/tool/test/version_check_test.dart index b9ace3811bff..ac0d378c2a26 100644 --- a/script/tool/test/version_check_test.dart +++ b/script/tool/test/version_check_test.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'package:args/command_runner.dart'; +import 'package:flutter_plugin_tools/src/common.dart'; import 'package:git/git.dart'; import 'package:mockito/mockito.dart'; import "package:test/test.dart"; @@ -74,18 +75,18 @@ void main() { }); test('allows valid version', () async { - createFakePlugin('plugin'); + createFakePlugin('plugin', includeChangeLog: true, includeVersion: true); gitDiffResponse = "packages/plugin/pubspec.yaml"; gitShowResponses = { 'master:packages/plugin/pubspec.yaml': 'version: 1.0.0', 'HEAD:packages/plugin/pubspec.yaml': 'version: 2.0.0', }; final List output = await runCapturingPrint( - runner, ['version-check', '--base_sha=master']); + runner, ['version-check', '--base-sha=master']); expect( output, - orderedEquals([ + containsAllInOrder([ 'No version check errors found!', ]), ); @@ -99,14 +100,14 @@ void main() { }); test('denies invalid version', () async { - createFakePlugin('plugin'); + createFakePlugin('plugin', includeChangeLog: true, includeVersion: true); gitDiffResponse = "packages/plugin/pubspec.yaml"; gitShowResponses = { 'master:packages/plugin/pubspec.yaml': 'version: 0.0.1', 'HEAD:packages/plugin/pubspec.yaml': 'version: 0.2.0', }; final Future> result = runCapturingPrint( - runner, ['version-check', '--base_sha=master']); + runner, ['version-check', '--base-sha=master']); await expectLater( result, @@ -122,7 +123,7 @@ void main() { }); test('gracefully handles missing pubspec.yaml', () async { - createFakePlugin('plugin'); + createFakePlugin('plugin', includeChangeLog: true, includeVersion: true); gitDiffResponse = "packages/plugin/pubspec.yaml"; mockFileSystem.currentDirectory .childDirectory('packages') @@ -130,11 +131,12 @@ void main() { .childFile('pubspec.yaml') .deleteSync(); final List output = await runCapturingPrint( - runner, ['version-check', '--base_sha=master']); + runner, ['version-check', '--base-sha=master']); expect( output, orderedEquals([ + 'Determine diff with base sha: master', 'No version check errors found!', ]), ); @@ -144,7 +146,8 @@ void main() { }); test('allows minor changes to platform interfaces', () async { - createFakePlugin('plugin_platform_interface'); + createFakePlugin('plugin_platform_interface', + includeChangeLog: true, includeVersion: true); gitDiffResponse = "packages/plugin_platform_interface/pubspec.yaml"; gitShowResponses = { 'master:packages/plugin_platform_interface/pubspec.yaml': @@ -153,10 +156,10 @@ void main() { 'version: 1.1.0', }; final List output = await runCapturingPrint( - runner, ['version-check', '--base_sha=master']); + runner, ['version-check', '--base-sha=master']); expect( output, - orderedEquals([ + containsAllInOrder([ 'No version check errors found!', ]), ); @@ -172,7 +175,8 @@ void main() { }); test('disallows breaking changes to platform interfaces', () async { - createFakePlugin('plugin_platform_interface'); + createFakePlugin('plugin_platform_interface', + includeChangeLog: true, includeVersion: true); gitDiffResponse = "packages/plugin_platform_interface/pubspec.yaml"; gitShowResponses = { 'master:packages/plugin_platform_interface/pubspec.yaml': @@ -181,7 +185,7 @@ void main() { 'version: 2.0.0', }; final Future> output = runCapturingPrint( - runner, ['version-check', '--base_sha=master']); + runner, ['version-check', '--base-sha=master']); await expectLater( output, throwsA(const TypeMatcher()), @@ -196,6 +200,138 @@ void main() { expect(gitDirCommands[2].join(' '), equals('show HEAD:packages/plugin_platform_interface/pubspec.yaml')); }); + + test('Allow empty lines in front of the first version in CHANGELOG', + () async { + createFakePlugin('plugin', includeChangeLog: true, includeVersion: true); + + final Directory pluginDirectory = + mockPackagesDir.childDirectory('plugin'); + + createFakePubspec(pluginDirectory, + isFlutter: true, includeVersion: true, version: '1.0.1'); + String changelog = ''' + + + +## 1.0.1 + +* Some changes. +'''; + createFakeCHANGELOG(pluginDirectory, changelog); + final List output = await runCapturingPrint( + runner, ['version-check', '--base-sha=master']); + await expect( + output, + containsAllInOrder([ + 'Checking the first version listed in CHANGELOG.MD matches the version in pubspec.yaml for plugin.', + 'plugin passed version check', + 'No version check errors found!' + ]), + ); + }); + + test('Throws if versions in changelog and pubspec do not match', () async { + createFakePlugin('plugin', includeChangeLog: true, includeVersion: true); + + final Directory pluginDirectory = + mockPackagesDir.childDirectory('plugin'); + + createFakePubspec(pluginDirectory, + isFlutter: true, includeVersion: true, version: '1.0.1'); + String changelog = ''' +## 1.0.2 + +* Some changes. +'''; + createFakeCHANGELOG(pluginDirectory, changelog); + final Future> output = runCapturingPrint( + runner, ['version-check', '--base-sha=master']); + await expectLater( + output, + throwsA(const TypeMatcher()), + ); + try { + List outputValue = await output; + await expectLater( + outputValue, + containsAllInOrder([ + ''' + versions for plugin in CHANGELOG.md and pubspec.yaml do not match. + The version in pubspec.yaml is 1.0.1. + The first version listed in CHANGELOG.md is 1.0.2. + ''', + ]), + ); + } on ToolExit catch (_) {} + }); + + test('Success if CHANGELOG and pubspec versions match', () async { + createFakePlugin('plugin', includeChangeLog: true, includeVersion: true); + + final Directory pluginDirectory = + mockPackagesDir.childDirectory('plugin'); + + createFakePubspec(pluginDirectory, + isFlutter: true, includeVersion: true, version: '1.0.1'); + String changelog = ''' +## 1.0.1 + +* Some changes. +'''; + createFakeCHANGELOG(pluginDirectory, changelog); + final List output = await runCapturingPrint( + runner, ['version-check', '--base-sha=master']); + await expect( + output, + containsAllInOrder([ + 'Checking the first version listed in CHANGELOG.MD matches the version in pubspec.yaml for plugin.', + 'plugin passed version check', + 'No version check errors found!' + ]), + ); + }); + + test( + 'Fail if pubspec version only matches an older version listed in CHANGELOG', + () async { + createFakePlugin('plugin', includeChangeLog: true, includeVersion: true); + + final Directory pluginDirectory = + mockPackagesDir.childDirectory('plugin'); + + createFakePubspec(pluginDirectory, + isFlutter: true, includeVersion: true, version: '1.0.0'); + String changelog = ''' +## 1.0.1 + +* Some changes. + +## 1.0.0 + +* Some other changes. +'''; + createFakeCHANGELOG(pluginDirectory, changelog); + Future> output = runCapturingPrint( + runner, ['version-check', '--base-sha=master']); + await expectLater( + output, + throwsA(const TypeMatcher()), + ); + try { + List outputValue = await output; + await expectLater( + outputValue, + containsAllInOrder([ + ''' + versions for plugin in CHANGELOG.md and pubspec.yaml do not match. + The version in pubspec.yaml is 1.0.0. + The first version listed in CHANGELOG.md is 1.0.1. + ''', + ]), + ); + } on ToolExit catch (_) {} + }); }); group("Pre 1.0", () { From d7724ad6f24a6deeec4a88a68d6903252b7961ff Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Wed, 10 Mar 2021 15:05:38 -0800 Subject: [PATCH 327/924] [cross_file] Delete. (#3698) The package now lives in flutter/packages. --- CODEOWNERS | 1 - packages/cross_file/CHANGELOG.md | 30 ---- packages/cross_file/LICENSE | 25 ---- packages/cross_file/README.md | 34 ----- packages/cross_file/lib/cross_file.dart | 5 - packages/cross_file/lib/src/types/base.dart | 86 ----------- packages/cross_file/lib/src/types/html.dart | 135 ------------------ .../cross_file/lib/src/types/interface.dart | 58 -------- packages/cross_file/lib/src/types/io.dart | 115 --------------- .../lib/src/web_helpers/web_helpers.dart | 38 ----- packages/cross_file/lib/src/x_file.dart | 7 - packages/cross_file/pubspec.yaml | 18 --- packages/cross_file/test/assets/hello.txt | 1 - .../cross_file/test/x_file_html_test.dart | 106 -------------- packages/cross_file/test/x_file_io_test.dart | 90 ------------ 15 files changed, 749 deletions(-) delete mode 100644 packages/cross_file/CHANGELOG.md delete mode 100644 packages/cross_file/LICENSE delete mode 100644 packages/cross_file/README.md delete mode 100644 packages/cross_file/lib/cross_file.dart delete mode 100644 packages/cross_file/lib/src/types/base.dart delete mode 100644 packages/cross_file/lib/src/types/html.dart delete mode 100644 packages/cross_file/lib/src/types/interface.dart delete mode 100644 packages/cross_file/lib/src/types/io.dart delete mode 100644 packages/cross_file/lib/src/web_helpers/web_helpers.dart delete mode 100644 packages/cross_file/lib/src/x_file.dart delete mode 100644 packages/cross_file/pubspec.yaml delete mode 100644 packages/cross_file/test/assets/hello.txt delete mode 100644 packages/cross_file/test/x_file_html_test.dart delete mode 100644 packages/cross_file/test/x_file_io_test.dart diff --git a/CODEOWNERS b/CODEOWNERS index 01732888ad89..8ab65bbb5a63 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,7 +6,6 @@ packages/camera/** @bparrishMines -packages/cross_file/** @ditman @mvanbeusekom packages/file_selector/** @ditman packages/google_maps_flutter/** @cyanglaz packages/image_picker/** @cyanglaz diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md deleted file mode 100644 index 94bf4b29322a..000000000000 --- a/packages/cross_file/CHANGELOG.md +++ /dev/null @@ -1,30 +0,0 @@ -## 0.3.1 - -* Fix nullability of `XFileBase`'s `path` and `name` to match the - implementations to avoid potential analyzer issues. - -## 0.3.0 - -* Migrated package to null-safety. -* **breaking change** According to our unit tests, the API should be backwards-compatible. Some relevant changes were made, however: - * Web: `lastModified` returns the epoch time as a default value, to maintain the `Future` return type (and not `null`) - -## 0.2.1 - -* Prepare for breaking `package:http` change. - -## 0.2.0 - -* **breaking change** Make sure the `saveTo` method returns a `Future` so it can be awaited and users are sure the file has been written to disk. - -## 0.1.0+2 - -* Fix outdated links across a number of markdown files ([#3276](https://github.com/flutter/plugins/pull/3276)) - -## 0.1.0+1 - -* Update Flutter SDK constraint. - -## 0.1.0 - -* Initial open-source release. diff --git a/packages/cross_file/LICENSE b/packages/cross_file/LICENSE deleted file mode 100644 index 2c91f1438173..000000000000 --- a/packages/cross_file/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright 2020 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/packages/cross_file/README.md b/packages/cross_file/README.md deleted file mode 100644 index 65bd41896184..000000000000 --- a/packages/cross_file/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# cross_file - -An abstraction to allow working with files across multiple platforms. - -# Usage - -Import `package:cross/cross_info.dart`, instantiate a `CrossFile` -using a path or byte array and use its methods and properties to -access the file and its metadata. - -Example: - -```dart -import 'package:cross_file/cross_file.dart'; - -final file = CrossFile('assets/hello.txt'); - -print('File information:'); -print('- Path: ${file.path}'); -print('- Name: ${file.name}'); -print('- MIME type: ${file.mimeType}'); - -final fileContent = await file.readAsString(); -print('Content of the file: ${fileContent}'); // e.g. "Moto G (4)" -``` - -You will find links to the API docs on the [pub page](https://pub.dev/packages/cross_file). - -## Getting Started - -For help getting started with Flutter, view our online -[documentation](http://flutter.io/). - -For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). \ No newline at end of file diff --git a/packages/cross_file/lib/cross_file.dart b/packages/cross_file/lib/cross_file.dart deleted file mode 100644 index a3e2873e670d..000000000000 --- a/packages/cross_file/lib/cross_file.dart +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2018 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. - -export 'src/x_file.dart'; diff --git a/packages/cross_file/lib/src/types/base.dart b/packages/cross_file/lib/src/types/base.dart deleted file mode 100644 index 4522b7343c9b..000000000000 --- a/packages/cross_file/lib/src/types/base.dart +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2018 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:convert'; -import 'dart:typed_data'; - -/// The interface for a CrossFile. -/// -/// A CrossFile is a container that wraps the path of a selected -/// file by the user and (in some platforms, like web) the bytes -/// with the contents of the file. -/// -/// This class is a very limited subset of dart:io [File], so all -/// the methods should seem familiar. -abstract class XFileBase { - /// Construct a CrossFile - XFileBase(String? path); - - /// Save the CrossFile at the indicated file path. - Future saveTo(String path) { - throw UnimplementedError('saveTo has not been implemented.'); - } - - /// Get the path of the picked file. - /// - /// This should only be used as a backwards-compatibility clutch - /// for mobile apps, or cosmetic reasons only (to show the user - /// the path they've picked). - /// - /// Accessing the data contained in the picked file by its path - /// is platform-dependant (and won't work on web), so use the - /// byte getters in the CrossFile instance instead. - String get path { - throw UnimplementedError('.path has not been implemented.'); - } - - /// The name of the file as it was selected by the user in their device. - /// - /// Use only for cosmetic reasons, do not try to use this as a path. - String get name { - throw UnimplementedError('.name has not been implemented.'); - } - - /// For web, it may be necessary for a file to know its MIME type. - String? get mimeType { - throw UnimplementedError('.mimeType has not been implemented.'); - } - - /// Get the length of the file. Returns a `Future` that completes with the length in bytes. - Future length() { - throw UnimplementedError('.length() has not been implemented.'); - } - - /// Synchronously read the entire file contents as a string using the given [Encoding]. - /// - /// By default, `encoding` is [utf8]. - /// - /// Throws Exception if the operation fails. - Future readAsString({Encoding encoding = utf8}) { - throw UnimplementedError('readAsString() has not been implemented.'); - } - - /// Synchronously read the entire file contents as a list of bytes. - /// - /// Throws Exception if the operation fails. - Future readAsBytes() { - throw UnimplementedError('readAsBytes() has not been implemented.'); - } - - /// Create a new independent [Stream] for the contents of this file. - /// - /// If `start` is present, the file will be read from byte-offset `start`. Otherwise from the beginning (index 0). - /// - /// 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 openRead([int? start, int? end]) { - throw UnimplementedError('openRead() has not been implemented.'); - } - - /// Get the last-modified time for the CrossFile - Future lastModified() { - throw UnimplementedError('openRead() has not been implemented.'); - } -} diff --git a/packages/cross_file/lib/src/types/html.dart b/packages/cross_file/lib/src/types/html.dart deleted file mode 100644 index 203ab5d82e12..000000000000 --- a/packages/cross_file/lib/src/types/html.dart +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2018 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:convert'; -import 'dart:html'; -import 'dart:typed_data'; - -import 'package:meta/meta.dart'; - -import './base.dart'; -import '../web_helpers/web_helpers.dart'; - -/// A CrossFile that works on web. -/// -/// It wraps the bytes of a selected file. -class XFile extends XFileBase { - late String path; - - final String? mimeType; - final Uint8List? _data; - final int? _length; - final String name; - final DateTime? _lastModified; - - late Element _target; - - final CrossFileTestOverrides? _overrides; - - bool get _hasTestOverrides => _overrides != null; - - /// Construct a CrossFile object from its ObjectUrl. - /// - /// Optionally, this can be initialized with `bytes` and `length` - /// so no http requests are performed to retrieve files later. - /// - /// `name` needs to be passed from the outside, since we only have - /// access to it while we create the ObjectUrl. - XFile( - this.path, { - this.mimeType, - String? name, - int? length, - Uint8List? bytes, - DateTime? lastModified, - @visibleForTesting CrossFileTestOverrides? overrides, - }) : _data = bytes, - _length = length, - _overrides = overrides, - _lastModified = lastModified ?? DateTime.fromMillisecondsSinceEpoch(0), - name = name ?? '', - super(path); - - /// Construct an CrossFile from its data - XFile.fromData( - Uint8List bytes, { - this.mimeType, - String? name, - int? length, - DateTime? lastModified, - String? path, - @visibleForTesting CrossFileTestOverrides? overrides, - }) : _data = bytes, - _length = length, - _overrides = overrides, - _lastModified = lastModified ?? DateTime.fromMillisecondsSinceEpoch(0), - name = name ?? '', - super(path) { - if (path == null) { - final blob = (mimeType == null) ? Blob([bytes]) : Blob([bytes], mimeType); - this.path = Url.createObjectUrl(blob); - } else { - this.path = path; - } - } - - @override - Future lastModified() async => Future.value(_lastModified); - - Future get _bytes async { - if (_data != null) { - return Future.value(UnmodifiableUint8ListView(_data!)); - } - - // We can force 'response' to be a byte buffer by passing responseType: - ByteBuffer? response = - (await HttpRequest.request(path, responseType: 'arraybuffer')).response; - - return response?.asUint8List() ?? Uint8List(0); - } - - @override - Future length() async => _length ?? (await _bytes).length; - - @override - Future readAsString({Encoding encoding = utf8}) async { - return encoding.decode(await _bytes); - } - - @override - Future readAsBytes() async => Future.value(await _bytes); - - @override - Stream openRead([int? start, int? end]) async* { - final bytes = await _bytes; - yield bytes.sublist(start ?? 0, end ?? bytes.length); - } - - /// Saves the data of this CrossFile at the location indicated by path. - /// For the web implementation, the path variable is ignored. - Future saveTo(String path) async { - // Create a DOM container where we can host the anchor. - _target = ensureInitialized('__x_file_dom_element'); - - // Create an tag with the appropriate download attributes and click it - // May be overridden with CrossFileTestOverrides - final AnchorElement element = _hasTestOverrides - ? _overrides!.createAnchorElement(this.path, this.name) as AnchorElement - : createAnchorElement(this.path, this.name); - - // Clear the children in our container so we can add an element to click - _target.children.clear(); - addElementToContainerAndClick(_target, element); - } -} - -/// Overrides some functions to allow testing -@visibleForTesting -class CrossFileTestOverrides { - /// For overriding the creation of the file input element. - Element Function(String href, String suggestedName) createAnchorElement; - - /// Default constructor for overrides - CrossFileTestOverrides({required this.createAnchorElement}); -} diff --git a/packages/cross_file/lib/src/types/interface.dart b/packages/cross_file/lib/src/types/interface.dart deleted file mode 100644 index 122f3d1d9364..000000000000 --- a/packages/cross_file/lib/src/types/interface.dart +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2018 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:typed_data'; -import 'package:meta/meta.dart'; - -import './base.dart'; - -/// A CrossFile is a cross-platform, simplified File abstraction. -/// -/// It wraps the bytes of a selected file, and its (platform-dependant) path. -class XFile extends XFileBase { - /// Construct a CrossFile object from its path. - /// - /// Optionally, this can be initialized with `bytes` and `length` - /// so no http requests are performed to retrieve data later. - /// - /// `name` may be passed from the outside, for those cases where the effective - /// `path` of the file doesn't match what the user sees when selecting it - /// (like in web) - XFile( - String path, { - String? mimeType, - String? name, - int? length, - Uint8List? bytes, - DateTime? lastModified, - @visibleForTesting CrossFileTestOverrides? overrides, - }) : super(path) { - throw UnimplementedError( - 'CrossFile is not available in your current platform.'); - } - - /// Construct a CrossFile object from its data - XFile.fromData( - Uint8List bytes, { - String? mimeType, - String? name, - int? length, - DateTime? lastModified, - String? path, - @visibleForTesting CrossFileTestOverrides? overrides, - }) : super(path) { - throw UnimplementedError( - 'CrossFile is not available in your current platform.'); - } -} - -/// Overrides some functions of CrossFile for testing purposes -@visibleForTesting -class CrossFileTestOverrides { - /// For overriding the creation of the file input element. - dynamic Function(String href, String suggestedName) createAnchorElement; - - /// Default constructor for overrides - CrossFileTestOverrides({required this.createAnchorElement}); -} diff --git a/packages/cross_file/lib/src/types/io.dart b/packages/cross_file/lib/src/types/io.dart deleted file mode 100644 index 6eafaf0ce0cc..000000000000 --- a/packages/cross_file/lib/src/types/io.dart +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2018 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:convert'; -import 'dart:io'; -import 'dart:typed_data'; - -import './base.dart'; - -/// A CrossFile backed by a dart:io File. -class XFile extends XFileBase { - final File _file; - final String? mimeType; - final DateTime? _lastModified; - int? _length; - - final Uint8List? _bytes; - - /// Construct a CrossFile object backed by a dart:io File. - XFile( - String path, { - this.mimeType, - String? name, - int? length, - Uint8List? bytes, - DateTime? lastModified, - }) : _file = File(path), - _bytes = null, - _lastModified = lastModified, - super(path); - - /// Construct an CrossFile from its data - XFile.fromData( - Uint8List bytes, { - this.mimeType, - String? path, - String? name, - int? length, - DateTime? lastModified, - }) : _bytes = bytes, - _file = File(path ?? ''), - _length = length, - _lastModified = lastModified, - super(path) { - if (length == null) { - _length = bytes.length; - } - } - - @override - Future lastModified() { - if (_lastModified != null) { - return Future.value(_lastModified); - } - return _file.lastModified(); - } - - @override - Future saveTo(String path) async { - File fileToSave = File(path); - await fileToSave.writeAsBytes(_bytes ?? (await readAsBytes())); - await fileToSave.create(); - } - - @override - String get path { - return _file.path; - } - - @override - String get name { - return _file.path.split(Platform.pathSeparator).last; - } - - @override - Future length() { - if (_length != null) { - return Future.value(_length); - } - return _file.length(); - } - - @override - Future readAsString({Encoding encoding = utf8}) { - if (_bytes != null) { - return Future.value(String.fromCharCodes(_bytes!)); - } - return _file.readAsString(encoding: encoding); - } - - @override - Future readAsBytes() { - if (_bytes != null) { - return Future.value(_bytes); - } - return _file.readAsBytes(); - } - - Stream _getBytes(int? start, int? end) async* { - final bytes = _bytes!; - yield bytes.sublist(start ?? 0, end ?? bytes.length); - } - - @override - Stream openRead([int? start, int? end]) { - if (_bytes != null) { - return _getBytes(start, end); - } else { - return _file - .openRead(start ?? 0, end) - .map((chunk) => Uint8List.fromList(chunk)); - } - } -} diff --git a/packages/cross_file/lib/src/web_helpers/web_helpers.dart b/packages/cross_file/lib/src/web_helpers/web_helpers.dart deleted file mode 100644 index a963e9933f99..000000000000 --- a/packages/cross_file/lib/src/web_helpers/web_helpers.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 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:html'; - -/// Create anchor element with download attribute -AnchorElement createAnchorElement(String href, String suggestedName) { - final element = AnchorElement(href: href); - - if (suggestedName == null) { - element.download = 'download'; - } else { - element.download = suggestedName; - } - - return element; -} - -/// Add an element to a container and click it -void addElementToContainerAndClick(Element container, Element element) { - // Add the element and click it - // All previous elements will be removed before adding the new one - container.children.add(element); - element.click(); -} - -/// Initializes a DOM container where we can host elements. -Element ensureInitialized(String id) { - var target = querySelector('#${id}'); - if (target == null) { - final Element targetElement = Element.tag('flt-x-file')..id = id; - - querySelector('body')!.children.add(targetElement); - target = targetElement; - } - return target; -} diff --git a/packages/cross_file/lib/src/x_file.dart b/packages/cross_file/lib/src/x_file.dart deleted file mode 100644 index 6136bff39f36..000000000000 --- a/packages/cross_file/lib/src/x_file.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2018 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. - -export 'types/interface.dart' - if (dart.library.html) 'types/html.dart' - if (dart.library.io) 'types/io.dart'; diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml deleted file mode 100644 index 66d3f46a84e3..000000000000 --- a/packages/cross_file/pubspec.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: cross_file -description: An abstraction to allow working with files across multiple platforms. -homepage: https://github.com/flutter/plugins/tree/master/packages/cross_file -version: 0.3.1 - -dependencies: - flutter: - sdk: flutter - meta: ^1.3.0 - -dev_dependencies: - flutter_test: - sdk: flutter - pedantic: ^1.10.0 - -environment: - sdk: ">=2.12.0-259.9.beta <3.0.0" - flutter: ">=1.22.0" diff --git a/packages/cross_file/test/assets/hello.txt b/packages/cross_file/test/assets/hello.txt deleted file mode 100644 index 5dd01c177f5d..000000000000 --- a/packages/cross_file/test/assets/hello.txt +++ /dev/null @@ -1 +0,0 @@ -Hello, world! \ No newline at end of file diff --git a/packages/cross_file/test/x_file_html_test.dart b/packages/cross_file/test/x_file_html_test.dart deleted file mode 100644 index a271aa1f1525..000000000000 --- a/packages/cross_file/test/x_file_html_test.dart +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2020 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. - -@TestOn('chrome') // Uses web-only Flutter SDK - -import 'dart:convert'; -import 'dart:html' as html; -import 'dart:typed_data'; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:cross_file/cross_file.dart'; - -final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); -final html.File textFile = html.File([bytes], 'hello.txt'); -final String textFileUrl = html.Url.createObjectUrl(textFile); - -void main() { - group('Create with an objectUrl', () { - final file = XFile(textFileUrl); - - test('Can be read as a string', () async { - expect(await file.readAsString(), equals(expectedStringContents)); - }); - test('Can be read as bytes', () async { - expect(await file.readAsBytes(), equals(bytes)); - }); - - test('Can be read as a stream', () async { - expect(await file.openRead().first, equals(bytes)); - }); - - test('Stream can be sliced', () async { - expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); - }); - }); - - group('Create from data', () { - final file = XFile.fromData(bytes); - - test('Can be read as a string', () async { - expect(await file.readAsString(), equals(expectedStringContents)); - }); - test('Can be read as bytes', () async { - expect(await file.readAsBytes(), equals(bytes)); - }); - - test('Can be read as a stream', () async { - expect(await file.openRead().first, equals(bytes)); - }); - - test('Stream can be sliced', () async { - expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); - }); - }); - - group('saveTo(..)', () { - final String CrossFileDomElementId = '__x_file_dom_element'; - - group('CrossFile saveTo(..)', () { - test('creates a DOM container', () async { - XFile file = XFile.fromData(bytes); - - await file.saveTo(''); - - final container = html.querySelector('#${CrossFileDomElementId}'); - - expect(container, isNotNull); - }); - - test('create anchor element', () async { - XFile file = XFile.fromData(bytes, name: textFile.name); - - await file.saveTo('path'); - - final container = html.querySelector('#${CrossFileDomElementId}'); - final html.AnchorElement element = - container?.children.firstWhere((element) => element.tagName == 'A') - as html.AnchorElement; - - // if element is not found, the `firstWhere` call will throw StateError. - expect(element.href, file.path); - expect(element.download, file.name); - }); - - test('anchor element is clicked', () async { - final mockAnchor = html.AnchorElement(); - - CrossFileTestOverrides overrides = CrossFileTestOverrides( - createAnchorElement: (_, __) => mockAnchor, - ); - - XFile file = - XFile.fromData(bytes, name: textFile.name, overrides: overrides); - - bool clicked = false; - mockAnchor.onClick.listen((event) => clicked = true); - - await file.saveTo('path'); - - expect(clicked, true); - }); - }); - }); -} diff --git a/packages/cross_file/test/x_file_io_test.dart b/packages/cross_file/test/x_file_io_test.dart deleted file mode 100644 index 94ac81c4cac4..000000000000 --- a/packages/cross_file/test/x_file_io_test.dart +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2020 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. - -@TestOn('vm') // Uses dart:io - -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:flutter_test/flutter_test.dart'; -import 'package:cross_file/cross_file.dart'; - -final pathPrefix = - Directory.current.path.endsWith('test') ? './assets/' : './test/assets/'; -final path = pathPrefix + 'hello.txt'; -final String expectedStringContents = 'Hello, world!'; -final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); -final File textFile = File(path); -final String textFilePath = textFile.path; - -void main() { - group('Create with a path', () { - final XFile file = XFile(textFilePath); - - test('Can be read as a string', () async { - expect(await file.readAsString(), equals(expectedStringContents)); - }); - test('Can be read as bytes', () async { - expect(await file.readAsBytes(), equals(bytes)); - }); - - test('Can be read as a stream', () async { - expect(await file.openRead().first, equals(bytes)); - }); - - test('Stream can be sliced', () async { - expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); - }); - - test('saveTo(..) creates file', () async { - File removeBeforeTest = File(pathPrefix + 'newFilePath.txt'); - if (removeBeforeTest.existsSync()) { - await removeBeforeTest.delete(); - } - - await file.saveTo(pathPrefix + 'newFilePath.txt'); - File newFile = File(pathPrefix + 'newFilePath.txt'); - - expect(newFile.existsSync(), isTrue); - expect(newFile.readAsStringSync(), 'Hello, world!'); - - await newFile.delete(); - }); - }); - - group('Create with data', () { - final file = XFile.fromData(bytes); - - test('Can be read as a string', () async { - expect(await file.readAsString(), equals(expectedStringContents)); - }); - test('Can be read as bytes', () async { - expect(await file.readAsBytes(), equals(bytes)); - }); - - test('Can be read as a stream', () async { - expect(await file.openRead().first, equals(bytes)); - }); - - test('Stream can be sliced', () async { - expect(await file.openRead(2, 5).first, equals(bytes.sublist(2, 5))); - }); - - test('Function saveTo(..) creates file', () async { - File removeBeforeTest = File(pathPrefix + 'newFileData.txt'); - if (removeBeforeTest.existsSync()) { - await removeBeforeTest.delete(); - } - - await file.saveTo(pathPrefix + 'newFileData.txt'); - File newFile = File(pathPrefix + 'newFileData.txt'); - - expect(newFile.existsSync(), isTrue); - expect(newFile.readAsStringSync(), 'Hello, world!'); - - await newFile.delete(); - }); - }); -} From fd52de8dfc29387c78c8657c44faabba8227d566 Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Wed, 10 Mar 2021 17:58:25 -0800 Subject: [PATCH 328/924] Skip flutter upgrade for pod linting Cirrus task (#3700) --- .cirrus.yml | 72 +++++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 8f61fabc4f2a..67669d783192 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,25 +1,37 @@ -root_task_template: &ROOT_TASK_TEMPLATE - # Don't run on release tags since it creates O(n^2) tasks where n is the - # number of plugins - only_if: $CIRRUS_TAG == '' - use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' - env: - INTEGRATION_TEST_PATH: "./packages/integration_test" - CHANNEL: "master" # Default to master when not explicitly set by a task. - PLUGIN_TOOLS: "dart run ./script/tool/lib/src/main.dart" - setup_script: - - flutter channel $CHANNEL - - flutter upgrade +# Don't run on release tags since it creates O(n^2) tasks where n is the +# number of plugins +only_if: $CIRRUS_TAG == '' +use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' +env: + INTEGRATION_TEST_PATH: "./packages/integration_test" + CHANNEL: "master" # Default to master when not explicitly set by a task. + PLUGIN_TOOLS: "dart run ./script/tool/lib/src/main.dart" + +tool_setup_template: &TOOL_SETUP_TEMPLATE + tool_setup_script: - git fetch origin master # To set FETCH_HEAD for "git merge-base" to work - cd script/tool - pub get +flutter_upgrade_template: &FLUTTER_UPGRADE_TEMPLATE + upgrade_flutter_script: + - flutter channel $CHANNEL + - flutter upgrade + << : *TOOL_SETUP_TEMPLATE + +macos_template: &MACOS_TEMPLATE + # Only one macOS task can run in parallel without credits, so use them for + # PRs on macOS. + use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' + osx_instance: + image: big-sur-xcode-12.3 + cocoapod_install_script: sudo gem install cocoapods # Light-workload Linux tasks. # These use default machines, with fewer CPUs, to reduce pressure on the # concurrency limits. task: - << : *ROOT_TASK_TEMPLATE + << : *FLUTTER_UPGRADE_TEMPLATE container: dockerfile: .ci/Dockerfile matrix: @@ -109,7 +121,7 @@ task: # tasks" block above once web_installers has been updated to support Chrome 89 # (which is what the current image generated from .ci/Dockerfile has). task: - << : *ROOT_TASK_TEMPLATE + << : *FLUTTER_UPGRADE_TEMPLATE container: dockerfile: .ci/Dockerfile-LegacyChrome matrix: @@ -134,7 +146,7 @@ task: # These use machines with more CPUs and memory, so will reduce parallelization # for non-credit runs. task: - << : *ROOT_TASK_TEMPLATE + << : *FLUTTER_UPGRADE_TEMPLATE container: dockerfile: .ci/Dockerfile cpu: 4 @@ -177,24 +189,9 @@ task: # macOS tasks. task: - << : *ROOT_TASK_TEMPLATE - # Only one macOS task can run in parallel without credits, so use them for - # PRs on macOS. - use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' - osx_instance: - image: big-sur-xcode-12.3 - cocoapod_install_script: sudo gem install cocoapods + << : *MACOS_TEMPLATE + << : *FLUTTER_UPGRADE_TEMPLATE matrix: - ### Platform-agnostic tasks ### - - name: lint_darwin_plugins - env: - matrix: - PLUGIN_SHARDING: "--shardIndex 0 --shardCount 2" - PLUGIN_SHARDING: "--shardIndex 1 --shardCount 2" - script: - # TODO(jmagman): Lint macOS podspecs but skip any that fail library validation. - - find . -name "*.podspec" | xargs grep -l "osx" | xargs rm - - ./script/incremental_build.sh podspecs ### iOS tasks ### - name: build_all_plugins_ipa env: @@ -245,3 +242,14 @@ task: - flutter config --enable-macos-desktop - ./script/incremental_build.sh build-examples --macos --no-ipa - ./script/incremental_build.sh drive-examples --macos + +task: + # Don't use FLUTTER_UPGRADE_TEMPLATE, Flutter tooling not needed. + << : *MACOS_TEMPLATE + << : *TOOL_SETUP_TEMPLATE + matrix: + - name: lint_darwin_plugins + script: + # TODO(jmagman): Lint macOS podspecs but skip any that fail library validation. + - find . -name "*.podspec" | xargs grep -l "osx" | xargs rm + - ./script/incremental_build.sh podspecs From d72cebd235220000cc7b438c7b48c9a27e07699b Mon Sep 17 00:00:00 2001 From: Adam Koprowski Date: Thu, 11 Mar 2021 18:15:02 +0000 Subject: [PATCH 329/924] Typos in comments (#2846) --- packages/in_app_purchase/example/lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/example/lib/main.dart b/packages/in_app_purchase/example/lib/main.dart index c9f0bb6ece25..32676cf799ea 100644 --- a/packages/in_app_purchase/example/lib/main.dart +++ b/packages/in_app_purchase/example/lib/main.dart @@ -343,7 +343,7 @@ class _MyAppState extends State<_MyApp> { } void deliverProduct(PurchaseDetails purchaseDetails) async { - // IMPORTANT!! Always verify a purchase purchase details before delivering the product. + // IMPORTANT!! Always verify purchase details before delivering the product. if (purchaseDetails.productID == _kConsumableId) { await ConsumableStore.save(purchaseDetails.purchaseID!); List consumables = await ConsumableStore.load(); From f4c513eb8c4169b7b7fd5c0e74fcf94cea7bad2d Mon Sep 17 00:00:00 2001 From: Sunbreak Date: Fri, 12 Mar 2021 21:34:14 +0800 Subject: [PATCH 330/924] Fix missing declaration of windows' default_package (#3705) Signed-off-by: Sunbreak --- packages/shared_preferences/shared_preferences/CHANGELOG.md | 4 ++++ packages/shared_preferences/shared_preferences/pubspec.yaml | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/shared_preferences/shared_preferences/CHANGELOG.md b/packages/shared_preferences/shared_preferences/CHANGELOG.md index b0899d57a3c5..583d8c238315 100644 --- a/packages/shared_preferences/shared_preferences/CHANGELOG.md +++ b/packages/shared_preferences/shared_preferences/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.5 + +* Fix missing declaration of windows' default_package + ## 2.0.4 * Fix a regression with simultaneous writes on Android. diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index b53bbfd93a38..3f8391f188d7 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -2,7 +2,7 @@ name: shared_preferences description: Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/shared_preferences/shared_preferences -version: 2.0.4 +version: 2.0.5 flutter: plugin: @@ -18,6 +18,8 @@ flutter: default_package: shared_preferences_macos web: default_package: shared_preferences_web + windows: + default_package: shared_preferences_windows dependencies: meta: ^1.3.0 From e23390260b9f3ad8964a4a18cd7ffc103b813acb Mon Sep 17 00:00:00 2001 From: Sunbreak Date: Sat, 13 Mar 2021 08:32:55 +0800 Subject: [PATCH 331/924] Re-endorse connectivity_for_web (#3708) Signed-off-by: Sunbreak --- packages/connectivity/connectivity/CHANGELOG.md | 4 ++++ packages/connectivity/connectivity/pubspec.yaml | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/connectivity/connectivity/CHANGELOG.md b/packages/connectivity/connectivity/CHANGELOG.md index 57de797ff045..3d69b7bad143 100644 --- a/packages/connectivity/connectivity/CHANGELOG.md +++ b/packages/connectivity/connectivity/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.3 + +* Re-endorse connectivity_for_web + ## 3.0.2 * Update platform_plugin_interface version requirement. diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index eeef53c4faa4..7b4dc60eee81 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -2,7 +2,7 @@ name: connectivity description: Flutter plugin for discovering the state of the network (WiFi & mobile/cellular) connectivity on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity -version: 3.0.2 +version: 3.0.3 flutter: plugin: @@ -22,10 +22,8 @@ dependencies: sdk: flutter meta: ^1.3.0 connectivity_platform_interface: ^2.0.0 - #TODO(cyanglaz): re-endorse the below plugins when they have migrated to nnbd. - # https://github.com/flutter/flutter/issues/68669 connectivity_macos: ^0.2.0 - # connectivity_for_web: ^0.3.0 + connectivity_for_web: ^0.4.0 dev_dependencies: flutter_test: From f7096d7d7be9883149a1fb6cebfaa6ff85fb01a5 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Fri, 12 Mar 2021 23:23:26 -0800 Subject: [PATCH 332/924] Reorder the checkboxes in the PR template (#3666) ...so that they are listed in more or less the likely order that people will do them in. --- .github/PULL_REQUEST_TEMPLATE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 741216982d35..84b9fd214751 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,16 +6,16 @@ ## Pre-launch Checklist -- [ ] The title of the PR starts with the name of the plugin surrounded by square brackets, e.g. `[shared_preferences]` - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. +- [ ] I signed the [CLA]. +- [ ] The title of the PR starts with the name of the plugin surrounded by square brackets, e.g. `[shared_preferences]` - [ ] I listed at least one issue that this PR fixes in the description above. -- [ ] I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test exempt. - [ ] I updated pubspec.yaml with an appropriate new version according to the [pub versioning philosophy]. - [ ] I updated CHANGELOG.md to add a description of the change. - [ ] I updated/added relevant documentation (doc comments with `///`). -- [ ] I signed the [CLA]. +- [ ] I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test exempt. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. From 4832a85d3b0c63afd0d1b5de46082a41ce92f70c Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Mon, 15 Mar 2021 08:12:45 -0700 Subject: [PATCH 333/924] [ci] Add libgcrypt to Docker image. (#3711) As recommended in https://github.com/flutter/website/pull/5466 --- .ci/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/Dockerfile b/.ci/Dockerfile index 14000e2032ed..13fd48be9c14 100644 --- a/.ci/Dockerfile +++ b/.ci/Dockerfile @@ -31,7 +31,7 @@ RUN sudo apt-get install -y xvfb libegl1-mesa # Install Linux desktop build tool requirements. RUN sudo apt-get install -y clang cmake ninja-build file pkg-config # Install necessary libraries. -RUN sudo apt-get install -y libgtk-3-dev libblkid-dev liblzma-dev +RUN sudo apt-get install -y libgtk-3-dev libblkid-dev liblzma-dev libgcrypt20-dev # Add repo for Google Chrome and install it RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - From 8169973d8cddd87429ff3e221b13fe62793b0a1a Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 16 Mar 2021 17:50:51 -0400 Subject: [PATCH 334/924] Add missing licenses, and add a check (#3720) Adds a new CI check that all code files have a copyright+license block (and that it's one we are expecting to see). Fixes the ~350 files (!) that did not have them. This includes all of the files in the .../example/ directories, following the example of flutter/flutter. (This does mean some manual intervention will be needed when generating new example directories in the future, but it's one-time per example.) Also standardized some variants that used different line breaks than most of the rest of the repo (likely added since I standardized them all a while ago, but didn't add a check for at the time to enforce going forward), to simplify the checks. Fixes flutter/flutter#77114 --- .cirrus.yml | 5 + .../Application.java | 4 + .../android_alarm_manager_test.dart | 6 +- .../example/test_driver/integration_test.dart | 6 +- .../androidintent/AndroidIntentPlugin.java | 4 + .../plugins/androidintent/IntentSender.java | 4 + .../androidintent/MethodCallHandlerImpl.java | 4 + .../MethodCallHandlerImplTest.java | 4 + .../EmbeddingV1ActivityTest.java | 4 + .../MainActivityTest.java | 4 + packages/android_intent/lib/flag.dart | 4 + .../integration_test/battery_test.dart | 6 +- .../lib/enums/battery_state.dart | 4 + .../method_channel_battery.dart | 4 + .../EmbeddingV1ActivityTest.java | 4 + .../cameraexample/FlutterActivityTest.java | 4 + .../cameraexample/EmbeddingV1Activity.java | 4 + .../example/integration_test/camera_test.dart | 6 +- .../camera/example/ios/Runner/AppDelegate.h | 4 + .../camera/example/ios/Runner/AppDelegate.m | 4 + .../camera/camera/example/ios/Runner/main.m | 4 + .../example/test_driver/integration_test.dart | 6 +- .../camera/ios/Tests/CameraPluginTests.m | 4 + .../camera/test/camera_image_stream_test.dart | 4 + .../lib/src/types/image_format_group.dart | 4 + .../lib/src/utils/utils.dart | 4 + .../test/types/image_group_test.dart | 4 + .../test/utils/utils_test.dart | 4 + .../connectivityexample/ActivityTest.java | 4 + .../example/macos/Runner/AppDelegate.swift | 4 + .../macos/Runner/MainFlutterWindow.swift | 4 + .../connectivity/example/web/index.html | 3 + .../network_information_test.dart | 4 + .../src/connectivity_mocks.dart | 4 + .../connectivity_for_web/example/run_test.sh | 4 + .../example/web/index.html | 3 + .../lib/connectivity_for_web.dart | 4 + .../src/dart_html_connectivity_plugin.dart | 4 + ...k_information_api_connectivity_plugin.dart | 4 + .../lib/src/utils/connectivity_result.dart | 4 + .../test/tests_exist_elsewhere_test.dart | 4 + .../example/macos/Runner/AppDelegate.swift | 4 + .../macos/Runner/MainFlutterWindow.swift | 4 + .../lib/src/enums.dart | 4 + .../lib/src/utils.dart | 4 + .../EmbeddingV1ActivityTest.java | 4 + .../integration_test/device_info_test.dart | 6 +- .../example/test_driver/integration_test.dart | 6 +- .../internal/jsonrpc/message/ErrorObject.java | 4 + .../com/example/espresso/EspressoPlugin.java | 4 + .../espresso_example/MainActivity.java | 4 + packages/espresso/example/lib/main.dart | 4 + .../espresso/example/test_driver/example.dart | 4 + .../example/lib/get_directory_page.dart | 4 + .../file_selector/example/lib/home_page.dart | 4 + .../file_selector/example/lib/main.dart | 4 + .../example/lib/open_image_page.dart | 4 + .../lib/open_multiple_images_page.dart | 4 + .../example/lib/open_text_page.dart | 4 + .../example/lib/save_text_page.dart | 4 + .../file_selector/example/web/index.html | 3 + .../lib/file_selector_platform_interface.dart | 4 + .../lib/src/types/types.dart | 4 + .../lib/src/web_helpers/web_helpers.dart | 4 + .../file_selector_web/example/run_test.sh | 3 + .../test/more_tests_exist_elsewhere_test.dart | 4 + .../FlutterLifecycleAdapterTest.java | 4 + .../EmbeddingV1Activity.java | 4 + ...flutter_plugin_android_lifecycle_test.dart | 6 +- .../example/lib/main.dart | 6 +- .../lib/flutter_plugin_android_lifecycle.dart | 4 + .../plugins/googlemaps/CircleBuilderTest.java | 4 + .../googlemaps/CircleControllerTest.java | 4 + .../googlemaps/PolygonBuilderTest.java | 4 + .../googlemaps/PolygonControllerTest.java | 4 + .../googlemaps/PolylineBuilderTest.java | 4 + .../googlemaps/PolylineControllerTest.java | 4 + .../googlemaps/EmbeddingV1ActivityTest.java | 4 + .../plugins/googlemaps/MainActivityTest.java | 4 + .../EmbeddingV1Activity.java | 4 + .../googlemaps/GoogleMapControllerTest.java | 4 + .../google_map_inspector.dart | 6 +- .../integration_test/google_maps_test.dart | 6 +- .../example/ios/Runner/AppDelegate.h | 4 + .../example/ios/Runner/AppDelegate.m | 4 + .../example/ios/Runner/main.m | 4 + .../example/test_driver/integration_test.dart | 6 +- .../test/tile_overlay_updates_test.dart | 4 + .../resources/icon_image_base64.dart | 4 + .../example/run_test.sh | 4 + .../test/tests_exist_elsewhere_test.dart | 4 + .../googlesignin/BackgroundTaskRunner.java | 6 +- .../plugins/googlesignin/Executors.java | 6 +- .../googlesignin/GoogleSignInPlugin.java | 6 +- .../googlesignin/GoogleSignInWrapper.java | 6 +- .../google_sign_in/example/web/index.html | 3 + .../integration_test/google_sign_in_test.dart | 4 + .../ios/Classes/FLTGoogleSignInPlugin.h | 6 +- .../ios/Classes/FLTGoogleSignInPlugin.m | 6 +- .../google_sign_in/lib/google_sign_in.dart | 6 +- .../google_sign_in/lib/src/common.dart | 6 +- .../google_sign_in/lib/widgets.dart | 6 +- .../test_driver/integration_test.dart | 6 +- .../google_sign_in_web/example/run_test.sh | 3 + .../test/tests_exist_elsewhere_test.dart | 4 + .../FlutterActivityTest.java | 4 + .../imagepicker/ImagePickerDelegateTest.java | 4 + .../imagepicker/ImagePickerPluginTest.java | 4 + .../test_driver/test/integration_test.dart | 6 +- .../image_picker/example/web/index.html | 3 + .../old_image_picker_test.dart | 4 + .../lib/image_picker_for_web.dart | 4 + .../lib/image_picker_platform_interface.dart | 4 + .../lib/src/types/picked_file/base.dart | 4 + .../lib/src/types/picked_file/html.dart | 4 + .../lib/src/types/picked_file/io.dart | 4 + .../src/types/picked_file/picked_file.dart | 4 + .../src/types/picked_file/unsupported.dart | 4 + .../lib/src/types/types.dart | 4 + .../plugins/inapppurchase/Translator.java | 4 +- .../inapppurchase/MethodCallHandlerTest.java | 4 + .../plugins/inapppurchase/TranslatorTest.java | 4 +- .../example/ios/Runner/AppDelegate.h | 4 + .../example/ios/Runner/AppDelegate.m | 4 + .../in_app_purchase/example/ios/Runner/main.m | 4 + .../test_driver/test/integration_test.dart | 6 +- .../in_app_purchase_test.dart | 6 +- .../purchase_wrapper.dart | 4 +- .../sku_details_wrapper.dart | 4 +- .../purchase_wrapper_test.dart | 4 +- .../sku_details_wrapper_test.dart | 4 +- .../e2e_example/EmbedderV1ActivityTest.java | 4 + .../e2e_example/FlutterActivityTest.java | 4 + .../FlutterActivityWithPermissionTest.java | 4 + .../integration_test/_example_test_io.dart | 4 + .../integration_test/_example_test_web.dart | 4 + .../integration_test/_extended_test_io.dart | 4 + .../integration_test/_extended_test_web.dart | 4 + .../integration_test/example_test.dart | 4 + .../integration_test/extended_test.dart | 4 + .../example/ios/Runner/AppDelegate.h | 4 + .../example/ios/Runner/AppDelegate.m | 4 + .../example/ios/Runner/main.m | 4 + .../example/ios/RunnerTests/RunnerTests.m | 4 + .../integration_test/example/lib/main.dart | 4 + .../integration_test/example/lib/my_app.dart | 4 + .../example/lib/my_web_app.dart | 4 + .../example/macos/Runner/AppDelegate.swift | 4 + .../macos/Runner/MainFlutterWindow.swift | 4 + .../extended_integration_test.dart | 4 + .../example/test_driver/failure_test.dart | 4 + .../example/test_driver/integration_test.dart | 4 + .../integration_test/example/web/index.html | 3 + .../ios/Classes/IntegrationTestIosTest.h | 4 + .../ios/Classes/IntegrationTestIosTest.m | 4 + .../ios/Classes/IntegrationTestPlugin.h | 4 + .../ios/Classes/IntegrationTestPlugin.m | 4 + .../lib/integration_test_driver_extended.dart | 4 + .../test/binding_fail_test.dart | 4 + .../integration_test/test/binding_test.dart | 4 + .../test/data/fail_test_script.dart | 4 + .../test/data/pass_test_script.dart | 4 + .../test/data/pass_then_fail_test_script.dart | 4 + .../test/response_serialization_test.dart | 4 + .../example/ios/Runner/AppDelegate.swift | 4 + .../ios/Runner/Runner-Bridging-Header.h | 6 +- .../ios_platform_images/example/lib/main.dart | 4 + .../example/test/widget_test.dart | 4 + .../ios/Classes/IosPlatformImagesPlugin.h | 4 + .../ios/Classes/IosPlatformImagesPlugin.m | 4 + .../localauth/EmbeddingV1ActivityTest.java | 4 + .../FlutterFragmentActivityTest.java | 4 + .../localauthexample/EmbeddingV1Activity.java | 4 + packages/local_auth/example/ios/Runner/main.m | 4 + .../integration_test/package_info_test.dart | 6 +- .../example/macos/Runner/AppDelegate.swift | 4 + .../macos/Runner/MainFlutterWindow.swift | 4 + .../example/test_driver/integration_test.dart | 6 +- .../pathprovider/StorageDirectoryMapper.java | 5 +- .../StorageDirectoryMapperTest.java | 5 +- .../java/EmbeddingV1ActivityTest.java | 3 + .../androidTest/java/MainActivityTest.java | 3 + .../EmbeddingV1Activity.java | 3 + .../integration_test/path_provider_test.dart | 6 +- .../path_provider/example/linux/main.cc | 4 + .../example/linux/my_application.cc | 4 + .../example/linux/my_application.h | 4 + .../example/macos/Runner/AppDelegate.swift | 4 + .../macos/Runner/MainFlutterWindow.swift | 4 + .../example/test_driver/integration_test.dart | 6 +- .../example/windows/runner/flutter_window.cpp | 4 + .../example/windows/runner/flutter_window.h | 4 + .../example/windows/runner/main.cpp | 4 + .../example/windows/runner/run_loop.cpp | 4 + .../example/windows/runner/run_loop.h | 4 + .../example/windows/runner/utils.cpp | 4 + .../example/windows/runner/utils.h | 4 + .../example/windows/runner/win32_window.cpp | 4 + .../example/windows/runner/win32_window.h | 4 + .../integration_test/path_provider_test.dart | 6 +- .../path_provider_linux/example/lib/main.dart | 4 + .../path_provider_linux/example/linux/main.cc | 4 + .../example/linux/my_application.cc | 4 + .../example/linux/my_application.h | 4 + .../example/test/widget_test.dart | 4 + .../example/test_driver/integration_test.dart | 6 +- .../integration_test/path_provider_test.dart | 6 +- .../example/macos/Runner/AppDelegate.swift | 4 + .../macos/Runner/MainFlutterWindow.swift | 4 + .../example/test_driver/integration_test.dart | 6 +- .../lib/src/enums.dart | 4 + .../integration_test/path_provider_test.dart | 6 +- .../example/test_driver/integration_test.dart | 6 +- .../example/windows/runner/flutter_window.cpp | 4 + .../example/windows/runner/flutter_window.h | 4 + .../example/windows/runner/main.cpp | 4 + .../example/windows/runner/run_loop.cpp | 4 + .../example/windows/runner/run_loop.h | 4 + .../example/windows/runner/utils.cpp | 4 + .../example/windows/runner/utils.h | 4 + .../example/windows/runner/win32_window.cpp | 4 + .../example/windows/runner/win32_window.h | 4 + .../integration_test/quick_actions_test.dart | 6 +- .../example/test_driver/integration_test.dart | 6 +- .../EmbeddingV1ActivityTest.java | 4 + .../sensors/example/ios/Runner/AppDelegate.h | 4 + .../sensors/example/ios/Runner/AppDelegate.m | 4 + packages/sensors/example/ios/Runner/main.m | 4 + .../test_driver/test/integration_test.dart | 6 +- .../integration_test/sensors_test.dart | 6 +- .../shareexample/EmbeddingV1ActivityTest.java | 4 + .../share/example/lib/image_previews.dart | 4 + .../test_driver/test/integration_test.dart | 6 +- .../share/integration_test/share_test.dart | 6 +- .../example/ios/Runner/AppDelegate.swift | 4 + .../ios/Runner/Runner-Bridging-Header.h | 4 + .../shared_preferences/example/linux/main.cc | 4 + .../example/linux/my_application.cc | 4 + .../example/linux/my_application.h | 4 + .../example/macos/Runner/AppDelegate.swift | 4 + .../macos/Runner/MainFlutterWindow.swift | 4 + .../example/test_driver/integration_test.dart | 6 +- .../shared_preferences/example/web/index.html | 3 + .../example/windows/runner/flutter_window.cpp | 4 + .../example/windows/runner/flutter_window.h | 4 + .../example/windows/runner/main.cpp | 4 + .../example/windows/runner/run_loop.cpp | 4 + .../example/windows/runner/run_loop.h | 4 + .../example/windows/runner/utils.cpp | 4 + .../example/windows/runner/utils.h | 4 + .../example/windows/runner/win32_window.cpp | 4 + .../example/windows/runner/win32_window.h | 4 + .../example/linux/main.cc | 4 + .../example/linux/my_application.cc | 4 + .../example/linux/my_application.h | 4 + .../example/test_driver/integration_test.dart | 6 +- .../shared_preferences_test.dart | 6 +- .../example/macos/Runner/AppDelegate.swift | 4 + .../macos/Runner/MainFlutterWindow.swift | 4 + .../example/test_driver/integration_test.dart | 6 +- .../shared_preferences_test.dart | 6 +- .../example/test_driver/integration_test.dart | 6 +- .../example/windows/runner/flutter_window.cpp | 4 + .../example/windows/runner/flutter_window.h | 4 + .../example/windows/runner/main.cpp | 4 + .../example/windows/runner/run_loop.cpp | 4 + .../example/windows/runner/run_loop.h | 4 + .../example/windows/runner/utils.cpp | 4 + .../example/windows/runner/utils.h | 4 + .../example/windows/runner/win32_window.cpp | 4 + .../example/windows/runner/win32_window.h | 4 + .../urllauncher/MethodCallHandlerImpl.java | 4 + .../plugins/urllauncher/UrlLauncher.java | 4 + .../urllauncher/UrlLauncherPlugin.java | 4 + .../plugins/urllauncher/WebViewActivity.java | 4 + .../MethodCallHandlerImplTest.java | 4 + .../EmbeddingV1ActivityTest.java | 4 + .../urllauncherexample/MainActivityTest.java | 4 + .../integration_test/url_launcher_test.dart | 6 +- .../url_launcher/example/linux/main.cc | 4 + .../example/linux/my_application.cc | 4 + .../example/linux/my_application.h | 4 + .../example/macos/Runner/AppDelegate.swift | 4 + .../macos/Runner/MainFlutterWindow.swift | 4 + .../example/test_driver/integration_test.dart | 6 +- .../url_launcher/example/web/index.html | 3 + .../example/windows/runner/flutter_window.cpp | 4 + .../example/windows/runner/flutter_window.h | 4 + .../example/windows/runner/main.cpp | 4 + .../example/windows/runner/run_loop.cpp | 4 + .../example/windows/runner/run_loop.h | 4 + .../example/windows/runner/utils.cpp | 4 + .../example/windows/runner/utils.h | 4 + .../example/windows/runner/win32_window.cpp | 4 + .../example/windows/runner/win32_window.h | 4 + .../integration_test/url_launcher_test.dart | 6 +- .../url_launcher_linux/example/linux/main.cc | 4 + .../example/linux/my_application.cc | 4 + .../example/linux/my_application.h | 4 + .../example/test_driver/integration_test.dart | 6 +- .../lib/url_launcher_linux.dart | 3 - .../integration_test/url_launcher_test.dart | 6 +- .../example/macos/Runner/AppDelegate.swift | 4 + .../macos/Runner/MainFlutterWindow.swift | 4 + .../example/test_driver/integration_test.dart | 6 +- .../lib/url_launcher_macos.dart | 3 - .../url_launcher_web_test.mocks.dart | 4 + .../url_launcher_web/example/run_test.sh | 4 + .../test/tests_exist_elsewhere_test.dart | 4 + .../integration_test/url_launcher_test.dart | 6 +- .../example/test_driver/integration_test.dart | 6 +- .../example/windows/runner/flutter_window.cpp | 4 + .../example/windows/runner/flutter_window.h | 4 + .../example/windows/runner/main.cpp | 4 + .../example/windows/runner/run_loop.cpp | 4 + .../example/windows/runner/run_loop.h | 4 + .../example/windows/runner/utils.cpp | 4 + .../example/windows/runner/utils.h | 4 + .../example/windows/runner/win32_window.cpp | 4 + .../example/windows/runner/win32_window.h | 4 + .../lib/url_launcher_windows.dart | 3 - .../videoplayer/CustomSSLSocketFactory.java | 4 + .../flutter/plugins/videoplayer/Messages.java | 4 + .../plugins/videoplayer/VideoPlayer.java | 4 + .../videoplayer/VideoPlayerOptions.java | 4 + .../FlutterActivityTest.java | 4 + .../integration_test/video_player_test.dart | 6 +- .../example/test_driver/integration_test.dart | 6 +- .../example/test_driver/video_player.dart | 6 +- .../test_driver/video_player_test.dart | 6 +- .../video_player/example/web/index.html | 3 + .../video_player/ios/Classes/messages.h | 4 + .../video_player/ios/Classes/messages.m | 4 + .../video_player/pigeons/messages.dart | 4 + .../lib/messages.dart | 4 + .../lib/test.dart | 4 + .../lib/video_player_web.dart | 4 + .../webviewflutter/DisplayListenerProxy.java | 4 + .../EmbeddingV1ActivityTest.java | 4 + .../MainActivityTest.java | 4 + .../webview_flutter_test.dart | 6 +- .../example/test_driver/integration_test.dart | 6 +- .../MainActivity.java | 4 + .../example/ios/Runner/AppDelegate.h | 4 + .../example/ios/Runner/AppDelegate.m | 4 + .../example/ios/Runner/main.m | 4 + script/build_all_plugins_app.sh | 3 + script/check_publish.sh | 4 + script/common.sh | 3 + script/incremental_build.sh | 4 + .../tool/lib/src/license_check_command.dart | 209 ++++++++++++ script/tool/lib/src/main.dart | 2 + .../tool/lib/src/publish_plugin_command.dart | 4 + script/tool/test/analyze_command_test.dart | 4 + .../test/build_examples_command_test.dart | 4 + script/tool/test/common_test.dart | 4 + .../test/drive_examples_command_test.dart | 4 + script/tool/test/firebase_test_lab_test.dart | 4 + .../tool/test/license_check_command_test.dart | 306 ++++++++++++++++++ .../tool/test/lint_podspecs_command_test.dart | 4 + script/tool/test/list_command_test.dart | 4 + script/tool/test/mocks.dart | 4 + .../test/publish_plugin_command_test.dart | 4 + script/tool/test/test_command_test.dart | 4 + script/tool/test/util.dart | 4 + script/tool/test/version_check_test.dart | 4 + 366 files changed, 1870 insertions(+), 207 deletions(-) delete mode 100644 packages/url_launcher/url_launcher_linux/lib/url_launcher_linux.dart delete mode 100644 packages/url_launcher/url_launcher_macos/lib/url_launcher_macos.dart delete mode 100644 packages/url_launcher/url_launcher_windows/lib/url_launcher_windows.dart create mode 100644 script/tool/lib/src/license_check_command.dart create mode 100644 script/tool/test/license_check_command_test.dart diff --git a/.cirrus.yml b/.cirrus.yml index 67669d783192..26264b3fb926 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -50,6 +50,11 @@ task: - ./script/check_publish.sh - name: format format_script: ./script/incremental_build.sh format --fail-on-change + license_script: + - cd script/tool + - pub get + - cd ../.. + - dart script/tool/lib/src/main.dart license-check - name: test env: matrix: diff --git a/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/Application.java b/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/Application.java index 55b789bcb6a4..e2b3e8aae73d 100644 --- a/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/Application.java +++ b/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/Application.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.androidalarmmanagerexample; import io.flutter.app.FlutterApplication; diff --git a/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart b/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart index 4d53a5a945e6..68e35d581d89 100644 --- a/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart +++ b/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/android_alarm_manager/example/test_driver/integration_test.dart b/packages/android_alarm_manager/example/test_driver/integration_test.dart index 4e78d04fa971..a2fa9e1147e1 100644 --- a/packages/android_alarm_manager/example/test_driver/integration_test.dart +++ b/packages/android_alarm_manager/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java index 30e0915aed1f..04df4d9f7c01 100644 --- a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java +++ b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.androidintent; import androidx.annotation.NonNull; diff --git a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java index b1a590d79c84..0d2ff0c829e5 100644 --- a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java +++ b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.androidintent; import android.app.Activity; diff --git a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java index 753541bf9338..2cce443fd182 100644 --- a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java +++ b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.androidintent; import android.content.ComponentName; diff --git a/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java b/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java index cf0a28e822d4..e36f4aab804d 100644 --- a/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java +++ b/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.androidintent; import static org.junit.Assert.assertEquals; diff --git a/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/EmbeddingV1ActivityTest.java b/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/EmbeddingV1ActivityTest.java index 7ab0e87e7c5a..a370318927ba 100644 --- a/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/EmbeddingV1ActivityTest.java +++ b/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/EmbeddingV1ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.androidintentexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/MainActivityTest.java b/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/MainActivityTest.java index 619dbcd853e7..f7cddca2832f 100644 --- a/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/MainActivityTest.java +++ b/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/MainActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.androidintentexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/android_intent/lib/flag.dart b/packages/android_intent/lib/flag.dart index e05aa6d12666..990eed9db8fc 100644 --- a/packages/android_intent/lib/flag.dart +++ b/packages/android_intent/lib/flag.dart @@ -1,3 +1,7 @@ +// 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. + /// Special flags that can be set on an intent to control how it is handled. /// /// See diff --git a/packages/battery/battery/integration_test/battery_test.dart b/packages/battery/battery/integration_test/battery_test.dart index 2b0e26967b6c..1732380919b2 100644 --- a/packages/battery/battery/integration_test/battery_test.dart +++ b/packages/battery/battery/integration_test/battery_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/battery/battery_platform_interface/lib/enums/battery_state.dart b/packages/battery/battery_platform_interface/lib/enums/battery_state.dart index 7dd5e400faf2..2ceb35128b4b 100644 --- a/packages/battery/battery_platform_interface/lib/enums/battery_state.dart +++ b/packages/battery/battery_platform_interface/lib/enums/battery_state.dart @@ -1,3 +1,7 @@ +// 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. + /// Indicates the current battery state. enum BatteryState { /// The battery is completely full of energy. diff --git a/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart b/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart index 739812dc95e5..dbc561bf0e64 100644 --- a/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart +++ b/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart @@ -1,3 +1,7 @@ +// 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:async'; import 'package:flutter/services.dart'; diff --git a/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java b/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java index 8a97e47072e9..08ae8e4274af 100644 --- a/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java +++ b/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.cameraexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java b/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java index c90c66defc32..4f30e83a138c 100644 --- a/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java +++ b/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.cameraexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/camera/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java b/packages/camera/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java index a53dd6b756ad..e30d5ec7b07b 100644 --- a/packages/camera/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java +++ b/packages/camera/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.cameraexample; import android.os.Bundle; diff --git a/packages/camera/camera/example/integration_test/camera_test.dart b/packages/camera/camera/example/integration_test/camera_test.dart index 4ff624c7d989..f30734180b20 100644 --- a/packages/camera/camera/example/integration_test/camera_test.dart +++ b/packages/camera/camera/example/integration_test/camera_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(mvanbeusekom): Remove this once flutter_driver supports null safety. // https://github.com/flutter/flutter/issues/71379 diff --git a/packages/camera/camera/example/ios/Runner/AppDelegate.h b/packages/camera/camera/example/ios/Runner/AppDelegate.h index 36e21bbf9cf4..31fc381e7066 100644 --- a/packages/camera/camera/example/ios/Runner/AppDelegate.h +++ b/packages/camera/camera/example/ios/Runner/AppDelegate.h @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import diff --git a/packages/camera/camera/example/ios/Runner/AppDelegate.m b/packages/camera/camera/example/ios/Runner/AppDelegate.m index 59a72e90be12..2147d3d605ac 100644 --- a/packages/camera/camera/example/ios/Runner/AppDelegate.m +++ b/packages/camera/camera/example/ios/Runner/AppDelegate.m @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "AppDelegate.h" #include "GeneratedPluginRegistrant.h" diff --git a/packages/camera/camera/example/ios/Runner/main.m b/packages/camera/camera/example/ios/Runner/main.m index dff6597e4513..f451b14cb751 100644 --- a/packages/camera/camera/example/ios/Runner/main.m +++ b/packages/camera/camera/example/ios/Runner/main.m @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import #import "AppDelegate.h" diff --git a/packages/camera/camera/example/test_driver/integration_test.dart b/packages/camera/camera/example/test_driver/integration_test.dart index 160b48f8f72f..8a35ec06803d 100644 --- a/packages/camera/camera/example/test_driver/integration_test.dart +++ b/packages/camera/camera/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(mvanbeusekom): Remove this once flutter_driver supports null safety. // https://github.com/flutter/flutter/issues/71379 diff --git a/packages/camera/camera/ios/Tests/CameraPluginTests.m b/packages/camera/camera/ios/Tests/CameraPluginTests.m index e5be3980bad0..8d9cbc2eb81a 100644 --- a/packages/camera/camera/ios/Tests/CameraPluginTests.m +++ b/packages/camera/camera/ios/Tests/CameraPluginTests.m @@ -1,3 +1,7 @@ +// Copyright 2019 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 camera; @import XCTest; diff --git a/packages/camera/camera/test/camera_image_stream_test.dart b/packages/camera/camera/test/camera_image_stream_test.dart index 57e3aeb36f3f..41faeb1fd4b0 100644 --- a/packages/camera/camera/test/camera_image_stream_test.dart +++ b/packages/camera/camera/test/camera_image_stream_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:camera/camera.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/widgets.dart'; diff --git a/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart b/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart index 3d2c0180fe65..61ccbfc2638a 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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. + /// Group of image formats that are comparable across Android and iOS platforms. enum ImageFormatGroup { /// The image format does not fit into any specific group. diff --git a/packages/camera/camera_platform_interface/lib/src/utils/utils.dart b/packages/camera/camera_platform_interface/lib/src/utils/utils.dart index 5413f25bb8b7..f4c21bfca6cc 100644 --- a/packages/camera/camera_platform_interface/lib/src/utils/utils.dart +++ b/packages/camera/camera_platform_interface/lib/src/utils/utils.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/services.dart'; diff --git a/packages/camera/camera_platform_interface/test/types/image_group_test.dart b/packages/camera/camera_platform_interface/test/types/image_group_test.dart index c49b2f03a7a0..ac975fa6e6ce 100644 --- a/packages/camera/camera_platform_interface/test/types/image_group_test.dart +++ b/packages/camera/camera_platform_interface/test/types/image_group_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:camera_platform_interface/src/types/types.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/camera/camera_platform_interface/test/utils/utils_test.dart b/packages/camera/camera_platform_interface/test/utils/utils_test.dart index 63e3baff265d..822798160439 100644 --- a/packages/camera/camera_platform_interface/test/utils/utils_test.dart +++ b/packages/camera/camera_platform_interface/test/utils/utils_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:camera_platform_interface/src/utils/utils.dart'; import 'package:flutter/services.dart'; diff --git a/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java b/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java index f8f4247a7ef5..b531a2db2897 100644 --- a/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java +++ b/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.connectivityexample; import static org.junit.Assert.assertNotNull; diff --git a/packages/connectivity/connectivity/example/macos/Runner/AppDelegate.swift b/packages/connectivity/connectivity/example/macos/Runner/AppDelegate.swift index d53ef6437726..ca19fe95f8cf 100644 --- a/packages/connectivity/connectivity/example/macos/Runner/AppDelegate.swift +++ b/packages/connectivity/connectivity/example/macos/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/connectivity/connectivity/example/macos/Runner/MainFlutterWindow.swift b/packages/connectivity/connectivity/example/macos/Runner/MainFlutterWindow.swift index 2722837ec918..2ce11b78604b 100644 --- a/packages/connectivity/connectivity/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/connectivity/connectivity/example/macos/Runner/MainFlutterWindow.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/connectivity/connectivity/example/web/index.html b/packages/connectivity/connectivity/example/web/index.html index 9b7a438f823a..97b1100c4244 100644 --- a/packages/connectivity/connectivity/example/web/index.html +++ b/packages/connectivity/connectivity/example/web/index.html @@ -1,4 +1,7 @@ + diff --git a/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart b/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart index f8e8059e7dba..1f4a1d5d8f60 100644 --- a/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart +++ b/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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:connectivity_for_web/src/network_information_api_connectivity_plugin.dart'; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart b/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart index fc795595e3f3..390a66556d10 100644 --- a/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart +++ b/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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 'dart:async'; import 'dart:html'; import 'dart:js_util' show getProperty; diff --git a/packages/connectivity/connectivity_for_web/example/run_test.sh b/packages/connectivity/connectivity_for_web/example/run_test.sh index 8e6f149358c9..9bfce94f63b2 100755 --- a/packages/connectivity/connectivity_for_web/example/run_test.sh +++ b/packages/connectivity/connectivity_for_web/example/run_test.sh @@ -1,4 +1,8 @@ #!/usr/bin/bash +# Copyright 2017 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. + if pgrep -lf chromedriver > /dev/null; then echo "chromedriver is running." diff --git a/packages/connectivity/connectivity_for_web/example/web/index.html b/packages/connectivity/connectivity_for_web/example/web/index.html index 6eff9a740d43..27464c33811a 100644 --- a/packages/connectivity/connectivity_for_web/example/web/index.html +++ b/packages/connectivity/connectivity_for_web/example/web/index.html @@ -1,4 +1,7 @@ + diff --git a/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart b/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart index fd061a878867..14de31db1125 100644 --- a/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart +++ b/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart @@ -1,3 +1,7 @@ +// 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 'dart:async'; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; diff --git a/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart index 950d26804371..09fbeaf7fd0d 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart @@ -1,3 +1,7 @@ +// 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 'dart:async'; import 'dart:html' as html show window; diff --git a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart index 800be2ef238f..2b319b1fb5ab 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart @@ -1,3 +1,7 @@ +// 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 'dart:async'; import 'dart:html' as html show window, NetworkInformation; import 'dart:js' show allowInterop; diff --git a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart index e7eb8969231a..9f1b111eccd3 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart @@ -1,3 +1,7 @@ +// 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 'dart:html' as html show NetworkInformation; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; diff --git a/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart b/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart index 334f52186d9d..64d8e547e485 100644 --- a/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart +++ b/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart @@ -1,3 +1,7 @@ +// 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_test/flutter_test.dart'; void main() { diff --git a/packages/connectivity/connectivity_macos/example/macos/Runner/AppDelegate.swift b/packages/connectivity/connectivity_macos/example/macos/Runner/AppDelegate.swift index d53ef6437726..ca19fe95f8cf 100644 --- a/packages/connectivity/connectivity_macos/example/macos/Runner/AppDelegate.swift +++ b/packages/connectivity/connectivity_macos/example/macos/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/connectivity/connectivity_macos/example/macos/Runner/MainFlutterWindow.swift b/packages/connectivity/connectivity_macos/example/macos/Runner/MainFlutterWindow.swift index 2722837ec918..2ce11b78604b 100644 --- a/packages/connectivity/connectivity_macos/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/connectivity/connectivity_macos/example/macos/Runner/MainFlutterWindow.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart b/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart index 9d8cef9e1a66..640e378de0ce 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart @@ -1,3 +1,7 @@ +// Copyright 2020 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. + /// Connection status check result. enum ConnectivityResult { /// WiFi: Device connected via Wi-Fi diff --git a/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart b/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart index 2ae22e1c9fc3..4df92974ba0c 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart @@ -1,3 +1,7 @@ +// Copyright 2020 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 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; /// Convert a String to a ConnectivityResult value. diff --git a/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1ActivityTest.java b/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1ActivityTest.java index 8fa880842d51..ca680684e3ea 100644 --- a/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1ActivityTest.java +++ b/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.deviceinfoexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/device_info/device_info/example/integration_test/device_info_test.dart b/packages/device_info/device_info/example/integration_test/device_info_test.dart index 61c4396b0d8e..a2a3ba7733ce 100644 --- a/packages/device_info/device_info/example/integration_test/device_info_test.dart +++ b/packages/device_info/device_info/example/integration_test/device_info_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(cyanglaz): Remove once https://github.com/flutter/plugins/pull/3158 is landed. // @dart = 2.9 diff --git a/packages/device_info/device_info/example/test_driver/integration_test.dart b/packages/device_info/device_info/example/test_driver/integration_test.dart index 13327bb884c9..84004cebd1a6 100644 --- a/packages/device_info/device_info/example/test_driver/integration_test.dart +++ b/packages/device_info/device_info/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(cyanglaz): Remove once https://github.com/flutter/flutter/issues/59879 is fixed. // @dart = 2.9 diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java index af5c68e574aa..d7779d3e5ec7 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package androidx.test.espresso.flutter.internal.jsonrpc.message; import com.google.gson.JsonObject; diff --git a/packages/espresso/android/src/main/java/com/example/espresso/EspressoPlugin.java b/packages/espresso/android/src/main/java/com/example/espresso/EspressoPlugin.java index e1b1e3ac86db..634b5fe53ad7 100644 --- a/packages/espresso/android/src/main/java/com/example/espresso/EspressoPlugin.java +++ b/packages/espresso/android/src/main/java/com/example/espresso/EspressoPlugin.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package com.example.espresso; import androidx.annotation.NonNull; diff --git a/packages/espresso/example/android/app/src/main/java/com/example/espresso_example/MainActivity.java b/packages/espresso/example/android/app/src/main/java/com/example/espresso_example/MainActivity.java index 413ef9e50448..ff62ed2521d5 100644 --- a/packages/espresso/example/android/app/src/main/java/com/example/espresso_example/MainActivity.java +++ b/packages/espresso/example/android/app/src/main/java/com/example/espresso_example/MainActivity.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package com.example.espresso_example; import androidx.annotation.NonNull; diff --git a/packages/espresso/example/lib/main.dart b/packages/espresso/example/lib/main.dart index 958d26a0c149..2ab6632113d5 100644 --- a/packages/espresso/example/lib/main.dart +++ b/packages/espresso/example/lib/main.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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/material.dart'; void main() => runApp(MyApp()); diff --git a/packages/espresso/example/test_driver/example.dart b/packages/espresso/example/test_driver/example.dart index ab74ff550930..42acdeb61a2c 100644 --- a/packages/espresso/example/test_driver/example.dart +++ b/packages/espresso/example/test_driver/example.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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_driver/driver_extension.dart'; import 'package:espresso_example/main.dart' as app; diff --git a/packages/file_selector/file_selector/example/lib/get_directory_page.dart b/packages/file_selector/file_selector/example/lib/get_directory_page.dart index cf4cde9fa9a8..be278f374fa8 100644 --- a/packages/file_selector/file_selector/example/lib/get_directory_page.dart +++ b/packages/file_selector/file_selector/example/lib/get_directory_page.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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:file_selector/file_selector.dart'; import 'package:flutter/material.dart'; diff --git a/packages/file_selector/file_selector/example/lib/home_page.dart b/packages/file_selector/file_selector/example/lib/home_page.dart index 1cb7ef261e88..842094c9acaa 100644 --- a/packages/file_selector/file_selector/example/lib/home_page.dart +++ b/packages/file_selector/file_selector/example/lib/home_page.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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/material.dart'; /// Home Page of the application diff --git a/packages/file_selector/file_selector/example/lib/main.dart b/packages/file_selector/file_selector/example/lib/main.dart index bb34918e36a3..e355109d1799 100644 --- a/packages/file_selector/file_selector/example/lib/main.dart +++ b/packages/file_selector/file_selector/example/lib/main.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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/material.dart'; import 'package:example/home_page.dart'; import 'package:example/get_directory_page.dart'; diff --git a/packages/file_selector/file_selector/example/lib/open_image_page.dart b/packages/file_selector/file_selector/example/lib/open_image_page.dart index 986bfe712893..da11ead1c09f 100644 --- a/packages/file_selector/file_selector/example/lib/open_image_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_image_page.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:file_selector/file_selector.dart'; diff --git a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart index c6f73f5aed12..d91d126c940f 100644 --- a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:file_selector/file_selector.dart'; diff --git a/packages/file_selector/file_selector/example/lib/open_text_page.dart b/packages/file_selector/file_selector/example/lib/open_text_page.dart index 74d79dd72b19..52296abd4379 100644 --- a/packages/file_selector/file_selector/example/lib/open_text_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_text_page.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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:file_selector/file_selector.dart'; import 'package:flutter/material.dart'; diff --git a/packages/file_selector/file_selector/example/lib/save_text_page.dart b/packages/file_selector/file_selector/example/lib/save_text_page.dart index 82046c35128a..982692bc40f8 100644 --- a/packages/file_selector/file_selector/example/lib/save_text_page.dart +++ b/packages/file_selector/file_selector/example/lib/save_text_page.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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 'dart:typed_data'; import 'package:file_selector/file_selector.dart'; import 'package:flutter/material.dart'; diff --git a/packages/file_selector/file_selector/example/web/index.html b/packages/file_selector/file_selector/example/web/index.html index 9b7a438f823a..97b1100c4244 100644 --- a/packages/file_selector/file_selector/example/web/index.html +++ b/packages/file_selector/file_selector/example/web/index.html @@ -1,4 +1,7 @@ + diff --git a/packages/file_selector/file_selector_platform_interface/lib/file_selector_platform_interface.dart b/packages/file_selector/file_selector_platform_interface/lib/file_selector_platform_interface.dart index 69e3064150b5..dcd87aaed4a7 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/file_selector_platform_interface.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/file_selector_platform_interface.dart @@ -1,2 +1,6 @@ +// Copyright 2020 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. + export 'src/platform_interface/file_selector_interface.dart'; export 'src/types/types.dart'; diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart index 88dc3c2a5f83..65a0bdcd1583 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart @@ -1,2 +1,6 @@ +// Copyright 2020 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. + export 'package:cross_file/cross_file.dart'; export 'x_type_group/x_type_group.dart'; diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart b/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart index 5330c5cf6dcd..f9e33aed1389 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart @@ -1,3 +1,7 @@ +// Copyright 2020 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 'dart:html'; /// Create anchor element with download attribute diff --git a/packages/file_selector/file_selector_web/example/run_test.sh b/packages/file_selector/file_selector_web/example/run_test.sh index c9f547a4f7d7..a381127c2716 100755 --- a/packages/file_selector/file_selector_web/example/run_test.sh +++ b/packages/file_selector/file_selector_web/example/run_test.sh @@ -1,4 +1,7 @@ #!/usr/bin/bash +# Copyright 2017 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. if pgrep -lf chromedriver > /dev/null; then echo "chromedriver is running." diff --git a/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart b/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart index e9faa3af4808..6aaf4475d537 100644 --- a/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart +++ b/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart @@ -1,3 +1,7 @@ +// Copyright 2020 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_test/flutter_test.dart'; void main() { diff --git a/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java b/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java index 2a5a91d02f60..6657dfbb5a71 100644 --- a/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java +++ b/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java @@ -1,3 +1,7 @@ +// Copyright 2019 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. + package io.flutter.embedding.engine.plugins.lifecycle; import static org.junit.Assert.assertEquals; diff --git a/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/EmbeddingV1Activity.java b/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/EmbeddingV1Activity.java index f303f4c61d20..5859e177b2fc 100644 --- a/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/EmbeddingV1Activity.java +++ b/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/EmbeddingV1Activity.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.flutter_plugin_android_lifecycle_example; import android.os.Bundle; diff --git a/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart b/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart index ba67043bcf43..e4b92c8db7ed 100644 --- a/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart +++ b/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/flutter_plugin_android_lifecycle/example/lib/main.dart b/packages/flutter_plugin_android_lifecycle/example/lib/main.dart index eb82aacd0237..c055c5359515 100644 --- a/packages/flutter_plugin_android_lifecycle/example/lib/main.dart +++ b/packages/flutter_plugin_android_lifecycle/example/lib/main.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // ignore_for_file: public_member_api_docs diff --git a/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart b/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart index 4352552e3eda..ea111552567d 100644 --- a/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart +++ b/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart @@ -1,2 +1,6 @@ +// Copyright 2019 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. + // The flutter_plugin_android_lifecycle plugin only provides a Java API // for use by Android plugins. This plugin has no Dart code. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java index 6585090e6e26..24bee4ea7550 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java @@ -1,3 +1,7 @@ +// Copyright 2018 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. + package io.flutter.plugins.googlemaps; import static junit.framework.TestCase.assertEquals; diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java index e032dd436d5a..7c8032b2b0d4 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java @@ -1,3 +1,7 @@ +// Copyright 2018 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. + package io.flutter.plugins.googlemaps; import static org.mockito.Mockito.mock; diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java index 644e8982f246..e3c2f339f250 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java @@ -1,3 +1,7 @@ +// Copyright 2018 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. + package io.flutter.plugins.googlemaps; import static junit.framework.TestCase.assertEquals; diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java index 834c42766e07..e65cb1f22dc9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java @@ -1,3 +1,7 @@ +// Copyright 2018 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. + package io.flutter.plugins.googlemaps; import static org.mockito.Mockito.mock; diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java index bf6d06066fbf..7e5d39c380fd 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java @@ -1,3 +1,7 @@ +// Copyright 2018 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. + package io.flutter.plugins.googlemaps; import static junit.framework.TestCase.assertEquals; diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java index acd231623825..1f0a7000f5e7 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java @@ -1,3 +1,7 @@ +// Copyright 2018 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. + package io.flutter.plugins.googlemaps; import static org.mockito.Mockito.mock; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/EmbeddingV1ActivityTest.java b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/EmbeddingV1ActivityTest.java index 76dc5df3422a..5ade4367835a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/EmbeddingV1ActivityTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/EmbeddingV1ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.googlemaps; import androidx.test.rule.ActivityTestRule; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/MainActivityTest.java b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/MainActivityTest.java index c70f16a17454..7c624bb556a9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/MainActivityTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/MainActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.googlemaps; import androidx.test.rule.ActivityTestRule; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/main/java/io/flutter/plugins/googlemapsexample/EmbeddingV1Activity.java b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/main/java/io/flutter/plugins/googlemapsexample/EmbeddingV1Activity.java index 3853b5d2d4df..9924fa03e3aa 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/main/java/io/flutter/plugins/googlemapsexample/EmbeddingV1Activity.java +++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/main/java/io/flutter/plugins/googlemapsexample/EmbeddingV1Activity.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.googlemapsexample; import android.os.Bundle; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java index 94b93473a5e1..7b81f287a9d1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.googlemaps; import static org.junit.Assert.assertNull; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart index a5025590d72a..33ad5d03778e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 import 'dart:typed_data'; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart index 01b0c9b03e68..44412d490ec0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 import 'dart:async'; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.h b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.h index 5abb821e75eb..8e973d51585b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.h +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.h @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.m b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.m index 6896c5c190b1..b22c283d4704 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.m +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.m @@ -1,3 +1,7 @@ +// Copyright 2017 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 "AppDelegate.h" #import "GeneratedPluginRegistrant.h" diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/main.m b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/main.m index dff6597e4513..f451b14cb751 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/main.m +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/main.m @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import #import "AppDelegate.h" diff --git a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart index ceb6c4d6a3a0..7a26a52ae1a1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 import 'dart:async'; diff --git a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart index d2b6efb69e66..953d85ec85e6 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart @@ -1,3 +1,7 @@ +// Copyright 2018 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 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/resources/icon_image_base64.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/resources/icon_image_base64.dart index aa4a80baddbb..66814d8df7ca 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/resources/icon_image_base64.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/resources/icon_image_base64.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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. + final iconImageBase64 = 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAIRlWElmTU' '0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIA' diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh index 8e6f149358c9..9bfce94f63b2 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh @@ -1,4 +1,8 @@ #!/usr/bin/bash +# Copyright 2017 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. + if pgrep -lf chromedriver > /dev/null; then echo "chromedriver is running." diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart index 334f52186d9d..a8cd22dbe285 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart @@ -1,3 +1,7 @@ +// 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 'package:flutter_test/flutter_test.dart'; void main() { diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java index e05130178ec4..e667be2aa0f9 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java @@ -1,6 +1,6 @@ -// Copyright 2017, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Flutter project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. package io.flutter.plugins.googlesignin; diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java index ee4273873d8d..80b9d187d939 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java @@ -1,6 +1,6 @@ -// Copyright 2017, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Flutter project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. package io.flutter.plugins.googlesignin; diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index dab6f4c4db8e..f6673e5d5978 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -1,6 +1,6 @@ -// Copyright 2017, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Flutter project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. package io.flutter.plugins.googlesignin; diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java index 985903f1853c..100069080bb4 100644 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java @@ -1,6 +1,6 @@ -// Copyright 2020, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2020, the Flutter project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. package io.flutter.plugins.googlesignin; diff --git a/packages/google_sign_in/google_sign_in/example/web/index.html b/packages/google_sign_in/google_sign_in/example/web/index.html index bd373458a2f1..187eeb5ff8ff 100644 --- a/packages/google_sign_in/google_sign_in/example/web/index.html +++ b/packages/google_sign_in/google_sign_in/example/web/index.html @@ -1,4 +1,7 @@ + diff --git a/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart index a900bfbfdc2e..86423507fffc 100644 --- a/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart @@ -1,3 +1,7 @@ +// Copyright 2017, the Flutter project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + // @dart = 2.9 import 'package:integration_test/integration_test.dart'; diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h index 9474e371e176..f9d7f322a2e3 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h @@ -1,6 +1,6 @@ -// Copyright 2017, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Flutter project 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 diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index f621d1e68312..660a32272f84 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -1,6 +1,6 @@ -// Copyright 2017, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Flutter project 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 "FLTGoogleSignInPlugin.h" #import diff --git a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart index 1317eb91ecfb..f803f96f85ed 100644 --- a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart @@ -1,6 +1,6 @@ -// Copyright 2017, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Flutter project 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:async'; import 'dart:ui' show hashValues; diff --git a/packages/google_sign_in/google_sign_in/lib/src/common.dart b/packages/google_sign_in/google_sign_in/lib/src/common.dart index 60c74ab4c6d5..f9aaf199b899 100644 --- a/packages/google_sign_in/google_sign_in/lib/src/common.dart +++ b/packages/google_sign_in/google_sign_in/lib/src/common.dart @@ -1,6 +1,6 @@ -// Copyright 2017, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Flutter project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. /// Encapsulation of the fields that represent a Google user's identity. abstract class GoogleIdentity { diff --git a/packages/google_sign_in/google_sign_in/lib/widgets.dart b/packages/google_sign_in/google_sign_in/lib/widgets.dart index c9682930b089..f47e78fde2b2 100644 --- a/packages/google_sign_in/google_sign_in/lib/widgets.dart +++ b/packages/google_sign_in/google_sign_in/lib/widgets.dart @@ -1,6 +1,6 @@ -// Copyright 2017, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Flutter project 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:typed_data'; diff --git a/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart b/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart index 4a27ac2f986b..abb86f07086a 100644 --- a/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart +++ b/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2020, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2020, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/google_sign_in/google_sign_in_web/example/run_test.sh b/packages/google_sign_in/google_sign_in_web/example/run_test.sh index 0f76f4a47e16..d6b5dbb18ae9 100755 --- a/packages/google_sign_in/google_sign_in_web/example/run_test.sh +++ b/packages/google_sign_in/google_sign_in_web/example/run_test.sh @@ -1,4 +1,7 @@ #!/usr/bin/bash +# Copyright 2017 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. if pgrep -lf chromedriver > /dev/null; then echo "chromedriver is running." diff --git a/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart b/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart index 334f52186d9d..d6a165667707 100644 --- a/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart +++ b/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019, the Flutter project 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_test/flutter_test.dart'; void main() { diff --git a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/FlutterActivityTest.java b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/FlutterActivityTest.java index 58f8df35dc4f..cfe112e39cb2 100644 --- a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/FlutterActivityTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/FlutterActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.imagepickerexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java index aa9b00521f53..858d929dbc5d 100644 --- a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.imagepicker; import static org.hamcrest.core.IsEqual.equalTo; diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java index de1623e93db4..27bc57bd2dcd 100644 --- a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.imagepicker; import static org.junit.Assert.assertTrue; diff --git a/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart b/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart index 0352d4aaeb2d..6332de2cfd8d 100644 --- a/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart +++ b/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 import 'dart:async'; diff --git a/packages/image_picker/image_picker/example/web/index.html b/packages/image_picker/image_picker/example/web/index.html index 787bbc72f6b1..a692cdb87e02 100644 --- a/packages/image_picker/image_picker/example/web/index.html +++ b/packages/image_picker/image_picker/example/web/index.html @@ -1,4 +1,7 @@ + diff --git a/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart b/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart index 76c971c2881b..953acd1a8da3 100644 --- a/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart +++ b/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart @@ -1,3 +1,7 @@ +// 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. + // @dart=2.9 import 'package:integration_test/integration_test.dart'; diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index 05afd2e54a4c..ccee15066b8c 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:async'; import 'dart:html' as html; diff --git a/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart b/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart index 6e7641324805..e46ee58e766b 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart @@ -1,2 +1,6 @@ +// 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. + export 'package:image_picker_platform_interface/src/platform_interface/image_picker_platform.dart'; export 'package:image_picker_platform_interface/src/types/types.dart'; 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 2b078ef28190..39db13951fd1 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 @@ -1,3 +1,7 @@ +// 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:convert'; import 'dart:typed_data'; 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 b855eb3fa20d..ea1ad9a84606 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 @@ -1,3 +1,7 @@ +// 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:convert'; import 'dart:typed_data'; 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 4b56add0add4..06bc52308095 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 @@ -1,3 +1,7 @@ +// 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:convert'; import 'dart:io'; import 'dart:typed_data'; diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart index b2a614ccb304..125b1e968740 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart @@ -1,3 +1,7 @@ +// 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. + export 'lost_data.dart'; export 'unsupported.dart' if (dart.library.html) 'html.dart' diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart index bc10a4890c8d..e204604f5a13 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart @@ -1,3 +1,7 @@ +// 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 './base.dart'; /// A PickedFile is a cross-platform, simplified File abstraction. 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 f38a4ec74005..8ea3cfe06de6 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,3 +1,7 @@ +// 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. + export 'camera_device.dart'; export 'image_source.dart'; export 'retrieve_type.dart'; diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java index 73180ec5ec05..f9fc12fbb34e 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java @@ -1,6 +1,6 @@ // Copyright 2019 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. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. package io.flutter.plugins.inapppurchase; diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java index eef43346f655..374dc3297e9e 100644 --- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java +++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.inapppurchase; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.ACKNOWLEDGE_PURCHASE; diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java index 2ee1044fe0c5..476577d330c8 100644 --- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java +++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java @@ -1,6 +1,6 @@ // Copyright 2019 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. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. package io.flutter.plugins.inapppurchase; diff --git a/packages/in_app_purchase/example/ios/Runner/AppDelegate.h b/packages/in_app_purchase/example/ios/Runner/AppDelegate.h index 36e21bbf9cf4..31fc381e7066 100644 --- a/packages/in_app_purchase/example/ios/Runner/AppDelegate.h +++ b/packages/in_app_purchase/example/ios/Runner/AppDelegate.h @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import diff --git a/packages/in_app_purchase/example/ios/Runner/AppDelegate.m b/packages/in_app_purchase/example/ios/Runner/AppDelegate.m index 59a72e90be12..2147d3d605ac 100644 --- a/packages/in_app_purchase/example/ios/Runner/AppDelegate.m +++ b/packages/in_app_purchase/example/ios/Runner/AppDelegate.m @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "AppDelegate.h" #include "GeneratedPluginRegistrant.h" diff --git a/packages/in_app_purchase/example/ios/Runner/main.m b/packages/in_app_purchase/example/ios/Runner/main.m index dff6597e4513..f451b14cb751 100644 --- a/packages/in_app_purchase/example/ios/Runner/main.m +++ b/packages/in_app_purchase/example/ios/Runner/main.m @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import #import "AppDelegate.h" diff --git a/packages/in_app_purchase/example/test_driver/test/integration_test.dart b/packages/in_app_purchase/example/test_driver/test/integration_test.dart index 0352d4aaeb2d..6332de2cfd8d 100644 --- a/packages/in_app_purchase/example/test_driver/test/integration_test.dart +++ b/packages/in_app_purchase/example/test_driver/test/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 import 'dart:async'; diff --git a/packages/in_app_purchase/integration_test/in_app_purchase_test.dart b/packages/in_app_purchase/integration_test/in_app_purchase_test.dart index aa3430fbc7d2..758d266e7f8b 100644 --- a/packages/in_app_purchase/integration_test/in_app_purchase_test.dart +++ b/packages/in_app_purchase/integration_test/in_app_purchase_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart index 929b58292a2f..567e8bbd4f2b 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -1,6 +1,6 @@ // Copyright 2019 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. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. import 'dart:ui' show hashValues; import 'package:flutter/foundation.dart'; diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart index f93dd60284f8..7451a24a8b4f 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart @@ -1,6 +1,6 @@ // Copyright 2019 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. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. import 'dart:ui' show hashValues; import 'package:flutter/foundation.dart'; diff --git a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart index df5b8f5bde22..f97b937c96df 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart @@ -1,6 +1,6 @@ // Copyright 2019 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. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart'; import 'package:test/test.dart'; diff --git a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart index 7a7b7fb86364..f7f410a1cd8b 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart @@ -1,6 +1,6 @@ // Copyright 2019 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. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. import 'package:test/test.dart'; import 'package:in_app_purchase/billing_client_wrappers.dart'; diff --git a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/EmbedderV1ActivityTest.java b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/EmbedderV1ActivityTest.java index 0ce7dc14d4a5..2ae8cbb37db2 100644 --- a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/EmbedderV1ActivityTest.java +++ b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/EmbedderV1ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package com.example.integration_test_example; import androidx.test.rule.ActivityTestRule; diff --git a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityTest.java b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityTest.java index 36ae1ddfc7e8..b84b290f175b 100644 --- a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityTest.java +++ b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package com.example.integration_test_example; import androidx.test.rule.ActivityTestRule; diff --git a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityWithPermissionTest.java b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityWithPermissionTest.java index c01d23466fed..a8e868a76838 100644 --- a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityWithPermissionTest.java +++ b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityWithPermissionTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package com.example.integration_test_example; import android.Manifest.permission; diff --git a/packages/integration_test/example/integration_test/_example_test_io.dart b/packages/integration_test/example/integration_test/_example_test_io.dart index 7ed28963c32b..01bcfe2928b1 100644 --- a/packages/integration_test/example/integration_test/_example_test_io.dart +++ b/packages/integration_test/example/integration_test/_example_test_io.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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. + // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester diff --git a/packages/integration_test/example/integration_test/_example_test_web.dart b/packages/integration_test/example/integration_test/_example_test_web.dart index e1141cc010c8..f0fd6212615a 100644 --- a/packages/integration_test/example/integration_test/_example_test_web.dart +++ b/packages/integration_test/example/integration_test/_example_test_web.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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. + // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester diff --git a/packages/integration_test/example/integration_test/_extended_test_io.dart b/packages/integration_test/example/integration_test/_extended_test_io.dart index 56fee6f7179c..ee0618a5adbc 100644 --- a/packages/integration_test/example/integration_test/_extended_test_io.dart +++ b/packages/integration_test/example/integration_test/_extended_test_io.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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. + // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester diff --git a/packages/integration_test/example/integration_test/_extended_test_web.dart b/packages/integration_test/example/integration_test/_extended_test_web.dart index 210c2dac75ba..878d9949af20 100644 --- a/packages/integration_test/example/integration_test/_extended_test_web.dart +++ b/packages/integration_test/example/integration_test/_extended_test_web.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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. + // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester diff --git a/packages/integration_test/example/integration_test/example_test.dart b/packages/integration_test/example/integration_test/example_test.dart index 918aec8777de..382094b9232f 100644 --- a/packages/integration_test/example/integration_test/example_test.dart +++ b/packages/integration_test/example/integration_test/example_test.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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. + // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester diff --git a/packages/integration_test/example/integration_test/extended_test.dart b/packages/integration_test/example/integration_test/extended_test.dart index 23d69a8f9438..b2a42ffafc00 100644 --- a/packages/integration_test/example/integration_test/extended_test.dart +++ b/packages/integration_test/example/integration_test/extended_test.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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. + // This is a Flutter widget test can take a screenshot. // // NOTE: Screenshots are only supported on Web for now. For Web, this needs to diff --git a/packages/integration_test/example/ios/Runner/AppDelegate.h b/packages/integration_test/example/ios/Runner/AppDelegate.h index 36e21bbf9cf4..b7984f089a9c 100644 --- a/packages/integration_test/example/ios/Runner/AppDelegate.h +++ b/packages/integration_test/example/ios/Runner/AppDelegate.h @@ -1,3 +1,7 @@ +// Copyright 2019 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 #import diff --git a/packages/integration_test/example/ios/Runner/AppDelegate.m b/packages/integration_test/example/ios/Runner/AppDelegate.m index 59a72e90be12..60df7408bded 100644 --- a/packages/integration_test/example/ios/Runner/AppDelegate.m +++ b/packages/integration_test/example/ios/Runner/AppDelegate.m @@ -1,3 +1,7 @@ +// Copyright 2019 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. + #include "AppDelegate.h" #include "GeneratedPluginRegistrant.h" diff --git a/packages/integration_test/example/ios/Runner/main.m b/packages/integration_test/example/ios/Runner/main.m index dff6597e4513..84022b1644c3 100644 --- a/packages/integration_test/example/ios/Runner/main.m +++ b/packages/integration_test/example/ios/Runner/main.m @@ -1,3 +1,7 @@ +// Copyright 2019 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 #import #import "AppDelegate.h" diff --git a/packages/integration_test/example/ios/RunnerTests/RunnerTests.m b/packages/integration_test/example/ios/RunnerTests/RunnerTests.m index ac89c60e5f06..15cc596a22cb 100644 --- a/packages/integration_test/example/ios/RunnerTests/RunnerTests.m +++ b/packages/integration_test/example/ios/RunnerTests/RunnerTests.m @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import diff --git a/packages/integration_test/example/lib/main.dart b/packages/integration_test/example/lib/main.dart index 1f33324acd01..76d2378b32e1 100644 --- a/packages/integration_test/example/lib/main.dart +++ b/packages/integration_test/example/lib/main.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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 'my_app.dart' if (dart.library.html) 'my_web_app.dart'; // ignore_for_file: public_member_api_docs diff --git a/packages/integration_test/example/lib/my_app.dart b/packages/integration_test/example/lib/my_app.dart index bfbdb860c76d..bfcee0911064 100644 --- a/packages/integration_test/example/lib/my_app.dart +++ b/packages/integration_test/example/lib/my_app.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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 'dart:io' show Platform; import 'package:flutter/material.dart'; diff --git a/packages/integration_test/example/lib/my_web_app.dart b/packages/integration_test/example/lib/my_web_app.dart index c2ced1af97ae..b3efb24a54a8 100644 --- a/packages/integration_test/example/lib/my_web_app.dart +++ b/packages/integration_test/example/lib/my_web_app.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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 'dart:html' as html; import 'package:flutter/material.dart'; diff --git a/packages/integration_test/example/macos/Runner/AppDelegate.swift b/packages/integration_test/example/macos/Runner/AppDelegate.swift index d53ef6437726..ca19fe95f8cf 100644 --- a/packages/integration_test/example/macos/Runner/AppDelegate.swift +++ b/packages/integration_test/example/macos/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/integration_test/example/macos/Runner/MainFlutterWindow.swift b/packages/integration_test/example/macos/Runner/MainFlutterWindow.swift index 2722837ec918..2ce11b78604b 100644 --- a/packages/integration_test/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/integration_test/example/macos/Runner/MainFlutterWindow.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/integration_test/example/test_driver/extended_integration_test.dart b/packages/integration_test/example/test_driver/extended_integration_test.dart index 056ba4bad722..059a3d13a2eb 100644 --- a/packages/integration_test/example/test_driver/extended_integration_test.dart +++ b/packages/integration_test/example/test_driver/extended_integration_test.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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_driver/flutter_driver.dart'; import 'package:integration_test/integration_test_driver_extended.dart'; diff --git a/packages/integration_test/example/test_driver/failure_test.dart b/packages/integration_test/example/test_driver/failure_test.dart index fce6adc42c92..c90eaafa7090 100644 --- a/packages/integration_test/example/test_driver/failure_test.dart +++ b/packages/integration_test/example/test_driver/failure_test.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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_driver/flutter_driver.dart'; import 'package:integration_test/common.dart' as common; import 'package:test/test.dart'; diff --git a/packages/integration_test/example/test_driver/integration_test.dart b/packages/integration_test/example/test_driver/integration_test.dart index b38629cca97b..8c650ee9f293 100644 --- a/packages/integration_test/example/test_driver/integration_test.dart +++ b/packages/integration_test/example/test_driver/integration_test.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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:integration_test/integration_test_driver.dart'; Future main() => integrationDriver(); diff --git a/packages/integration_test/example/web/index.html b/packages/integration_test/example/web/index.html index 96629657328f..492b9fd4cefc 100644 --- a/packages/integration_test/example/web/index.html +++ b/packages/integration_test/example/web/index.html @@ -1,4 +1,7 @@ + diff --git a/packages/integration_test/ios/Classes/IntegrationTestIosTest.h b/packages/integration_test/ios/Classes/IntegrationTestIosTest.h index 9c53edb160e9..7c09a1171267 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestIosTest.h +++ b/packages/integration_test/ios/Classes/IntegrationTestIosTest.h @@ -1,3 +1,7 @@ +// Copyright 2019 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 @interface IntegrationTestIosTest : NSObject diff --git a/packages/integration_test/ios/Classes/IntegrationTestIosTest.m b/packages/integration_test/ios/Classes/IntegrationTestIosTest.m index 1397f547e6f6..b3a7602b74b2 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestIosTest.m +++ b/packages/integration_test/ios/Classes/IntegrationTestIosTest.m @@ -1,3 +1,7 @@ +// Copyright 2019 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 "IntegrationTestIosTest.h" #import "IntegrationTestPlugin.h" diff --git a/packages/integration_test/ios/Classes/IntegrationTestPlugin.h b/packages/integration_test/ios/Classes/IntegrationTestPlugin.h index 8dd3109ffe09..6a6171fd16e8 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestPlugin.h +++ b/packages/integration_test/ios/Classes/IntegrationTestPlugin.h @@ -1,3 +1,7 @@ +// Copyright 2019 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 NS_ASSUME_NONNULL_BEGIN diff --git a/packages/integration_test/ios/Classes/IntegrationTestPlugin.m b/packages/integration_test/ios/Classes/IntegrationTestPlugin.m index e7e5a74c01ee..5c4d0e6bfb24 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestPlugin.m +++ b/packages/integration_test/ios/Classes/IntegrationTestPlugin.m @@ -1,3 +1,7 @@ +// Copyright 2019 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 "IntegrationTestPlugin.h" static NSString *const kIntegrationTestPluginChannel = @"plugins.flutter.io/integration_test"; diff --git a/packages/integration_test/lib/integration_test_driver_extended.dart b/packages/integration_test/lib/integration_test_driver_extended.dart index bc38bb71de50..c423f296c331 100644 --- a/packages/integration_test/lib/integration_test_driver_extended.dart +++ b/packages/integration_test/lib/integration_test_driver_extended.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:async'; import 'dart:io'; diff --git a/packages/integration_test/test/binding_fail_test.dart b/packages/integration_test/test/binding_fail_test.dart index 7ec176897c0c..d0d5fd423b67 100644 --- a/packages/integration_test/test/binding_fail_test.dart +++ b/packages/integration_test/test/binding_fail_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:async'; import 'dart:io'; import 'dart:convert'; diff --git a/packages/integration_test/test/binding_test.dart b/packages/integration_test/test/binding_test.dart index ef4efc59aac0..10e3c093b140 100644 --- a/packages/integration_test/test/binding_test.dart +++ b/packages/integration_test/test/binding_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:convert'; import 'package:flutter/material.dart'; diff --git a/packages/integration_test/test/data/fail_test_script.dart b/packages/integration_test/test/data/fail_test_script.dart index 05a75d7d031e..a495a3b3f698 100644 --- a/packages/integration_test/test/data/fail_test_script.dart +++ b/packages/integration_test/test/data/fail_test_script.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:convert'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/integration_test/test/data/pass_test_script.dart b/packages/integration_test/test/data/pass_test_script.dart index 7e222c8e8961..e31651de74ac 100644 --- a/packages/integration_test/test/data/pass_test_script.dart +++ b/packages/integration_test/test/data/pass_test_script.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:convert'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/integration_test/test/data/pass_then_fail_test_script.dart b/packages/integration_test/test/data/pass_then_fail_test_script.dart index 324c1c21cfa6..9116fde266e0 100644 --- a/packages/integration_test/test/data/pass_then_fail_test_script.dart +++ b/packages/integration_test/test/data/pass_then_fail_test_script.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:convert'; import 'package:integration_test/integration_test.dart'; diff --git a/packages/integration_test/test/response_serialization_test.dart b/packages/integration_test/test/response_serialization_test.dart index 8b969402035d..ee6cacc73a5e 100644 --- a/packages/integration_test/test/response_serialization_test.dart +++ b/packages/integration_test/test/response_serialization_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/common.dart'; diff --git a/packages/ios_platform_images/example/ios/Runner/AppDelegate.swift b/packages/ios_platform_images/example/ios/Runner/AppDelegate.swift index 70693e4a8c12..f26669f6bd4f 100644 --- a/packages/ios_platform_images/example/ios/Runner/AppDelegate.swift +++ b/packages/ios_platform_images/example/ios/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 UIKit import Flutter diff --git a/packages/ios_platform_images/example/ios/Runner/Runner-Bridging-Header.h b/packages/ios_platform_images/example/ios/Runner/Runner-Bridging-Header.h index 7335fdf9000c..3a69a7befa44 100644 --- a/packages/ios_platform_images/example/ios/Runner/Runner-Bridging-Header.h +++ b/packages/ios_platform_images/example/ios/Runner/Runner-Bridging-Header.h @@ -1 +1,5 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +// Copyright 2017 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 "GeneratedPluginRegistrant.h" diff --git a/packages/ios_platform_images/example/lib/main.dart b/packages/ios_platform_images/example/lib/main.dart index 394d983ab66c..aa4392243785 100644 --- a/packages/ios_platform_images/example/lib/main.dart +++ b/packages/ios_platform_images/example/lib/main.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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/material.dart'; import 'package:ios_platform_images/ios_platform_images.dart'; diff --git a/packages/ios_platform_images/example/test/widget_test.dart b/packages/ios_platform_images/example/test/widget_test.dart index ae8e5a41e4be..66d964302180 100644 --- a/packages/ios_platform_images/example/test/widget_test.dart +++ b/packages/ios_platform_images/example/test/widget_test.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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 'dart:io'; import 'package:flutter/material.dart'; diff --git a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h index d4106b598d75..e53977a3d9cd 100644 --- a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h +++ b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h @@ -1,3 +1,7 @@ +// 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 /// A plugin for Flutter that allows Flutter to load images in a platform diff --git a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m index bad6f11417b9..151c418c2f6a 100644 --- a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m +++ b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m @@ -1,3 +1,7 @@ +// 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 "IosPlatformImagesPlugin.h" #if !__has_feature(objc_arc) diff --git a/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/EmbeddingV1ActivityTest.java b/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/EmbeddingV1ActivityTest.java index 30d2126f0609..dc28926caa08 100644 --- a/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/EmbeddingV1ActivityTest.java +++ b/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/EmbeddingV1ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.localauth; import androidx.test.rule.ActivityTestRule; diff --git a/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java b/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java index 3d2d55bce0fa..ebaf3ccf92ba 100644 --- a/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java +++ b/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.localauth; import androidx.test.rule.ActivityTestRule; diff --git a/packages/local_auth/example/android/app/src/main/java/io/flutter/plugins/localauthexample/EmbeddingV1Activity.java b/packages/local_auth/example/android/app/src/main/java/io/flutter/plugins/localauthexample/EmbeddingV1Activity.java index 91bef9dd13d7..83af839a9fbb 100644 --- a/packages/local_auth/example/android/app/src/main/java/io/flutter/plugins/localauthexample/EmbeddingV1Activity.java +++ b/packages/local_auth/example/android/app/src/main/java/io/flutter/plugins/localauthexample/EmbeddingV1Activity.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.localauthexample; import android.os.Bundle; diff --git a/packages/local_auth/example/ios/Runner/main.m b/packages/local_auth/example/ios/Runner/main.m index dff6597e4513..f451b14cb751 100644 --- a/packages/local_auth/example/ios/Runner/main.m +++ b/packages/local_auth/example/ios/Runner/main.m @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import #import "AppDelegate.h" diff --git a/packages/package_info/example/integration_test/package_info_test.dart b/packages/package_info/example/integration_test/package_info_test.dart index e70c8a5f0eca..75bae13cc8f7 100644 --- a/packages/package_info/example/integration_test/package_info_test.dart +++ b/packages/package_info/example/integration_test/package_info_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/package_info/example/macos/Runner/AppDelegate.swift b/packages/package_info/example/macos/Runner/AppDelegate.swift index d53ef6437726..ca19fe95f8cf 100644 --- a/packages/package_info/example/macos/Runner/AppDelegate.swift +++ b/packages/package_info/example/macos/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/package_info/example/macos/Runner/MainFlutterWindow.swift b/packages/package_info/example/macos/Runner/MainFlutterWindow.swift index 2722837ec918..2ce11b78604b 100644 --- a/packages/package_info/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/package_info/example/macos/Runner/MainFlutterWindow.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/package_info/example/test_driver/integration_test.dart b/packages/package_info/example/test_driver/integration_test.dart index 437b3609d119..a2977d367f9f 100644 --- a/packages/package_info/example/test_driver/integration_test.dart +++ b/packages/package_info/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java b/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java index 820509ba86ea..c41b81deaff6 100644 --- a/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java +++ b/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.pathprovider; import android.os.Build.VERSION; @@ -6,7 +10,6 @@ /** Helps to map the Dart `StorageDirectory` enum to a Android system constant. */ class StorageDirectoryMapper { - /** * Return a Android Environment constant for a Dart Index. * diff --git a/packages/path_provider/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java b/packages/path_provider/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java index 74a4e6d5169d..2df4497332b3 100644 --- a/packages/path_provider/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java +++ b/packages/path_provider/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.pathprovider; import static org.junit.Assert.assertEquals; @@ -8,7 +12,6 @@ import org.junit.Test; public class StorageDirectoryMapperTest { - @org.junit.Test public void testAndroidType_null() { assertNull(StorageDirectoryMapper.androidType(null)); diff --git a/packages/path_provider/path_provider/example/android/app/src/androidTest/java/EmbeddingV1ActivityTest.java b/packages/path_provider/path_provider/example/android/app/src/androidTest/java/EmbeddingV1ActivityTest.java index 385740db166d..9292edb43dd7 100644 --- a/packages/path_provider/path_provider/example/android/app/src/androidTest/java/EmbeddingV1ActivityTest.java +++ b/packages/path_provider/path_provider/example/android/app/src/androidTest/java/EmbeddingV1ActivityTest.java @@ -1,3 +1,6 @@ +// Copyright 2017 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. package io.flutter.plugins.pathprovider; diff --git a/packages/path_provider/path_provider/example/android/app/src/androidTest/java/MainActivityTest.java b/packages/path_provider/path_provider/example/android/app/src/androidTest/java/MainActivityTest.java index a99767c4ccf9..986e3a439b0f 100644 --- a/packages/path_provider/path_provider/example/android/app/src/androidTest/java/MainActivityTest.java +++ b/packages/path_provider/path_provider/example/android/app/src/androidTest/java/MainActivityTest.java @@ -1,3 +1,6 @@ +// Copyright 2017 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. package io.flutter.plugins.pathprovider; diff --git a/packages/path_provider/path_provider/example/android/app/src/main/java/io/flutter/plugins/pathproviderexample/EmbeddingV1Activity.java b/packages/path_provider/path_provider/example/android/app/src/main/java/io/flutter/plugins/pathproviderexample/EmbeddingV1Activity.java index 2ff41b25a4fc..2853fb394179 100644 --- a/packages/path_provider/path_provider/example/android/app/src/main/java/io/flutter/plugins/pathproviderexample/EmbeddingV1Activity.java +++ b/packages/path_provider/path_provider/example/android/app/src/main/java/io/flutter/plugins/pathproviderexample/EmbeddingV1Activity.java @@ -1,3 +1,6 @@ +// Copyright 2017 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. package io.flutter.plugins.pathproviderexample; diff --git a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart index 2b12c82f959b..cb0b8744c84f 100644 --- a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/path_provider/path_provider/example/linux/main.cc b/packages/path_provider/path_provider/example/linux/main.cc index 10835acb58ed..a15afa068a7b 100644 --- a/packages/path_provider/path_provider/example/linux/main.cc +++ b/packages/path_provider/path_provider/example/linux/main.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" int main(int argc, char** argv) { diff --git a/packages/path_provider/path_provider/example/linux/my_application.cc b/packages/path_provider/path_provider/example/linux/my_application.cc index 67ed0b9025b2..3843c07aaf04 100644 --- a/packages/path_provider/path_provider/example/linux/my_application.cc +++ b/packages/path_provider/path_provider/example/linux/my_application.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" #include diff --git a/packages/path_provider/path_provider/example/linux/my_application.h b/packages/path_provider/path_provider/example/linux/my_application.h index 72271d5e4170..abbdf1213815 100644 --- a/packages/path_provider/path_provider/example/linux/my_application.h +++ b/packages/path_provider/path_provider/example/linux/my_application.h @@ -1,3 +1,7 @@ +// 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. + #ifndef FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_ diff --git a/packages/path_provider/path_provider/example/macos/Runner/AppDelegate.swift b/packages/path_provider/path_provider/example/macos/Runner/AppDelegate.swift index d53ef6437726..ca19fe95f8cf 100644 --- a/packages/path_provider/path_provider/example/macos/Runner/AppDelegate.swift +++ b/packages/path_provider/path_provider/example/macos/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/path_provider/path_provider/example/macos/Runner/MainFlutterWindow.swift b/packages/path_provider/path_provider/example/macos/Runner/MainFlutterWindow.swift index 2722837ec918..2ce11b78604b 100644 --- a/packages/path_provider/path_provider/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/path_provider/path_provider/example/macos/Runner/MainFlutterWindow.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/path_provider/path_provider/example/test_driver/integration_test.dart b/packages/path_provider/path_provider/example/test_driver/integration_test.dart index ac106b63b339..a82b5fb51e77 100644 --- a/packages/path_provider/path_provider/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp b/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp index c422723045ca..dd2e3cca5666 100644 --- a/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp @@ -1,3 +1,7 @@ +// 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. + #include "flutter_window.h" #include diff --git a/packages/path_provider/path_provider/example/windows/runner/flutter_window.h b/packages/path_provider/path_provider/example/windows/runner/flutter_window.h index b663ddd50125..9b4ef089621b 100644 --- a/packages/path_provider/path_provider/example/windows/runner/flutter_window.h +++ b/packages/path_provider/path_provider/example/windows/runner/flutter_window.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ diff --git a/packages/path_provider/path_provider/example/windows/runner/main.cpp b/packages/path_provider/path_provider/example/windows/runner/main.cpp index fc17fec6140c..e74157ed999a 100644 --- a/packages/path_provider/path_provider/example/windows/runner/main.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/main.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include #include #include diff --git a/packages/path_provider/path_provider/example/windows/runner/run_loop.cpp b/packages/path_provider/path_provider/example/windows/runner/run_loop.cpp index 2d6636ab6bc6..ee2e2fd5eae9 100644 --- a/packages/path_provider/path_provider/example/windows/runner/run_loop.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/run_loop.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "run_loop.h" #include diff --git a/packages/path_provider/path_provider/example/windows/runner/run_loop.h b/packages/path_provider/path_provider/example/windows/runner/run_loop.h index 5f2c4a9ad7d3..a24c47f2e55f 100644 --- a/packages/path_provider/path_provider/example/windows/runner/run_loop.h +++ b/packages/path_provider/path_provider/example/windows/runner/run_loop.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_RUN_LOOP_H_ #define RUNNER_RUN_LOOP_H_ diff --git a/packages/path_provider/path_provider/example/windows/runner/utils.cpp b/packages/path_provider/path_provider/example/windows/runner/utils.cpp index 37501e5db777..9eba364025d0 100644 --- a/packages/path_provider/path_provider/example/windows/runner/utils.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/utils.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "utils.h" #include diff --git a/packages/path_provider/path_provider/example/windows/runner/utils.h b/packages/path_provider/path_provider/example/windows/runner/utils.h index d792603bb139..640587eb23ab 100644 --- a/packages/path_provider/path_provider/example/windows/runner/utils.h +++ b/packages/path_provider/path_provider/example/windows/runner/utils.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ diff --git a/packages/path_provider/path_provider/example/windows/runner/win32_window.cpp b/packages/path_provider/path_provider/example/windows/runner/win32_window.cpp index c63ad013b02d..97628170c2c2 100644 --- a/packages/path_provider/path_provider/example/windows/runner/win32_window.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/win32_window.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "win32_window.h" #include diff --git a/packages/path_provider/path_provider/example/windows/runner/win32_window.h b/packages/path_provider/path_provider/example/windows/runner/win32_window.h index 4ae64a12b465..59b78382b27d 100644 --- a/packages/path_provider/path_provider/example/windows/runner/win32_window.h +++ b/packages/path_provider/path_provider/example/windows/runner/win32_window.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ diff --git a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart index d08b3878a4d5..6cd19401cf0e 100644 --- a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/path_provider/path_provider_linux/example/lib/main.dart b/packages/path_provider/path_provider_linux/example/lib/main.dart index 6958ed10cb23..bd1c80a12fb7 100644 --- a/packages/path_provider/path_provider_linux/example/lib/main.dart +++ b/packages/path_provider/path_provider_linux/example/lib/main.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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/material.dart'; import 'dart:async'; diff --git a/packages/path_provider/path_provider_linux/example/linux/main.cc b/packages/path_provider/path_provider_linux/example/linux/main.cc index 10835acb58ed..a15afa068a7b 100644 --- a/packages/path_provider/path_provider_linux/example/linux/main.cc +++ b/packages/path_provider/path_provider_linux/example/linux/main.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" int main(int argc, char** argv) { diff --git a/packages/path_provider/path_provider_linux/example/linux/my_application.cc b/packages/path_provider/path_provider_linux/example/linux/my_application.cc index 67ed0b9025b2..3843c07aaf04 100644 --- a/packages/path_provider/path_provider_linux/example/linux/my_application.cc +++ b/packages/path_provider/path_provider_linux/example/linux/my_application.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" #include diff --git a/packages/path_provider/path_provider_linux/example/linux/my_application.h b/packages/path_provider/path_provider_linux/example/linux/my_application.h index 72271d5e4170..b3d62442a005 100644 --- a/packages/path_provider/path_provider_linux/example/linux/my_application.h +++ b/packages/path_provider/path_provider_linux/example/linux/my_application.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_ diff --git a/packages/path_provider/path_provider_linux/example/test/widget_test.dart b/packages/path_provider/path_provider_linux/example/test/widget_test.dart index 086b6d614e13..e25ebe36fb08 100644 --- a/packages/path_provider/path_provider_linux/example/test/widget_test.dart +++ b/packages/path_provider/path_provider_linux/example/test/widget_test.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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. + // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester diff --git a/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart index ac106b63b339..a82b5fb51e77 100644 --- a/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart index 1bb079051cfc..10be231d064e 100644 --- a/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/path_provider/path_provider_macos/example/macos/Runner/AppDelegate.swift b/packages/path_provider/path_provider_macos/example/macos/Runner/AppDelegate.swift index d53ef6437726..ca19fe95f8cf 100644 --- a/packages/path_provider/path_provider_macos/example/macos/Runner/AppDelegate.swift +++ b/packages/path_provider/path_provider_macos/example/macos/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/path_provider/path_provider_macos/example/macos/Runner/MainFlutterWindow.swift b/packages/path_provider/path_provider_macos/example/macos/Runner/MainFlutterWindow.swift index 2722837ec918..2ce11b78604b 100644 --- a/packages/path_provider/path_provider_macos/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/path_provider/path_provider_macos/example/macos/Runner/MainFlutterWindow.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart index ac106b63b339..a82b5fb51e77 100644 --- a/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart b/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart index c97ef5d2b0f5..f563b5ed0b2d 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart @@ -1,3 +1,7 @@ +// Copyright 2020 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. + /// Corresponds to constants defined in Androids `android.os.Environment` class. /// /// https://developer.android.com/reference/android/os/Environment.html#fields_1 diff --git a/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart index 0953fc100950..0d521a5df247 100644 --- a/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart index ac106b63b339..a82b5fb51e77 100644 --- a/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.cpp b/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.cpp index c422723045ca..b7d078e4d4a5 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.cpp +++ b/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "flutter_window.h" #include diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.h b/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.h index b663ddd50125..9b4ef089621b 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.h +++ b/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/main.cpp b/packages/path_provider/path_provider_windows/example/windows/runner/main.cpp index fc17fec6140c..e74157ed999a 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/main.cpp +++ b/packages/path_provider/path_provider_windows/example/windows/runner/main.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include #include #include diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.cpp b/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.cpp index 2d6636ab6bc6..ee2e2fd5eae9 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.cpp +++ b/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "run_loop.h" #include diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.h b/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.h index 5f2c4a9ad7d3..a24c47f2e55f 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.h +++ b/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_RUN_LOOP_H_ #define RUNNER_RUN_LOOP_H_ diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/utils.cpp b/packages/path_provider/path_provider_windows/example/windows/runner/utils.cpp index 37501e5db777..9eba364025d0 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/utils.cpp +++ b/packages/path_provider/path_provider_windows/example/windows/runner/utils.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "utils.h" #include diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/utils.h b/packages/path_provider/path_provider_windows/example/windows/runner/utils.h index d792603bb139..640587eb23ab 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/utils.h +++ b/packages/path_provider/path_provider_windows/example/windows/runner/utils.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.cpp b/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.cpp index c63ad013b02d..97628170c2c2 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.cpp +++ b/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "win32_window.h" #include diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.h b/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.h index 4ae64a12b465..59b78382b27d 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.h +++ b/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ diff --git a/packages/quick_actions/example/integration_test/quick_actions_test.dart b/packages/quick_actions/example/integration_test/quick_actions_test.dart index 43822c9e8b2b..bad84debefd6 100644 --- a/packages/quick_actions/example/integration_test/quick_actions_test.dart +++ b/packages/quick_actions/example/integration_test/quick_actions_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/quick_actions/example/test_driver/integration_test.dart b/packages/quick_actions/example/test_driver/integration_test.dart index 0352d4aaeb2d..6332de2cfd8d 100644 --- a/packages/quick_actions/example/test_driver/integration_test.dart +++ b/packages/quick_actions/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 import 'dart:async'; diff --git a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java index 65a4dca981aa..9760ef098572 100644 --- a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java +++ b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.sensorsexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/sensors/example/ios/Runner/AppDelegate.h b/packages/sensors/example/ios/Runner/AppDelegate.h index 36e21bbf9cf4..31fc381e7066 100644 --- a/packages/sensors/example/ios/Runner/AppDelegate.h +++ b/packages/sensors/example/ios/Runner/AppDelegate.h @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import diff --git a/packages/sensors/example/ios/Runner/AppDelegate.m b/packages/sensors/example/ios/Runner/AppDelegate.m index 59a72e90be12..2147d3d605ac 100644 --- a/packages/sensors/example/ios/Runner/AppDelegate.m +++ b/packages/sensors/example/ios/Runner/AppDelegate.m @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "AppDelegate.h" #include "GeneratedPluginRegistrant.h" diff --git a/packages/sensors/example/ios/Runner/main.m b/packages/sensors/example/ios/Runner/main.m index dff6597e4513..f451b14cb751 100644 --- a/packages/sensors/example/ios/Runner/main.m +++ b/packages/sensors/example/ios/Runner/main.m @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import #import "AppDelegate.h" diff --git a/packages/sensors/example/test_driver/test/integration_test.dart b/packages/sensors/example/test_driver/test/integration_test.dart index a8a56aa90f6a..c62ef5dba800 100644 --- a/packages/sensors/example/test_driver/test/integration_test.dart +++ b/packages/sensors/example/test_driver/test/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/sensors/integration_test/sensors_test.dart b/packages/sensors/integration_test/sensors_test.dart index 348bda00d86e..5ae15967d8e4 100644 --- a/packages/sensors/integration_test/sensors_test.dart +++ b/packages/sensors/integration_test/sensors_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java index 489b224a62ea..77bc7cedcfa5 100644 --- a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java +++ b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.shareexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/share/example/lib/image_previews.dart b/packages/share/example/lib/image_previews.dart index 9070749267fc..7298ed4348b1 100644 --- a/packages/share/example/lib/image_previews.dart +++ b/packages/share/example/lib/image_previews.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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 'dart:io'; import 'package:flutter/material.dart'; diff --git a/packages/share/example/test_driver/test/integration_test.dart b/packages/share/example/test_driver/test/integration_test.dart index a8a56aa90f6a..c62ef5dba800 100644 --- a/packages/share/example/test_driver/test/integration_test.dart +++ b/packages/share/example/test_driver/test/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/share/integration_test/share_test.dart b/packages/share/integration_test/share_test.dart index 7b66480d0681..a6a2ddb4f7cd 100644 --- a/packages/share/integration_test/share_test.dart +++ b/packages/share/integration_test/share_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift index 70693e4a8c12..f26669f6bd4f 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 UIKit import Flutter diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h b/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h index 308a2a560b42..0592e2dd559c 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h @@ -1 +1,5 @@ +// 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 "GeneratedPluginRegistrant.h" diff --git a/packages/shared_preferences/shared_preferences/example/linux/main.cc b/packages/shared_preferences/shared_preferences/example/linux/main.cc index 10835acb58ed..a15afa068a7b 100644 --- a/packages/shared_preferences/shared_preferences/example/linux/main.cc +++ b/packages/shared_preferences/shared_preferences/example/linux/main.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" int main(int argc, char** argv) { diff --git a/packages/shared_preferences/shared_preferences/example/linux/my_application.cc b/packages/shared_preferences/shared_preferences/example/linux/my_application.cc index 67ed0b9025b2..3843c07aaf04 100644 --- a/packages/shared_preferences/shared_preferences/example/linux/my_application.cc +++ b/packages/shared_preferences/shared_preferences/example/linux/my_application.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" #include diff --git a/packages/shared_preferences/shared_preferences/example/linux/my_application.h b/packages/shared_preferences/shared_preferences/example/linux/my_application.h index 72271d5e4170..abbdf1213815 100644 --- a/packages/shared_preferences/shared_preferences/example/linux/my_application.h +++ b/packages/shared_preferences/shared_preferences/example/linux/my_application.h @@ -1,3 +1,7 @@ +// 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. + #ifndef FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_ diff --git a/packages/shared_preferences/shared_preferences/example/macos/Runner/AppDelegate.swift b/packages/shared_preferences/shared_preferences/example/macos/Runner/AppDelegate.swift index d53ef6437726..ca19fe95f8cf 100644 --- a/packages/shared_preferences/shared_preferences/example/macos/Runner/AppDelegate.swift +++ b/packages/shared_preferences/shared_preferences/example/macos/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/shared_preferences/shared_preferences/example/macos/Runner/MainFlutterWindow.swift b/packages/shared_preferences/shared_preferences/example/macos/Runner/MainFlutterWindow.swift index 2722837ec918..2ce11b78604b 100644 --- a/packages/shared_preferences/shared_preferences/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/shared_preferences/shared_preferences/example/macos/Runner/MainFlutterWindow.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart index ac106b63b339..a82b5fb51e77 100644 --- a/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/shared_preferences/shared_preferences/example/web/index.html b/packages/shared_preferences/shared_preferences/example/web/index.html index 6eff9a740d43..27464c33811a 100644 --- a/packages/shared_preferences/shared_preferences/example/web/index.html +++ b/packages/shared_preferences/shared_preferences/example/web/index.html @@ -1,4 +1,7 @@ + diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp index c422723045ca..dd2e3cca5666 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp @@ -1,3 +1,7 @@ +// 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. + #include "flutter_window.h" #include diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h index b663ddd50125..a9d273e419eb 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h @@ -1,3 +1,7 @@ +// 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. + #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp index fc17fec6140c..40492ac76edb 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp @@ -1,3 +1,7 @@ +// 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. + #include #include #include diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp index 2d6636ab6bc6..4dd13b6d1db9 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp @@ -1,3 +1,7 @@ +// 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. + #include "run_loop.h" #include diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h index 5f2c4a9ad7d3..12aaab42c59b 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h @@ -1,3 +1,7 @@ +// 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. + #ifndef RUNNER_RUN_LOOP_H_ #define RUNNER_RUN_LOOP_H_ diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp index 37501e5db777..c408cb3f7a74 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp @@ -1,3 +1,7 @@ +// 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. + #include "utils.h" #include diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h index d792603bb139..2754c7a7f9ef 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h @@ -1,3 +1,7 @@ +// 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. + #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp index c63ad013b02d..878b64afe276 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp @@ -1,3 +1,7 @@ +// 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. + #include "win32_window.h" #include diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h index 4ae64a12b465..99e24a555afa 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h @@ -1,3 +1,7 @@ +// 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. + #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc b/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc index e7c5c5437037..612325f29cd7 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" int main(int argc, char** argv) { diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc index f079e19eb396..a8f67ccc9a86 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc @@ -1,3 +1,7 @@ +// Copyright 2020 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. + #include "my_application.h" #include diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h index 72271d5e4170..d1c3f9c4fb0b 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h @@ -1,3 +1,7 @@ +// Copyright 2020 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. + #ifndef FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_ diff --git a/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart index ac106b63b339..a82b5fb51e77 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart index 58b59463b352..94dee2d73c9d 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart @@ -1,6 +1,6 @@ -// Copyright 2017, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/AppDelegate.swift b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/AppDelegate.swift index d53ef6437726..ca19fe95f8cf 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/AppDelegate.swift +++ b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/MainFlutterWindow.swift b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/MainFlutterWindow.swift index 2722837ec918..2ce11b78604b 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/MainFlutterWindow.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart index ac106b63b339..a82b5fb51e77 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart index 027daa6eaeb1..41fc5dbf8b2a 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart @@ -1,6 +1,6 @@ -// Copyright 2017, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart index 353548ee0e8c..5504f8c79080 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2017, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2017, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart=2.9 diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp index c422723045ca..dd2e3cca5666 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp @@ -1,3 +1,7 @@ +// 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. + #include "flutter_window.h" #include diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h index b663ddd50125..a9d273e419eb 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h @@ -1,3 +1,7 @@ +// 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. + #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp index fc17fec6140c..40492ac76edb 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp @@ -1,3 +1,7 @@ +// 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. + #include #include #include diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp index 2d6636ab6bc6..4dd13b6d1db9 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp @@ -1,3 +1,7 @@ +// 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. + #include "run_loop.h" #include diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h index 5f2c4a9ad7d3..12aaab42c59b 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h @@ -1,3 +1,7 @@ +// 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. + #ifndef RUNNER_RUN_LOOP_H_ #define RUNNER_RUN_LOOP_H_ diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp index 37501e5db777..c408cb3f7a74 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp @@ -1,3 +1,7 @@ +// 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. + #include "utils.h" #include diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h index d792603bb139..2754c7a7f9ef 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h @@ -1,3 +1,7 @@ +// 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. + #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp index c63ad013b02d..878b64afe276 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp @@ -1,3 +1,7 @@ +// 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. + #include "win32_window.h" #include diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h index 4ae64a12b465..99e24a555afa 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h @@ -1,3 +1,7 @@ +// 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. + #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java index 2ca6b7ce3fde..7a4b37488e69 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.urllauncher; import android.os.Bundle; diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java index 44ecc337c43b..a6f29e1af68d 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.urllauncher; import android.app.Activity; diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java index 17af0abda23c..79198200c526 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.urllauncher; import android.util.Log; diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java index 7c6978fd657d..160e24e331d3 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.urllauncher; import android.annotation.TargetApi; diff --git a/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java b/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java index e759dedd5f75..e9d27e3e3b01 100644 --- a/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java +++ b/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.urllauncher; import static org.mockito.Matchers.any; diff --git a/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java index b144786fe925..9002012ce18c 100644 --- a/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java +++ b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.urllauncherexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java index 5b50523f7f40..7760741b2127 100644 --- a/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java +++ b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.urllauncherexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart index 80d21b740c1e..9e7b04b38b46 100644 --- a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(egarciad): Remove once integration_test is migrated to null safety. // @dart = 2.9 diff --git a/packages/url_launcher/url_launcher/example/linux/main.cc b/packages/url_launcher/url_launcher/example/linux/main.cc index e7c5c5437037..612325f29cd7 100644 --- a/packages/url_launcher/url_launcher/example/linux/main.cc +++ b/packages/url_launcher/url_launcher/example/linux/main.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" int main(int argc, char** argv) { diff --git a/packages/url_launcher/url_launcher/example/linux/my_application.cc b/packages/url_launcher/url_launcher/example/linux/my_application.cc index f079e19eb396..1a873cdf7b19 100644 --- a/packages/url_launcher/url_launcher/example/linux/my_application.cc +++ b/packages/url_launcher/url_launcher/example/linux/my_application.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" #include diff --git a/packages/url_launcher/url_launcher/example/linux/my_application.h b/packages/url_launcher/url_launcher/example/linux/my_application.h index 72271d5e4170..b3d62442a005 100644 --- a/packages/url_launcher/url_launcher/example/linux/my_application.h +++ b/packages/url_launcher/url_launcher/example/linux/my_application.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_ diff --git a/packages/url_launcher/url_launcher/example/macos/Runner/AppDelegate.swift b/packages/url_launcher/url_launcher/example/macos/Runner/AppDelegate.swift index d53ef6437726..ca19fe95f8cf 100644 --- a/packages/url_launcher/url_launcher/example/macos/Runner/AppDelegate.swift +++ b/packages/url_launcher/url_launcher/example/macos/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/url_launcher/url_launcher/example/macos/Runner/MainFlutterWindow.swift b/packages/url_launcher/url_launcher/example/macos/Runner/MainFlutterWindow.swift index 2722837ec918..2ce11b78604b 100644 --- a/packages/url_launcher/url_launcher/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/url_launcher/url_launcher/example/macos/Runner/MainFlutterWindow.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart index e56756f38cbd..3e3caf844689 100644 --- a/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(egarciad): Remove once flutter_driver is migrated to null safety. // @dart = 2.9 diff --git a/packages/url_launcher/url_launcher/example/web/index.html b/packages/url_launcher/url_launcher/example/web/index.html index 3d1872c20298..1127c04820dd 100644 --- a/packages/url_launcher/url_launcher/example/web/index.html +++ b/packages/url_launcher/url_launcher/example/web/index.html @@ -1,4 +1,7 @@ + diff --git a/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.cpp b/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.cpp index c422723045ca..b7d078e4d4a5 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.cpp +++ b/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "flutter_window.h" #include diff --git a/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.h b/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.h index b663ddd50125..9b4ef089621b 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.h +++ b/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ diff --git a/packages/url_launcher/url_launcher/example/windows/runner/main.cpp b/packages/url_launcher/url_launcher/example/windows/runner/main.cpp index fc17fec6140c..e74157ed999a 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/main.cpp +++ b/packages/url_launcher/url_launcher/example/windows/runner/main.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include #include #include diff --git a/packages/url_launcher/url_launcher/example/windows/runner/run_loop.cpp b/packages/url_launcher/url_launcher/example/windows/runner/run_loop.cpp index 2d6636ab6bc6..ee2e2fd5eae9 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/run_loop.cpp +++ b/packages/url_launcher/url_launcher/example/windows/runner/run_loop.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "run_loop.h" #include diff --git a/packages/url_launcher/url_launcher/example/windows/runner/run_loop.h b/packages/url_launcher/url_launcher/example/windows/runner/run_loop.h index 5f2c4a9ad7d3..a24c47f2e55f 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/run_loop.h +++ b/packages/url_launcher/url_launcher/example/windows/runner/run_loop.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_RUN_LOOP_H_ #define RUNNER_RUN_LOOP_H_ diff --git a/packages/url_launcher/url_launcher/example/windows/runner/utils.cpp b/packages/url_launcher/url_launcher/example/windows/runner/utils.cpp index 37501e5db777..9eba364025d0 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/utils.cpp +++ b/packages/url_launcher/url_launcher/example/windows/runner/utils.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "utils.h" #include diff --git a/packages/url_launcher/url_launcher/example/windows/runner/utils.h b/packages/url_launcher/url_launcher/example/windows/runner/utils.h index d792603bb139..640587eb23ab 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/utils.h +++ b/packages/url_launcher/url_launcher/example/windows/runner/utils.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ diff --git a/packages/url_launcher/url_launcher/example/windows/runner/win32_window.cpp b/packages/url_launcher/url_launcher/example/windows/runner/win32_window.cpp index c63ad013b02d..97628170c2c2 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/win32_window.cpp +++ b/packages/url_launcher/url_launcher/example/windows/runner/win32_window.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "win32_window.h" #include diff --git a/packages/url_launcher/url_launcher/example/windows/runner/win32_window.h b/packages/url_launcher/url_launcher/example/windows/runner/win32_window.h index 4ae64a12b465..59b78382b27d 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/win32_window.h +++ b/packages/url_launcher/url_launcher/example/windows/runner/win32_window.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ diff --git a/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart index e1008fddd4e1..aa668ed747b5 100644 --- a/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/url_launcher/url_launcher_linux/example/linux/main.cc b/packages/url_launcher/url_launcher_linux/example/linux/main.cc index e7c5c5437037..612325f29cd7 100644 --- a/packages/url_launcher/url_launcher_linux/example/linux/main.cc +++ b/packages/url_launcher/url_launcher_linux/example/linux/main.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" int main(int argc, char** argv) { diff --git a/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc b/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc index f079e19eb396..1a873cdf7b19 100644 --- a/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc +++ b/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "my_application.h" #include diff --git a/packages/url_launcher/url_launcher_linux/example/linux/my_application.h b/packages/url_launcher/url_launcher_linux/example/linux/my_application.h index 72271d5e4170..b3d62442a005 100644 --- a/packages/url_launcher/url_launcher_linux/example/linux/my_application.h +++ b/packages/url_launcher/url_launcher_linux/example/linux/my_application.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_ diff --git a/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart index a8a56aa90f6a..c62ef5dba800 100644 --- a/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/url_launcher/url_launcher_linux/lib/url_launcher_linux.dart b/packages/url_launcher/url_launcher_linux/lib/url_launcher_linux.dart deleted file mode 100644 index 18f7af1836ce..000000000000 --- a/packages/url_launcher/url_launcher_linux/lib/url_launcher_linux.dart +++ /dev/null @@ -1,3 +0,0 @@ -// The url_launcher_platform_interface defaults to MethodChannelUrlLauncher -// as its instance, which is all the Linux implementation needs. This file -// is here to silence warnings when publishing to pub. diff --git a/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart index d0c1a8bd7325..6775a637f7dc 100644 --- a/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/url_launcher/url_launcher_macos/example/macos/Runner/AppDelegate.swift b/packages/url_launcher/url_launcher_macos/example/macos/Runner/AppDelegate.swift index d53ef6437726..ca19fe95f8cf 100644 --- a/packages/url_launcher/url_launcher_macos/example/macos/Runner/AppDelegate.swift +++ b/packages/url_launcher/url_launcher_macos/example/macos/Runner/AppDelegate.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/url_launcher/url_launcher_macos/example/macos/Runner/MainFlutterWindow.swift b/packages/url_launcher/url_launcher_macos/example/macos/Runner/MainFlutterWindow.swift index 2722837ec918..2ce11b78604b 100644 --- a/packages/url_launcher/url_launcher_macos/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/url_launcher/url_launcher_macos/example/macos/Runner/MainFlutterWindow.swift @@ -1,3 +1,7 @@ +// Copyright 2017 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 Cocoa import FlutterMacOS diff --git a/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart index a8a56aa90f6a..c62ef5dba800 100644 --- a/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/url_launcher/url_launcher_macos/lib/url_launcher_macos.dart b/packages/url_launcher/url_launcher_macos/lib/url_launcher_macos.dart deleted file mode 100644 index 5a1956c9a9c1..000000000000 --- a/packages/url_launcher/url_launcher_macos/lib/url_launcher_macos.dart +++ /dev/null @@ -1,3 +0,0 @@ -// The url_launcher_platform_interface defaults to MethodChannelUrlLauncher -// as its instance, which is all the macOS implementation needs. This file -// is here to silence warnings when publishing to pub. diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart index 73d3bf355d67..7e72b5ff1da3 100644 --- a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart +++ b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart @@ -1,3 +1,7 @@ +// Copyright 2017 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 'dart:async' as _i4; import 'dart:html' as _i2; import 'dart:math' as _i5; diff --git a/packages/url_launcher/url_launcher_web/example/run_test.sh b/packages/url_launcher/url_launcher_web/example/run_test.sh index b243f2938b1f..5d235967ac3d 100755 --- a/packages/url_launcher/url_launcher_web/example/run_test.sh +++ b/packages/url_launcher/url_launcher_web/example/run_test.sh @@ -1,4 +1,8 @@ #!/usr/bin/bash +# Copyright 2017 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. + if pgrep -lf chromedriver > /dev/null; then echo "chromedriver is running." diff --git a/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart b/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart index 334f52186d9d..11f9b24dc878 100644 --- a/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart +++ b/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:flutter_test/flutter_test.dart'; void main() { diff --git a/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart index e1008fddd4e1..aa668ed747b5 100644 --- a/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart index a8a56aa90f6a..c62ef5dba800 100644 --- a/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.cpp b/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.cpp index c422723045ca..b7d078e4d4a5 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.cpp +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "flutter_window.h" #include diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.h b/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.h index b663ddd50125..9b4ef089621b 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.h +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/main.cpp b/packages/url_launcher/url_launcher_windows/example/windows/runner/main.cpp index fc17fec6140c..e74157ed999a 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/main.cpp +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/main.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include #include #include diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.cpp b/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.cpp index 2d6636ab6bc6..ee2e2fd5eae9 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.cpp +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "run_loop.h" #include diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.h b/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.h index 5f2c4a9ad7d3..a24c47f2e55f 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.h +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_RUN_LOOP_H_ #define RUNNER_RUN_LOOP_H_ diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.cpp b/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.cpp index 37501e5db777..9eba364025d0 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.cpp +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "utils.h" #include diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.h b/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.h index d792603bb139..640587eb23ab 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.h +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.cpp b/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.cpp index c63ad013b02d..97628170c2c2 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.cpp +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.cpp @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #include "win32_window.h" #include diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.h b/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.h index 4ae64a12b465..59b78382b27d 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.h +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.h @@ -1,3 +1,7 @@ +// Copyright 2017 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. + #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ diff --git a/packages/url_launcher/url_launcher_windows/lib/url_launcher_windows.dart b/packages/url_launcher/url_launcher_windows/lib/url_launcher_windows.dart deleted file mode 100644 index 83435f981838..000000000000 --- a/packages/url_launcher/url_launcher_windows/lib/url_launcher_windows.dart +++ /dev/null @@ -1,3 +0,0 @@ -// The url_launcher_platform_interface defaults to MethodChannelUrlLauncher -// as its instance, which is all the Windows implementation needs. This file -// is here to silence warnings when publishing to pub. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java index a7b609f4d930..adccd2e2cdcd 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.videoplayer; import java.io.IOException; diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java index 053e3faa9694..0d108caa0597 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java @@ -1,3 +1,7 @@ +// 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. + // Autogenerated from Pigeon (v0.1.19), do not edit directly. // See also: https://pub.dev/packages/pigeon diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java index c3a31432e896..bba301666993 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.videoplayer; import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL; diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java index 7381f4a941a5..fa51fbf50b43 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java @@ -1,3 +1,7 @@ +// 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. + package io.flutter.plugins.videoplayer; class VideoPlayerOptions { diff --git a/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java b/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java index 0286237cf7ea..e62e70cd54ad 100644 --- a/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java +++ b/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.videoplayerexample; import static org.mockito.Mockito.mock; diff --git a/packages/video_player/video_player/example/integration_test/video_player_test.dart b/packages/video_player/video_player/example/integration_test/video_player_test.dart index 9e273e02dc4d..b39bb087a21c 100644 --- a/packages/video_player/video_player/example/integration_test/video_player_test.dart +++ b/packages/video_player/video_player/example/integration_test/video_player_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(amirh): Remove this once flutter_driver supports null safety. // https://github.com/flutter/flutter/issues/71379 diff --git a/packages/video_player/video_player/example/test_driver/integration_test.dart b/packages/video_player/video_player/example/test_driver/integration_test.dart index 7873abae2996..ca76cd86091a 100644 --- a/packages/video_player/video_player/example/test_driver/integration_test.dart +++ b/packages/video_player/video_player/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(egarciad): Remove once Flutter driver is migrated to null safety. // @dart = 2.9 diff --git a/packages/video_player/video_player/example/test_driver/video_player.dart b/packages/video_player/video_player/example/test_driver/video_player.dart index c1ced19e9b7e..b942d20c17ba 100644 --- a/packages/video_player/video_player/example/test_driver/video_player.dart +++ b/packages/video_player/video_player/example/test_driver/video_player.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(egarciad): Remove once Flutter driver is migrated to null safety. // @dart = 2.9 diff --git a/packages/video_player/video_player/example/test_driver/video_player_test.dart b/packages/video_player/video_player/example/test_driver/video_player_test.dart index fcbdbb274f7a..232a88d89926 100644 --- a/packages/video_player/video_player/example/test_driver/video_player_test.dart +++ b/packages/video_player/video_player/example/test_driver/video_player_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // TODO(egarciad): Remove once Flutter driver is migrated to null safety. // @dart = 2.9 diff --git a/packages/video_player/video_player/example/web/index.html b/packages/video_player/video_player/example/web/index.html index b1c45bdcd57f..763ea662e8e3 100644 --- a/packages/video_player/video_player/example/web/index.html +++ b/packages/video_player/video_player/example/web/index.html @@ -1,4 +1,7 @@ + diff --git a/packages/video_player/video_player/ios/Classes/messages.h b/packages/video_player/video_player/ios/Classes/messages.h index 80137c9d61f5..8e2ae130643f 100644 --- a/packages/video_player/video_player/ios/Classes/messages.h +++ b/packages/video_player/video_player/ios/Classes/messages.h @@ -1,3 +1,7 @@ +// 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. + // Autogenerated from Pigeon (v0.1.19), do not edit directly. // See also: https://pub.dev/packages/pigeon #import diff --git a/packages/video_player/video_player/ios/Classes/messages.m b/packages/video_player/video_player/ios/Classes/messages.m index 3f787fcdf92d..368601b9d6cb 100644 --- a/packages/video_player/video_player/ios/Classes/messages.m +++ b/packages/video_player/video_player/ios/Classes/messages.m @@ -1,3 +1,7 @@ +// 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. + // Autogenerated from Pigeon (v0.1.19), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "messages.h" diff --git a/packages/video_player/video_player/pigeons/messages.dart b/packages/video_player/video_player/pigeons/messages.dart index ebef9e526b6a..33ca12e7969e 100644 --- a/packages/video_player/video_player/pigeons/messages.dart +++ b/packages/video_player/video_player/pigeons/messages.dart @@ -1,3 +1,7 @@ +// 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. + // @dart = 2.9 import 'package:pigeon/pigeon_lib.dart'; diff --git a/packages/video_player/video_player_platform_interface/lib/messages.dart b/packages/video_player/video_player_platform_interface/lib/messages.dart index dc5237f2e151..96ff20ea907f 100644 --- a/packages/video_player/video_player_platform_interface/lib/messages.dart +++ b/packages/video_player/video_player_platform_interface/lib/messages.dart @@ -1,3 +1,7 @@ +// 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. + // Autogenerated from Pigeon (v0.1.21), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import diff --git a/packages/video_player/video_player_platform_interface/lib/test.dart b/packages/video_player/video_player_platform_interface/lib/test.dart index 457a838e8d24..7365f6dfb391 100644 --- a/packages/video_player/video_player_platform_interface/lib/test.dart +++ b/packages/video_player/video_player_platform_interface/lib/test.dart @@ -1,3 +1,7 @@ +// 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. + // Autogenerated from Pigeon (v0.1.21), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import diff --git a/packages/video_player/video_player_web/lib/video_player_web.dart b/packages/video_player/video_player_web/lib/video_player_web.dart index 18f9e5e58cd6..d22c8f4f983c 100644 --- a/packages/video_player/video_player_web/lib/video_player_web.dart +++ b/packages/video_player/video_player_web/lib/video_player_web.dart @@ -1,3 +1,7 @@ +// 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:async'; import 'dart:html'; import 'src/shims/dart_ui.dart' as ui; diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java index 1273e7349620..e98c2b0fc4da 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java @@ -1,3 +1,7 @@ +// Copyright 2018 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. + package io.flutter.plugins.webviewflutter; import static android.hardware.display.DisplayManager.DisplayListener; diff --git a/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java index 07f9bf2f7802..aebeb6d0a3b0 100644 --- a/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java +++ b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.webviewflutterexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java index a9b1a9412cbd..e3d794e52dcc 100644 --- a/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java +++ b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.webviewflutterexample; import androidx.test.rule.ActivityTestRule; diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index d91ccc53b231..20391f70d2ff 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/webview_flutter/example/test_driver/integration_test.dart b/packages/webview_flutter/example/test_driver/integration_test.dart index a8a56aa90f6a..c62ef5dba800 100644 --- a/packages/webview_flutter/example/test_driver/integration_test.dart +++ b/packages/webview_flutter/example/test_driver/integration_test.dart @@ -1,6 +1,6 @@ -// Copyright 2019, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. +// Copyright 2019, the Chromium project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. // @dart = 2.9 diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/java/io/flutter/plugins/wifi_info_flutter_example/MainActivity.java b/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/java/io/flutter/plugins/wifi_info_flutter_example/MainActivity.java index 87e41d0dea51..f3747669929d 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/java/io/flutter/plugins/wifi_info_flutter_example/MainActivity.java +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/java/io/flutter/plugins/wifi_info_flutter_example/MainActivity.java @@ -1,3 +1,7 @@ +// Copyright 2017 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. + package io.flutter.plugins.wifi_info_flutter_example; import io.flutter.embedding.android.FlutterActivity; diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.h b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.h index 36e21bbf9cf4..31fc381e7066 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.h +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.h @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.m b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.m index 70e83933db14..558d1adc9a4a 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.m +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.m @@ -1,3 +1,7 @@ +// Copyright 2017 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 "AppDelegate.h" #import "GeneratedPluginRegistrant.h" diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/main.m b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/main.m index dff6597e4513..f451b14cb751 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/main.m +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/main.m @@ -1,3 +1,7 @@ +// Copyright 2017 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 #import #import "AppDelegate.h" diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 27726bd53426..cfd783e64d1e 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -1,4 +1,7 @@ #!/bin/bash +# 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. # Usage: # diff --git a/script/check_publish.sh b/script/check_publish.sh index c92de4be2e08..ead4aa3b2b34 100755 --- a/script/check_publish.sh +++ b/script/check_publish.sh @@ -1,4 +1,8 @@ #!/bin/bash +# 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. + set -e # This script checks to make sure that each of the plugins *could* be published. diff --git a/script/common.sh b/script/common.sh index 28c37540af88..9668688f50b2 100644 --- a/script/common.sh +++ b/script/common.sh @@ -1,4 +1,7 @@ #!/bin/bash +# 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. function error() { echo "$@" 1>&2 diff --git a/script/incremental_build.sh b/script/incremental_build.sh index 38a4d2d8edc7..b46f500ae414 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -1,4 +1,8 @@ #!/bin/bash +# 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. + set -e readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" diff --git a/script/tool/lib/src/license_check_command.dart b/script/tool/lib/src/license_check_command.dart new file mode 100644 index 000000000000..4e0e5931d3ee --- /dev/null +++ b/script/tool/lib/src/license_check_command.dart @@ -0,0 +1,209 @@ +// 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:async'; + +import 'package:file/file.dart'; +import 'package:path/path.dart' as p; + +import 'common.dart'; + +const Set _codeFileExtensions = { + '.c', + '.cc', + '.cpp', + '.dart', + '.h', + '.html', + '.java', + '.m', + '.mm', + '.swift', + '.sh', +}; + +// Basenames without extensions of files to ignore. +const Set _ignoreBasenameList = { + 'flutter_export_environment', + 'GeneratedPluginRegistrant', + 'generated_plugin_registrant', +}; + +// File suffixes that otherwise match _codeFileExtensions to ignore. +const Set _ignoreSuffixList = { + '.g.dart', // Generated API code. + '.mocks.dart', // Generated by Mockito. +}; + +// Full basenames of files to ignore. +const Set _ignoredFullBasenameList = { + 'resource.h', // Generated by VS. +}; + +// Copyright and license regexes. +// +// These are intentionally very simple, since almost all source in this +// repository should be using the same license text, comment style, etc., so +// they shouldn't need to be very flexible. Complexity can be added as-needed +// on a case-by-case basis. +final RegExp _copyrightRegex = + RegExp(r'^(?://|#|'), + }; + + for (final File file in codeFiles) { + _print('Checking ${file.path}'); + final String content = await file.readAsString(); + + final RegExpMatch copyright = _copyrightRegex.firstMatch(content); + if (copyright == null) { + filesWithoutDetectedCopyright.add(file); + continue; + } + final String author = copyright.group(1); + if (!_firstPartyAuthors.contains(author) && + !p.split(file.path).contains('third_party')) { + misplacedThirdPartyFiles.add(file); + } + + final String bsdLicense = + bsdLicenseBlockByExtension[p.extension(file.path)] ?? + defaultBsdLicenseBlock; + if (!content.contains(bsdLicense) && + !_workivaLicenseRegex.hasMatch(content)) { + filesWithoutDetectedLicense.add(file); + } + } + _print('\n\n'); + + // Sort by path for more usable output. + final pathCompare = (File a, File b) => a.path.compareTo(b.path); + filesWithoutDetectedCopyright.sort(pathCompare); + filesWithoutDetectedLicense.sort(pathCompare); + misplacedThirdPartyFiles.sort(pathCompare); + + if (filesWithoutDetectedCopyright.isNotEmpty) { + _print('No copyright line was found for the following files:'); + for (final File file in filesWithoutDetectedCopyright) { + _print(' ${file.path}'); + } + _print('Please check that they have a copyright and license block. ' + 'If they do, the license check may need to be updated to recognize its ' + 'format.\n'); + } + + if (filesWithoutDetectedLicense.isNotEmpty) { + _print('No recognized license was found for the following files:'); + for (final File file in filesWithoutDetectedLicense) { + _print(' ${file.path}'); + } + _print('Please check that they have a license at the top of the file. ' + 'If they do, the license check may need to be updated to recognize ' + 'either the license or the specific format of the license ' + 'block.\n'); + } + + if (misplacedThirdPartyFiles.isNotEmpty) { + _print('The following files do not have a recognized first-party author ' + 'but are not in a "third_party/" directory:'); + for (final File file in misplacedThirdPartyFiles) { + _print(' ${file.path}'); + } + _print('Please move these files to "third_party/".\n'); + } + + bool succeeded = filesWithoutDetectedCopyright.isEmpty && + filesWithoutDetectedLicense.isEmpty && + misplacedThirdPartyFiles.isEmpty; + if (succeeded) { + _print('All files passed validation!'); + } + return succeeded; + } + + bool _shouldIgnoreFile(File file) { + final String path = file.path; + return _ignoreBasenameList.contains(p.basenameWithoutExtension(path)) || + _ignoreSuffixList.any((String suffix) => + path.endsWith(suffix) || + _ignoredFullBasenameList.contains(p.basename(path))); + } + + Future> _getAllFiles() => packagesDir.parent + .list(recursive: true, followLinks: false) + .where((FileSystemEntity entity) => entity is File) + .map((FileSystemEntity file) => file as File) + .toList(); +} diff --git a/script/tool/lib/src/main.dart b/script/tool/lib/src/main.dart index fa81597237d7..329112931251 100644 --- a/script/tool/lib/src/main.dart +++ b/script/tool/lib/src/main.dart @@ -19,6 +19,7 @@ import 'drive_examples_command.dart'; import 'firebase_test_lab_command.dart'; import 'format_command.dart'; import 'java_test_command.dart'; +import 'license_check_command.dart'; import 'lint_podspecs_command.dart'; import 'list_command.dart'; import 'test_command.dart'; @@ -50,6 +51,7 @@ void main(List args) { ..addCommand(FirebaseTestLabCommand(packagesDir, fileSystem)) ..addCommand(FormatCommand(packagesDir, fileSystem)) ..addCommand(JavaTestCommand(packagesDir, fileSystem)) + ..addCommand(LicenseCheckCommand(packagesDir, fileSystem)) ..addCommand(LintPodspecsCommand(packagesDir, fileSystem)) ..addCommand(ListCommand(packagesDir, fileSystem)) ..addCommand(PublishCheckCommand(packagesDir, fileSystem)) diff --git a/script/tool/lib/src/publish_plugin_command.dart b/script/tool/lib/src/publish_plugin_command.dart index f7e3b5deeecf..f61a76947c9e 100644 --- a/script/tool/lib/src/publish_plugin_command.dart +++ b/script/tool/lib/src/publish_plugin_command.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:async'; import 'dart:convert'; import 'dart:io'; diff --git a/script/tool/test/analyze_command_test.dart b/script/tool/test/analyze_command_test.dart index 9e7a42bbb680..63afb51c8595 100644 --- a/script/tool/test/analyze_command_test.dart +++ b/script/tool/test/analyze_command_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:flutter_plugin_tools/src/analyze_command.dart'; diff --git a/script/tool/test/build_examples_command_test.dart b/script/tool/test/build_examples_command_test.dart index 65417525d710..e0213893db38 100644 --- a/script/tool/test/build_examples_command_test.dart +++ b/script/tool/test/build_examples_command_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:flutter_plugin_tools/src/build_examples_command.dart'; diff --git a/script/tool/test/common_test.dart b/script/tool/test/common_test.dart index 0fb3ce74c373..a8deacc8e483 100644 --- a/script/tool/test/common_test.dart +++ b/script/tool/test/common_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:args/command_runner.dart'; diff --git a/script/tool/test/drive_examples_command_test.dart b/script/tool/test/drive_examples_command_test.dart index f4bdd95c1664..7a8e9f3e9f95 100644 --- a/script/tool/test/drive_examples_command_test.dart +++ b/script/tool/test/drive_examples_command_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:flutter_plugin_tools/src/common.dart'; diff --git a/script/tool/test/firebase_test_lab_test.dart b/script/tool/test/firebase_test_lab_test.dart index 97b977619d57..d11624671523 100644 --- a/script/tool/test/firebase_test_lab_test.dart +++ b/script/tool/test/firebase_test_lab_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:args/command_runner.dart'; diff --git a/script/tool/test/license_check_command_test.dart b/script/tool/test/license_check_command_test.dart new file mode 100644 index 000000000000..524e72712360 --- /dev/null +++ b/script/tool/test/license_check_command_test.dart @@ -0,0 +1,306 @@ +// Copyright 2019 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 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:flutter_plugin_tools/src/common.dart'; +import 'package:flutter_plugin_tools/src/license_check_command.dart'; +import 'package:test/test.dart'; + +void main() { + group('$LicenseCheckCommand', () { + CommandRunner runner; + FileSystem fileSystem; + List printedMessages; + Directory root; + + setUp(() { + fileSystem = MemoryFileSystem(); + final Directory packagesDir = + fileSystem.currentDirectory.childDirectory('packages'); + root = packagesDir.parent; + + printedMessages = []; + final LicenseCheckCommand command = LicenseCheckCommand( + packagesDir, + fileSystem, + print: (Object message) => printedMessages.add(message.toString()), + ); + runner = + CommandRunner('license_test', 'Test for $LicenseCheckCommand'); + runner.addCommand(command); + }); + + /// Writes a copyright+license block to [file], defaulting to a standard + /// block for this repository. + /// + /// [commentString] is added to the start of each line. + /// [prefix] is added to the start of the entire block. + /// [suffix] is added to the end of the entire block. + void _writeLicense( + File file, { + String comment = '// ', + String prefix = '', + String suffix = '', + String copyright = + 'Copyright 2019 The Chromium Authors. All rights reserved.', + List license = const [ + 'Use of this source code is governed by a BSD-style license that can be', + 'found in the LICENSE file.', + ], + }) { + List lines = ['$prefix$comment$copyright']; + for (String line in license) { + lines.add('$comment$line'); + } + file.writeAsStringSync(lines.join('\n') + suffix + '\n'); + } + + test('looks at only expected extensions', () async { + Map extensions = { + 'c': true, + 'cc': true, + 'cpp': true, + 'dart': true, + 'h': true, + 'html': true, + 'java': true, + 'json': false, + 'm': true, + 'md': false, + 'mm': true, + 'png': false, + 'swift': true, + 'sh': true, + 'yaml': false, + }; + + const String filenameBase = 'a_file'; + for (final String fileExtension in extensions.keys) { + root.childFile('$filenameBase.$fileExtension').createSync(); + } + + try { + await runner.run(['license-check']); + } on ToolExit { + // Ignore failure; the files are empty so the check is expected to fail, + // but this test isn't for that behavior. + } + + extensions.forEach((String fileExtension, bool shouldCheck) { + final Matcher logLineMatcher = + contains('Checking $filenameBase.$fileExtension'); + expect(printedMessages, + shouldCheck ? logLineMatcher : isNot(logLineMatcher)); + }); + }); + + test('ignore list overrides extension matches', () async { + List ignoredFiles = [ + // Ignored base names. + 'flutter_export_environment.sh', + 'GeneratedPluginRegistrant.java', + 'GeneratedPluginRegistrant.m', + 'generated_plugin_registrant.cc', + 'generated_plugin_registrant.cpp', + // Ignored path suffixes. + 'foo.g.dart', + 'foo.mocks.dart', + // Ignored files. + 'resource.h', + ]; + + for (final String name in ignoredFiles) { + root.childFile(name).createSync(); + } + + await runner.run(['license-check']); + + for (final String name in ignoredFiles) { + expect(printedMessages, isNot(contains('Checking $name'))); + } + }); + + test('passes if all checked files have license blocks', () async { + File checked = root.childFile('checked.cc'); + checked.createSync(); + _writeLicense(checked); + File not_checked = root.childFile('not_checked.md'); + not_checked.createSync(); + + await runner.run(['license-check']); + + // Sanity check that the test did actually check a file. + expect(printedMessages, contains('Checking checked.cc')); + expect(printedMessages, contains('All files passed validation!')); + }); + + test('handles the comment styles for all supported languages', () async { + File file_a = root.childFile('file_a.cc'); + file_a.createSync(); + _writeLicense(file_a, comment: '// '); + File file_b = root.childFile('file_b.sh'); + file_b.createSync(); + _writeLicense(file_b, comment: '# '); + File file_c = root.childFile('file_c.html'); + file_c.createSync(); + _writeLicense(file_c, comment: '', prefix: ''); + + await runner.run(['license-check']); + + // Sanity check that the test did actually check the files. + expect(printedMessages, contains('Checking file_a.cc')); + expect(printedMessages, contains('Checking file_b.sh')); + expect(printedMessages, contains('Checking file_c.html')); + expect(printedMessages, contains('All files passed validation!')); + }); + + test('fails if any checked files are missing license blocks', () async { + File good_a = root.childFile('good.cc'); + good_a.createSync(); + _writeLicense(good_a); + File good_b = root.childFile('good.h'); + good_b.createSync(); + _writeLicense(good_b); + root.childFile('bad.cc').createSync(); + root.childFile('bad.h').createSync(); + + await expectLater(() => runner.run(['license-check']), + throwsA(const TypeMatcher())); + + // Failure should give information about the problematic files. + expect(printedMessages, + contains('No copyright line was found for the following files:')); + expect(printedMessages, contains(' bad.cc')); + expect(printedMessages, contains(' bad.h')); + // Failure shouldn't print the success message. + expect(printedMessages, isNot(contains('All files passed validation!'))); + }); + + test('fails if any checked files are missing just the copyright', () async { + File good = root.childFile('good.cc'); + good.createSync(); + _writeLicense(good); + File bad = root.childFile('bad.cc'); + bad.createSync(); + _writeLicense(bad, copyright: ''); + + await expectLater(() => runner.run(['license-check']), + throwsA(const TypeMatcher())); + + // Failure should give information about the problematic files. + expect(printedMessages, + contains('No copyright line was found for the following files:')); + expect(printedMessages, contains(' bad.cc')); + // Failure shouldn't print the success message. + expect(printedMessages, isNot(contains('All files passed validation!'))); + }); + + test('fails if any checked files are missing just the license', () async { + File good = root.childFile('good.cc'); + good.createSync(); + _writeLicense(good); + File bad = root.childFile('bad.cc'); + bad.createSync(); + _writeLicense(bad, license: []); + + await expectLater(() => runner.run(['license-check']), + throwsA(const TypeMatcher())); + + // Failure should give information about the problematic files. + expect(printedMessages, + contains('No recognized license was found for the following files:')); + expect(printedMessages, contains(' bad.cc')); + // Failure shouldn't print the success message. + expect(printedMessages, isNot(contains('All files passed validation!'))); + }); + + test('fails if any third-party code is not in a third_party directory', + () async { + File thirdPartyFile = root.childFile('third_party.cc'); + thirdPartyFile.createSync(); + _writeLicense(thirdPartyFile, copyright: 'Copyright 2017 Someone Else'); + + await expectLater(() => runner.run(['license-check']), + throwsA(const TypeMatcher())); + + // Failure should give information about the problematic files. + expect( + printedMessages, + contains( + 'The following files do not have a recognized first-party author ' + 'but are not in a "third_party/" directory:')); + expect(printedMessages, contains(' third_party.cc')); + // Failure shouldn't print the success message. + expect(printedMessages, isNot(contains('All files passed validation!'))); + }); + + test('succeeds for third-party code in a third_party directory', () async { + File thirdPartyFile = root + .childDirectory('a_plugin') + .childDirectory('lib') + .childDirectory('src') + .childDirectory('third_party') + .childFile('file.cc'); + thirdPartyFile.createSync(recursive: true); + _writeLicense(thirdPartyFile, copyright: 'Copyright 2017 Someone Else'); + + await runner.run(['license-check']); + + // Sanity check that the test did actually check the file. + expect(printedMessages, + contains('Checking a_plugin/lib/src/third_party/file.cc')); + expect(printedMessages, contains('All files passed validation!')); + }); + + test('fails for licenses that the tool does not expect', () async { + File good = root.childFile('good.cc'); + good.createSync(); + _writeLicense(good); + File bad = root.childDirectory('third_party').childFile('bad.cc'); + bad.createSync(recursive: true); + _writeLicense(bad, license: [ + 'This program is free software: you can redistribute it and/or modify', + 'it under the terms of the GNU General Public License', + ]); + + await expectLater(() => runner.run(['license-check']), + throwsA(const TypeMatcher())); + + // Failure should give information about the problematic files. + expect(printedMessages, + contains('No recognized license was found for the following files:')); + expect(printedMessages, contains(' third_party/bad.cc')); + // Failure shouldn't print the success message. + expect(printedMessages, isNot(contains('All files passed validation!'))); + }); + + test('Apache is not recognized for new authors without validation changes', + () async { + File good = root.childFile('good.cc'); + good.createSync(); + _writeLicense(good); + File bad = root.childDirectory('third_party').childFile('bad.cc'); + bad.createSync(recursive: true); + _writeLicense( + bad, + copyright: 'Copyright 2017 Some New Authors', + license: [ + 'Licensed under the Apache License, Version 2.0', + ], + ); + + await expectLater(() => runner.run(['license-check']), + throwsA(const TypeMatcher())); + + // Failure should give information about the problematic files. + expect(printedMessages, + contains('No recognized license was found for the following files:')); + expect(printedMessages, contains(' third_party/bad.cc')); + // Failure shouldn't print the success message. + expect(printedMessages, isNot(contains('All files passed validation!'))); + }); + }); +} diff --git a/script/tool/test/lint_podspecs_command_test.dart b/script/tool/test/lint_podspecs_command_test.dart index 1c59d2d7e55a..2a3e60853d08 100644 --- a/script/tool/test/lint_podspecs_command_test.dart +++ b/script/tool/test/lint_podspecs_command_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:args/command_runner.dart'; diff --git a/script/tool/test/list_command_test.dart b/script/tool/test/list_command_test.dart index 478625283dd0..d06f6d2ca464 100644 --- a/script/tool/test/list_command_test.dart +++ b/script/tool/test/list_command_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:flutter_plugin_tools/src/list_command.dart'; diff --git a/script/tool/test/mocks.dart b/script/tool/test/mocks.dart index 3e17ff8efd32..35a4eb7cbacb 100644 --- a/script/tool/test/mocks.dart +++ b/script/tool/test/mocks.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:async'; import 'dart:io' as io; diff --git a/script/tool/test/publish_plugin_command_test.dart b/script/tool/test/publish_plugin_command_test.dart index ada4bf08fd72..4f770b2054f9 100644 --- a/script/tool/test/publish_plugin_command_test.dart +++ b/script/tool/test/publish_plugin_command_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:async'; import 'dart:convert'; import 'dart:io' as io; diff --git a/script/tool/test/test_command_test.dart b/script/tool/test/test_command_test.dart index 514e4c27190a..520f4c316f5c 100644 --- a/script/tool/test/test_command_test.dart +++ b/script/tool/test/test_command_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:flutter_plugin_tools/src/test_command.dart'; diff --git a/script/tool/test/util.dart b/script/tool/test/util.dart index 1538d9b554e8..63cd5defbb27 100644 --- a/script/tool/test/util.dart +++ b/script/tool/test/util.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:async'; import 'dart:io' as io; diff --git a/script/tool/test/version_check_test.dart b/script/tool/test/version_check_test.dart index ac0d378c2a26..400d4263357c 100644 --- a/script/tool/test/version_check_test.dart +++ b/script/tool/test/version_check_test.dart @@ -1,3 +1,7 @@ +// Copyright 2019 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:async'; import 'dart:io'; From 3222a3e4458b659d98714722f3ad9577d07c5903 Mon Sep 17 00:00:00 2001 From: Balvinder Singh Gambhir Date: Wed, 17 Mar 2021 04:27:49 +0530 Subject: [PATCH 335/924] [image_picker] Endorse image_picker_for_web (#3717) --- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ packages/image_picker/image_picker/pubspec.yaml | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 4f2a054f1520..fc3d5c156a17 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.3 + +* Endorse image_picker_for_web + ## 0.7.2+1 * Android: fixes an issue where videos could be wrongly picked with `.jpg` extension. diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 9ea8e5ddcbd4..cd4089e58798 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.7.2+1 +version: 0.7.3 flutter: plugin: @@ -12,12 +12,15 @@ flutter: pluginClass: ImagePickerPlugin ios: pluginClass: FLTImagePickerPlugin + web: + default_package: image_picker_for_web dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: ^2.0.0 image_picker_platform_interface: ^2.0.0 + image_picker_for_web: ^2.0.0 dev_dependencies: flutter_test: From d7125cdb91c0ea6781bfc9ca8c570070592aa851 Mon Sep 17 00:00:00 2001 From: Guy Kogus Date: Wed, 17 Mar 2021 21:23:52 +0100 Subject: [PATCH 336/924] [google_maps_flutter_platform_interface] Mark constructors as const for ids (#3718) --- .../CHANGELOG.md | 4 ++ .../method_channel_google_maps_flutter.dart | 6 +- .../lib/src/types/camera.dart | 6 +- .../lib/src/types/circle.dart | 2 +- .../lib/src/types/maps_object.dart | 2 +- .../lib/src/types/marker.dart | 2 +- .../lib/src/types/polygon.dart | 4 +- .../lib/src/types/polyline.dart | 2 +- .../lib/src/types/tile_overlay.dart | 5 +- .../pubspec.yaml | 2 +- .../test/types/camera_test.dart | 3 +- .../test/types/maps_object_test.dart | 24 ++++---- .../test/types/maps_object_updates_test.dart | 60 ++++++++++--------- .../test/types/test_maps_object.dart | 5 +- .../test/types/tile_overlay_test.dart | 25 ++++---- .../test/types/tile_overlay_updates_test.dart | 57 +++++++++--------- .../test/types/tile_test.dart | 3 +- 17 files changed, 111 insertions(+), 101 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index b0ad668c8ddc..e8b12f79220d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.2 + +* Mark constructors for CameraUpdate, CircleId, MapsObjectId, MarkerId, PolygonId, PolylineId and TileOverlayId as const + ## 2.0.1 * Update platform_plugin_interface version requirement. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index 3d16127ab7a9..9d447701fdd8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -5,13 +5,13 @@ import 'dart:async'; import 'dart:typed_data'; -import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'package:flutter/gestures.dart'; - +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:stream_transform/stream_transform.dart'; + import '../types/tile_overlay_updates.dart'; import '../types/utils/tile_overlay.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart index 28acf35962b6..f15254104b0e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart @@ -109,7 +109,7 @@ class CameraPosition { /// Defines a camera move, supporting absolute moves as well as moves relative /// the current position. class CameraUpdate { - CameraUpdate._(this._json); + const CameraUpdate._(this._json); /// Returns a camera update that moves the camera to the specified position. static CameraUpdate newCameraPosition(CameraPosition cameraPosition) { @@ -176,7 +176,7 @@ class CameraUpdate { /// /// Equivalent to the result of calling `zoomBy(1.0)`. static CameraUpdate zoomIn() { - return CameraUpdate._(['zoomIn']); + return const CameraUpdate._(['zoomIn']); } /// Returns a camera update that zooms the camera out, bringing the camera @@ -184,7 +184,7 @@ class CameraUpdate { /// /// Equivalent to the result of calling `zoomBy(-1.0)`. static CameraUpdate zoomOut() { - return CameraUpdate._(['zoomOut']); + return const CameraUpdate._(['zoomOut']); } /// Returns a camera update that sets the camera zoom level. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart index e3198dfd6512..daf7c918f67a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart @@ -14,7 +14,7 @@ import 'types.dart'; @immutable class CircleId extends MapsObjectId { /// Creates an immutable identifier for a [Circle]. - CircleId(String value) : super(value); + const CircleId(String value) : super(value); } /// Draws a circle on the map. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart index 545d46272215..1e7932c7cde2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart @@ -14,7 +14,7 @@ class MapsObjectId { /// Creates an immutable object representing a [T] among [GoogleMap] Ts. /// /// An [AssertionError] will be thrown if [value] is null. - MapsObjectId(this.value) : assert(value != null); + const MapsObjectId(this.value) : assert(value != null); /// The value of the id. final String value; diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart index 15351d58168b..e493d6cec8cc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart @@ -104,7 +104,7 @@ class InfoWindow { @immutable class MarkerId extends MapsObjectId { /// Creates an immutable identifier for a [Marker]. - MarkerId(String value) : super(value); + const MarkerId(String value) : super(value); } /// Marks a geographical location on the map. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart index 4e5e9bf13d84..57438287a156 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart @@ -15,7 +15,7 @@ import 'types.dart'; @immutable class PolygonId extends MapsObjectId { /// Creates an immutable identifier for a [Polygon]. - PolygonId(String value) : super(value); + const PolygonId(String value) : super(value); } /// Draws a polygon through geographical locations on the map. @@ -167,7 +167,7 @@ class Polygon implements MapsObject { fillColor == typedOther.fillColor && geodesic == typedOther.geodesic && listEquals(points, typedOther.points) && - DeepCollectionEquality().equals(holes, typedOther.holes) && + const DeepCollectionEquality().equals(holes, typedOther.holes) && visible == typedOther.visible && strokeColor == typedOther.strokeColor && strokeWidth == typedOther.strokeWidth && diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart index 3f87395164f6..6738bbf2f079 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart @@ -16,7 +16,7 @@ class PolylineId extends MapsObjectId { /// Creates an immutable object representing a [PolylineId] among [GoogleMap] polylines. /// /// An [AssertionError] will be thrown if [value] is null. - PolylineId(String value) : super(value); + const PolylineId(String value) : super(value); } /// Draws a line through geographical locations on the map. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart index e31bfb461fb4..7f7ef09123b0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart @@ -3,16 +3,17 @@ // found in the LICENSE file. import 'dart:ui' show hashValues; + import 'package:flutter/foundation.dart'; +import 'package:meta/meta.dart' show immutable; import 'types.dart'; -import 'package:meta/meta.dart' show immutable; /// Uniquely identifies a [TileOverlay] among [GoogleMap] tile overlays. @immutable class TileOverlayId extends MapsObjectId { /// Creates an immutable identifier for a [TileOverlay]. - TileOverlayId(String value) : super(value); + const TileOverlayId(String value) : super(value); } /// A set of images which are displayed on top of the base map tiles. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index 0796b71fbb62..9d419351e85f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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: 2.0.1 +version: 2.0.2 dependencies: flutter: diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart index 3b6d237e05d4..4774311feb90 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart @@ -3,14 +3,13 @@ // found in the LICENSE file. import 'package:flutter_test/flutter_test.dart'; - import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); test('toMap / fromMap', () { - final cameraPosition = CameraPosition( + const cameraPosition = CameraPosition( target: LatLng(10.0, 15.0), bearing: 0.5, tilt: 30.0, zoom: 1.5); // Cast to to ensure that recreating from JSON, where // type information will have likely been lost, still works. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart index 65692bd2a385..2d1ae8314a94 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart @@ -12,12 +12,12 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); test('keyByMapsObjectId', () async { - final MapsObjectId id1 = MapsObjectId('1'); - final MapsObjectId id2 = MapsObjectId('2'); - final MapsObjectId id3 = MapsObjectId('3'); - final TestMapsObject object1 = TestMapsObject(id1); - final TestMapsObject object2 = TestMapsObject(id2, data: 2); - final TestMapsObject object3 = TestMapsObject(id3); + const MapsObjectId id1 = MapsObjectId('1'); + const MapsObjectId id2 = MapsObjectId('2'); + const MapsObjectId id3 = MapsObjectId('3'); + const TestMapsObject object1 = TestMapsObject(id1); + const TestMapsObject object2 = TestMapsObject(id2, data: 2); + const TestMapsObject object3 = TestMapsObject(id3); expect( keyByMapsObjectId({object1, object2, object3}), , TestMapsObject>{ @@ -28,12 +28,12 @@ void main() { }); test('serializeMapsObjectSet', () async { - final MapsObjectId id1 = MapsObjectId('1'); - final MapsObjectId id2 = MapsObjectId('2'); - final MapsObjectId id3 = MapsObjectId('3'); - final TestMapsObject object1 = TestMapsObject(id1); - final TestMapsObject object2 = TestMapsObject(id2, data: 2); - final TestMapsObject object3 = TestMapsObject(id3); + const MapsObjectId id1 = MapsObjectId('1'); + const MapsObjectId id2 = MapsObjectId('2'); + const MapsObjectId id3 = MapsObjectId('3'); + const TestMapsObject object1 = TestMapsObject(id1); + const TestMapsObject object2 = TestMapsObject(id2, data: 2); + const TestMapsObject object3 = TestMapsObject(id3); expect( serializeMapsObjectSet({object1, object2, object3}), >[ diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart index 68f4c587c2f2..673b3c63c59e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart @@ -6,9 +6,9 @@ import 'dart:ui' show hashValues, hashList; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:google_maps_flutter_platform_interface/src/types/utils/maps_object.dart'; -import 'package:google_maps_flutter_platform_interface/src/types/maps_object_updates.dart'; import 'package:google_maps_flutter_platform_interface/src/types/maps_object.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/maps_object_updates.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/utils/maps_object.dart'; import 'test_maps_object.dart'; @@ -23,15 +23,15 @@ void main() { group('tile overlay updates tests', () { test('Correctly set toRemove, toAdd and toChange', () async { - final TestMapsObject to1 = + const TestMapsObject to1 = TestMapsObject(MapsObjectId('id1')); - final TestMapsObject to2 = + const TestMapsObject to2 = TestMapsObject(MapsObjectId('id2')); - final TestMapsObject to3 = + const TestMapsObject to3 = TestMapsObject(MapsObjectId('id3')); - final TestMapsObject to3Changed = + const TestMapsObject to3Changed = TestMapsObject(MapsObjectId('id3'), data: 2); - final TestMapsObject to4 = + const TestMapsObject to4 = TestMapsObject(MapsObjectId('id4')); final Set previous = Set.from([to1, to2, to3]); @@ -40,8 +40,10 @@ void main() { final TestMapsObjectUpdate updates = TestMapsObjectUpdate.from(previous, current); - final Set> toRemove = Set.from( - >[MapsObjectId('id1')]); + final Set> toRemove = + Set.from(>[ + const MapsObjectId('id1') + ]); expect(updates.objectIdsToRemove, toRemove); final Set toAdd = Set.from([to4]); @@ -53,15 +55,15 @@ void main() { }); test('toJson', () async { - final TestMapsObject to1 = + const TestMapsObject to1 = TestMapsObject(MapsObjectId('id1')); - final TestMapsObject to2 = + const TestMapsObject to2 = TestMapsObject(MapsObjectId('id2')); - final TestMapsObject to3 = + const TestMapsObject to3 = TestMapsObject(MapsObjectId('id3')); - final TestMapsObject to3Changed = + const TestMapsObject to3Changed = TestMapsObject(MapsObjectId('id3'), data: 2); - final TestMapsObject to4 = + const TestMapsObject to4 = TestMapsObject(MapsObjectId('id4')); final Set previous = Set.from([to1, to2, to3]); @@ -81,15 +83,15 @@ void main() { }); test('equality', () async { - final TestMapsObject to1 = + const TestMapsObject to1 = TestMapsObject(MapsObjectId('id1')); - final TestMapsObject to2 = + const TestMapsObject to2 = TestMapsObject(MapsObjectId('id2')); - final TestMapsObject to3 = + const TestMapsObject to3 = TestMapsObject(MapsObjectId('id3')); - final TestMapsObject to3Changed = + const TestMapsObject to3Changed = TestMapsObject(MapsObjectId('id3'), data: 2); - final TestMapsObject to4 = + const TestMapsObject to4 = TestMapsObject(MapsObjectId('id4')); final Set previous = Set.from([to1, to2, to3]); @@ -109,15 +111,15 @@ void main() { }); test('hashCode', () async { - final TestMapsObject to1 = + const TestMapsObject to1 = TestMapsObject(MapsObjectId('id1')); - final TestMapsObject to2 = + const TestMapsObject to2 = TestMapsObject(MapsObjectId('id2')); - final TestMapsObject to3 = + const TestMapsObject to3 = TestMapsObject(MapsObjectId('id3')); - final TestMapsObject to3Changed = + const TestMapsObject to3Changed = TestMapsObject(MapsObjectId('id3'), data: 2); - final TestMapsObject to4 = + const TestMapsObject to4 = TestMapsObject(MapsObjectId('id4')); final Set previous = Set.from([to1, to2, to3]); @@ -134,15 +136,15 @@ void main() { }); test('toString', () async { - final TestMapsObject to1 = + const TestMapsObject to1 = TestMapsObject(MapsObjectId('id1')); - final TestMapsObject to2 = + const TestMapsObject to2 = TestMapsObject(MapsObjectId('id2')); - final TestMapsObject to3 = + const TestMapsObject to3 = TestMapsObject(MapsObjectId('id3')); - final TestMapsObject to3Changed = + const TestMapsObject to3Changed = TestMapsObject(MapsObjectId('id3'), data: 2); - final TestMapsObject to4 = + const TestMapsObject to4 = TestMapsObject(MapsObjectId('id4')); final Set previous = Set.from([to1, to2, to3]); diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart index e15c73f08a54..360d86617754 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart @@ -3,13 +3,14 @@ // found in the LICENSE file. import 'dart:ui' show hashValues; + import 'package:flutter/rendering.dart'; -import 'package:google_maps_flutter_platform_interface/src/types/maps_object_updates.dart'; import 'package:google_maps_flutter_platform_interface/src/types/maps_object.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/maps_object_updates.dart'; /// A trivial TestMapsObject implementation for testing updates with. class TestMapsObject implements MapsObject { - TestMapsObject(this.mapsId, {this.data = 1}); + const TestMapsObject(this.mapsId, {this.data = 1}); final MapsObjectId mapsId; diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart index 87380fdd651b..992438fafef1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:ui' show hashValues; + import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; @@ -11,22 +12,22 @@ void main() { group('tile overlay id tests', () { test('equality', () async { - final TileOverlayId id1 = TileOverlayId('1'); - final TileOverlayId id2 = TileOverlayId('1'); - final TileOverlayId id3 = TileOverlayId('2'); + const TileOverlayId id1 = TileOverlayId('1'); + const TileOverlayId id2 = TileOverlayId('1'); + const TileOverlayId id3 = TileOverlayId('2'); expect(id1, id2); expect(id1, isNot(id3)); }); test('toString', () async { - final TileOverlayId id1 = TileOverlayId('1'); + const TileOverlayId id1 = TileOverlayId('1'); expect(id1.toString(), 'TileOverlayId(1)'); }); }); group('tile overlay tests', () { test('toJson returns correct format', () async { - final TileOverlay tileOverlay = TileOverlay( + const TileOverlay tileOverlay = TileOverlay( tileOverlayId: TileOverlayId('id'), fadeIn: false, tileProvider: null, @@ -48,16 +49,16 @@ void main() { test('invalid transparency throws', () async { expect( () => TileOverlay( - tileOverlayId: TileOverlayId('id1'), transparency: -0.1), + tileOverlayId: const TileOverlayId('id1'), transparency: -0.1), throwsAssertionError); expect( () => TileOverlay( - tileOverlayId: TileOverlayId('id2'), transparency: 1.2), + tileOverlayId: const TileOverlayId('id2'), transparency: 1.2), throwsAssertionError); }); test('equality', () async { - final TileOverlay tileOverlay1 = TileOverlay( + const TileOverlay tileOverlay1 = TileOverlay( tileOverlayId: TileOverlayId('id1'), fadeIn: false, tileProvider: null, @@ -65,7 +66,7 @@ void main() { zIndex: 1, visible: false, tileSize: 128); - final TileOverlay tileOverlay2 = TileOverlay( + const TileOverlay tileOverlay2 = TileOverlay( tileOverlayId: TileOverlayId('id1'), fadeIn: false, tileProvider: null, @@ -73,7 +74,7 @@ void main() { zIndex: 1, visible: false, tileSize: 128); - final TileOverlay tileOverlay3 = TileOverlay( + const TileOverlay tileOverlay3 = TileOverlay( tileOverlayId: TileOverlayId('id2'), fadeIn: false, tileProvider: null, @@ -86,8 +87,8 @@ void main() { }); test('hashCode', () async { - TileOverlayId id = TileOverlayId('id1'); - final TileOverlay tileOverlay = TileOverlay( + const TileOverlayId id = TileOverlayId('id1'); + const TileOverlay tileOverlay = TileOverlay( tileOverlayId: id, fadeIn: false, tileProvider: null, diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart index f622ca5213ef..0db7d9d33324 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart @@ -3,22 +3,23 @@ // found in the LICENSE file. import 'dart:ui' show hashValues, hashList; + import 'package:flutter_test/flutter_test.dart'; -import 'package:google_maps_flutter_platform_interface/src/types/utils/tile_overlay.dart'; -import 'package:google_maps_flutter_platform_interface/src/types/tile_overlay_updates.dart'; import 'package:google_maps_flutter_platform_interface/src/types/tile_overlay.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/tile_overlay_updates.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/utils/tile_overlay.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('tile overlay updates tests', () { test('Correctly set toRemove, toAdd and toChange', () async { - final TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); - final TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); - final TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); - final TileOverlay to3Changed = + const TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); + const TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); + const TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); + const TileOverlay to3Changed = TileOverlay(tileOverlayId: TileOverlayId('id3'), transparency: 0.5); - final TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); + const TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); final Set previous = Set.from([to1, to2, to3]); final Set current = Set.from([to2, to3Changed, to4]); @@ -26,7 +27,7 @@ void main() { TileOverlayUpdates.from(previous, current); final Set toRemove = - Set.from([TileOverlayId('id1')]); + Set.from([const TileOverlayId('id1')]); expect(updates.tileOverlayIdsToRemove, toRemove); final Set toAdd = Set.from([to4]); @@ -37,12 +38,12 @@ void main() { }); test('toJson', () async { - final TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); - final TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); - final TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); - final TileOverlay to3Changed = + const TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); + const TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); + const TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); + const TileOverlay to3Changed = TileOverlay(tileOverlayId: TileOverlayId('id3'), transparency: 0.5); - final TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); + const TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); final Set previous = Set.from([to1, to2, to3]); final Set current = Set.from([to2, to3Changed, to4]); @@ -61,12 +62,12 @@ void main() { }); test('equality', () async { - final TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); - final TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); - final TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); - final TileOverlay to3Changed = + const TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); + const TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); + const TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); + const TileOverlay to3Changed = TileOverlay(tileOverlayId: TileOverlayId('id3'), transparency: 0.5); - final TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); + const TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); final Set previous = Set.from([to1, to2, to3]); final Set current1 = Set.from([to2, to3Changed, to4]); @@ -84,12 +85,12 @@ void main() { }); test('hashCode', () async { - final TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); - final TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); - final TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); - final TileOverlay to3Changed = + const TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); + const TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); + const TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); + const TileOverlay to3Changed = TileOverlay(tileOverlayId: TileOverlayId('id3'), transparency: 0.5); - final TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); + const TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); final Set previous = Set.from([to1, to2, to3]); final Set current = Set.from([to2, to3Changed, to4]); @@ -104,12 +105,12 @@ void main() { }); test('toString', () async { - final TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); - final TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); - final TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); - final TileOverlay to3Changed = + const TileOverlay to1 = TileOverlay(tileOverlayId: TileOverlayId('id1')); + const TileOverlay to2 = TileOverlay(tileOverlayId: TileOverlayId('id2')); + const TileOverlay to3 = TileOverlay(tileOverlayId: TileOverlayId('id3')); + const TileOverlay to3Changed = TileOverlay(tileOverlayId: TileOverlayId('id3'), transparency: 0.5); - final TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); + const TileOverlay to4 = TileOverlay(tileOverlayId: TileOverlayId('id4')); final Set previous = Set.from([to1, to2, to3]); final Set current = Set.from([to2, to3Changed, to4]); diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart index 3e0fe99ec18c..d985ac30136e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:typed_data'; + import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; @@ -22,7 +23,7 @@ void main() { }); test('toJson handles null data', () async { - final Tile tile = Tile(0, 0, null); + const Tile tile = Tile(0, 0, null); final Object json = tile.toJson(); expect(json, { 'width': 0, From d443a59b14ec654692b82bd5b05e75f45ca2cf55 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Wed, 17 Mar 2021 16:25:28 -0400 Subject: [PATCH 337/924] Prep for alignment with Flutter analysis options (#3703) Renames the old analysis_options.yaml to analysis_options_legacy.yaml, replacing it with a slightly modified copy of flutter/flutter's analysis options. Each plugins has a temporary local analysis_options.yaml that points to the legacy version. This allows for inceremental conversion on a per-plugin basis, which should make the problem more tractable. Since this hasn't yet been enabled for any packages, it's likely that as it is we'll find a few local modification we need to make to the root analysis_options (e.g., things that conflict with 'dart format'). Part of https://github.com/flutter/flutter/issues/76229 --- analysis_options.yaml | 242 +++++++++++++++++- analysis_options_legacy.yaml | 13 + .../analysis_options.yaml | 1 + packages/android_intent/analysis_options.yaml | 1 + packages/battery/analysis_options.yaml | 1 + packages/camera/analysis_options.yaml | 1 + packages/connectivity/analysis_options.yaml | 1 + packages/cross_file/analysis_options.yaml | 1 + packages/device_info/analysis_options.yaml | 1 + packages/e2e/analysis_options.yaml | 1 + packages/espresso/analysis_options.yaml | 1 + packages/file_selector/analysis_options.yaml | 1 + .../analysis_options.yaml | 1 + .../google_maps_flutter/analysis_options.yaml | 1 + packages/google_sign_in/analysis_options.yaml | 1 + packages/image_picker/analysis_options.yaml | 1 + .../in_app_purchase/analysis_options.yaml | 1 + .../integration_test/analysis_options.yaml | 1 + .../ios_platform_images/analysis_options.yaml | 1 + packages/local_auth/analysis_options.yaml | 1 + packages/package_info/analysis_options.yaml | 1 + packages/path_provider/analysis_options.yaml | 1 + .../analysis_options.yaml | 1 + packages/quick_actions/analysis_options.yaml | 1 + packages/sensors/analysis_options.yaml | 1 + packages/share/analysis_options.yaml | 1 + .../shared_preferences/analysis_options.yaml | 1 + packages/url_launcher/analysis_options.yaml | 1 + packages/video_player/analysis_options.yaml | 1 + .../webview_flutter/analysis_options.yaml | 1 + .../wifi_info_flutter/analysis_options.yaml | 1 + script/tool/analysis_options.yaml | 1 + 32 files changed, 280 insertions(+), 5 deletions(-) create mode 100644 analysis_options_legacy.yaml create mode 100644 packages/android_alarm_manager/analysis_options.yaml create mode 100644 packages/android_intent/analysis_options.yaml create mode 100644 packages/battery/analysis_options.yaml create mode 100644 packages/camera/analysis_options.yaml create mode 100644 packages/connectivity/analysis_options.yaml create mode 100644 packages/cross_file/analysis_options.yaml create mode 100644 packages/device_info/analysis_options.yaml create mode 100644 packages/e2e/analysis_options.yaml create mode 100644 packages/espresso/analysis_options.yaml create mode 100644 packages/file_selector/analysis_options.yaml create mode 100644 packages/flutter_plugin_android_lifecycle/analysis_options.yaml create mode 100644 packages/google_maps_flutter/analysis_options.yaml create mode 100644 packages/google_sign_in/analysis_options.yaml create mode 100644 packages/image_picker/analysis_options.yaml create mode 100644 packages/in_app_purchase/analysis_options.yaml create mode 100644 packages/integration_test/analysis_options.yaml create mode 100644 packages/ios_platform_images/analysis_options.yaml create mode 100644 packages/local_auth/analysis_options.yaml create mode 100644 packages/package_info/analysis_options.yaml create mode 100644 packages/path_provider/analysis_options.yaml create mode 100644 packages/plugin_platform_interface/analysis_options.yaml create mode 100644 packages/quick_actions/analysis_options.yaml create mode 100644 packages/sensors/analysis_options.yaml create mode 100644 packages/share/analysis_options.yaml create mode 100644 packages/shared_preferences/analysis_options.yaml create mode 100644 packages/url_launcher/analysis_options.yaml create mode 100644 packages/video_player/analysis_options.yaml create mode 100644 packages/webview_flutter/analysis_options.yaml create mode 100644 packages/wifi_info_flutter/analysis_options.yaml create mode 100644 script/tool/analysis_options.yaml diff --git a/analysis_options.yaml b/analysis_options.yaml index 2b62a6a9e2b9..858560e41e8a 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,13 +1,245 @@ -include: package:pedantic/analysis_options.1.8.0.yaml +# This is a copy (as of March 2021) of flutter/flutter's analysis_options file, +# with minimal changes for this repository. The goal is to move toward using a +# shared set of analysis options as much as possible, and eventually a shared +# file. +# +# Plugins that have not yet switched from the previous set of options have a +# local analysis_options.yaml that points to analysis_options_legacy.yaml +# instead. + +# Specify analysis options. +# +# Until there are meta linter rules, each desired lint must be explicitly enabled. +# See: https://github.com/dart-lang/linter/issues/288 +# +# 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 +# +# There are other similar analysis options files in the flutter repos, +# which should be kept in sync with this file: +# +# - analysis_options.yaml (this file) +# - packages/flutter/lib/analysis_options_user.yaml +# - https://github.com/flutter/plugins/blob/master/analysis_options.yaml +# - https://github.com/flutter/engine/blob/master/analysis_options.yaml +# +# This file contains the analysis options used by Flutter tools, such as IntelliJ, +# Android Studio, and the `flutter analyze` command. + analyzer: + strong-mode: + implicit-casts: false + 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 + # allow self-reference to deprecated members (we do this because otherwise we have + # to annotate every member in every test, assert, etc, when we deprecate something) + deprecated_member_use_from_same_package: ignore + # Ignore analyzer hints for updating pubspecs when using Future or + # Stream and not importing dart:async + # Please see https://github.com/flutter/flutter/pull/24528 for details. + sdk_version_async_exported_from_core: ignore + ### Local flutter/plugins changes ### + # Allow null checks for as long as mixed mode is officially supported. + unnecessary_null_comparison: false + always_require_non_null_named_parameters: false # not needed with nnbd exclude: # Ignore generated files - '**/*.g.dart' - 'lib/src/generated/*.dart' - '**/*.mocks.dart' # Mockito @GenerateMocks - errors: - always_require_non_null_named_parameters: false # not needed with nnbd - unnecessary_null_comparison: false # Turned as long as nnbd mix-mode is supported. + linter: rules: - - public_member_api_docs + # these rules are documented on and in the same order as + # the Dart Lint rules page to make maintenance easier + # https://github.com/dart-lang/linter/blob/master/example/all.yaml + - always_declare_return_types + - always_put_control_body_on_new_line + # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 + - always_require_non_null_named_parameters + - always_specify_types + # - always_use_package_imports # we do this commonly + - annotate_overrides + # - avoid_annotating_with_dynamic # conflicts with always_specify_types + # - avoid_as # required for implicit-casts: true + - avoid_bool_literals_in_conditional_expressions + # - avoid_catches_without_on_clauses # we do this commonly + # - avoid_catching_errors # we do this commonly + - avoid_classes_with_only_static_members + # - avoid_double_and_int_checks # only useful when targeting JS runtime + - avoid_empty_else + - avoid_equals_and_hash_code_on_mutable_classes + # - avoid_escaping_inner_quotes # not yet tested + - avoid_field_initializers_in_const_classes + - avoid_function_literals_in_foreach_calls + # - avoid_implementing_value_types # not yet tested + - avoid_init_to_null + # - avoid_js_rounded_ints # only useful when targeting JS runtime + - avoid_null_checks_in_equality_operators + # - avoid_positional_boolean_parameters # not yet tested + # - avoid_print # not yet tested + # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) + # - avoid_redundant_argument_values # not yet tested + - avoid_relative_lib_imports + - avoid_renaming_method_parameters + - avoid_return_types_on_setters + # - avoid_returning_null # there are plenty of valid reasons to return null + # - avoid_returning_null_for_future # not yet tested + - avoid_returning_null_for_void + # - avoid_returning_this # there are plenty of valid reasons to return this + # - avoid_setters_without_getters # not yet tested + - avoid_shadowing_type_parameters + - avoid_single_cascade_in_expression_statements + - avoid_slow_async_io + # - avoid_type_to_string # we do this commonly + - avoid_types_as_parameter_names + # - avoid_types_on_closure_parameters # conflicts with always_specify_types + # - avoid_unnecessary_containers # not yet tested + - avoid_unused_constructor_parameters + - avoid_void_async + # - avoid_web_libraries_in_flutter # not yet tested + - await_only_futures + - camel_case_extensions + - camel_case_types + - cancel_subscriptions + # - cascade_invocations # not yet tested + - cast_nullable_to_non_nullable + # - close_sinks # not reliable enough + # - comment_references # blocked on https://github.com/flutter/flutter/issues/20765 + # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 + - control_flow_in_finally + # - curly_braces_in_flow_control_structures # not required by flutter style + # - diagnostic_describe_all_properties # not yet tested + - directives_ordering + # - do_not_use_environment # we do this commonly + - empty_catches + - empty_constructor_bodies + - empty_statements + - exhaustive_cases + # - file_names # not yet tested + - flutter_style_todos + - hash_and_equals + - implementation_imports + # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 + - iterable_contains_unrelated_type + # - join_return_with_assignment # not required by flutter style + - leading_newlines_in_multiline_strings + - library_names + - library_prefixes + # - lines_longer_than_80_chars # not required by flutter style + - list_remove_unrelated_type + # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181 + # - missing_whitespace_between_adjacent_strings # not yet tested + - no_adjacent_strings_in_list + # - no_default_cases # too many false positives + - no_duplicate_case_values + - no_logic_in_create_state + # - no_runtimeType_toString # ok in tests; we enable this only in packages/ + - non_constant_identifier_names + - null_check_on_nullable_type_parameter + # - null_closures # not required by flutter style + # - 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_names # non conforming packages in sdk + - package_prefixed_library_names + # - parameter_assignments # we do this commonly + - prefer_adjacent_string_concatenation + - prefer_asserts_in_initializer_lists + # - prefer_asserts_with_message # not required by flutter style + - prefer_collection_literals + - prefer_conditional_assignment + - prefer_const_constructors + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + # - prefer_constructors_over_static_methods # far too many false positives + - prefer_contains + # - prefer_double_quotes # opposite of prefer_single_quotes + - prefer_equal_for_default_values + # - 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 + - prefer_final_in_for_each + - prefer_final_locals + - prefer_for_elements_to_map_fromIterable + - prefer_foreach + # - prefer_function_declarations_over_variables # not yet tested + - prefer_generic_function_type_aliases + - prefer_if_elements_to_conditional_expressions + - prefer_if_null_operators + - prefer_initializing_formals + - prefer_inlined_adds + # - prefer_int_literals # not yet tested + # - prefer_interpolation_to_compose_strings # not yet tested + - prefer_is_empty + - prefer_is_not_empty + - prefer_is_not_operator + - prefer_iterable_whereType + # - prefer_mixin # https://github.com/dart-lang/language/issues/32 + # - prefer_null_aware_operators # disable until NNBD, see https://github.com/flutter/flutter/pull/32711#issuecomment-492930932 + # - prefer_relative_imports # not yet tested + - prefer_single_quotes + - prefer_spread_collections + - prefer_typing_uninitialized_variables + - prefer_void_to_null + # - provide_deprecation_message # not yet tested + # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml + - recursive_getters + # - sized_box_for_whitespace # not yet tested + - slash_for_doc_comments + # - sort_child_properties_last # not yet tested + - sort_constructors_first + # - sort_pub_dependencies # prevents separating pinned transitive dependencies + - sort_unnamed_constructors_first + - test_types_in_equals + - throw_in_finally + - tighten_type_of_initializing_formals + # - type_annotate_public_apis # subset of always_specify_types + - type_init_formals + # - unawaited_futures # too many false positives + # - unnecessary_await_in_return # not yet tested + - unnecessary_brace_in_string_interps + - unnecessary_const + # - unnecessary_final # conflicts with prefer_final_locals + - unnecessary_getters_setters + # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 + - unnecessary_new + - unnecessary_null_aware_assignments + # - unnecessary_null_checks # not yet tested + - unnecessary_null_in_if_null_operators + - unnecessary_nullable_for_final_variable_declarations + - unnecessary_overrides + - unnecessary_parenthesis + # - unnecessary_raw_strings # not yet tested + - unnecessary_statements + - unnecessary_string_escapes + - unnecessary_string_interpolations + - unnecessary_this + - unrelated_type_equality_checks + # - unsafe_html # not yet tested + - use_full_hex_values_for_flutter_colors + # - use_function_type_syntax_for_parameters # not yet tested + - use_is_even_rather_than_modulo + # - use_key_in_widget_constructors # not yet tested + - use_late_for_private_fields_and_variables + - use_raw_strings + - use_rethrow_when_possible + # - use_setters_to_change_properties # not yet tested + # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 + # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review + - valid_regexps + - void_checks + ### Local flutter/plugins changes ### + # These are from flutter/flutter/packages, so will need to be preserved + # separately when moving to a shared file. + - no_runtimeType_toString # use objectRuntimeType from package:foundation + - public_member_api_docs # see https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#documentation-dartdocs-javadocs-etc diff --git a/analysis_options_legacy.yaml b/analysis_options_legacy.yaml new file mode 100644 index 000000000000..2b62a6a9e2b9 --- /dev/null +++ b/analysis_options_legacy.yaml @@ -0,0 +1,13 @@ +include: package:pedantic/analysis_options.1.8.0.yaml +analyzer: + exclude: + # Ignore generated files + - '**/*.g.dart' + - 'lib/src/generated/*.dart' + - '**/*.mocks.dart' # Mockito @GenerateMocks + errors: + always_require_non_null_named_parameters: false # not needed with nnbd + unnecessary_null_comparison: false # Turned as long as nnbd mix-mode is supported. +linter: + rules: + - public_member_api_docs diff --git a/packages/android_alarm_manager/analysis_options.yaml b/packages/android_alarm_manager/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/android_alarm_manager/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/android_intent/analysis_options.yaml b/packages/android_intent/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/android_intent/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/battery/analysis_options.yaml b/packages/battery/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/battery/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/camera/analysis_options.yaml b/packages/camera/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/camera/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/connectivity/analysis_options.yaml b/packages/connectivity/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/connectivity/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/cross_file/analysis_options.yaml b/packages/cross_file/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/cross_file/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/device_info/analysis_options.yaml b/packages/device_info/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/device_info/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/e2e/analysis_options.yaml b/packages/e2e/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/e2e/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/espresso/analysis_options.yaml b/packages/espresso/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/espresso/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/file_selector/analysis_options.yaml b/packages/file_selector/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/file_selector/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/flutter_plugin_android_lifecycle/analysis_options.yaml b/packages/flutter_plugin_android_lifecycle/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/flutter_plugin_android_lifecycle/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/google_maps_flutter/analysis_options.yaml b/packages/google_maps_flutter/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/google_maps_flutter/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/google_sign_in/analysis_options.yaml b/packages/google_sign_in/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/google_sign_in/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/image_picker/analysis_options.yaml b/packages/image_picker/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/image_picker/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/in_app_purchase/analysis_options.yaml b/packages/in_app_purchase/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/in_app_purchase/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/integration_test/analysis_options.yaml b/packages/integration_test/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/integration_test/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/ios_platform_images/analysis_options.yaml b/packages/ios_platform_images/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/ios_platform_images/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/local_auth/analysis_options.yaml b/packages/local_auth/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/local_auth/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/package_info/analysis_options.yaml b/packages/package_info/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/package_info/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/path_provider/analysis_options.yaml b/packages/path_provider/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/path_provider/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/plugin_platform_interface/analysis_options.yaml b/packages/plugin_platform_interface/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/plugin_platform_interface/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/quick_actions/analysis_options.yaml b/packages/quick_actions/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/quick_actions/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/sensors/analysis_options.yaml b/packages/sensors/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/sensors/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/share/analysis_options.yaml b/packages/share/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/share/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/shared_preferences/analysis_options.yaml b/packages/shared_preferences/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/shared_preferences/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/url_launcher/analysis_options.yaml b/packages/url_launcher/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/url_launcher/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/video_player/analysis_options.yaml b/packages/video_player/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/video_player/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/webview_flutter/analysis_options.yaml b/packages/webview_flutter/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/webview_flutter/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/packages/wifi_info_flutter/analysis_options.yaml b/packages/wifi_info_flutter/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/packages/wifi_info_flutter/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml diff --git a/script/tool/analysis_options.yaml b/script/tool/analysis_options.yaml new file mode 100644 index 000000000000..cda4f6e153e6 --- /dev/null +++ b/script/tool/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options_legacy.yaml From a8551330e9939da054b24db03f15337cae9af753 Mon Sep 17 00:00:00 2001 From: Guilherme Girotto Date: Thu, 18 Mar 2021 13:06:03 -0300 Subject: [PATCH 338/924] [google_sign_in] Adds support to send `clientId` as a parameter (#3640) --- .../google_sign_in/CHANGELOG.md | 5 +++++ .../googlesignin/GoogleSignInPlugin.java | 20 +++++++++++++++---- .../google_sign_in/example/lib/main.dart | 2 ++ .../ios/Classes/FLTGoogleSignInPlugin.m | 10 +++++++++- .../google_sign_in/pubspec.yaml | 4 ++-- .../test/google_sign_in_test.dart | 19 ++++++++++++++++++ 6 files changed, 53 insertions(+), 7 deletions(-) diff --git a/packages/google_sign_in/google_sign_in/CHANGELOG.md b/packages/google_sign_in/google_sign_in/CHANGELOG.md index 57d1c9be3743..429b07b47472 100644 --- a/packages/google_sign_in/google_sign_in/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in/CHANGELOG.md @@ -1,3 +1,8 @@ +## 5.0.1 + +* Update platforms `init` function to prioritize `clientId` property when available; +* Updates `google_sign_in_platform_interface` version. + ## 5.0.0 * Migrate to null safety. diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index f6673e5d5978..eb3a3d0d91ec 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -136,7 +136,8 @@ public void onMethodCall(MethodCall call, Result result) { String signInOption = call.argument("signInOption"); List requestedScopes = call.argument("scopes"); String hostedDomain = call.argument("hostedDomain"); - delegate.init(result, signInOption, requestedScopes, hostedDomain); + String clientId = call.argument("clientId"); + delegate.init(result, signInOption, requestedScopes, hostedDomain, clientId); break; case METHOD_SIGN_IN_SILENTLY: @@ -188,7 +189,11 @@ public void onMethodCall(MethodCall call, Result result) { public interface IDelegate { /** Initializes this delegate so that it is ready to perform other operations. */ public void init( - Result result, String signInOption, List requestedScopes, String hostedDomain); + Result result, + String signInOption, + List requestedScopes, + String hostedDomain, + String clientId); /** * Returns the account information for the user who is signed in to this app. If no user is @@ -309,7 +314,11 @@ private void checkAndSetPendingOperation(String method, Result result, Object da */ @Override public void init( - Result result, String signInOption, List requestedScopes, String hostedDomain) { + Result result, + String signInOption, + List requestedScopes, + String hostedDomain, + String clientId) { try { GoogleSignInOptions.Builder optionsBuilder; @@ -334,7 +343,10 @@ public void init( context .getResources() .getIdentifier("default_web_client_id", "string", context.getPackageName()); - if (clientIdIdentifier != 0) { + if (!Strings.isNullOrEmpty(clientId)) { + optionsBuilder.requestIdToken(clientId); + optionsBuilder.requestServerAuthCode(clientId); + } else if (clientIdIdentifier != 0) { optionsBuilder.requestIdToken(context.getString(clientIdIdentifier)); optionsBuilder.requestServerAuthCode(context.getString(clientIdIdentifier)); } diff --git a/packages/google_sign_in/google_sign_in/example/lib/main.dart b/packages/google_sign_in/google_sign_in/example/lib/main.dart index e003225af5cc..c87063297373 100755 --- a/packages/google_sign_in/google_sign_in/example/lib/main.dart +++ b/packages/google_sign_in/google_sign_in/example/lib/main.dart @@ -12,6 +12,8 @@ import 'package:flutter/material.dart'; import 'package:google_sign_in/google_sign_in.dart'; GoogleSignIn _googleSignIn = GoogleSignIn( + // Optional clientId + // clientId: '479882132969-9i9aqik3jfjd7qhci1nqf0bm2g71rm1u.apps.googleusercontent.com', scopes: [ 'email', 'https://www.googleapis.com/auth/contacts.readonly', diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index 660a32272f84..fdc6e31e9291 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -77,7 +77,15 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result ofType:@"plist"]; if (path) { NSMutableDictionary *plist = [[NSMutableDictionary alloc] initWithContentsOfFile:path]; - [GIDSignIn sharedInstance].clientID = plist[kClientIdKey]; + BOOL hasDynamicClientId = + [[call.arguments valueForKey:@"clientId"] isKindOfClass:[NSString class]]; + + if (hasDynamicClientId) { + [GIDSignIn sharedInstance].clientID = [call.arguments valueForKey:@"clientId"]; + } else { + [GIDSignIn sharedInstance].clientID = plist[kClientIdKey]; + } + [GIDSignIn sharedInstance].serverClientID = plist[kServerClientIdKey]; [GIDSignIn sharedInstance].scopes = call.arguments[@"scopes"]; [GIDSignIn sharedInstance].hostedDomain = call.arguments[@"hostedDomain"]; diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index 06fa12c0f4c0..23f2588c8f90 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in/google_sign_in -version: 5.0.0 +version: 5.0.1 flutter: plugin: @@ -16,7 +16,7 @@ flutter: default_package: google_sign_in_web dependencies: - google_sign_in_platform_interface: ^2.0.0 + google_sign_in_platform_interface: ^2.0.1 google_sign_in_web: ^0.10.0 flutter: sdk: flutter diff --git a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart index 79fa74ad1be1..4eb45a5dc38e 100755 --- a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart @@ -82,6 +82,25 @@ void main() { ); }); + test('signIn prioritize clientId parameter when available', () async { + final fakeClientId = 'fakeClientId'; + googleSignIn = GoogleSignIn(clientId: fakeClientId); + await googleSignIn.signIn(); + expect(googleSignIn.currentUser, isNotNull); + expect( + log, + [ + isMethodCall('init', arguments: { + 'signInOption': 'SignInOption.standard', + 'scopes': [], + 'hostedDomain': null, + 'clientId': fakeClientId, + }), + isMethodCall('signIn', arguments: null), + ], + ); + }); + test('signOut', () async { await googleSignIn.signOut(); expect(googleSignIn.currentUser, isNull); From c870bbb97057bb2a95a9d905d9a7d34fe5ca46ba Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 18 Mar 2021 13:00:10 -0400 Subject: [PATCH 339/924] Add an AUTHORS file to each plugin (#3725) This ensures that the AUTHORS list is distributed with the plugins whose copyright blocks refer to the project authors, for ease of reference. This is currently a copy of the top-level authors list, but over time they are expected to diverge as people contribute to specific plugins. This does not bump plugin versions or CHANGLELOGs, since it has no effect on the plugin itself; it will be picked up over time as we ship new versions of plugins. Part of https://github.com/flutter/flutter/issues/78448 --- CONTRIBUTING.md | 5 +- packages/android_alarm_manager/AUTHORS | 65 +++++++++++++++++++ packages/android_intent/AUTHORS | 65 +++++++++++++++++++ packages/battery/battery/AUTHORS | 65 +++++++++++++++++++ .../battery_platform_interface/AUTHORS | 65 +++++++++++++++++++ packages/camera/camera/AUTHORS | 65 +++++++++++++++++++ .../camera/camera_platform_interface/AUTHORS | 65 +++++++++++++++++++ packages/connectivity/connectivity/AUTHORS | 65 +++++++++++++++++++ .../connectivity/connectivity_for_web/AUTHORS | 65 +++++++++++++++++++ .../connectivity/connectivity_macos/AUTHORS | 65 +++++++++++++++++++ .../connectivity_platform_interface/AUTHORS | 65 +++++++++++++++++++ packages/device_info/device_info/AUTHORS | 65 +++++++++++++++++++ .../device_info_platform_interface/AUTHORS | 65 +++++++++++++++++++ packages/espresso/AUTHORS | 65 +++++++++++++++++++ packages/file_selector/file_selector/AUTHORS | 65 +++++++++++++++++++ .../file_selector_platform_interface/AUTHORS | 65 +++++++++++++++++++ .../file_selector/file_selector_web/AUTHORS | 65 +++++++++++++++++++ .../flutter_plugin_android_lifecycle/AUTHORS | 65 +++++++++++++++++++ .../google_maps_flutter/AUTHORS | 65 +++++++++++++++++++ .../AUTHORS | 65 +++++++++++++++++++ .../google_maps_flutter_web/AUTHORS | 65 +++++++++++++++++++ .../google_sign_in/google_sign_in/AUTHORS | 65 +++++++++++++++++++ .../google_sign_in_platform_interface/AUTHORS | 65 +++++++++++++++++++ .../google_sign_in/google_sign_in_web/AUTHORS | 65 +++++++++++++++++++ packages/image_picker/image_picker/AUTHORS | 65 +++++++++++++++++++ .../image_picker/image_picker_for_web/AUTHORS | 65 +++++++++++++++++++ .../image_picker_platform_interface/AUTHORS | 65 +++++++++++++++++++ packages/in_app_purchase/AUTHORS | 65 +++++++++++++++++++ packages/integration_test/AUTHORS | 65 +++++++++++++++++++ packages/ios_platform_images/AUTHORS | 65 +++++++++++++++++++ packages/local_auth/AUTHORS | 65 +++++++++++++++++++ packages/package_info/AUTHORS | 65 +++++++++++++++++++ packages/path_provider/path_provider/AUTHORS | 65 +++++++++++++++++++ .../path_provider/path_provider_linux/AUTHORS | 65 +++++++++++++++++++ .../path_provider/path_provider_macos/AUTHORS | 65 +++++++++++++++++++ .../path_provider_platform_interface/AUTHORS | 65 +++++++++++++++++++ .../path_provider_windows/AUTHORS | 65 +++++++++++++++++++ packages/plugin_platform_interface/AUTHORS | 65 +++++++++++++++++++ packages/quick_actions/AUTHORS | 65 +++++++++++++++++++ packages/sensors/AUTHORS | 65 +++++++++++++++++++ packages/share/AUTHORS | 65 +++++++++++++++++++ .../shared_preferences/AUTHORS | 65 +++++++++++++++++++ .../shared_preferences_linux/AUTHORS | 65 +++++++++++++++++++ .../shared_preferences_macos/AUTHORS | 65 +++++++++++++++++++ .../AUTHORS | 65 +++++++++++++++++++ .../shared_preferences_web/AUTHORS | 65 +++++++++++++++++++ .../shared_preferences_windows/AUTHORS | 65 +++++++++++++++++++ .../example/AUTHORS | 65 +++++++++++++++++++ packages/url_launcher/url_launcher/AUTHORS | 65 +++++++++++++++++++ .../url_launcher/url_launcher_linux/AUTHORS | 65 +++++++++++++++++++ .../url_launcher/url_launcher_macos/AUTHORS | 65 +++++++++++++++++++ .../url_launcher_platform_interface/AUTHORS | 65 +++++++++++++++++++ .../url_launcher/url_launcher_web/AUTHORS | 65 +++++++++++++++++++ .../src/third_party/platform_detect/AUTHORS | 65 +++++++++++++++++++ .../url_launcher/url_launcher_windows/AUTHORS | 65 +++++++++++++++++++ packages/video_player/video_player/AUTHORS | 65 +++++++++++++++++++ .../video_player_platform_interface/AUTHORS | 65 +++++++++++++++++++ .../video_player/video_player_web/AUTHORS | 65 +++++++++++++++++++ packages/webview_flutter/AUTHORS | 65 +++++++++++++++++++ .../wifi_info_flutter/AUTHORS | 65 +++++++++++++++++++ .../AUTHORS | 65 +++++++++++++++++++ 61 files changed, 3903 insertions(+), 2 deletions(-) create mode 100644 packages/android_alarm_manager/AUTHORS create mode 100644 packages/android_intent/AUTHORS create mode 100644 packages/battery/battery/AUTHORS create mode 100644 packages/battery/battery_platform_interface/AUTHORS create mode 100644 packages/camera/camera/AUTHORS create mode 100644 packages/camera/camera_platform_interface/AUTHORS create mode 100644 packages/connectivity/connectivity/AUTHORS create mode 100644 packages/connectivity/connectivity_for_web/AUTHORS create mode 100644 packages/connectivity/connectivity_macos/AUTHORS create mode 100644 packages/connectivity/connectivity_platform_interface/AUTHORS create mode 100644 packages/device_info/device_info/AUTHORS create mode 100644 packages/device_info/device_info_platform_interface/AUTHORS create mode 100644 packages/espresso/AUTHORS create mode 100644 packages/file_selector/file_selector/AUTHORS create mode 100644 packages/file_selector/file_selector_platform_interface/AUTHORS create mode 100644 packages/file_selector/file_selector_web/AUTHORS create mode 100644 packages/flutter_plugin_android_lifecycle/AUTHORS create mode 100644 packages/google_maps_flutter/google_maps_flutter/AUTHORS create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/AUTHORS create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/AUTHORS create mode 100644 packages/google_sign_in/google_sign_in/AUTHORS create mode 100644 packages/google_sign_in/google_sign_in_platform_interface/AUTHORS create mode 100644 packages/google_sign_in/google_sign_in_web/AUTHORS create mode 100644 packages/image_picker/image_picker/AUTHORS create mode 100644 packages/image_picker/image_picker_for_web/AUTHORS create mode 100644 packages/image_picker/image_picker_platform_interface/AUTHORS create mode 100644 packages/in_app_purchase/AUTHORS create mode 100644 packages/integration_test/AUTHORS create mode 100644 packages/ios_platform_images/AUTHORS create mode 100644 packages/local_auth/AUTHORS create mode 100644 packages/package_info/AUTHORS create mode 100644 packages/path_provider/path_provider/AUTHORS create mode 100644 packages/path_provider/path_provider_linux/AUTHORS create mode 100644 packages/path_provider/path_provider_macos/AUTHORS create mode 100644 packages/path_provider/path_provider_platform_interface/AUTHORS create mode 100644 packages/path_provider/path_provider_windows/AUTHORS create mode 100644 packages/plugin_platform_interface/AUTHORS create mode 100644 packages/quick_actions/AUTHORS create mode 100644 packages/sensors/AUTHORS create mode 100644 packages/share/AUTHORS create mode 100644 packages/shared_preferences/shared_preferences/AUTHORS create mode 100644 packages/shared_preferences/shared_preferences_linux/AUTHORS create mode 100644 packages/shared_preferences/shared_preferences_macos/AUTHORS create mode 100644 packages/shared_preferences/shared_preferences_platform_interface/AUTHORS create mode 100644 packages/shared_preferences/shared_preferences_web/AUTHORS create mode 100644 packages/shared_preferences/shared_preferences_windows/AUTHORS create mode 100644 packages/shared_preferences/shared_preferences_windows/example/AUTHORS create mode 100644 packages/url_launcher/url_launcher/AUTHORS create mode 100644 packages/url_launcher/url_launcher_linux/AUTHORS create mode 100644 packages/url_launcher/url_launcher_macos/AUTHORS create mode 100644 packages/url_launcher/url_launcher_platform_interface/AUTHORS create mode 100644 packages/url_launcher/url_launcher_web/AUTHORS create mode 100644 packages/url_launcher/url_launcher_web/lib/src/third_party/platform_detect/AUTHORS create mode 100644 packages/url_launcher/url_launcher_windows/AUTHORS create mode 100644 packages/video_player/video_player/AUTHORS create mode 100644 packages/video_player/video_player_platform_interface/AUTHORS create mode 100644 packages/video_player/video_player_web/AUTHORS create mode 100644 packages/webview_flutter/AUTHORS create mode 100644 packages/wifi_info_flutter/wifi_info_flutter/AUTHORS create mode 100644 packages/wifi_info_flutter/wifi_info_flutter_platform_interface/AUTHORS diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a8a9ec5522f..d5ea4766b363 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -188,8 +188,9 @@ to merge the pull request and `pub submit` any affected packages. You must complete the [Contributor License Agreement](https://cla.developers.google.com/clas). You can do this online, and it only takes a minute. -If you've never submitted code before, you must add your (or your -organization's) name and contact info to the [AUTHORS](AUTHORS) file. +If you've never submitted code for that plugin before, you may also add your (or +your organization's) name and contact info to the AUTHORS file for the plugin. +You may also add it to the AUTHORS file for [the repository](AUTHORS). ### The review process diff --git a/packages/android_alarm_manager/AUTHORS b/packages/android_alarm_manager/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/android_alarm_manager/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/android_intent/AUTHORS b/packages/android_intent/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/android_intent/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/battery/battery/AUTHORS b/packages/battery/battery/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/battery/battery/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/battery/battery_platform_interface/AUTHORS b/packages/battery/battery_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/battery/battery_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/camera/camera/AUTHORS b/packages/camera/camera/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/camera/camera/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/camera/camera_platform_interface/AUTHORS b/packages/camera/camera_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/camera/camera_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/connectivity/connectivity/AUTHORS b/packages/connectivity/connectivity/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/connectivity/connectivity/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/connectivity/connectivity_for_web/AUTHORS b/packages/connectivity/connectivity_for_web/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/connectivity/connectivity_for_web/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/connectivity/connectivity_macos/AUTHORS b/packages/connectivity/connectivity_macos/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/connectivity/connectivity_macos/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/connectivity/connectivity_platform_interface/AUTHORS b/packages/connectivity/connectivity_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/connectivity/connectivity_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/device_info/device_info/AUTHORS b/packages/device_info/device_info/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/device_info/device_info/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/device_info/device_info_platform_interface/AUTHORS b/packages/device_info/device_info_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/device_info/device_info_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/espresso/AUTHORS b/packages/espresso/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/espresso/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/file_selector/file_selector/AUTHORS b/packages/file_selector/file_selector/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/file_selector/file_selector/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/file_selector/file_selector_platform_interface/AUTHORS b/packages/file_selector/file_selector_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/file_selector/file_selector_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/file_selector/file_selector_web/AUTHORS b/packages/file_selector/file_selector_web/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/file_selector/file_selector_web/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/flutter_plugin_android_lifecycle/AUTHORS b/packages/flutter_plugin_android_lifecycle/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/flutter_plugin_android_lifecycle/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/google_maps_flutter/google_maps_flutter/AUTHORS b/packages/google_maps_flutter/google_maps_flutter/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/AUTHORS b/packages/google_maps_flutter/google_maps_flutter_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/google_maps_flutter/google_maps_flutter_web/AUTHORS b/packages/google_maps_flutter/google_maps_flutter_web/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/google_sign_in/google_sign_in/AUTHORS b/packages/google_sign_in/google_sign_in/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/google_sign_in/google_sign_in/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/google_sign_in/google_sign_in_platform_interface/AUTHORS b/packages/google_sign_in/google_sign_in_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/google_sign_in/google_sign_in_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/google_sign_in/google_sign_in_web/AUTHORS b/packages/google_sign_in/google_sign_in_web/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/google_sign_in/google_sign_in_web/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/image_picker/image_picker/AUTHORS b/packages/image_picker/image_picker/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/image_picker/image_picker/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/image_picker/image_picker_for_web/AUTHORS b/packages/image_picker/image_picker_for_web/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/image_picker/image_picker_for_web/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/image_picker/image_picker_platform_interface/AUTHORS b/packages/image_picker/image_picker_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/image_picker/image_picker_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/in_app_purchase/AUTHORS b/packages/in_app_purchase/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/in_app_purchase/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/integration_test/AUTHORS b/packages/integration_test/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/integration_test/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/ios_platform_images/AUTHORS b/packages/ios_platform_images/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/ios_platform_images/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/local_auth/AUTHORS b/packages/local_auth/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/local_auth/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/package_info/AUTHORS b/packages/package_info/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/package_info/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/path_provider/path_provider/AUTHORS b/packages/path_provider/path_provider/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/path_provider/path_provider/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/path_provider/path_provider_linux/AUTHORS b/packages/path_provider/path_provider_linux/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/path_provider/path_provider_linux/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/path_provider/path_provider_macos/AUTHORS b/packages/path_provider/path_provider_macos/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/path_provider/path_provider_macos/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/path_provider/path_provider_platform_interface/AUTHORS b/packages/path_provider/path_provider_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/path_provider/path_provider_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/path_provider/path_provider_windows/AUTHORS b/packages/path_provider/path_provider_windows/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/path_provider/path_provider_windows/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/plugin_platform_interface/AUTHORS b/packages/plugin_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/plugin_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/quick_actions/AUTHORS b/packages/quick_actions/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/quick_actions/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/sensors/AUTHORS b/packages/sensors/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/sensors/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/share/AUTHORS b/packages/share/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/share/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/shared_preferences/shared_preferences/AUTHORS b/packages/shared_preferences/shared_preferences/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/shared_preferences/shared_preferences/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/shared_preferences/shared_preferences_linux/AUTHORS b/packages/shared_preferences/shared_preferences_linux/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/shared_preferences/shared_preferences_linux/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/shared_preferences/shared_preferences_macos/AUTHORS b/packages/shared_preferences/shared_preferences_macos/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/shared_preferences/shared_preferences_macos/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/shared_preferences/shared_preferences_platform_interface/AUTHORS b/packages/shared_preferences/shared_preferences_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/shared_preferences/shared_preferences_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/shared_preferences/shared_preferences_web/AUTHORS b/packages/shared_preferences/shared_preferences_web/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/shared_preferences/shared_preferences_web/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/shared_preferences/shared_preferences_windows/AUTHORS b/packages/shared_preferences/shared_preferences_windows/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/shared_preferences/shared_preferences_windows/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/shared_preferences/shared_preferences_windows/example/AUTHORS b/packages/shared_preferences/shared_preferences_windows/example/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/shared_preferences/shared_preferences_windows/example/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/url_launcher/url_launcher/AUTHORS b/packages/url_launcher/url_launcher/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/url_launcher/url_launcher/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/url_launcher/url_launcher_linux/AUTHORS b/packages/url_launcher/url_launcher_linux/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/url_launcher/url_launcher_linux/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/url_launcher/url_launcher_macos/AUTHORS b/packages/url_launcher/url_launcher_macos/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/url_launcher/url_launcher_macos/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/url_launcher/url_launcher_platform_interface/AUTHORS b/packages/url_launcher/url_launcher_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/url_launcher/url_launcher_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/url_launcher/url_launcher_web/AUTHORS b/packages/url_launcher/url_launcher_web/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/url_launcher/url_launcher_web/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/url_launcher/url_launcher_web/lib/src/third_party/platform_detect/AUTHORS b/packages/url_launcher/url_launcher_web/lib/src/third_party/platform_detect/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/url_launcher/url_launcher_web/lib/src/third_party/platform_detect/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/url_launcher/url_launcher_windows/AUTHORS b/packages/url_launcher/url_launcher_windows/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/url_launcher/url_launcher_windows/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/video_player/video_player/AUTHORS b/packages/video_player/video_player/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/video_player/video_player/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/video_player/video_player_platform_interface/AUTHORS b/packages/video_player/video_player_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/video_player/video_player_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/video_player/video_player_web/AUTHORS b/packages/video_player/video_player_web/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/video_player/video_player_web/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/webview_flutter/AUTHORS b/packages/webview_flutter/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/webview_flutter/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/wifi_info_flutter/wifi_info_flutter/AUTHORS b/packages/wifi_info_flutter/wifi_info_flutter/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/wifi_info_flutter/wifi_info_flutter/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/AUTHORS b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/AUTHORS new file mode 100644 index 000000000000..dbf9d190931b --- /dev/null +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/AUTHORS @@ -0,0 +1,65 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> From 6047b3f1bbb970d748bd5b213f5d0c206a0c2da8 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 18 Mar 2021 13:28:44 -0700 Subject: [PATCH 340/924] Fix cosmetic variations in copyrights and license files (#3730) - Replaces "the Flutter project authors" with the repo-standard version "The Flutter Authors" - Updates the license check not to allow "the Flutter project authors" in the future - Fixes a few minor cosmetic variations that had crept back into LICENSE files since my mass-standardization of those files. - Updates the license check to validate those to prevent such drift in the future. --- .../connectivity/connectivity_for_web/LICENSE | 2 +- packages/file_selector/file_selector/LICENSE | 2 +- .../file_selector_platform_interface/LICENSE | 2 +- .../file_selector/file_selector_web/LICENSE | 2 +- .../google_maps_flutter_web/LICENSE | 2 +- .../google_sign_in/google_sign_in/LICENSE | 2 +- .../googlesignin/BackgroundTaskRunner.java | 2 +- .../plugins/googlesignin/Executors.java | 2 +- .../googlesignin/GoogleSignInPlugin.java | 2 +- .../googlesignin/GoogleSignInWrapper.java | 2 +- .../integration_test/google_sign_in_test.dart | 2 +- .../ios/Classes/FLTGoogleSignInPlugin.h | 2 +- .../ios/Classes/FLTGoogleSignInPlugin.m | 2 +- .../google_sign_in/lib/google_sign_in.dart | 2 +- .../google_sign_in/lib/src/common.dart | 2 +- .../google_sign_in/lib/widgets.dart | 2 +- .../google_sign_in/google_sign_in_web/LICENSE | 2 +- .../test/tests_exist_elsewhere_test.dart | 2 +- packages/image_picker/image_picker/LICENSE | 2 +- packages/path_provider/path_provider/LICENSE | 2 +- packages/share/LICENSE | 2 +- .../shared_preferences_macos/LICENSE | 2 +- .../shared_preferences_windows/LICENSE | 52 ++++---- .../example/LICENSE | 52 ++++---- .../tool/lib/src/license_check_command.dart | 86 ++++++++++-- .../tool/test/license_check_command_test.dart | 123 ++++++++++++++++-- 26 files changed, 263 insertions(+), 94 deletions(-) diff --git a/packages/connectivity/connectivity_for_web/LICENSE b/packages/connectivity/connectivity_for_web/LICENSE index 26351460d9de..1d7bbaf70add 100644 --- a/packages/connectivity/connectivity_for_web/LICENSE +++ b/packages/connectivity/connectivity_for_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2016, the Flutter project authors. All rights reserved. +Copyright 2016 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/file_selector/file_selector/LICENSE b/packages/file_selector/file_selector/LICENSE index 2c91f1438173..67c7e2c52e46 100644 --- a/packages/file_selector/file_selector/LICENSE +++ b/packages/file_selector/file_selector/LICENSE @@ -22,4 +22,4 @@ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/file_selector/file_selector_platform_interface/LICENSE b/packages/file_selector/file_selector_platform_interface/LICENSE index 2c91f1438173..67c7e2c52e46 100644 --- a/packages/file_selector/file_selector_platform_interface/LICENSE +++ b/packages/file_selector/file_selector_platform_interface/LICENSE @@ -22,4 +22,4 @@ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/file_selector/file_selector_web/LICENSE b/packages/file_selector/file_selector_web/LICENSE index 2c91f1438173..67c7e2c52e46 100644 --- a/packages/file_selector/file_selector_web/LICENSE +++ b/packages/file_selector/file_selector_web/LICENSE @@ -22,4 +22,4 @@ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/LICENSE b/packages/google_maps_flutter/google_maps_flutter_web/LICENSE index 447867e0637e..bb6f2c07756f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/LICENSE +++ b/packages/google_maps_flutter/google_maps_flutter_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017, the Flutter project authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_sign_in/google_sign_in/LICENSE b/packages/google_sign_in/google_sign_in/LICENSE index 26351460d9de..1d7bbaf70add 100644 --- a/packages/google_sign_in/google_sign_in/LICENSE +++ b/packages/google_sign_in/google_sign_in/LICENSE @@ -1,4 +1,4 @@ -Copyright 2016, the Flutter project authors. All rights reserved. +Copyright 2016 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java index e667be2aa0f9..95bc0153e41a 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java @@ -1,4 +1,4 @@ -// Copyright 2017, the Flutter project authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java index 80b9d187d939..008a33c30052 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java @@ -1,4 +1,4 @@ -// Copyright 2017, the Flutter project authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index eb3a3d0d91ec..351ed731cccd 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017, the Flutter project authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java index 100069080bb4..3c84968f986c 100644 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java @@ -1,4 +1,4 @@ -// Copyright 2020, the Flutter project authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart index 86423507fffc..d3896b57174c 100644 --- a/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017, the Flutter project authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h index f9d7f322a2e3..6447e9243483 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017, the Flutter project authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index fdc6e31e9291..23584fd36922 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017, the Flutter project authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart index f803f96f85ed..2e094a8b1575 100644 --- a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart @@ -1,4 +1,4 @@ -// Copyright 2017, the Flutter project authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/lib/src/common.dart b/packages/google_sign_in/google_sign_in/lib/src/common.dart index f9aaf199b899..e341a27a740d 100644 --- a/packages/google_sign_in/google_sign_in/lib/src/common.dart +++ b/packages/google_sign_in/google_sign_in/lib/src/common.dart @@ -1,4 +1,4 @@ -// Copyright 2017, the Flutter project authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/lib/widgets.dart b/packages/google_sign_in/google_sign_in/lib/widgets.dart index f47e78fde2b2..c3537ab90394 100644 --- a/packages/google_sign_in/google_sign_in/lib/widgets.dart +++ b/packages/google_sign_in/google_sign_in/lib/widgets.dart @@ -1,4 +1,4 @@ -// Copyright 2017, the Flutter project authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in_web/LICENSE b/packages/google_sign_in/google_sign_in_web/LICENSE index 26351460d9de..1d7bbaf70add 100644 --- a/packages/google_sign_in/google_sign_in_web/LICENSE +++ b/packages/google_sign_in/google_sign_in_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2016, the Flutter project authors. All rights reserved. +Copyright 2016 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart b/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart index d6a165667707..64d8e547e485 100644 --- a/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart +++ b/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Flutter project authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/LICENSE b/packages/image_picker/image_picker/LICENSE index c4e4de2acfcd..7cd0a6f3b98f 100644 --- a/packages/image_picker/image_picker/LICENSE +++ b/packages/image_picker/image_picker/LICENSE @@ -1,6 +1,6 @@ image_picker -Copyright 2017, the Flutter project authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/path_provider/path_provider/LICENSE b/packages/path_provider/path_provider/LICENSE index 447867e0637e..bb6f2c07756f 100644 --- a/packages/path_provider/path_provider/LICENSE +++ b/packages/path_provider/path_provider/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017, the Flutter project authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/share/LICENSE b/packages/share/LICENSE index 447867e0637e..bb6f2c07756f 100644 --- a/packages/share/LICENSE +++ b/packages/share/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017, the Flutter project authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_macos/LICENSE b/packages/shared_preferences/shared_preferences_macos/LICENSE index 447867e0637e..bb6f2c07756f 100644 --- a/packages/shared_preferences/shared_preferences_macos/LICENSE +++ b/packages/shared_preferences/shared_preferences_macos/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017, the Flutter project authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_windows/LICENSE b/packages/shared_preferences/shared_preferences_windows/LICENSE index c89293372cf3..a6d6c0749818 100644 --- a/packages/shared_preferences/shared_preferences_windows/LICENSE +++ b/packages/shared_preferences/shared_preferences_windows/LICENSE @@ -1,27 +1,25 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Copyright 2017 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/shared_preferences/shared_preferences_windows/example/LICENSE b/packages/shared_preferences/shared_preferences_windows/example/LICENSE index c89293372cf3..a6d6c0749818 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/LICENSE +++ b/packages/shared_preferences/shared_preferences_windows/example/LICENSE @@ -1,27 +1,25 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Copyright 2017 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/script/tool/lib/src/license_check_command.dart b/script/tool/lib/src/license_check_command.dart index 4e0e5931d3ee..e70e60b154d9 100644 --- a/script/tool/lib/src/license_check_command.dart +++ b/script/tool/lib/src/license_check_command.dart @@ -66,9 +66,40 @@ final List _firstPartyAuthors = [ 'The Chromium Authors', 'the Chromium project authors', 'The Flutter Authors', - 'the Flutter project authors', ]; +// The exact format of the BSD license that our license files should contain. +// Slight variants are not accepted because they may prevent consolidation in +// tools that assemble all licenses used in distributed applications. +// +// TODO(stuartmorgan): Add the copyright string here once that's completely +// standardized. +final String _fullBsdLicenseText = ''' +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +'''; + /// Validates that code files have copyright and license blocks. class LicenseCheckCommand extends PluginCommand { /// Creates a new license check command for [packagesDir]. @@ -90,13 +121,19 @@ class LicenseCheckCommand extends PluginCommand { @override Future run() async { - Iterable codeFiles = (await _getAllFiles()).where((File file) => + final Iterable codeFiles = (await _getAllFiles()).where((File file) => _codeFileExtensions.contains(p.extension(file.path)) && !_shouldIgnoreFile(file)); + final Iterable firstPartyLicenseFiles = (await _getAllFiles()).where( + (File file) => + p.basename(file.basename) == 'LICENSE' && !_isThirdParty(file)); - bool succeeded = await _checkLicenses(codeFiles); + final bool copyrightCheckSucceeded = await _checkCodeLicenses(codeFiles); + print('\n=======================================\n'); + final bool licenseCheckSucceeded = + await _checkLicenseFiles(firstPartyLicenseFiles); - if (!succeeded) { + if (!copyrightCheckSucceeded || !licenseCheckSucceeded) { throw ToolExit(1); } } @@ -110,7 +147,7 @@ class LicenseCheckCommand extends PluginCommand { // Checks all license blocks for [codeFiles], returning false if any of them // fail validation. - Future _checkLicenses(Iterable codeFiles) async { + Future _checkCodeLicenses(Iterable codeFiles) async { final List filesWithoutDetectedCopyright = []; final List filesWithoutDetectedLicense = []; final List misplacedThirdPartyFiles = []; @@ -133,8 +170,7 @@ class LicenseCheckCommand extends PluginCommand { continue; } final String author = copyright.group(1); - if (!_firstPartyAuthors.contains(author) && - !p.split(file.path).contains('third_party')) { + if (!_firstPartyAuthors.contains(author) && !_isThirdParty(file)) { misplacedThirdPartyFiles.add(file); } @@ -146,7 +182,7 @@ class LicenseCheckCommand extends PluginCommand { filesWithoutDetectedLicense.add(file); } } - _print('\n\n'); + _print('\n'); // Sort by path for more usable output. final pathCompare = (File a, File b) => a.path.compareTo(b.path); @@ -188,7 +224,35 @@ class LicenseCheckCommand extends PluginCommand { filesWithoutDetectedLicense.isEmpty && misplacedThirdPartyFiles.isEmpty; if (succeeded) { - _print('All files passed validation!'); + _print('All source files passed validation!'); + } + return succeeded; + } + + // Checks all provide LICENSE files, returning false if any of them + // fail validation. + Future _checkLicenseFiles(Iterable files) async { + final List incorrectLicenseFiles = []; + + for (final File file in files) { + _print('Checking ${file.path}'); + if (!file.readAsStringSync().contains(_fullBsdLicenseText)) { + incorrectLicenseFiles.add(file); + } + } + _print('\n'); + + if (incorrectLicenseFiles.isNotEmpty) { + _print('The following LICENSE files do not follow the expected format:'); + for (final File file in incorrectLicenseFiles) { + _print(' ${file.path}'); + } + _print('Please ensure that they use the exact format used in this repository".\n'); + } + + bool succeeded = incorrectLicenseFiles.isEmpty; + if (succeeded) { + _print('All LICENSE files passed validation!'); } return succeeded; } @@ -201,6 +265,10 @@ class LicenseCheckCommand extends PluginCommand { _ignoredFullBasenameList.contains(p.basename(path))); } + bool _isThirdParty(File file) { + return p.split(file.path).contains('third_party'); + } + Future> _getAllFiles() => packagesDir.parent .list(recursive: true, followLinks: false) .where((FileSystemEntity entity) => entity is File) diff --git a/script/tool/test/license_check_command_test.dart b/script/tool/test/license_check_command_test.dart index 524e72712360..8ae956740d72 100644 --- a/script/tool/test/license_check_command_test.dart +++ b/script/tool/test/license_check_command_test.dart @@ -134,7 +134,7 @@ void main() { // Sanity check that the test did actually check a file. expect(printedMessages, contains('Checking checked.cc')); - expect(printedMessages, contains('All files passed validation!')); + expect(printedMessages, contains('All source files passed validation!')); }); test('handles the comment styles for all supported languages', () async { @@ -154,7 +154,7 @@ void main() { expect(printedMessages, contains('Checking file_a.cc')); expect(printedMessages, contains('Checking file_b.sh')); expect(printedMessages, contains('Checking file_c.html')); - expect(printedMessages, contains('All files passed validation!')); + expect(printedMessages, contains('All source files passed validation!')); }); test('fails if any checked files are missing license blocks', () async { @@ -176,7 +176,8 @@ void main() { expect(printedMessages, contains(' bad.cc')); expect(printedMessages, contains(' bad.h')); // Failure shouldn't print the success message. - expect(printedMessages, isNot(contains('All files passed validation!'))); + expect(printedMessages, + isNot(contains('All source files passed validation!'))); }); test('fails if any checked files are missing just the copyright', () async { @@ -195,7 +196,8 @@ void main() { contains('No copyright line was found for the following files:')); expect(printedMessages, contains(' bad.cc')); // Failure shouldn't print the success message. - expect(printedMessages, isNot(contains('All files passed validation!'))); + expect(printedMessages, + isNot(contains('All source files passed validation!'))); }); test('fails if any checked files are missing just the license', () async { @@ -214,7 +216,8 @@ void main() { contains('No recognized license was found for the following files:')); expect(printedMessages, contains(' bad.cc')); // Failure shouldn't print the success message. - expect(printedMessages, isNot(contains('All files passed validation!'))); + expect(printedMessages, + isNot(contains('All source files passed validation!'))); }); test('fails if any third-party code is not in a third_party directory', @@ -234,7 +237,8 @@ void main() { 'but are not in a "third_party/" directory:')); expect(printedMessages, contains(' third_party.cc')); // Failure shouldn't print the success message. - expect(printedMessages, isNot(contains('All files passed validation!'))); + expect(printedMessages, + isNot(contains('All source files passed validation!'))); }); test('succeeds for third-party code in a third_party directory', () async { @@ -252,7 +256,7 @@ void main() { // Sanity check that the test did actually check the file. expect(printedMessages, contains('Checking a_plugin/lib/src/third_party/file.cc')); - expect(printedMessages, contains('All files passed validation!')); + expect(printedMessages, contains('All source files passed validation!')); }); test('fails for licenses that the tool does not expect', () async { @@ -274,7 +278,8 @@ void main() { contains('No recognized license was found for the following files:')); expect(printedMessages, contains(' third_party/bad.cc')); // Failure shouldn't print the success message. - expect(printedMessages, isNot(contains('All files passed validation!'))); + expect(printedMessages, + isNot(contains('All source files passed validation!'))); }); test('Apache is not recognized for new authors without validation changes', @@ -300,7 +305,107 @@ void main() { contains('No recognized license was found for the following files:')); expect(printedMessages, contains(' third_party/bad.cc')); // Failure shouldn't print the success message. - expect(printedMessages, isNot(contains('All files passed validation!'))); + expect(printedMessages, + isNot(contains('All source files passed validation!'))); + }); + + test('passes if all first-party LICENSE files are correctly formatted', + () async { + File license = root.childFile('LICENSE'); + license.createSync(); + license.writeAsStringSync(_correctLicenseFileText); + + await runner.run(['license-check']); + + // Sanity check that the test did actually check the file. + expect(printedMessages, contains('Checking LICENSE')); + expect(printedMessages, contains('All LICENSE files passed validation!')); + }); + + test('fails if any first-party LICENSE files are incorrectly formatted', + () async { + File license = root.childFile('LICENSE'); + license.createSync(); + license.writeAsStringSync(_incorrectLicenseFileText); + + await expectLater(() => runner.run(['license-check']), + throwsA(const TypeMatcher())); + + expect(printedMessages, + isNot(contains('All LICENSE files passed validation!'))); + }); + + test('ignores third-party LICENSE format', + () async { + File license = root.childDirectory('third_party').childFile('LICENSE'); + license.createSync(recursive: true); + license.writeAsStringSync(_incorrectLicenseFileText); + + await runner.run(['license-check']); + + // The file shouldn't be checked. + expect(printedMessages, isNot(contains('Checking third_party/LICENSE'))); + expect(printedMessages, contains('All LICENSE files passed validation!')); }); }); } + +const String _correctLicenseFileText = + '''Copyright 2017 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +'''; + +// A common incorrect version created by copying text intended for a code file, +// with comment markers. +const String _incorrectLicenseFileText = + '''// Copyright 2017 The Flutter Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +'''; From 089a88739745442f248fbf022c80a6711d6a56a6 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 18 Mar 2021 16:05:33 -0700 Subject: [PATCH 341/924] Standardize Copyrights: Chromium->Flutter (#2996) In all copyright messages (and in the Xcode project organization name) standardize on "The Flutter Authors", adding "The Chromium Authors" to the Flutter AUTHORS list. This reduces inconsistency in the copyright lines in this repository, moving closer to a single consistent copyright+license (as in flutter/engine and flutter/flutter) Updates the validation script to no longer accept "The Chromium Authors" or "the Chromium project authors" in first-party code. --- AUTHORS | 1 + LICENSE | 2 +- packages/android_alarm_manager/AUTHORS | 1 + packages/android_alarm_manager/LICENSE | 2 +- .../AlarmBroadcastReceiver.java | 2 +- .../plugins/androidalarmmanager/AlarmService.java | 2 +- .../AndroidAlarmManagerPlugin.java | 2 +- .../FlutterBackgroundExecutor.java | 2 +- .../PluginRegistrantException.java | 2 +- .../RebootBroadcastReceiver.java | 2 +- .../BackgroundExecutionTest.java | 2 +- .../DriverExtensionActivity.java | 2 +- .../androidalarmmanager/MainActivityTest.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../android_alarm_manager_test.dart | 2 +- .../android_alarm_manager/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../lib/android_alarm_manager.dart | 2 +- .../test/android_alarm_manager_test.dart | 2 +- packages/android_intent/AUTHORS | 1 + packages/android_intent/LICENSE | 2 +- .../plugins/androidintent/AndroidIntentPlugin.java | 2 +- .../plugins/androidintent/IntentSender.java | 2 +- .../androidintent/MethodCallHandlerImpl.java | 2 +- .../androidintent/MethodCallHandlerImplTest.java | 2 +- .../androidintentexample/EmbeddingV1Activity.java | 2 +- .../integration_test/android_intent_test.dart | 2 +- packages/android_intent/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- packages/android_intent/lib/android_intent.dart | 2 +- packages/android_intent/lib/flag.dart | 2 +- packages/battery/battery/AUTHORS | 1 + packages/battery/battery/LICENSE | 2 +- .../io/flutter/plugins/battery/BatteryPlugin.java | 2 +- .../plugins/battery/EmbedderV1ActivityTest.java | 2 +- .../plugins/battery/FlutterActivityTest.java | 2 +- .../plugins/batteryexample/EmbedderV1Activity.java | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../battery/example/ios/Runner/AppDelegate.h | 2 +- .../battery/example/ios/Runner/AppDelegate.m | 2 +- packages/battery/battery/example/ios/Runner/main.m | 2 +- packages/battery/battery/example/lib/main.dart | 2 +- .../battery/integration_test/battery_test.dart | 2 +- .../battery/battery/ios/Classes/FLTBatteryPlugin.h | 2 +- .../battery/battery/ios/Classes/FLTBatteryPlugin.m | 2 +- packages/battery/battery/lib/battery.dart | 2 +- packages/battery/battery/test/battery_test.dart | 2 +- .../battery/battery_platform_interface/AUTHORS | 1 + .../battery/battery_platform_interface/LICENSE | 2 +- .../lib/battery_platform_interface.dart | 2 +- .../lib/enums/battery_state.dart | 2 +- .../lib/method_channel/method_channel_battery.dart | 2 +- .../test/method_channel_battery_test.dart | 2 +- packages/camera/camera/AUTHORS | 1 + packages/camera/camera/LICENSE | 2 +- .../java/io/flutter/plugins/camera/Camera.java | 2 +- .../flutter/plugins/camera/CameraPermissions.java | 2 +- .../io/flutter/plugins/camera/CameraPlugin.java | 2 +- .../io/flutter/plugins/camera/CameraRegions.java | 2 +- .../io/flutter/plugins/camera/CameraUtils.java | 2 +- .../java/io/flutter/plugins/camera/CameraZoom.java | 2 +- .../io/flutter/plugins/camera/DartMessenger.java | 2 +- .../plugins/camera/DeviceOrientationManager.java | 2 +- .../plugins/camera/MethodCallHandlerImpl.java | 2 +- .../plugins/camera/PictureCaptureRequest.java | 2 +- .../plugins/camera/media/MediaRecorderBuilder.java | 2 +- .../flutter/plugins/camera/types/ExposureMode.java | 2 +- .../io/flutter/plugins/camera/types/FlashMode.java | 2 +- .../io/flutter/plugins/camera/types/FocusMode.java | 2 +- .../plugins/camera/types/ResolutionPreset.java | 2 +- .../plugins/camera/CameraPermissionsTest.java | 2 +- .../flutter/plugins/camera/CameraRegionsTest.java | 2 +- .../io/flutter/plugins/camera/CameraUtilsTest.java | 2 +- .../io/flutter/plugins/camera/CameraZoomTest.java | 2 +- .../flutter/plugins/camera/DartMessengerTest.java | 2 +- .../plugins/camera/PictureCaptureRequestTest.java | 2 +- .../camera/media/MediaRecorderBuilderTest.java | 2 +- .../plugins/camera/types/ExposureModeTest.java | 2 +- .../plugins/camera/types/FlashModeTest.java | 2 +- .../plugins/camera/types/FocusModeTest.java | 2 +- .../example/integration_test/camera_test.dart | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- packages/camera/camera/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- packages/camera/camera/ios/Classes/CameraPlugin.h | 2 +- packages/camera/camera/ios/Classes/CameraPlugin.m | 2 +- .../camera/camera/ios/Tests/CameraPluginTests.m | 2 +- packages/camera/camera/lib/camera.dart | 2 +- .../camera/camera/lib/src/camera_controller.dart | 2 +- packages/camera/camera/lib/src/camera_image.dart | 2 +- packages/camera/camera/lib/src/camera_preview.dart | 2 +- .../camera/test/camera_image_stream_test.dart | 2 +- packages/camera/camera/test/camera_image_test.dart | 2 +- packages/camera/camera/test/camera_test.dart | 2 +- packages/camera/camera/test/camera_value_test.dart | 2 +- .../camera/test/utils/method_channel_mock.dart | 2 +- packages/camera/camera_platform_interface/AUTHORS | 1 + packages/camera/camera_platform_interface/LICENSE | 2 +- .../lib/camera_platform_interface.dart | 2 +- .../lib/src/events/camera_event.dart | 2 +- .../lib/src/events/device_event.dart | 2 +- .../src/method_channel/method_channel_camera.dart | 2 +- .../src/platform_interface/camera_platform.dart | 2 +- .../lib/src/types/camera_description.dart | 2 +- .../lib/src/types/camera_exception.dart | 2 +- .../lib/src/types/exposure_mode.dart | 2 +- .../lib/src/types/flash_mode.dart | 2 +- .../lib/src/types/focus_mode.dart | 2 +- .../lib/src/types/image_format_group.dart | 2 +- .../lib/src/types/resolution_preset.dart | 2 +- .../lib/src/types/types.dart | 2 +- .../lib/src/utils/utils.dart | 2 +- .../test/camera_platform_interface_test.dart | 2 +- .../test/events/camera_event_test.dart | 2 +- .../test/events/device_event_test.dart | 2 +- .../method_channel/method_channel_camera_test.dart | 2 +- .../test/types/camera_description_test.dart | 2 +- .../test/types/camera_exception_test.dart | 2 +- .../test/types/exposure_mode_test.dart | 2 +- .../test/types/flash_mode_test.dart | 2 +- .../test/types/focus_mode_test.dart | 2 +- .../test/types/image_group_test.dart | 2 +- .../test/types/resolution_preset_test.dart | 2 +- .../test/utils/method_channel_mock.dart | 2 +- .../test/utils/utils_test.dart | 2 +- packages/connectivity/connectivity/AUTHORS | 1 + packages/connectivity/connectivity/LICENSE | 2 +- .../flutter/plugins/connectivity/Connectivity.java | 2 +- .../ConnectivityBroadcastReceiver.java | 2 +- .../ConnectivityMethodChannelHandler.java | 2 +- .../plugins/connectivity/ConnectivityPlugin.java | 2 +- .../connectivityexample/EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../connectivityexample/FlutterActivityTest.java | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../connectivity/example/ios/Runner/AppDelegate.h | 2 +- .../connectivity/example/ios/Runner/AppDelegate.m | 2 +- .../connectivity/example/ios/Runner/main.m | 2 +- .../connectivity/example/lib/main.dart | 2 +- .../integration_test/connectivity_test.dart | 2 +- .../example/test_driver/test/integration_test.dart | 2 +- .../integration_test/connectivity_test.dart | 2 +- .../ios/Classes/FLTConnectivityPlugin.h | 2 +- .../ios/Classes/FLTConnectivityPlugin.m | 2 +- .../connectivity/lib/connectivity.dart | 2 +- .../connectivity/test/connectivity_test.dart | 2 +- packages/connectivity/connectivity_for_web/AUTHORS | 1 + .../example/test_driver/integration_driver.dart | 2 +- packages/connectivity/connectivity_macos/AUTHORS | 1 + packages/connectivity/connectivity_macos/LICENSE | 2 +- .../connectivity_macos/example/lib/main.dart | 2 +- .../integration_test/connectivity_test.dart | 2 +- .../example/test_driver/test/integration_test.dart | 2 +- .../macos/Classes/ConnectivityPlugin.swift | 2 +- .../connectivity_macos/macos/Classes/IPHelper.h | 2 +- .../connectivity_platform_interface/AUTHORS | 1 + .../connectivity_platform_interface/LICENSE | 2 +- .../lib/connectivity_platform_interface.dart | 2 +- .../lib/src/enums.dart | 2 +- .../lib/src/method_channel_connectivity.dart | 2 +- .../lib/src/utils.dart | 2 +- .../test/method_channel_connectivity_test.dart | 2 +- packages/device_info/device_info/AUTHORS | 1 + packages/device_info/device_info/LICENSE | 2 +- .../plugins/deviceinfo/DeviceInfoPlugin.java | 2 +- .../plugins/deviceinfo/MethodCallHandlerImpl.java | 2 +- .../deviceinfoexample/EmbeddingV1Activity.java | 2 +- .../example/integration_test/device_info_test.dart | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../device_info/example/ios/Runner/AppDelegate.h | 2 +- .../device_info/example/ios/Runner/AppDelegate.m | 2 +- .../device_info/example/ios/Runner/main.m | 2 +- .../device_info/device_info/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../device_info/ios/Classes/FLTDeviceInfoPlugin.h | 2 +- .../device_info/ios/Classes/FLTDeviceInfoPlugin.m | 2 +- .../device_info/device_info/lib/device_info.dart | 2 +- .../device_info_platform_interface/AUTHORS | 1 + .../device_info_platform_interface/LICENSE | 2 +- .../lib/device_info_platform_interface.dart | 2 +- .../method_channel/method_channel_device_info.dart | 2 +- .../lib/model/android_device_info.dart | 2 +- .../lib/model/ios_device_info.dart | 2 +- .../test/method_channel_device_info_test.dart | 2 +- packages/espresso/AUTHORS | 1 + packages/espresso/LICENSE | 2 +- .../test/espresso/flutter/EspressoFlutter.java | 2 +- .../test/espresso/flutter/action/ActionUtil.java | 2 +- .../test/espresso/flutter/action/ClickAction.java | 2 +- .../espresso/flutter/action/FlutterActions.java | 2 +- .../flutter/action/FlutterScrollToAction.java | 2 +- .../flutter/action/FlutterTypeTextAction.java | 2 +- .../espresso/flutter/action/FlutterViewAction.java | 2 +- .../flutter/action/SyntheticClickAction.java | 2 +- .../flutter/action/WaitUntilIdleAction.java | 2 +- .../action/WidgetCoordinatesCalculator.java | 2 +- .../espresso/flutter/action/WidgetInfoFetcher.java | 2 +- .../test/espresso/flutter/api/FlutterAction.java | 2 +- .../flutter/api/FlutterTestingProtocol.java | 2 +- .../test/espresso/flutter/api/SyntheticAction.java | 2 +- .../test/espresso/flutter/api/WidgetAction.java | 2 +- .../test/espresso/flutter/api/WidgetAssertion.java | 2 +- .../test/espresso/flutter/api/WidgetMatcher.java | 2 +- .../flutter/assertion/FlutterAssertions.java | 2 +- .../flutter/assertion/FlutterViewAssertion.java | 2 +- .../test/espresso/flutter/common/Constants.java | 2 +- .../test/espresso/flutter/common/Duration.java | 2 +- .../exception/AmbiguousWidgetMatcherException.java | 2 +- .../exception/InvalidFlutterViewException.java | 2 +- .../exception/NoMatchingWidgetException.java | 2 +- .../flutter/internal/idgenerator/IdException.java | 2 +- .../flutter/internal/idgenerator/IdGenerator.java | 2 +- .../flutter/internal/idgenerator/IdGenerators.java | 2 +- .../flutter/internal/jsonrpc/JsonRpcClient.java | 2 +- .../internal/jsonrpc/message/ErrorObject.java | 2 +- .../internal/jsonrpc/message/JsonRpcRequest.java | 2 +- .../internal/jsonrpc/message/JsonRpcResponse.java | 2 +- .../internal/protocol/impl/DartVmService.java | 2 +- .../internal/protocol/impl/DartVmServiceUtil.java | 2 +- .../protocol/impl/FlutterProtocolException.java | 2 +- .../internal/protocol/impl/GetOffsetAction.java | 2 +- .../internal/protocol/impl/GetOffsetResponse.java | 2 +- .../internal/protocol/impl/GetVmResponse.java | 2 +- .../protocol/impl/GetWidgetDiagnosticsAction.java | 2 +- .../impl/GetWidgetDiagnosticsResponse.java | 2 +- .../protocol/impl/NoPendingFrameCondition.java | 2 +- .../impl/NoPendingPlatformMessagesCondition.java | 2 +- .../impl/NoTransientCallbacksCondition.java | 2 +- .../internal/protocol/impl/WaitCondition.java | 2 +- .../protocol/impl/WaitForConditionAction.java | 2 +- .../internal/protocol/impl/WidgetInfoFactory.java | 2 +- .../espresso/flutter/matcher/FlutterMatchers.java | 2 +- .../flutter/matcher/IsDescendantOfMatcher.java | 2 +- .../flutter/matcher/IsExistingMatcher.java | 2 +- .../espresso/flutter/matcher/WithTextMatcher.java | 2 +- .../flutter/matcher/WithTooltipMatcher.java | 2 +- .../espresso/flutter/matcher/WithTypeMatcher.java | 2 +- .../flutter/matcher/WithValueKeyMatcher.java | 2 +- .../test/espresso/flutter/model/WidgetInfo.java | 2 +- .../espresso/flutter/model/WidgetInfoBuilder.java | 2 +- .../java/com/example/MainActivityTest.java | 2 +- packages/flutter_plugin_android_lifecycle/AUTHORS | 1 + packages/flutter_plugin_android_lifecycle/LICENSE | 2 +- .../plugins/lifecycle/FlutterLifecycleAdapter.java | 2 +- .../FlutterAndroidLifecyclePlugin.java | 2 +- .../lifecycle/FlutterLifecycleAdapterTest.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../MainActivityTest.java | 2 +- .../MainActivity.java | 2 +- .../flutter_plugin_android_lifecycle_test.dart | 2 +- .../example/lib/main.dart | 2 +- .../lib/flutter_plugin_android_lifecycle.dart | 2 +- .../google_maps_flutter/AUTHORS | 1 + .../google_maps_flutter/LICENSE | 2 +- .../flutter/plugins/googlemaps/CircleBuilder.java | 2 +- .../plugins/googlemaps/CircleController.java | 2 +- .../plugins/googlemaps/CircleOptionsSink.java | 2 +- .../plugins/googlemaps/CirclesController.java | 2 +- .../io/flutter/plugins/googlemaps/Convert.java | 2 +- .../plugins/googlemaps/GoogleMapBuilder.java | 2 +- .../plugins/googlemaps/GoogleMapController.java | 2 +- .../plugins/googlemaps/GoogleMapFactory.java | 2 +- .../plugins/googlemaps/GoogleMapListener.java | 2 +- .../plugins/googlemaps/GoogleMapOptionsSink.java | 2 +- .../plugins/googlemaps/GoogleMapsPlugin.java | 2 +- .../plugins/googlemaps/LifecycleProvider.java | 2 +- .../flutter/plugins/googlemaps/MarkerBuilder.java | 2 +- .../plugins/googlemaps/MarkerController.java | 2 +- .../plugins/googlemaps/MarkerOptionsSink.java | 2 +- .../plugins/googlemaps/MarkersController.java | 2 +- .../flutter/plugins/googlemaps/PolygonBuilder.java | 2 +- .../plugins/googlemaps/PolygonController.java | 2 +- .../plugins/googlemaps/PolygonOptionsSink.java | 2 +- .../plugins/googlemaps/PolygonsController.java | 2 +- .../plugins/googlemaps/PolylineBuilder.java | 2 +- .../plugins/googlemaps/PolylineController.java | 2 +- .../plugins/googlemaps/PolylineOptionsSink.java | 2 +- .../plugins/googlemaps/PolylinesController.java | 2 +- .../plugins/googlemaps/TileOverlayBuilder.java | 2 +- .../plugins/googlemaps/TileOverlayController.java | 2 +- .../plugins/googlemaps/TileOverlaySink.java | 2 +- .../plugins/googlemaps/TileOverlaysController.java | 2 +- .../plugins/googlemaps/TileProviderController.java | 2 +- .../plugins/googlemaps/CircleBuilderTest.java | 2 +- .../plugins/googlemaps/CircleControllerTest.java | 2 +- .../plugins/googlemaps/PolygonBuilderTest.java | 2 +- .../plugins/googlemaps/PolygonControllerTest.java | 2 +- .../plugins/googlemaps/PolylineBuilderTest.java | 2 +- .../plugins/googlemaps/PolylineControllerTest.java | 2 +- .../integration_test/google_map_inspector.dart | 2 +- .../example/integration_test/google_maps_test.dart | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../example/lib/animate_camera.dart | 2 +- .../google_maps_flutter/example/lib/lite_mode.dart | 2 +- .../google_maps_flutter/example/lib/main.dart | 2 +- .../google_maps_flutter/example/lib/map_click.dart | 2 +- .../example/lib/map_coordinates.dart | 2 +- .../google_maps_flutter/example/lib/map_ui.dart | 2 +- .../example/lib/marker_icons.dart | 2 +- .../example/lib/move_camera.dart | 2 +- .../google_maps_flutter/example/lib/padding.dart | 2 +- .../google_maps_flutter/example/lib/page.dart | 2 +- .../example/lib/place_circle.dart | 2 +- .../example/lib/place_marker.dart | 2 +- .../example/lib/place_polygon.dart | 2 +- .../example/lib/place_polyline.dart | 2 +- .../example/lib/scrolling_map.dart | 2 +- .../google_maps_flutter/example/lib/snapshot.dart | 2 +- .../example/lib/tile_overlay.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../Classes/FLTGoogleMapTileOverlayController.h | 2 +- .../Classes/FLTGoogleMapTileOverlayController.m | 2 +- .../ios/Classes/FLTGoogleMapsPlugin.h | 2 +- .../ios/Classes/FLTGoogleMapsPlugin.m | 2 +- .../ios/Classes/GoogleMapCircleController.h | 2 +- .../ios/Classes/GoogleMapCircleController.m | 2 +- .../ios/Classes/GoogleMapController.h | 2 +- .../ios/Classes/GoogleMapController.m | 2 +- .../ios/Classes/GoogleMapMarkerController.h | 4 ++-- .../ios/Classes/GoogleMapMarkerController.m | 2 +- .../ios/Classes/GoogleMapPolygonController.h | 2 +- .../ios/Classes/GoogleMapPolygonController.m | 2 +- .../ios/Classes/GoogleMapPolylineController.h | 2 +- .../ios/Classes/GoogleMapPolylineController.m | 2 +- .../ios/Classes/JsonConversions.h | 2 +- .../ios/Classes/JsonConversions.m | 2 +- .../lib/google_maps_flutter.dart | 2 +- .../google_maps_flutter/lib/src/controller.dart | 2 +- .../google_maps_flutter/lib/src/google_map.dart | 2 +- .../test/android_google_map_test.dart | 2 +- .../test/circle_updates_test.dart | 2 +- .../test/fake_maps_controllers.dart | 2 +- .../google_maps_flutter/test/google_map_test.dart | 2 +- .../test/map_creation_test.dart | 2 +- .../test/marker_updates_test.dart | 2 +- .../test/polygon_updates_test.dart | 2 +- .../test/polyline_updates_test.dart | 2 +- .../test/tile_overlay_updates_test.dart | 2 +- .../google_maps_flutter_platform_interface/AUTHORS | 1 + .../google_maps_flutter_platform_interface/LICENSE | 2 +- .../google_maps_flutter_platform_interface.dart | 2 +- .../lib/src/events/map_event.dart | 2 +- .../method_channel_google_maps_flutter.dart | 2 +- .../google_maps_flutter_platform.dart | 2 +- .../lib/src/types/bitmap.dart | 2 +- .../lib/src/types/callbacks.dart | 2 +- .../lib/src/types/camera.dart | 2 +- .../lib/src/types/cap.dart | 2 +- .../lib/src/types/circle.dart | 2 +- .../lib/src/types/circle_updates.dart | 2 +- .../lib/src/types/joint_type.dart | 2 +- .../lib/src/types/location.dart | 2 +- .../lib/src/types/maps_object.dart | 2 +- .../lib/src/types/maps_object_updates.dart | 2 +- .../lib/src/types/marker.dart | 2 +- .../lib/src/types/marker_updates.dart | 2 +- .../lib/src/types/pattern_item.dart | 2 +- .../lib/src/types/polygon.dart | 2 +- .../lib/src/types/polygon_updates.dart | 2 +- .../lib/src/types/polyline.dart | 2 +- .../lib/src/types/polyline_updates.dart | 2 +- .../lib/src/types/screen_coordinate.dart | 2 +- .../lib/src/types/tile.dart | 2 +- .../lib/src/types/tile_overlay.dart | 2 +- .../lib/src/types/tile_overlay_updates.dart | 2 +- .../lib/src/types/tile_provider.dart | 2 +- .../lib/src/types/types.dart | 2 +- .../lib/src/types/ui.dart | 2 +- .../lib/src/types/utils/circle.dart | 2 +- .../lib/src/types/utils/maps_object.dart | 2 +- .../lib/src/types/utils/marker.dart | 2 +- .../lib/src/types/utils/polygon.dart | 2 +- .../lib/src/types/utils/polyline.dart | 2 +- .../lib/src/types/utils/tile_overlay.dart | 2 +- .../google_maps_flutter_platform_test.dart | 2 +- .../test/types/bitmap_test.dart | 2 +- .../test/types/camera_test.dart | 2 +- .../test/types/maps_object_test.dart | 2 +- .../test/types/maps_object_updates_test.dart | 2 +- .../test/types/test_maps_object.dart | 2 +- .../test/types/tile_overlay_test.dart | 2 +- .../test/types/tile_overlay_updates_test.dart | 2 +- .../test/types/tile_test.dart | 2 +- .../google_maps_flutter_web/AUTHORS | 1 + .../google_maps_controller_test.dart | 2 +- .../integration_test/google_maps_plugin_test.dart | 2 +- .../example/integration_test/marker_test.dart | 2 +- .../example/integration_test/markers_test.dart | 2 +- .../example/integration_test/shape_test.dart | 2 +- .../example/integration_test/shapes_test.dart | 2 +- .../example/test_driver/integration_driver.dart | 2 +- .../lib/google_maps_flutter_web.dart | 2 +- .../google_maps_flutter_web/lib/src/circle.dart | 2 +- .../google_maps_flutter_web/lib/src/circles.dart | 2 +- .../google_maps_flutter_web/lib/src/convert.dart | 2 +- .../lib/src/google_maps_controller.dart | 2 +- .../lib/src/google_maps_flutter_web.dart | 2 +- .../google_maps_flutter_web/lib/src/marker.dart | 2 +- .../google_maps_flutter_web/lib/src/markers.dart | 2 +- .../google_maps_flutter_web/lib/src/polygon.dart | 2 +- .../google_maps_flutter_web/lib/src/polygons.dart | 2 +- .../google_maps_flutter_web/lib/src/polyline.dart | 2 +- .../google_maps_flutter_web/lib/src/polylines.dart | 2 +- .../lib/src/shims/dart_ui.dart | 2 +- .../lib/src/shims/dart_ui_fake.dart | 2 +- .../lib/src/shims/dart_ui_real.dart | 2 +- .../google_maps_flutter_web/lib/src/types.dart | 2 +- .../test/tests_exist_elsewhere_test.dart | 2 +- packages/google_sign_in/google_sign_in/AUTHORS | 1 + .../googlesigninexample/EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../googlesigninexample/FlutterActivityTest.java | 2 +- .../googlesignin/GoogleSignInPluginTests.java | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../google_sign_in/example/ios/Runner/main.m | 2 +- .../ios/Tests/GoogleSignInPluginTest.m | 2 +- .../test_driver/integration_test.dart | 2 +- .../google_sign_in_platform_interface/AUTHORS | 1 + .../google_sign_in_platform_interface/LICENSE | 2 +- .../lib/google_sign_in_platform_interface.dart | 2 +- .../lib/src/method_channel_google_sign_in.dart | 2 +- .../lib/src/types.dart | 2 +- .../lib/src/utils.dart | 2 +- .../google_sign_in_platform_interface_test.dart | 2 +- .../test/method_channel_google_sign_in_test.dart | 2 +- packages/google_sign_in/google_sign_in_web/AUTHORS | 1 + .../example/integration_test/auth2_test.dart | 2 +- .../example/integration_test/gapi_load_test.dart | 2 +- .../integration_test/gapi_mocks/gapi_mocks.dart | 2 +- .../gapi_mocks/src/auth2_init.dart | 2 +- .../integration_test/gapi_mocks/src/gapi.dart | 2 +- .../gapi_mocks/src/google_user.dart | 2 +- .../integration_test/gapi_mocks/src/test_iife.dart | 2 +- .../example/integration_test/gapi_utils_test.dart | 2 +- .../example/integration_test/src/test_utils.dart | 2 +- .../example/test_driver/integration_driver.dart | 2 +- .../google_sign_in_web/lib/google_sign_in_web.dart | 2 +- .../google_sign_in_web/lib/src/generated/gapi.dart | 2 +- .../lib/src/generated/gapiauth2.dart | 2 +- .../google_sign_in_web/lib/src/load_gapi.dart | 2 +- .../google_sign_in_web/lib/src/utils.dart | 2 +- packages/image_picker/image_picker/AUTHORS | 1 + .../imagepickerexample/EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../image_picker/example/ios/Runner/AppDelegate.h | 2 +- .../image_picker/example/ios/Runner/AppDelegate.m | 2 +- .../image_picker/example/ios/Runner/main.m | 2 +- .../RunnerUITests/ImagePickerFromGalleryUITests.m | 2 +- .../example/test_driver/test/integration_test.dart | 2 +- .../ios/Tests/ImagePickerPluginTests.m | 2 +- .../image_picker/ios/Tests/ImagePickerTestImages.h | 2 +- .../image_picker/ios/Tests/ImagePickerTestImages.m | 2 +- .../image_picker/ios/Tests/ImageUtilTests.m | 2 +- .../image_picker/ios/Tests/MetaDataUtilTests.m | 2 +- .../image_picker/ios/Tests/PhotoAssetUtilTests.m | 2 +- packages/image_picker/image_picker_for_web/AUTHORS | 1 + packages/image_picker/image_picker_for_web/LICENSE | 2 +- .../lib/image_picker_for_web.dart | 2 +- .../test/image_picker_for_web_test.dart | 2 +- .../image_picker_platform_interface/AUTHORS | 1 + .../image_picker_platform_interface/LICENSE | 2 +- .../lib/image_picker_platform_interface.dart | 2 +- .../method_channel_image_picker.dart | 2 +- .../platform_interface/image_picker_platform.dart | 2 +- .../lib/src/types/camera_device.dart | 2 +- .../lib/src/types/image_source.dart | 2 +- .../lib/src/types/picked_file/base.dart | 2 +- .../lib/src/types/picked_file/html.dart | 2 +- .../lib/src/types/picked_file/io.dart | 2 +- .../lib/src/types/picked_file/lost_data.dart | 2 +- .../lib/src/types/picked_file/picked_file.dart | 2 +- .../lib/src/types/picked_file/unsupported.dart | 2 +- .../lib/src/types/retrieve_type.dart | 2 +- .../lib/src/types/types.dart | 2 +- .../test/picked_file_html_test.dart | 2 +- .../test/picked_file_io_test.dart | 2 +- packages/in_app_purchase/AUTHORS | 1 + packages/in_app_purchase/LICENSE | 2 +- .../inapppurchase/BillingClientFactory.java | 2 +- .../inapppurchase/BillingClientFactoryImpl.java | 2 +- .../plugins/inapppurchase/InAppPurchasePlugin.java | 2 +- .../inapppurchase/MethodCallHandlerImpl.java | 2 +- .../inapppurchase/PluginPurchaseListener.java | 2 +- .../flutter/plugins/inapppurchase/Translator.java | 2 +- .../inapppurchaseexample/EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../inapppurchaseexample/FlutterActivityTest.java | 2 +- .../inapppurchase/InAppPurchasePluginTest.java | 2 +- .../plugins/inapppurchase/TranslatorTest.java | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../example/lib/consumable_store.dart | 2 +- packages/in_app_purchase/example/lib/main.dart | 2 +- .../example/test_driver/test/integration_test.dart | 2 +- .../integration_test/in_app_purchase_test.dart | 2 +- .../ios/Classes/FIAObjectTranslator.h | 2 +- .../ios/Classes/FIAObjectTranslator.m | 2 +- .../ios/Classes/FIAPReceiptManager.h | 2 +- .../ios/Classes/FIAPReceiptManager.m | 2 +- .../ios/Classes/FIAPRequestHandler.h | 2 +- .../ios/Classes/FIAPRequestHandler.m | 2 +- .../ios/Classes/FIAPaymentQueueHandler.h | 2 +- .../ios/Classes/FIAPaymentQueueHandler.m | 2 +- .../ios/Classes/InAppPurchasePlugin.h | 2 +- .../ios/Classes/InAppPurchasePlugin.m | 2 +- .../ios/Tests/InAppPurchasePluginTest.m | 2 +- .../in_app_purchase/ios/Tests/PaymentQueueTest.m | 2 +- .../ios/Tests/ProductRequestHandlerTest.m | 2 +- packages/in_app_purchase/ios/Tests/Stubs.h | 2 +- packages/in_app_purchase/ios/Tests/Stubs.m | 2 +- .../in_app_purchase/ios/Tests/TranslatorTest.m | 2 +- .../lib/billing_client_wrappers.dart | 2 +- packages/in_app_purchase/lib/in_app_purchase.dart | 2 +- .../billing_client_wrapper.dart | 2 +- .../billing_client_wrappers/enum_converters.dart | 2 +- .../billing_client_wrappers/purchase_wrapper.dart | 2 +- .../sku_details_wrapper.dart | 2 +- packages/in_app_purchase/lib/src/channel.dart | 2 +- .../src/in_app_purchase/app_store_connection.dart | 2 +- .../in_app_purchase/google_play_connection.dart | 2 +- .../in_app_purchase_connection.dart | 2 +- .../lib/src/in_app_purchase/product_details.dart | 2 +- .../lib/src/in_app_purchase/purchase_details.dart | 2 +- .../src/store_kit_wrappers/enum_converters.dart | 2 +- .../sk_payment_queue_wrapper.dart | 2 +- .../sk_payment_transaction_wrappers.dart | 2 +- .../src/store_kit_wrappers/sk_product_wrapper.dart | 2 +- .../src/store_kit_wrappers/sk_receipt_manager.dart | 2 +- .../src/store_kit_wrappers/sk_request_maker.dart | 2 +- .../in_app_purchase/lib/store_kit_wrappers.dart | 2 +- .../billing_client_wrapper_test.dart | 2 +- .../purchase_wrapper_test.dart | 2 +- .../sku_details_wrapper_test.dart | 2 +- .../app_store_connection_test.dart | 2 +- .../google_play_connection_test.dart | 2 +- .../sk_methodchannel_apis_test.dart | 2 +- .../test/store_kit_wrappers/sk_product_test.dart | 2 +- .../store_kit_wrappers/sk_test_stub_objects.dart | 2 +- .../test/stub_in_app_purchase_platform.dart | 2 +- packages/integration_test/AUTHORS | 1 + packages/integration_test/LICENSE | 2 +- .../integration_test/FlutterTestRunner.java | 2 +- .../integration_test/IntegrationTestPlugin.java | 2 +- .../example/e2e_example/EmbedderV1Activity.java | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../integration_test/example/ios/Runner/main.m | 2 +- .../example/test_driver/failure.dart | 2 +- .../ios/Classes/IntegrationTestIosTest.h | 2 +- .../ios/Classes/IntegrationTestIosTest.m | 2 +- .../ios/Classes/IntegrationTestPlugin.h | 2 +- .../ios/Classes/IntegrationTestPlugin.m | 2 +- packages/integration_test/lib/_callback_io.dart | 2 +- packages/integration_test/lib/_callback_web.dart | 2 +- packages/integration_test/lib/_extension_io.dart | 2 +- packages/integration_test/lib/_extension_web.dart | 2 +- packages/integration_test/lib/common.dart | 2 +- .../integration_test/lib/integration_test.dart | 2 +- .../lib/integration_test_driver_extended.dart | 2 +- .../integration_test/test/binding_fail_test.dart | 2 +- packages/integration_test/test/binding_test.dart | 2 +- .../test/data/fail_test_script.dart | 2 +- .../test/data/pass_test_script.dart | 2 +- .../test/data/pass_then_fail_test_script.dart | 2 +- .../test/response_serialization_test.dart | 2 +- packages/ios_platform_images/AUTHORS | 1 + packages/ios_platform_images/LICENSE | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../ios/Classes/IosPlatformImagesPlugin.h | 2 +- .../ios/Classes/IosPlatformImagesPlugin.m | 2 +- .../lib/ios_platform_images.dart | 2 +- .../test/ios_platform_images_test.dart | 2 +- packages/local_auth/AUTHORS | 1 + packages/local_auth/LICENSE | 2 +- .../plugins/localauth/AuthenticationHelper.java | 2 +- .../flutter/plugins/localauth/LocalAuthPlugin.java | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../local_auth/example/ios/Runner/AppDelegate.h | 2 +- .../local_auth/example/ios/Runner/AppDelegate.m | 2 +- packages/local_auth/example/lib/main.dart | 2 +- .../integration_test/local_auth_test.dart | 2 +- .../local_auth/ios/Classes/FLTLocalAuthPlugin.h | 2 +- .../local_auth/ios/Classes/FLTLocalAuthPlugin.m | 2 +- packages/local_auth/lib/auth_strings.dart | 2 +- packages/local_auth/lib/error_codes.dart | 2 +- packages/local_auth/lib/local_auth.dart | 2 +- packages/package_info/AUTHORS | 1 + packages/package_info/LICENSE | 2 +- .../plugins/packageinfo/PackageInfoPlugin.java | 2 +- .../darwin/Classes/FLTPackageInfoPlugin.m | 2 +- .../packageinfoexample/EmbedderV1ActivityTest.java | 2 +- .../packageinfoexample/MainActivityTest.java | 2 +- .../packageinfoexample/EmbedderV1Activity.java | 2 +- .../integration_test/package_info_test.dart | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../package_info/example/ios/Runner/AppDelegate.h | 2 +- .../package_info/example/ios/Runner/AppDelegate.m | 2 +- packages/package_info/example/ios/Runner/main.m | 2 +- packages/package_info/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../ios/Classes/FLTPackageInfoPlugin.h | 2 +- packages/package_info/lib/package_info.dart | 2 +- .../macos/Classes/FLTPackageInfoPlugin.h | 2 +- packages/path_provider/path_provider/AUTHORS | 1 + .../integration_test/path_provider_test.dart | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../path_provider/example/ios/Runner/AppDelegate.h | 2 +- .../path_provider/example/ios/Runner/AppDelegate.m | 2 +- .../path_provider/example/ios/Runner/main.m | 2 +- .../path_provider/example/linux/my_application.h | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../example/windows/runner/flutter_window.cpp | 2 +- packages/path_provider/path_provider_linux/AUTHORS | 1 + packages/path_provider/path_provider_linux/LICENSE | 2 +- .../integration_test/path_provider_test.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../lib/path_provider_linux.dart | 2 +- .../test/path_provider_linux_test.dart | 2 +- packages/path_provider/path_provider_macos/AUTHORS | 1 + packages/path_provider/path_provider_macos/LICENSE | 2 +- .../integration_test/path_provider_test.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../macos/Classes/PathProviderPlugin.swift | 2 +- .../path_provider_platform_interface/AUTHORS | 1 + .../path_provider_platform_interface/LICENSE | 2 +- .../lib/path_provider_platform_interface.dart | 2 +- .../lib/src/enums.dart | 2 +- .../lib/src/method_channel_path_provider.dart | 2 +- .../test/method_channel_path_provider_test.dart | 2 +- .../path_provider/path_provider_windows/AUTHORS | 1 + .../path_provider/path_provider_windows/LICENSE | 2 +- .../integration_test/path_provider_test.dart | 2 +- .../path_provider_windows/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../lib/path_provider_windows.dart | 2 +- .../path_provider_windows/lib/src/folders.dart | 2 +- .../lib/src/folders_stub.dart | 2 +- .../lib/src/path_provider_windows_real.dart | 2 +- .../lib/src/path_provider_windows_stub.dart | 2 +- .../test/path_provider_windows_test.dart | 2 +- packages/plugin_platform_interface/AUTHORS | 1 + packages/plugin_platform_interface/LICENSE | 2 +- .../lib/plugin_platform_interface.dart | 2 +- .../test/plugin_platform_interface_test.dart | 2 +- packages/quick_actions/AUTHORS | 1 + packages/quick_actions/LICENSE | 2 +- .../quickactions/MethodCallHandlerImpl.java | 2 +- .../plugins/quickactions/QuickActionsPlugin.java | 2 +- .../quickactionsexample/EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../quickactionsexample/FlutterActivityTest.java | 2 +- .../integration_test/quick_actions_test.dart | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../quick_actions/example/ios/Runner/AppDelegate.h | 2 +- .../quick_actions/example/ios/Runner/AppDelegate.m | 2 +- packages/quick_actions/example/ios/Runner/main.m | 2 +- .../example/ios/RunnerUITests/RunnerUITests.m | 2 +- packages/quick_actions/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../ios/Classes/FLTQuickActionsPlugin.h | 2 +- .../ios/Classes/FLTQuickActionsPlugin.m | 2 +- packages/quick_actions/lib/quick_actions.dart | 2 +- .../quick_actions/test/quick_actions_test.dart | 2 +- packages/sensors/AUTHORS | 1 + packages/sensors/LICENSE | 2 +- .../io/flutter/plugins/sensors/SensorsPlugin.java | 2 +- .../flutter/plugins/sensors/StreamHandlerImpl.java | 2 +- .../sensorsexample/EmbeddingV1Activity.java | 2 +- .../sensorsexample/FlutterActivityTest.java | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- packages/sensors/example/lib/main.dart | 2 +- packages/sensors/example/lib/snake.dart | 2 +- .../example/test_driver/test/integration_test.dart | 2 +- .../sensors/integration_test/sensors_test.dart | 2 +- packages/sensors/ios/Classes/FLTSensorsPlugin.h | 2 +- packages/sensors/ios/Classes/FLTSensorsPlugin.m | 2 +- packages/sensors/lib/sensors.dart | 2 +- packages/sensors/test/sensors_test.dart | 2 +- packages/share/AUTHORS | 1 + .../plugins/shareexample/EmbeddingV1Activity.java | 2 +- .../plugins/shareexample/FlutterActivityTest.java | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- packages/share/example/ios/Runner/AppDelegate.h | 2 +- packages/share/example/ios/Runner/AppDelegate.m | 2 +- packages/share/example/ios/Runner/main.m | 2 +- .../ios/RunnerUITests/FLTShareExampleUITests.m | 2 +- .../example/test_driver/test/integration_test.dart | 2 +- packages/share/integration_test/share_test.dart | 2 +- .../shared_preferences/shared_preferences/AUTHORS | 1 + .../shared_preferences/shared_preferences/LICENSE | 2 +- .../sharedpreferences/MethodCallHandlerImpl.java | 2 +- .../sharedpreferences/SharedPreferencesPlugin.java | 2 +- .../integration_test/shared_preferences_test.dart | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../example/ios/Runner/Runner-Bridging-Header.h | 2 +- .../shared_preferences/example/ios/Runner/main.m | 2 +- .../shared_preferences/example/lib/main.dart | 2 +- .../example/linux/my_application.h | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../example/windows/runner/flutter_window.cpp | 2 +- .../example/windows/runner/flutter_window.h | 2 +- .../example/windows/runner/main.cpp | 2 +- .../example/windows/runner/run_loop.cpp | 2 +- .../example/windows/runner/run_loop.h | 2 +- .../example/windows/runner/utils.cpp | 2 +- .../example/windows/runner/utils.h | 2 +- .../example/windows/runner/win32_window.cpp | 2 +- .../example/windows/runner/win32_window.h | 2 +- .../ios/Classes/FLTSharedPreferencesPlugin.h | 2 +- .../ios/Classes/FLTSharedPreferencesPlugin.m | 2 +- .../shared_preferences/lib/shared_preferences.dart | 2 +- .../test/shared_preferences_test.dart | 2 +- .../shared_preferences_linux/AUTHORS | 1 + .../shared_preferences_linux/LICENSE | 2 +- .../integration_test/shared_preferences_test.dart | 2 +- .../shared_preferences_linux/example/lib/main.dart | 2 +- .../example/linux/my_application.h | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../lib/shared_preferences_linux.dart | 2 +- .../test/shared_preferences_linux_test.dart | 2 +- .../shared_preferences_macos/AUTHORS | 1 + .../integration_test/shared_preferences_test.dart | 2 +- .../shared_preferences_macos/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../macos/Classes/SharedPreferencesPlugin.swift | 2 +- .../shared_preferences_platform_interface/AUTHORS | 1 + .../shared_preferences_platform_interface/LICENSE | 2 +- .../lib/method_channel_shared_preferences.dart | 2 +- .../lib/shared_preferences_platform_interface.dart | 2 +- .../method_channel_shared_preferences_test.dart | 2 +- ...shared_preferences_platform_interface_test.dart | 2 +- .../shared_preferences_web/LICENSE | 2 +- .../lib/shared_preferences_web.dart | 2 +- .../test/shared_preferences_web_test.dart | 2 +- .../shared_preferences_windows/AUTHORS | 1 + .../shared_preferences_windows/LICENSE | 2 +- .../shared_preferences_windows/example/LICENSE | 2 +- .../integration_test/shared_preferences_test.dart | 2 +- .../example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../example/windows/runner/flutter_window.cpp | 2 +- .../example/windows/runner/flutter_window.h | 2 +- .../example/windows/runner/main.cpp | 2 +- .../example/windows/runner/run_loop.cpp | 2 +- .../example/windows/runner/run_loop.h | 2 +- .../example/windows/runner/utils.cpp | 2 +- .../example/windows/runner/utils.h | 2 +- .../example/windows/runner/win32_window.cpp | 2 +- .../example/windows/runner/win32_window.h | 2 +- .../lib/shared_preferences_windows.dart | 2 +- .../test/shared_preferences_windows_test.dart | 2 +- packages/url_launcher/url_launcher/AUTHORS | 1 + packages/url_launcher/url_launcher/LICENSE | 2 +- .../plugins/urllauncher/MethodCallHandlerImpl.java | 2 +- .../flutter/plugins/urllauncher/UrlLauncher.java | 2 +- .../plugins/urllauncher/UrlLauncherPlugin.java | 2 +- .../plugins/urllauncher/WebViewActivity.java | 2 +- .../urllauncher/MethodCallHandlerImplTest.java | 2 +- .../urllauncherexample/EmbeddingV1Activity.java | 2 +- .../integration_test/url_launcher_test.dart | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../url_launcher/example/ios/Runner/AppDelegate.h | 2 +- .../url_launcher/example/ios/Runner/AppDelegate.m | 2 +- .../url_launcher/example/ios/Runner/main.m | 2 +- .../url_launcher/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../ios/Classes/FLTURLLauncherPlugin.h | 2 +- .../ios/Classes/FLTURLLauncherPlugin.m | 2 +- packages/url_launcher/url_launcher/lib/link.dart | 2 +- .../url_launcher/url_launcher/lib/src/link.dart | 2 +- .../url_launcher/lib/url_launcher.dart | 2 +- .../url_launcher/url_launcher/test/link_test.dart | 2 +- .../test/mock_url_launcher_platform.dart | 2 +- .../url_launcher/test/url_launcher_test.dart | 2 +- packages/url_launcher/url_launcher_linux/AUTHORS | 1 + packages/url_launcher/url_launcher_linux/LICENSE | 2 +- .../integration_test/url_launcher_test.dart | 2 +- .../url_launcher_linux/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../url_launcher_linux/url_launcher_plugin.h | 2 +- .../linux/url_launcher_plugin.cc | 2 +- packages/url_launcher/url_launcher_macos/AUTHORS | 1 + packages/url_launcher/url_launcher_macos/LICENSE | 2 +- .../integration_test/url_launcher_test.dart | 2 +- .../url_launcher_macos/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../macos/Classes/UrlLauncherPlugin.swift | 2 +- .../url_launcher_platform_interface/AUTHORS | 1 + .../url_launcher_platform_interface/LICENSE | 2 +- .../url_launcher_platform_interface/lib/link.dart | 2 +- .../lib/method_channel_url_launcher.dart | 2 +- .../lib/url_launcher_platform_interface.dart | 2 +- .../test/link_test.dart | 2 +- .../test/method_channel_url_launcher_test.dart | 2 +- packages/url_launcher/url_launcher_web/AUTHORS | 1 + packages/url_launcher/url_launcher_web/LICENSE | 2 +- .../example/integration_test/link_widget_test.dart | 2 +- .../integration_test/url_launcher_web_test.dart | 2 +- .../test_driver/integration_test_driver.dart | 2 +- .../url_launcher_web/lib/src/link.dart | 2 +- .../url_launcher_web/lib/src/shims/dart_ui.dart | 2 +- .../lib/src/shims/dart_ui_fake.dart | 2 +- .../lib/src/shims/dart_ui_real.dart | 2 +- .../url_launcher_web/lib/url_launcher_web.dart | 2 +- .../test/tests_exist_elsewhere_test.dart | 2 +- packages/url_launcher/url_launcher_windows/AUTHORS | 1 + packages/url_launcher/url_launcher_windows/LICENSE | 2 +- .../integration_test/url_launcher_test.dart | 2 +- .../url_launcher_windows/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../url_launcher_windows/url_launcher_plugin.h | 2 +- .../windows/url_launcher_plugin.cpp | 2 +- packages/video_player/video_player/AUTHORS | 1 + packages/video_player/video_player/LICENSE | 2 +- .../videoplayer/CustomSSLSocketFactory.java | 2 +- .../io/flutter/plugins/videoplayer/Messages.java | 2 +- .../plugins/videoplayer/QueuingEventSink.java | 2 +- .../flutter/plugins/videoplayer/VideoPlayer.java | 2 +- .../plugins/videoplayer/VideoPlayerOptions.java | 2 +- .../plugins/videoplayer/VideoPlayerPlugin.java | 2 +- .../videoplayerexample/EmbeddingV1Activity.java | 2 +- .../integration_test/video_player_test.dart | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../video_player/example/ios/Runner/AppDelegate.h | 2 +- .../video_player/example/ios/Runner/AppDelegate.m | 2 +- .../video_player/example/ios/Runner/main.m | 2 +- .../video_player/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../example/test_driver/video_player.dart | 2 +- .../example/test_driver/video_player_test.dart | 2 +- .../ios/Classes/FLTVideoPlayerPlugin.h | 2 +- .../ios/Classes/FLTVideoPlayerPlugin.m | 2 +- .../video_player/ios/Classes/messages.h | 2 +- .../video_player/ios/Classes/messages.m | 2 +- .../video_player/lib/src/closed_caption_file.dart | 2 +- .../video_player/video_player/lib/src/sub_rip.dart | 2 +- .../video_player/lib/video_player.dart | 2 +- .../video_player/pigeons/messages.dart | 2 +- .../test/closed_caption_file_test.dart | 2 +- .../video_player/test/sub_rip_file_test.dart | 2 +- .../test/video_player_initialization_test.dart | 2 +- .../video_player/test/video_player_test.dart | 2 +- .../video_player_platform_interface/AUTHORS | 1 + .../video_player_platform_interface/LICENSE | 2 +- .../lib/messages.dart | 2 +- .../lib/method_channel_video_player.dart | 2 +- .../video_player_platform_interface/lib/test.dart | 2 +- .../lib/video_player_platform_interface.dart | 2 +- .../test/method_channel_video_player_test.dart | 2 +- packages/video_player/video_player_web/AUTHORS | 1 + packages/video_player/video_player_web/LICENSE | 2 +- .../video_player_web/lib/src/shims/dart_ui.dart | 2 +- .../lib/src/shims/dart_ui_fake.dart | 2 +- .../lib/src/shims/dart_ui_real.dart | 2 +- .../video_player_web/lib/video_player_web.dart | 2 +- .../test/video_player_web_test.dart | 2 +- packages/webview_flutter/AUTHORS | 1 + packages/webview_flutter/LICENSE | 2 +- .../webviewflutter/DisplayListenerProxy.java | 2 +- .../webviewflutter/FlutterCookieManager.java | 2 +- .../plugins/webviewflutter/FlutterWebView.java | 2 +- .../webviewflutter/FlutterWebViewClient.java | 2 +- .../plugins/webviewflutter/InputAwareWebView.java | 2 +- .../plugins/webviewflutter/JavaScriptChannel.java | 2 +- .../ThreadedInputConnectionProxyAdapterView.java | 2 +- .../plugins/webviewflutter/WebViewFactory.java | 2 +- .../webviewflutter/WebViewFlutterPlugin.java | 2 +- .../webviewflutterexample/EmbeddingV1Activity.java | 2 +- .../integration_test/webview_flutter_test.dart | 2 +- .../example/ios/Runner.xcodeproj/project.pbxproj | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- packages/webview_flutter/example/ios/Runner/main.m | 2 +- packages/webview_flutter/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../webview_flutter/ios/Classes/FLTCookieManager.h | 2 +- .../webview_flutter/ios/Classes/FLTCookieManager.m | 2 +- .../ios/Classes/FLTWKNavigationDelegate.h | 2 +- .../ios/Classes/FLTWKNavigationDelegate.m | 2 +- .../ios/Classes/FLTWKProgressionDelegate.h | 2 +- .../ios/Classes/FLTWKProgressionDelegate.m | 2 +- .../ios/Classes/FLTWebViewFlutterPlugin.h | 2 +- .../ios/Classes/FLTWebViewFlutterPlugin.m | 2 +- .../webview_flutter/ios/Classes/FlutterWebView.h | 2 +- .../webview_flutter/ios/Classes/FlutterWebView.m | 2 +- .../ios/Classes/JavaScriptChannelHandler.h | 2 +- .../ios/Classes/JavaScriptChannelHandler.m | 2 +- .../ios/Tests/FLTWKNavigationDelegateTests.m | 2 +- .../webview_flutter/ios/Tests/FLTWebViewTests.m | 2 +- .../webview_flutter/lib/platform_interface.dart | 2 +- .../webview_flutter/lib/src/webview_android.dart | 2 +- .../webview_flutter/lib/src/webview_cupertino.dart | 2 +- .../lib/src/webview_method_channel.dart | 2 +- packages/webview_flutter/lib/webview_flutter.dart | 2 +- .../webview_flutter/test/webview_flutter_test.dart | 2 +- .../wifi_info_flutter/wifi_info_flutter/AUTHORS | 1 + .../wifi_info_flutter/wifi_info_flutter/LICENSE | 2 +- .../plugins/wifi_info_flutter/WifiInfoFlutter.java | 2 +- .../WifiInfoFlutterMethodChannelHandler.java | 2 +- .../wifi_info_flutter/WifiInfoFlutterPlugin.java | 2 +- .../wifi_info_flutter/example/lib/main.dart | 2 +- .../integration_test/wifi_info_test.dart | 2 +- .../example/test_driver/test/integration_test.dart | 2 +- .../integration_test/wifi_info_test.dart | 2 +- .../ios/Classes/FLTWifiInfoLocationHandler.h | 2 +- .../ios/Classes/FLTWifiInfoLocationHandler.m | 2 +- .../ios/Classes/WifiInfoFlutterPlugin.h | 2 +- .../ios/Classes/WifiInfoFlutterPlugin.m | 2 +- .../wifi_info_flutter/lib/wifi_info_flutter.dart | 2 +- .../test/wifi_info_flutter_test.dart | 2 +- .../wifi_info_flutter_platform_interface/AUTHORS | 1 + .../wifi_info_flutter_platform_interface/LICENSE | 2 +- .../lib/src/enums.dart | 2 +- .../lib/src/method_channel_wifi_info_flutter.dart | 2 +- .../lib/wifi_info_flutter_platform_interface.dart | 2 +- .../method_channel_wifi_info_flutter_test.dart | 2 +- script/build_all_plugins_app.sh | 2 +- script/check_publish.sh | 2 +- script/common.sh | 2 +- script/incremental_build.sh | 2 +- script/tool/lib/src/analyze_command.dart | 2 +- script/tool/lib/src/build_examples_command.dart | 2 +- script/tool/lib/src/common.dart | 2 +- .../lib/src/create_all_plugins_app_command.dart | 2 +- script/tool/lib/src/drive_examples_command.dart | 2 +- script/tool/lib/src/firebase_test_lab_command.dart | 2 +- script/tool/lib/src/format_command.dart | 2 +- script/tool/lib/src/java_test_command.dart | 2 +- script/tool/lib/src/license_check_command.dart | 14 ++++---------- script/tool/lib/src/lint_podspecs_command.dart | 2 +- script/tool/lib/src/list_command.dart | 2 +- script/tool/lib/src/main.dart | 2 +- script/tool/lib/src/publish_check_command.dart | 2 +- script/tool/lib/src/publish_plugin_command.dart | 2 +- script/tool/lib/src/test_command.dart | 2 +- script/tool/lib/src/version_check_command.dart | 2 +- script/tool/lib/src/xctest_command.dart | 2 +- script/tool/test/analyze_command_test.dart | 2 +- script/tool/test/build_examples_command_test.dart | 2 +- script/tool/test/common_test.dart | 2 +- script/tool/test/drive_examples_command_test.dart | 2 +- script/tool/test/firebase_test_lab_test.dart | 2 +- script/tool/test/license_check_command_test.dart | 4 ++-- script/tool/test/lint_podspecs_command_test.dart | 2 +- script/tool/test/list_command_test.dart | 2 +- script/tool/test/mocks.dart | 2 +- script/tool/test/publish_plugin_command_test.dart | 2 +- script/tool/test/test_command_test.dart | 2 +- script/tool/test/util.dart | 2 +- script/tool/test/version_check_test.dart | 4 ++-- script/tool/test/xctest_command_test.dart | 2 +- 956 files changed, 962 insertions(+), 913 deletions(-) diff --git a/AUTHORS b/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/LICENSE b/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/android_alarm_manager/AUTHORS b/packages/android_alarm_manager/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/android_alarm_manager/AUTHORS +++ b/packages/android_alarm_manager/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/android_alarm_manager/LICENSE b/packages/android_alarm_manager/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/android_alarm_manager/LICENSE +++ b/packages/android_alarm_manager/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmBroadcastReceiver.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmBroadcastReceiver.java index a8968a2095d9..0b8a1455f9ae 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmBroadcastReceiver.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmBroadcastReceiver.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmService.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmService.java index 3287789f6c3d..5311911a3d7d 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmService.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmService.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java index 557913a626d5..1587bca71a80 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/FlutterBackgroundExecutor.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/FlutterBackgroundExecutor.java index 86010ff3f089..fc438753f3cc 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/FlutterBackgroundExecutor.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/FlutterBackgroundExecutor.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/PluginRegistrantException.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/PluginRegistrantException.java index debcd7ee7529..f38c2b8b0461 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/PluginRegistrantException.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/PluginRegistrantException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/RebootBroadcastReceiver.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/RebootBroadcastReceiver.java index b920afa1c1b7..5f5c5cacd86f 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/RebootBroadcastReceiver.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/RebootBroadcastReceiver.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/BackgroundExecutionTest.java b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/BackgroundExecutionTest.java index ce34b25ec505..457599b0da91 100644 --- a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/BackgroundExecutionTest.java +++ b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/BackgroundExecutionTest.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/DriverExtensionActivity.java b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/DriverExtensionActivity.java index 4f521a387bac..57c3f4122578 100644 --- a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/DriverExtensionActivity.java +++ b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/DriverExtensionActivity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/MainActivityTest.java b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/MainActivityTest.java index 373e770697d5..82503c9d54c5 100644 --- a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/MainActivityTest.java +++ b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/EmbeddingV1Activity.java b/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/EmbeddingV1Activity.java index 26a542be2598..8e77dbd1b46b 100644 --- a/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/EmbeddingV1Activity.java +++ b/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart b/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart index 68e35d581d89..67dcb520a3a2 100644 --- a/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart +++ b/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/android_alarm_manager/example/lib/main.dart b/packages/android_alarm_manager/example/lib/main.dart index dc3779c8cbe2..ff164a6275b3 100644 --- a/packages/android_alarm_manager/example/lib/main.dart +++ b/packages/android_alarm_manager/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_alarm_manager/example/test_driver/integration_test.dart b/packages/android_alarm_manager/example/test_driver/integration_test.dart index a2fa9e1147e1..88461d1c79a1 100644 --- a/packages/android_alarm_manager/example/test_driver/integration_test.dart +++ b/packages/android_alarm_manager/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/android_alarm_manager/lib/android_alarm_manager.dart b/packages/android_alarm_manager/lib/android_alarm_manager.dart index 218959bc4bcc..e074dfb3af36 100644 --- a/packages/android_alarm_manager/lib/android_alarm_manager.dart +++ b/packages/android_alarm_manager/lib/android_alarm_manager.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_alarm_manager/test/android_alarm_manager_test.dart b/packages/android_alarm_manager/test/android_alarm_manager_test.dart index 1f9d2856838e..4b340f563fd4 100644 --- a/packages/android_alarm_manager/test/android_alarm_manager_test.dart +++ b/packages/android_alarm_manager/test/android_alarm_manager_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/android_intent/AUTHORS b/packages/android_intent/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/android_intent/AUTHORS +++ b/packages/android_intent/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/android_intent/LICENSE b/packages/android_intent/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/android_intent/LICENSE +++ b/packages/android_intent/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java index 04df4d9f7c01..ff73b6de5485 100644 --- a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java +++ b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java index 0d2ff0c829e5..1c9aa9ac6b02 100644 --- a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java +++ b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java index 2cce443fd182..9bdcbec08465 100644 --- a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java +++ b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java b/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java index e36f4aab804d..bf3fdf976d9d 100644 --- a/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java +++ b/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_intent/example/android/app/src/main/java/io/flutter/plugins/androidintentexample/EmbeddingV1Activity.java b/packages/android_intent/example/android/app/src/main/java/io/flutter/plugins/androidintentexample/EmbeddingV1Activity.java index f64ae47a7656..87e822274f85 100644 --- a/packages/android_intent/example/android/app/src/main/java/io/flutter/plugins/androidintentexample/EmbeddingV1Activity.java +++ b/packages/android_intent/example/android/app/src/main/java/io/flutter/plugins/androidintentexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_intent/example/integration_test/android_intent_test.dart b/packages/android_intent/example/integration_test/android_intent_test.dart index e11a5e4e4898..28de6b785c70 100644 --- a/packages/android_intent/example/integration_test/android_intent_test.dart +++ b/packages/android_intent/example/integration_test/android_intent_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_intent/example/lib/main.dart b/packages/android_intent/example/lib/main.dart index 4fd2440285f3..99413c1d5701 100644 --- a/packages/android_intent/example/lib/main.dart +++ b/packages/android_intent/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_intent/example/test_driver/integration_test.dart b/packages/android_intent/example/test_driver/integration_test.dart index 0378ec31ee3c..993729f6ac3d 100644 --- a/packages/android_intent/example/test_driver/integration_test.dart +++ b/packages/android_intent/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_intent/lib/android_intent.dart b/packages/android_intent/lib/android_intent.dart index 0ab2d7bee420..698a584ce7ea 100644 --- a/packages/android_intent/lib/android_intent.dart +++ b/packages/android_intent/lib/android_intent.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/android_intent/lib/flag.dart b/packages/android_intent/lib/flag.dart index 990eed9db8fc..147c6a1d932c 100644 --- a/packages/android_intent/lib/flag.dart +++ b/packages/android_intent/lib/flag.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery/AUTHORS b/packages/battery/battery/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/battery/battery/AUTHORS +++ b/packages/battery/battery/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/battery/battery/LICENSE b/packages/battery/battery/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/battery/battery/LICENSE +++ b/packages/battery/battery/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/battery/battery/android/src/main/java/io/flutter/plugins/battery/BatteryPlugin.java b/packages/battery/battery/android/src/main/java/io/flutter/plugins/battery/BatteryPlugin.java index f16d219291d1..92405a9900d3 100644 --- a/packages/battery/battery/android/src/main/java/io/flutter/plugins/battery/BatteryPlugin.java +++ b/packages/battery/battery/android/src/main/java/io/flutter/plugins/battery/BatteryPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/EmbedderV1ActivityTest.java b/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/EmbedderV1ActivityTest.java index 1bd860eb147c..3c4eabeaf23f 100644 --- a/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/EmbedderV1ActivityTest.java +++ b/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/EmbedderV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/FlutterActivityTest.java b/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/FlutterActivityTest.java index 636c716d7a91..2fec9365b756 100644 --- a/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/FlutterActivityTest.java +++ b/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/battery/battery/example/android/app/src/main/java/io/flutter/plugins/batteryexample/EmbedderV1Activity.java b/packages/battery/battery/example/android/app/src/main/java/io/flutter/plugins/batteryexample/EmbedderV1Activity.java index 5fa885cdd9d8..6877a5013737 100644 --- a/packages/battery/battery/example/android/app/src/main/java/io/flutter/plugins/batteryexample/EmbedderV1Activity.java +++ b/packages/battery/battery/example/android/app/src/main/java/io/flutter/plugins/batteryexample/EmbedderV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery/example/ios/Runner.xcodeproj/project.pbxproj b/packages/battery/battery/example/ios/Runner.xcodeproj/project.pbxproj index aa42a8509346..3abde6d9a3d0 100644 --- a/packages/battery/battery/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/battery/battery/example/ios/Runner.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/battery/battery/example/ios/Runner/AppDelegate.h b/packages/battery/battery/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/battery/battery/example/ios/Runner/AppDelegate.h +++ b/packages/battery/battery/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery/example/ios/Runner/AppDelegate.m b/packages/battery/battery/example/ios/Runner/AppDelegate.m index a4b51c88eb60..abfe2106b092 100644 --- a/packages/battery/battery/example/ios/Runner/AppDelegate.m +++ b/packages/battery/battery/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery/example/ios/Runner/main.m b/packages/battery/battery/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/battery/battery/example/ios/Runner/main.m +++ b/packages/battery/battery/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery/example/lib/main.dart b/packages/battery/battery/example/lib/main.dart index 8482655771f2..8c0edec04f74 100644 --- a/packages/battery/battery/example/lib/main.dart +++ b/packages/battery/battery/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery/integration_test/battery_test.dart b/packages/battery/battery/integration_test/battery_test.dart index 1732380919b2..4912f3f81fd3 100644 --- a/packages/battery/battery/integration_test/battery_test.dart +++ b/packages/battery/battery/integration_test/battery_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/battery/battery/ios/Classes/FLTBatteryPlugin.h b/packages/battery/battery/ios/Classes/FLTBatteryPlugin.h index 9743ca501208..b555de48ebf4 100644 --- a/packages/battery/battery/ios/Classes/FLTBatteryPlugin.h +++ b/packages/battery/battery/ios/Classes/FLTBatteryPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery/ios/Classes/FLTBatteryPlugin.m b/packages/battery/battery/ios/Classes/FLTBatteryPlugin.m index f1e82a64eb1b..151dbda1ce32 100644 --- a/packages/battery/battery/ios/Classes/FLTBatteryPlugin.m +++ b/packages/battery/battery/ios/Classes/FLTBatteryPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery/lib/battery.dart b/packages/battery/battery/lib/battery.dart index e3943e49599a..8781979a7eac 100644 --- a/packages/battery/battery/lib/battery.dart +++ b/packages/battery/battery/lib/battery.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery/test/battery_test.dart b/packages/battery/battery/test/battery_test.dart index ff1bf1596250..5db0798d906e 100644 --- a/packages/battery/battery/test/battery_test.dart +++ b/packages/battery/battery/test/battery_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery_platform_interface/AUTHORS b/packages/battery/battery_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/battery/battery_platform_interface/AUTHORS +++ b/packages/battery/battery_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/battery/battery_platform_interface/LICENSE b/packages/battery/battery_platform_interface/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/battery/battery_platform_interface/LICENSE +++ b/packages/battery/battery_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart b/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart index f803c7aaa8fd..c839b02bc18d 100644 --- a/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart +++ b/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery_platform_interface/lib/enums/battery_state.dart b/packages/battery/battery_platform_interface/lib/enums/battery_state.dart index 2ceb35128b4b..b8458224df4a 100644 --- a/packages/battery/battery_platform_interface/lib/enums/battery_state.dart +++ b/packages/battery/battery_platform_interface/lib/enums/battery_state.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart b/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart index dbc561bf0e64..8f38b6616702 100644 --- a/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart +++ b/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart b/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart index 2b17cf97e711..0e36e0a1fbba 100644 --- a/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart +++ b/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/camera/camera/AUTHORS b/packages/camera/camera/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/camera/camera/AUTHORS +++ b/packages/camera/camera/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/camera/camera/LICENSE b/packages/camera/camera/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/camera/camera/LICENSE +++ b/packages/camera/camera/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 5169a3babb74..4faedf3aa0c2 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java index 3529e69a2b0b..4442fce9b2fd 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java index 93183bb7c0a7..849ca3ccc489 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java index 04412a56631f..67030ebe9667 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java index 03993a3b51f9..4ad260f7347f 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java index 5eed9f4734b7..ff3f04ade0fd 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java index 3892452892d9..8e7be0937000 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java index b2a504b629d6..af1a0c2082c5 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index aa7483f55679..c1afd64febec 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java index 396f782a2a08..4a6fafff50c8 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java index 4c3fb3add230..9873a3c12972 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java index 595206fa2216..fd2475649b89 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java index c4f0998c418a..3880874779be 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java index b0dba047f7eb..d4e8348ab8ed 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java index 1508dcefb293..1c2ce8b0c8aa 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java index 2b19b5dbb0d6..930b5ad08ab3 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java index 99745e56a857..d0074d295ca2 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java index 8026b6349aa1..aa89669459bb 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java index 8f05da71b5c5..445174b3b357 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java index e835b08f441a..ff77b32cd1d0 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java index 3252b3e111c4..8542fc615c35 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java index 823975803994..04eb3e031cca 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java index 63810f0b5684..600c426063e2 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java index 1f5f0c6272ed..8b812b4b011d 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java index 4aa6fadf776b..114aaa342e9b 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/example/integration_test/camera_test.dart b/packages/camera/camera/example/integration_test/camera_test.dart index f30734180b20..1b08200ed68d 100644 --- a/packages/camera/camera/example/integration_test/camera_test.dart +++ b/packages/camera/camera/example/integration_test/camera_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj index 3f71bb69d6b6..c865799d6a02 100644 --- a/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj @@ -164,7 +164,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 5eebc9a379ca..0148ce41d725 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/example/test_driver/integration_test.dart b/packages/camera/camera/example/test_driver/integration_test.dart index 8a35ec06803d..0ad951cb063d 100644 --- a/packages/camera/camera/example/test_driver/integration_test.dart +++ b/packages/camera/camera/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.h b/packages/camera/camera/ios/Classes/CameraPlugin.h index ae865e496a45..f42084125e6c 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.h +++ b/packages/camera/camera/ios/Classes/CameraPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index c1770ff6d40b..308ca886a45f 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/ios/Tests/CameraPluginTests.m b/packages/camera/camera/ios/Tests/CameraPluginTests.m index 8d9cbc2eb81a..3d8443901672 100644 --- a/packages/camera/camera/ios/Tests/CameraPluginTests.m +++ b/packages/camera/camera/ios/Tests/CameraPluginTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/lib/camera.dart b/packages/camera/camera/lib/camera.dart index d6e32affdd7a..daab70128ada 100644 --- a/packages/camera/camera/lib/camera.dart +++ b/packages/camera/camera/lib/camera.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index bb976d1c85fe..f7710d45c7fd 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/camera/camera/lib/src/camera_image.dart b/packages/camera/camera/lib/src/camera_image.dart index 46aa2a6e3091..fd551082bc83 100644 --- a/packages/camera/camera/lib/src/camera_image.dart +++ b/packages/camera/camera/lib/src/camera_image.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/camera/camera/lib/src/camera_preview.dart b/packages/camera/camera/lib/src/camera_preview.dart index f6d357b41b77..caa8c04885c7 100644 --- a/packages/camera/camera/lib/src/camera_preview.dart +++ b/packages/camera/camera/lib/src/camera_preview.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/camera/camera/test/camera_image_stream_test.dart b/packages/camera/camera/test/camera_image_stream_test.dart index 41faeb1fd4b0..6832466a25ba 100644 --- a/packages/camera/camera/test/camera_image_stream_test.dart +++ b/packages/camera/camera/test/camera_image_stream_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/test/camera_image_test.dart b/packages/camera/camera/test/camera_image_test.dart index c7f8e4320434..40d7194e36d1 100644 --- a/packages/camera/camera/test/camera_image_test.dart +++ b/packages/camera/camera/test/camera_image_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 40ce29e363b1..272587e9955b 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/camera/camera/test/camera_value_test.dart b/packages/camera/camera/test/camera_value_test.dart index de7971d963c0..f1809fc61167 100644 --- a/packages/camera/camera/test/camera_value_test.dart +++ b/packages/camera/camera/test/camera_value_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera/test/utils/method_channel_mock.dart b/packages/camera/camera/test/utils/method_channel_mock.dart index c667bed76e89..6e0b28e224d8 100644 --- a/packages/camera/camera/test/utils/method_channel_mock.dart +++ b/packages/camera/camera/test/utils/method_channel_mock.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/AUTHORS b/packages/camera/camera_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/camera/camera_platform_interface/AUTHORS +++ b/packages/camera/camera_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/camera/camera_platform_interface/LICENSE b/packages/camera/camera_platform_interface/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/camera/camera_platform_interface/LICENSE +++ b/packages/camera/camera_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart b/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart index d7e5fcd0834c..b7a7b2ff29b8 100644 --- a/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart +++ b/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart index 20aa41c5ce40..137a0002ef17 100644 --- a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart +++ b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/lib/src/events/device_event.dart b/packages/camera/camera_platform_interface/lib/src/events/device_event.dart index 82febcab2290..a4edbef0d317 100644 --- a/packages/camera/camera_platform_interface/lib/src/events/device_event.dart +++ b/packages/camera/camera_platform_interface/lib/src/events/device_event.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index 9f7f723bcd79..321104e695e9 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 39a17e43dc0f..92e3587ee04b 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart b/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart index 9707bd34d0d2..dffb5d1bff01 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart b/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart index 59f3e4e6647e..f8da81392b43 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart index 836f53826479..a1cfbfcc08a5 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart index 7feb59caeab8..e851857a26d6 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart index 8da2a90fa858..76d429463a29 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart b/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart index 61ccbfc2638a..3c07dfe0faca 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart b/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart index ead592364131..cabeb6a0b9cc 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/types.dart b/packages/camera/camera_platform_interface/lib/src/types/types.dart index 256558dff3e7..5b9999ece037 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/types.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/types.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/camera/camera_platform_interface/lib/src/utils/utils.dart b/packages/camera/camera_platform_interface/lib/src/utils/utils.dart index f4c21bfca6cc..b8703d603801 100644 --- a/packages/camera/camera_platform_interface/lib/src/utils/utils.dart +++ b/packages/camera/camera_platform_interface/lib/src/utils/utils.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart index f663db9776d1..b3d61a467373 100644 --- a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart +++ b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/events/camera_event_test.dart b/packages/camera/camera_platform_interface/test/events/camera_event_test.dart index f146b7e7e7bc..120cafc238c3 100644 --- a/packages/camera/camera_platform_interface/test/events/camera_event_test.dart +++ b/packages/camera/camera_platform_interface/test/events/camera_event_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/events/device_event_test.dart b/packages/camera/camera_platform_interface/test/events/device_event_test.dart index c2fef49be04f..950a12e21484 100644 --- a/packages/camera/camera_platform_interface/test/events/device_event_test.dart +++ b/packages/camera/camera_platform_interface/test/events/device_event_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index 5248d34c46b9..ea7e9787a817 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/types/camera_description_test.dart b/packages/camera/camera_platform_interface/test/types/camera_description_test.dart index 03909dbafb97..a098df07b094 100644 --- a/packages/camera/camera_platform_interface/test/types/camera_description_test.dart +++ b/packages/camera/camera_platform_interface/test/types/camera_description_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart b/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart index 17370e4561f5..338238e0bb75 100644 --- a/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart +++ b/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart b/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart index c34c1d7b4157..b8e77fe5df80 100644 --- a/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart +++ b/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart b/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart index c9df64152cef..8c6903087fdd 100644 --- a/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart +++ b/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart b/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart index ca7ad902820a..5ce379400e37 100644 --- a/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart +++ b/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/types/image_group_test.dart b/packages/camera/camera_platform_interface/test/types/image_group_test.dart index ac975fa6e6ce..9ae4b9bb4c3c 100644 --- a/packages/camera/camera_platform_interface/test/types/image_group_test.dart +++ b/packages/camera/camera_platform_interface/test/types/image_group_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart b/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart index aadf589f87c4..4da08cf2f0b7 100644 --- a/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart +++ b/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart b/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart index c667bed76e89..6e0b28e224d8 100644 --- a/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart +++ b/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/camera/camera_platform_interface/test/utils/utils_test.dart b/packages/camera/camera_platform_interface/test/utils/utils_test.dart index 822798160439..d99f9ab01443 100644 --- a/packages/camera/camera_platform_interface/test/utils/utils_test.dart +++ b/packages/camera/camera_platform_interface/test/utils/utils_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity/AUTHORS b/packages/connectivity/connectivity/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/connectivity/connectivity/AUTHORS +++ b/packages/connectivity/connectivity/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/connectivity/connectivity/LICENSE b/packages/connectivity/connectivity/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/connectivity/connectivity/LICENSE +++ b/packages/connectivity/connectivity/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java index a8902fa62ef9..f2f16ae61629 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java index dbf96bda9fe8..e44e7b4e8f5d 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityMethodChannelHandler.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityMethodChannelHandler.java index de1958a1f4f1..3f8541ed1c54 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityMethodChannelHandler.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityMethodChannelHandler.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityPlugin.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityPlugin.java index 3de60f06c67e..91d00839145f 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityPlugin.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1Activity.java b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1Activity.java index 591f1ec604d7..89438471ace3 100644 --- a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1Activity.java +++ b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1ActivityTest.java b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1ActivityTest.java index 2adc0c268bde..1667a7317c68 100644 --- a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1ActivityTest.java +++ b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/FlutterActivityTest.java b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/FlutterActivityTest.java index 0f0dcf2555f3..8d7f9d0c460f 100644 --- a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/FlutterActivityTest.java +++ b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity/example/ios/Runner.xcodeproj/project.pbxproj b/packages/connectivity/connectivity/example/ios/Runner.xcodeproj/project.pbxproj index e497d093be56..e77d9f454116 100644 --- a/packages/connectivity/connectivity/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/connectivity/connectivity/example/ios/Runner.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.h b/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.h +++ b/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.m b/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.m index f08675707182..2147d3d605ac 100644 --- a/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.m +++ b/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/connectivity/connectivity/example/ios/Runner/main.m b/packages/connectivity/connectivity/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/connectivity/connectivity/example/ios/Runner/main.m +++ b/packages/connectivity/connectivity/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/connectivity/connectivity/example/lib/main.dart b/packages/connectivity/connectivity/example/lib/main.dart index 19285ce889fd..6f6356f0fc2b 100644 --- a/packages/connectivity/connectivity/example/lib/main.dart +++ b/packages/connectivity/connectivity/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart b/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart index 3177b66ea48a..13c9d4b5e8fb 100644 --- a/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart +++ b/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart b/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart index 33421c335bdd..9887033fc5dd 100644 --- a/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart +++ b/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity/integration_test/connectivity_test.dart b/packages/connectivity/connectivity/integration_test/connectivity_test.dart index 3177b66ea48a..13c9d4b5e8fb 100644 --- a/packages/connectivity/connectivity/integration_test/connectivity_test.dart +++ b/packages/connectivity/connectivity/integration_test/connectivity_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.h b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.h index 5014624f2f69..bb0ff07dc712 100644 --- a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.h +++ b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m index fb996c1b11ba..241d01c1b007 100644 --- a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m +++ b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/connectivity/connectivity/lib/connectivity.dart b/packages/connectivity/connectivity/lib/connectivity.dart index 0f30a9347b74..e4199d55f699 100644 --- a/packages/connectivity/connectivity/lib/connectivity.dart +++ b/packages/connectivity/connectivity/lib/connectivity.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/connectivity/connectivity/test/connectivity_test.dart b/packages/connectivity/connectivity/test/connectivity_test.dart index c95d0862444f..cde833c9d71e 100644 --- a/packages/connectivity/connectivity/test/connectivity_test.dart +++ b/packages/connectivity/connectivity/test/connectivity_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/connectivity/connectivity_for_web/AUTHORS b/packages/connectivity/connectivity_for_web/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/connectivity/connectivity_for_web/AUTHORS +++ b/packages/connectivity/connectivity_for_web/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart b/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart index 64e2248a4f9b..0dd5f694f16b 100644 --- a/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart +++ b/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity_macos/AUTHORS b/packages/connectivity/connectivity_macos/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/connectivity/connectivity_macos/AUTHORS +++ b/packages/connectivity/connectivity_macos/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/connectivity/connectivity_macos/LICENSE b/packages/connectivity/connectivity_macos/LICENSE index 507569823f1b..b257ce7c224c 100644 --- a/packages/connectivity/connectivity_macos/LICENSE +++ b/packages/connectivity/connectivity_macos/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Chromium Authors. All rights reserved. +Copyright 2019 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/connectivity/connectivity_macos/example/lib/main.dart b/packages/connectivity/connectivity_macos/example/lib/main.dart index 07746ed0f722..97baf2678fd3 100644 --- a/packages/connectivity/connectivity_macos/example/lib/main.dart +++ b/packages/connectivity/connectivity_macos/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart b/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart index 3abe491d193b..d38614076190 100644 --- a/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart +++ b/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart b/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart index 425dac924e7c..49af1cbb81a5 100644 --- a/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart +++ b/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity_macos/macos/Classes/ConnectivityPlugin.swift b/packages/connectivity/connectivity_macos/macos/Classes/ConnectivityPlugin.swift index 8eafbc3188cf..302c6d7d55e3 100644 --- a/packages/connectivity/connectivity_macos/macos/Classes/ConnectivityPlugin.swift +++ b/packages/connectivity/connectivity_macos/macos/Classes/ConnectivityPlugin.swift @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity_macos/macos/Classes/IPHelper.h b/packages/connectivity/connectivity_macos/macos/Classes/IPHelper.h index e5a067b9069f..a1bc4ce12179 100644 --- a/packages/connectivity/connectivity_macos/macos/Classes/IPHelper.h +++ b/packages/connectivity/connectivity_macos/macos/Classes/IPHelper.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/connectivity/connectivity_platform_interface/AUTHORS b/packages/connectivity/connectivity_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/connectivity/connectivity_platform_interface/AUTHORS +++ b/packages/connectivity/connectivity_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/connectivity/connectivity_platform_interface/LICENSE b/packages/connectivity/connectivity_platform_interface/LICENSE index d7412e0a1e0c..67c7e2c52e46 100644 --- a/packages/connectivity/connectivity_platform_interface/LICENSE +++ b/packages/connectivity/connectivity_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Chromium Authors. All rights reserved. +Copyright 2020 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart b/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart index 8e9f0fd6af06..b137509f650a 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart b/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart index 640e378de0ce..9c8398f2f67a 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart b/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart index b411b5bc069b..f04eb9193fb5 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart b/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart index 4df92974ba0c..5c62c61220ec 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart b/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart index 0c30530fc9ab..5ae66acabc36 100644 --- a/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart +++ b/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/device_info/device_info/AUTHORS b/packages/device_info/device_info/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/device_info/device_info/AUTHORS +++ b/packages/device_info/device_info/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/device_info/device_info/LICENSE b/packages/device_info/device_info/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/device_info/device_info/LICENSE +++ b/packages/device_info/device_info/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java b/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java index 137daf508ac2..28fdc888560b 100644 --- a/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java +++ b/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java b/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java index 800ca6dcddb7..fb44bc821e6d 100644 --- a/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java +++ b/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1Activity.java b/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1Activity.java index 0256c6b8a1fb..6be74796a0b6 100644 --- a/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1Activity.java +++ b/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info/example/integration_test/device_info_test.dart b/packages/device_info/device_info/example/integration_test/device_info_test.dart index a2a3ba7733ce..9fbb682df2e8 100644 --- a/packages/device_info/device_info/example/integration_test/device_info_test.dart +++ b/packages/device_info/device_info/example/integration_test/device_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/device_info/device_info/example/ios/Runner.xcodeproj/project.pbxproj b/packages/device_info/device_info/example/ios/Runner.xcodeproj/project.pbxproj index 8f80e80abb09..1c6c6e8f4d50 100644 --- a/packages/device_info/device_info/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/device_info/device_info/example/ios/Runner.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/device_info/device_info/example/ios/Runner/AppDelegate.h b/packages/device_info/device_info/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/device_info/device_info/example/ios/Runner/AppDelegate.h +++ b/packages/device_info/device_info/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info/example/ios/Runner/AppDelegate.m b/packages/device_info/device_info/example/ios/Runner/AppDelegate.m index f08675707182..2147d3d605ac 100644 --- a/packages/device_info/device_info/example/ios/Runner/AppDelegate.m +++ b/packages/device_info/device_info/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info/example/ios/Runner/main.m b/packages/device_info/device_info/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/device_info/device_info/example/ios/Runner/main.m +++ b/packages/device_info/device_info/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info/example/lib/main.dart b/packages/device_info/device_info/example/lib/main.dart index 805de1417f15..24129aa04b1c 100644 --- a/packages/device_info/device_info/example/lib/main.dart +++ b/packages/device_info/device_info/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info/example/test_driver/integration_test.dart b/packages/device_info/device_info/example/test_driver/integration_test.dart index 84004cebd1a6..29b5b21a5941 100644 --- a/packages/device_info/device_info/example/test_driver/integration_test.dart +++ b/packages/device_info/device_info/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.h b/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.h index b5e95ed10e84..e4e287c584d5 100644 --- a/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.h +++ b/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.m b/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.m index 423896061ac7..bc2d172c576e 100644 --- a/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.m +++ b/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info/lib/device_info.dart b/packages/device_info/device_info/lib/device_info.dart index bccc3d2fbfa6..a357844cf2d9 100644 --- a/packages/device_info/device_info/lib/device_info.dart +++ b/packages/device_info/device_info/lib/device_info.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info_platform_interface/AUTHORS b/packages/device_info/device_info_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/device_info/device_info_platform_interface/AUTHORS +++ b/packages/device_info/device_info_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/device_info/device_info_platform_interface/LICENSE b/packages/device_info/device_info_platform_interface/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/device_info/device_info_platform_interface/LICENSE +++ b/packages/device_info/device_info_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart b/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart index 2dd41dcc580f..676207ba07fe 100644 --- a/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart +++ b/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart b/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart index 331f718989ce..d9eb455684e7 100644 --- a/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart index c5210ab10f50..00195a8f42b2 100644 --- a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart index 20ec8362f66d..e779ddc8a129 100644 --- a/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart index b257109fe2f6..cc0b4b4d10a7 100644 --- a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart +++ b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/espresso/AUTHORS b/packages/espresso/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/espresso/AUTHORS +++ b/packages/espresso/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/espresso/LICENSE b/packages/espresso/LICENSE index 507569823f1b..b257ce7c224c 100644 --- a/packages/espresso/LICENSE +++ b/packages/espresso/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Chromium Authors. All rights reserved. +Copyright 2019 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java index 6730a66a5406..89233e64799f 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ActionUtil.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ActionUtil.java index 7dcb05b41724..8ab4c4a137cf 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ActionUtil.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ActionUtil.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ClickAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ClickAction.java index 5da56fd402ad..949c1e1cffbd 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ClickAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ClickAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterActions.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterActions.java index 258daf67a66e..3fdcb08eb525 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterActions.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterActions.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterScrollToAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterScrollToAction.java index b97252a2306e..4462ff6d6646 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterScrollToAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterScrollToAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterTypeTextAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterTypeTextAction.java index bb62250eefcb..b0b744773066 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterTypeTextAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterTypeTextAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java index fc554d761db5..0d8d94844d97 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/SyntheticClickAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/SyntheticClickAction.java index 5036be1fd290..ddc347defa55 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/SyntheticClickAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/SyntheticClickAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WaitUntilIdleAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WaitUntilIdleAction.java index b83e29b7e582..054c00e86d60 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WaitUntilIdleAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WaitUntilIdleAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetCoordinatesCalculator.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetCoordinatesCalculator.java index 8d541ae823ee..0ef5a5761dc3 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetCoordinatesCalculator.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetCoordinatesCalculator.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetInfoFetcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetInfoFetcher.java index 90d494e0b8ea..3e5f48d56983 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetInfoFetcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetInfoFetcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterAction.java index 24b264c00a27..3f1d3a23d99a 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterTestingProtocol.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterTestingProtocol.java index d01aaf5fdc09..54be97652157 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterTestingProtocol.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterTestingProtocol.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/SyntheticAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/SyntheticAction.java index aed0c4bc7570..0d2f0cbf49cf 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/SyntheticAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/SyntheticAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAction.java index e49d3ef2bb0f..b04cb0cb1d8a 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAssertion.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAssertion.java index 313dd2672336..d69972b09b3f 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAssertion.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAssertion.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetMatcher.java index 9f47e0bbeee6..a8e0b6a07c75 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterAssertions.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterAssertions.java index 63ec0f6f6fdc..6573f2a2a705 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterAssertions.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterAssertions.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterViewAssertion.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterViewAssertion.java index 5f4697de947a..6bc81b5862e4 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterViewAssertion.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterViewAssertion.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Constants.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Constants.java index c47f8df1e34d..170830fc7abb 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Constants.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Constants.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Duration.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Duration.java index d620153fc2f5..1d7bac224ec6 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Duration.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Duration.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/AmbiguousWidgetMatcherException.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/AmbiguousWidgetMatcherException.java index 24d495f74945..adf2e39db0b8 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/AmbiguousWidgetMatcherException.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/AmbiguousWidgetMatcherException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/InvalidFlutterViewException.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/InvalidFlutterViewException.java index ca69e39802d0..16c49220e0b9 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/InvalidFlutterViewException.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/InvalidFlutterViewException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/NoMatchingWidgetException.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/NoMatchingWidgetException.java index 49c949a07c8a..55ce0f4e3935 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/NoMatchingWidgetException.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/NoMatchingWidgetException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdException.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdException.java index 1a3666ec24e1..5be422184fe6 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdException.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerator.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerator.java index b69d8f61aa4f..ee6d693d97ee 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerator.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerator.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerators.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerators.java index f8f72dc2a37d..28d6816b7306 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerators.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerators.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/JsonRpcClient.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/JsonRpcClient.java index 028a78028406..7b5f8458a8f5 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/JsonRpcClient.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/JsonRpcClient.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java index d7779d3e5ec7..bf31679d7b3b 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcRequest.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcRequest.java index fa033407eabf..6eff736b5434 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcRequest.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcRequest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcResponse.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcResponse.java index f845765a98e5..45b376a3f793 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcResponse.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcResponse.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java index c6ec0e08b03a..7e3b277558c9 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java index a943194e348e..2534cc4d4736 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/FlutterProtocolException.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/FlutterProtocolException.java index 71cdb26ebf5c..b2b182f10640 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/FlutterProtocolException.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/FlutterProtocolException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetAction.java index 9b92f672f356..4dbf78836223 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetResponse.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetResponse.java index 52fcd4ce45ab..202f774f5d6b 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetResponse.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetResponse.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetVmResponse.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetVmResponse.java index 2fe0d44bfcda..e3f97afb97fa 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetVmResponse.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetVmResponse.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsAction.java index 5982ee481ed8..4753dd3dc451 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsResponse.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsResponse.java index 65a456c0939a..6ee27de06705 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsResponse.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsResponse.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingFrameCondition.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingFrameCondition.java index 7e7739b6a1a0..64c37d31a782 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingFrameCondition.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingFrameCondition.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingPlatformMessagesCondition.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingPlatformMessagesCondition.java index 8430ee23f92d..7969ef851b3e 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingPlatformMessagesCondition.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingPlatformMessagesCondition.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoTransientCallbacksCondition.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoTransientCallbacksCondition.java index 4548b28b66bd..d4eb77810d0b 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoTransientCallbacksCondition.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoTransientCallbacksCondition.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitCondition.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitCondition.java index 7017e88765f3..5baba66b89cb 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitCondition.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitCondition.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitForConditionAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitForConditionAction.java index efbe588828c3..2880130e8438 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitForConditionAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitForConditionAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WidgetInfoFactory.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WidgetInfoFactory.java index 2353577e5f4b..264f6cb77e5d 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WidgetInfoFactory.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WidgetInfoFactory.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java index f867b7dcbed4..634e2197ee94 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsDescendantOfMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsDescendantOfMatcher.java index 24a441549624..947a0f79cad4 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsDescendantOfMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsDescendantOfMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsExistingMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsExistingMatcher.java index 3380d2146b87..843d331d10a3 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsExistingMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsExistingMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTextMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTextMatcher.java index 4b86aed03216..711a835a45a5 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTextMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTextMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTooltipMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTooltipMatcher.java index 27d4314b3039..fde9cd805ce8 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTooltipMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTooltipMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTypeMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTypeMatcher.java index 84cf0e03feae..b30fdf38674c 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTypeMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTypeMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithValueKeyMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithValueKeyMatcher.java index 0e3df39be9b8..719f8adcab4d 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithValueKeyMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithValueKeyMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfo.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfo.java index d6394d2052f3..5b90a0002b53 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfo.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfo.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfoBuilder.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfoBuilder.java index 53ea8a27cddc..c119278af645 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfoBuilder.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfoBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/espresso/example/android/app/src/androidTest/java/com/example/MainActivityTest.java b/packages/espresso/example/android/app/src/androidTest/java/com/example/MainActivityTest.java index aaedd6cbd7cb..8a432809e9cb 100644 --- a/packages/espresso/example/android/app/src/androidTest/java/com/example/MainActivityTest.java +++ b/packages/espresso/example/android/app/src/androidTest/java/com/example/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/flutter_plugin_android_lifecycle/AUTHORS b/packages/flutter_plugin_android_lifecycle/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/flutter_plugin_android_lifecycle/AUTHORS +++ b/packages/flutter_plugin_android_lifecycle/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/flutter_plugin_android_lifecycle/LICENSE b/packages/flutter_plugin_android_lifecycle/LICENSE index 507569823f1b..b257ce7c224c 100644 --- a/packages/flutter_plugin_android_lifecycle/LICENSE +++ b/packages/flutter_plugin_android_lifecycle/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Chromium Authors. All rights reserved. +Copyright 2019 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapter.java b/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapter.java index 91ac6e0fd15f..3c91bb744d5c 100644 --- a/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapter.java +++ b/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapter.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle/FlutterAndroidLifecyclePlugin.java b/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle/FlutterAndroidLifecyclePlugin.java index bd77c1545ac7..fa90a210ffd2 100644 --- a/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle/FlutterAndroidLifecyclePlugin.java +++ b/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle/FlutterAndroidLifecyclePlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. // diff --git a/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java b/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java index 6657dfbb5a71..c184b1ad88db 100644 --- a/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java +++ b/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/EmbeddingV1ActivityTest.java b/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/EmbeddingV1ActivityTest.java index e61cadd3a9d3..89b9192c1676 100644 --- a/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/EmbeddingV1ActivityTest.java +++ b/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/MainActivityTest.java b/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/MainActivityTest.java index 4c3c9a247883..22bc3fe68d46 100644 --- a/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/MainActivityTest.java +++ b/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/MainActivity.java b/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/MainActivity.java index e2d2560e9105..a05da9ebb71a 100644 --- a/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/MainActivity.java +++ b/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/MainActivity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart b/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart index e4b92c8db7ed..8890f14925ab 100644 --- a/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart +++ b/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/lib/main.dart b/packages/flutter_plugin_android_lifecycle/example/lib/main.dart index c055c5359515..d9ee842364a6 100644 --- a/packages/flutter_plugin_android_lifecycle/example/lib/main.dart +++ b/packages/flutter_plugin_android_lifecycle/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart b/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart index ea111552567d..38bb867225d1 100644 --- a/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart +++ b/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/AUTHORS b/packages/google_maps_flutter/google_maps_flutter/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/google_maps_flutter/google_maps_flutter/AUTHORS +++ b/packages/google_maps_flutter/google_maps_flutter/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/google_maps_flutter/google_maps_flutter/LICENSE b/packages/google_maps_flutter/google_maps_flutter/LICENSE index ad33cf3c3ed1..050e2c7cac4f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/LICENSE +++ b/packages/google_maps_flutter/google_maps_flutter/LICENSE @@ -1,4 +1,4 @@ -Copyright 2018 The Chromium Authors. All rights reserved. +Copyright 2018 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleBuilder.java index 751887a6fa22..230659d2bf71 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleController.java index 709045a1b9f6..27accafd9bd9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleOptionsSink.java index 950c3209ee62..51e6c2194ab7 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleOptionsSink.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java index b7b562ee94a6..d9661e9e80f8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index f9e0ed9c32d0..30e7339f3de5 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java index 6d5c8c64ae1d..8d3414edfc4c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index 7db65c56a5e8..92d0e044e577 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java index bf9188ffd1b1..96cfee088ad3 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java index 518d45c4a9f6..c240f89deddb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java index 03377d4b760e..4ed31fabdab0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java index 69ba8cb222c0..0a0a17a05f47 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/LifecycleProvider.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/LifecycleProvider.java index 154de200fd86..0e06321e7267 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/LifecycleProvider.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/LifecycleProvider.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java index 29e4de00c5b0..69637a12bff0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java index 412daee5cf68..667254ea9d7f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java index 3f853b9f1459..25ed42927189 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java index 70feb978af3f..8a9897886f11 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java index 7691e58e4ae6..149c1246f596 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java index 43f1bfd7ec4c..3fe58f2fb900 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java index 2985a7b762e5..6b4aea89efc1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java index 07f2ad0f7c38..734525b2b0a3 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineBuilder.java index 9fd242a4706f..2a8718710262 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineController.java index ec0fed83be49..172c807eb2a2 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineOptionsSink.java index adaf867b92d1..d05059860d68 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineOptionsSink.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java index a6ad61adc170..b6f3a90f4745 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java index 1b5593358536..cbe6cfbd5e51 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java index 1204bcdaafd7..9f07d7e6859f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java index fd611d7c57f3..b32ae8fb6f67 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java index cd583e247cdd..f72dd7d6c1af 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java index f28118c91db4..e760fafca8b7 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java index 24bee4ea7550..5b24902e17f1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java index 7c8032b2b0d4..33765e71e7a1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java index e3c2f339f250..0d167a5dbe1e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java index e65cb1f22dc9..f4a0248240a4 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java index 7e5d39c380fd..bca2ebe5b8ce 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java index 1f0a7000f5e7..7cfa33acbd7c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart index 33ad5d03778e..02e1ac430e2e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. // @dart=2.9 diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart index 44412d490ec0..0230a2157297 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. // @dart=2.9 diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj index 75392aeb82e5..9cbff5466ec5 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -166,7 +166,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart index f6a2fecf5b0d..6581bc0af7b8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart index 7c814f31a660..cb7fe0b861d8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart index b795040658e6..9a6cf91a987d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart index eaeb463e1b33..cea5c3ee3d35 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart index 20cccd6b61fd..4819fcbd577b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart index edae82e4074c..703523efc2ec 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart index 90404c347dd8..d37fe5fb2203 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart index 860b19e7925c..add70fbdd7a8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart index 45b4a9e09e5c..fa35ae0c90f3 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/page.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/page.dart index eaa43fc9f26d..536cbbc361d3 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/page.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/page.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart index 59d30e51ce8b..9885747e7cba 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart index c650ca34c1b0..8ba85eff1b37 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart index 8ee58420f508..192416a92e01 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart index c66343d78f00..7f24979b5ed1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart index b7d88bc46a58..684a66b993ef 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart index 3ba12bfac3f2..fadfc1775f31 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart index 8ae3b3bca979..a8cb34133dcf 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart index 7a26a52ae1a1..80715b0ee874 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. // @dart=2.9 diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h index f84ad7c20bb4..5ef5eb86dfbb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m index 7fbd7c53b90a..68884c650ecb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h index 645ace34f9ed..ca815956de9a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m index 14585bcdb29c..2b345a1ddee2 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h index 166cf996a572..2a8022a3ef2a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m index 6688d4d57695..25c0f37b427b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h index 1bc8536f97d9..f261722cf7e1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m index 749ce9e84a4e..a823c4bbe660 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h index 593d2ff9931b..468c399e808f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. @@ -52,4 +52,4 @@ NS_ASSUME_NONNULL_BEGIN - (void)isMarkerInfoWindowShown:(NSString*)markerId result:(FlutterResult)result; @end -NS_ASSUME_NONNULL_END \ No newline at end of file +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m index cd51b2fd9896..a6d395b0c505 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h index eb1735d134b8..ad611a759548 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m index 1063a8cda990..445e4aebde1d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h index d1e10ace462e..c0f46070c945 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m index 9bb57ed897ac..0d54cf13c458 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h index 099ff3be1bd5..a0e09f7b6fe2 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m index 829f87791a07..d2fd2c1c82eb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart index 703ba63e5ccc..11f674b197a3 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart index 9b61ec002ff9..529950566ccc 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart index deac00658d6b..82549c3b491a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart index 2399b7b15eff..e6ac4331a935 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart index d61526b2bbeb..d39173197d31 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart index 8bc0fbb1d86e..5871745fc1da 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart index 857344f5ac5e..0718d59a674b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart index 684e8659c4b5..c90c47d0a038 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart index ce0da4235c9c..ec3a89b72886 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart index e187426bf7f6..f4df8ac137ad 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart index 3644f83a1adc..c82693cad9c8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart index 953d85ec85e6..c7f5ef8e8286 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/AUTHORS b/packages/google_maps_flutter/google_maps_flutter_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/AUTHORS +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/LICENSE b/packages/google_maps_flutter/google_maps_flutter_platform_interface/LICENSE index ad33cf3c3ed1..050e2c7cac4f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/LICENSE +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2018 The Chromium Authors. All rights reserved. +Copyright 2018 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/google_maps_flutter_platform_interface.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/google_maps_flutter_platform_interface.dart index cb28b40470fd..3b01002e8d92 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/google_maps_flutter_platform_interface.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/google_maps_flutter_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart index c462b4b182e2..9afc6db8cb94 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index 9d447701fdd8..dee04c92db14 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart index a363fc30f83c..c38a87f5a5c0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart index cc9887512d0e..0f2192fda1db 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/callbacks.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/callbacks.dart index c20ece5d6c7c..62b535bec08e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/callbacks.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/callbacks.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart index f15254104b0e..a4d762e87f48 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart index c88923a59404..9580a89189b8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart index daf7c918f67a..8d1d9ac7dbb6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart index a0b064b7be2a..b063a6bec0d6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/joint_type.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/joint_type.dart index c7df0b298624..5dc15b394fd8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/joint_type.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/joint_type.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart index a719f0bc741f..cd9d0ee6993f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart index 1e7932c7cde2..d8cdfdce9f48 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart index 01cf967f54e3..0d94b77b48f4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart index e493d6cec8cc..014e5515e6cb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart index 9c96ab63af18..8c0a1336ad32 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart index f1cd7f4cb8eb..89422a3423ec 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart index 57438287a156..78e25c1f91cf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart index 29b74aecbd66..cb5b2a1faf6a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart index 6738bbf2f079..f4d70dc1dcf8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart index 60e0bfe6c7ce..2fddcfe26619 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart index af7a951a149c..efbd77942a46 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart index bfc322856b5a..4aa07669c2e7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart index 7f7ef09123b0..d430623cdafe 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart index 1436880e9626..914aacdc8393 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart index abaf38ba719d..eb87bb6bb15d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart index 9b7da87f2cb0..c49ad7c47171 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart index 1c030e338353..3490c121acbc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart index 18bd31ec7df6..e0374269daea 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart index fa5a7e7591ee..4418638353ce 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart index 057bebdc8b8a..1c112a68ceb9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart index 050ecafce31f..53e946e11943 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart index 8f4098feedf7..0b163f7b84ee 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart index 336f814d329a..9f8c51906abd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart index 582acea54dd1..be20335e834b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart index afcf57debef1..81ca300a6955 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart index 4774311feb90..aa48b7b74760 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart index 2d1ae8314a94..4f9fc7cca2dd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart index 673b3c63c59e..252303076a04 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart index 360d86617754..077f823a1e05 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart index 992438fafef1..ddcb693cc217 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart index 0db7d9d33324..f2054c676d41 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart index d985ac30136e..f7f0c285168a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/AUTHORS b/packages/google_maps_flutter/google_maps_flutter_web/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/AUTHORS +++ b/packages/google_maps_flutter/google_maps_flutter_web/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart index 0eca5b82d922..11d054a64c42 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart index f0cae1dcdaf6..b33d8ae69205 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart index c83e92dbb79d..a8858bedcdab 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart index 71cf41522d67..e8526d9f314a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart index b1a691d18def..91ad7dfac90f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart index 26db542c60fe..3735bd06a5c8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart index 39444c0daa24..dba91905cd68 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart index 2ce3923c7ea9..df2d04853c8a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart index 96f9be7aa001..ea24d4d6ab15 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart index c7c33ed1811f..6463c9e11ba1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index 5212679fb5fe..ca15df56cbd0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart index a119f2aab9f2..7ccce3bde370 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart index cb2a8aa238f9..92ee16ad3d49 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart index 30db477ee5f4..c0efc6b5bdda 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart index fea6164515b8..a3128043d575 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart index f4c692d2ee83..3cb5638846df 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart index 5c078ea0aa7a..bb232d0d94a7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart index f8ff2c62191d..cf9de5b36d33 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart index f24ca4b1bb42..9fbcf119100e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart index 27d39b528e51..ec93f431138b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart index 7f8c2b2c0796..2a8c7f5f5c6e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart index 16654a0fa967..b6c2f8812a1b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart index 039cc473db5e..0393cb205200 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart index a8cd22dbe285..ab69a33ba215 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/AUTHORS b/packages/google_sign_in/google_sign_in/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/google_sign_in/google_sign_in/AUTHORS +++ b/packages/google_sign_in/google_sign_in/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java index 5ec19822734c..215136625dc2 100644 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java index 3e7250cea0ee..893a13d2379b 100644 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java index f9aa77b30e5d..6ab856eca8bd 100644 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java index acc7996ee94b..b2a13a712823 100644 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj index faaaa58070bd..72aaf05b41b2 100644 --- a/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_sign_in/google_sign_in/example/ios/Runner.xcodeproj/project.pbxproj @@ -169,7 +169,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.h b/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.h +++ b/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.m b/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.m index f08675707182..2147d3d605ac 100644 --- a/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.m +++ b/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/example/ios/Runner/main.m b/packages/google_sign_in/google_sign_in/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/google_sign_in/google_sign_in/example/ios/Runner/main.m +++ b/packages/google_sign_in/google_sign_in/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m index f3968a15622e..d00ef82237c0 100644 --- a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m +++ b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart b/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart index abb86f07086a..c85665696a0f 100644 --- a/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart +++ b/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020, the Chromium project authors. All rights reserved. +// Copyright 2020, 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/AUTHORS b/packages/google_sign_in/google_sign_in_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/AUTHORS +++ b/packages/google_sign_in/google_sign_in_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/google_sign_in/google_sign_in_platform_interface/LICENSE b/packages/google_sign_in/google_sign_in_platform_interface/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/LICENSE +++ b/packages/google_sign_in/google_sign_in_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart index 3499558f9114..560b72088978 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart index ea2426159e21..b2718d0f08b0 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart index a4c5906723dd..e20d44fae473 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart index f6236d4ca12e..14701897933a 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart b/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart index e2565d799e1f..e49f6a1074e2 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart index 9447cd0edfc4..dbc5bb00f17f 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/AUTHORS b/packages/google_sign_in/google_sign_in_web/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/google_sign_in/google_sign_in_web/AUTHORS +++ b/packages/google_sign_in/google_sign_in_web/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart index b80080935d42..0df203f2f4d8 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart index e0729bcf9b5e..0e0363bdd760 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart index 9a7d4f403f97..eb77900d27b6 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart index 79d798ad2c85..acda5d525a91 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart index 42d9a8be262c..587920494692 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart index f8e794ae48a5..98e978641d3d 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart index 43a7a044fc1b..277dfa39104a 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart index e03974a145b7..2b439c9c74fb 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart index 5a6c8906682c..f01c801dcb14 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart b/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart index 39444c0daa24..dba91905cd68 100644 --- a/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart +++ b/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart index 41e8106802de..320dad4ea220 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart index f0f886ce7880..d2c00a840597 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart index b2b5c368b6ab..b42486b9fd7f 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart b/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart index 0d3e4165227c..5aad2d9c52ba 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart b/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart index 98cb24efaeeb..12cdd0a3162b 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/AUTHORS b/packages/image_picker/image_picker/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/image_picker/image_picker/AUTHORS +++ b/packages/image_picker/image_picker/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1Activity.java b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1Activity.java index 55f3f92eef7c..215fcfdb9212 100644 --- a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1Activity.java +++ b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1ActivityTest.java b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1ActivityTest.java index e7fcd25142ad..34a827eed3ae 100644 --- a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1ActivityTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj index 492dd014ce6d..f9895f0cc06f 100644 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj @@ -258,7 +258,7 @@ attributes = { DefaultBuildSystemTypeForWorkspace = Original; LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 6801C8352555D726009DAF8D = { CreatedOnToolsVersion = 11.7; diff --git a/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.h b/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.h +++ b/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.m b/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.m index a4b51c88eb60..abfe2106b092 100644 --- a/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.m +++ b/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/image_picker/image_picker/example/ios/Runner/main.m b/packages/image_picker/image_picker/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/image_picker/image_picker/example/ios/Runner/main.m +++ b/packages/image_picker/image_picker/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m index 8be41dc63587..68ca6304e17e 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart b/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart index 6332de2cfd8d..b02d7d397106 100644 --- a/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart +++ b/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m b/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m index c8d5a2bb5368..f34fa7049616 100644 --- a/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m +++ b/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.h b/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.h index 7173e1c455ba..8ba64a4d03b6 100644 --- a/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.h +++ b/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.m b/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.m index 53559f0b637b..536e3b3cba8e 100644 --- a/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.m +++ b/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/ios/Tests/ImageUtilTests.m b/packages/image_picker/image_picker/ios/Tests/ImageUtilTests.m index 126795f8bdc9..87c8249e78a4 100644 --- a/packages/image_picker/image_picker/ios/Tests/ImageUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/ImageUtilTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/ios/Tests/MetaDataUtilTests.m b/packages/image_picker/image_picker/ios/Tests/MetaDataUtilTests.m index 120ba3890a0e..505ccbfecab8 100644 --- a/packages/image_picker/image_picker/ios/Tests/MetaDataUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/MetaDataUtilTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m index 7491c907724c..ac408b22c387 100644 --- a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker_for_web/AUTHORS b/packages/image_picker/image_picker_for_web/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/image_picker/image_picker_for_web/AUTHORS +++ b/packages/image_picker/image_picker_for_web/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/image_picker/image_picker_for_web/LICENSE b/packages/image_picker/image_picker_for_web/LICENSE index 507569823f1b..b257ce7c224c 100644 --- a/packages/image_picker/image_picker_for_web/LICENSE +++ b/packages/image_picker/image_picker_for_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Chromium Authors. All rights reserved. +Copyright 2019 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index ccee15066b8c..75e185470d60 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart index fcc2c003a10b..aa97170bf800 100644 --- a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart +++ b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker_platform_interface/AUTHORS b/packages/image_picker/image_picker_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/image_picker/image_picker_platform_interface/AUTHORS +++ b/packages/image_picker/image_picker_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/image_picker/image_picker_platform_interface/LICENSE b/packages/image_picker/image_picker_platform_interface/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/image_picker/image_picker_platform_interface/LICENSE +++ b/packages/image_picker/image_picker_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart b/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart index e46ee58e766b..e04027cbd744 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. 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 8535f9dfb20e..272a018a3e35 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. 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 44b85f17f3db..66986d35719f 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/camera_device.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/camera_device.dart index 6c70fd451a0e..658adc5f2c7f 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/camera_device.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/camera_device.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/image_source.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/image_source.dart index 37981e3038f1..6676a9dab30b 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/image_source.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/image_source.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. 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 39db13951fd1..a6cbeeed5c97 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. 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 ea1ad9a84606..8e757774042b 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. 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 06bc52308095..08c172a98a05 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. 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 831c7bd6cb15..3bd9a696d035 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart index 125b1e968740..34fa2f624f0d 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart index e204604f5a13..25a0a73d49a9 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/retrieve_type.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/retrieve_type.dart index cc32be9711c2..3090513b5b8d 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/retrieve_type.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/retrieve_type.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. 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 8ea3cfe06de6..c07ac524335e 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,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. 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 ee0edbea03e0..00d6e99ec0bf 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 @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart index 28c0886b864e..c721326e17a4 100644 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/AUTHORS b/packages/in_app_purchase/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/in_app_purchase/AUTHORS +++ b/packages/in_app_purchase/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/in_app_purchase/LICENSE b/packages/in_app_purchase/LICENSE index ad33cf3c3ed1..050e2c7cac4f 100644 --- a/packages/in_app_purchase/LICENSE +++ b/packages/in_app_purchase/LICENSE @@ -1,4 +1,4 @@ -Copyright 2018 The Chromium Authors. All rights reserved. +Copyright 2018 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java index b320c17aa992..915a18eee7ac 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java index 9bfddaf57545..38e59321ce8a 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java index 65904b12da28..f412b517cf1c 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java index d90fc6040454..1663c39cfa0f 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java index 20ab8ad92e65..04f980429eaf 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java index f9fc12fbb34e..c7e7e9029ebd 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java index f6849a867b0a..dd4ad6db07a7 100644 --- a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java +++ b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java index 4b5a14472b4f..165bc4b42c67 100644 --- a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java +++ b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java index 15ec0da9958e..eaacdf16282d 100644 --- a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java +++ b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java index 0befa87e1d05..248e4105b200 100644 --- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java +++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java index 476577d330c8..63f670dc26e1 100644 --- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java +++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj b/packages/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj index 1065ac201e4a..95b145bc544b 100644 --- a/packages/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj @@ -243,7 +243,7 @@ attributes = { DefaultBuildSystemTypeForWorkspace = Original; LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/in_app_purchase/example/lib/consumable_store.dart b/packages/in_app_purchase/example/lib/consumable_store.dart index 3c2bec95646d..271291ca6eee 100644 --- a/packages/in_app_purchase/example/lib/consumable_store.dart +++ b/packages/in_app_purchase/example/lib/consumable_store.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/example/lib/main.dart b/packages/in_app_purchase/example/lib/main.dart index 32676cf799ea..2172ca3480f5 100644 --- a/packages/in_app_purchase/example/lib/main.dart +++ b/packages/in_app_purchase/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/example/test_driver/test/integration_test.dart b/packages/in_app_purchase/example/test_driver/test/integration_test.dart index 6332de2cfd8d..b02d7d397106 100644 --- a/packages/in_app_purchase/example/test_driver/test/integration_test.dart +++ b/packages/in_app_purchase/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/integration_test/in_app_purchase_test.dart b/packages/in_app_purchase/integration_test/in_app_purchase_test.dart index 758d266e7f8b..f7edfb71412c 100644 --- a/packages/in_app_purchase/integration_test/in_app_purchase_test.dart +++ b/packages/in_app_purchase/integration_test/in_app_purchase_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.h b/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.h index 5243a391ddaf..383e5440509a 100644 --- a/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.h +++ b/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.m b/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.m index f1e5c538cb0e..e54504a67218 100644 --- a/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.m +++ b/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.h b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.h index c5b67756bad0..797e4a6f4216 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.h +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m index f6bdf0c4f249..deeed2873b30 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.h b/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.h index 892f5f013cc9..6c75a9fcdf44 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.h +++ b/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.m b/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.m index 5dc2cea2e9db..7172687956bf 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.m +++ b/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h index a27855230adb..4776062aa04c 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h +++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m index 8d179aee7ba8..8eed06ce022c 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m +++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h index a7c00f18bc37..6974b33fd230 100644 --- a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h +++ b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m index e9b6bb9b8490..b254e622e69f 100644 --- a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m +++ b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m index 31e0f255034d..7ef757b7c4c5 100644 --- a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m +++ b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m b/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m index 07b6bbb42a65..f5248da74635 100644 --- a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m +++ b/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m b/packages/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m index 5e214e8c795e..25d11de5f6ad 100644 --- a/packages/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m +++ b/packages/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Tests/Stubs.h b/packages/in_app_purchase/ios/Tests/Stubs.h index 630ae2f633dd..f93d41325199 100644 --- a/packages/in_app_purchase/ios/Tests/Stubs.h +++ b/packages/in_app_purchase/ios/Tests/Stubs.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Tests/Stubs.m b/packages/in_app_purchase/ios/Tests/Stubs.m index 58b77c14127d..640352a82146 100644 --- a/packages/in_app_purchase/ios/Tests/Stubs.m +++ b/packages/in_app_purchase/ios/Tests/Stubs.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/ios/Tests/TranslatorTest.m b/packages/in_app_purchase/ios/Tests/TranslatorTest.m index 135c7f3616f4..e1db3d154310 100644 --- a/packages/in_app_purchase/ios/Tests/TranslatorTest.m +++ b/packages/in_app_purchase/ios/Tests/TranslatorTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/billing_client_wrappers.dart b/packages/in_app_purchase/lib/billing_client_wrappers.dart index 127c980c15e6..e8d13e7d2315 100644 --- a/packages/in_app_purchase/lib/billing_client_wrappers.dart +++ b/packages/in_app_purchase/lib/billing_client_wrappers.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/in_app_purchase.dart b/packages/in_app_purchase/lib/in_app_purchase.dart index 5a68075db3e5..b197583614a6 100644 --- a/packages/in_app_purchase/lib/in_app_purchase.dart +++ b/packages/in_app_purchase/lib/in_app_purchase.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart index f14e8dbec6bd..909c4d70b101 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart index 469d71b63637..0b1e96a19d53 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart index 567e8bbd4f2b..2353175b15b4 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart index 7451a24a8b4f..bfaafb7faf08 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/channel.dart b/packages/in_app_purchase/lib/src/channel.dart index 5d140e281e7b..9976ea6e23d1 100644 --- a/packages/in_app_purchase/lib/src/channel.dart +++ b/packages/in_app_purchase/lib/src/channel.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index e437e7f99cfc..cf0b4df2fbbe 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart index 83435d23d395..044144e04f24 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart index 751bab62803c..c53d40914874 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart b/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart index a3eb79d9a450..0f23c3a8e557 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart b/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart index b4a509055f14..e346c7f42e42 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart index ce2c1fad406f..2a20b21eabb7 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart index f17166fbc969..f4a766a9f4c6 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart index 9921380e6e96..edf0708b8041 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart index d77ea81c2d38..045c2fcd5b07 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart index 16bcb77a2c70..5cab368558a5 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart index c22df0a9dbdd..6f143edd50da 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/lib/store_kit_wrappers.dart b/packages/in_app_purchase/lib/store_kit_wrappers.dart index 12af4ba0a18f..3b94a17f9ad9 100644 --- a/packages/in_app_purchase/lib/store_kit_wrappers.dart +++ b/packages/in_app_purchase/lib/store_kit_wrappers.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart index 7ba560257b39..b1bfa7f3b6dd 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart index f97b937c96df..8aeef23cda3b 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart index f7f410a1cd8b..46ec9c602e23 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index 14383b96774d..9b979e6ef021 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart index 13582736f86f..d29c0e43d9bc 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart index 8df380bc223b..57932cd44af6 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart index 6e1f59bf377e..6508c83bceb1 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart index f7d86f5cf59b..7c92a11962fb 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart b/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart index 431d8859d44d..325b48931896 100644 --- a/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart +++ b/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/AUTHORS b/packages/integration_test/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/integration_test/AUTHORS +++ b/packages/integration_test/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/integration_test/LICENSE b/packages/integration_test/LICENSE index 507569823f1b..b257ce7c224c 100644 --- a/packages/integration_test/LICENSE +++ b/packages/integration_test/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Chromium Authors. All rights reserved. +Copyright 2019 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterTestRunner.java b/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterTestRunner.java index fc6b99b30f64..3cada2f44a58 100644 --- a/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterTestRunner.java +++ b/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterTestRunner.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/IntegrationTestPlugin.java b/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/IntegrationTestPlugin.java index 919eb7add9ba..01adf98ad90d 100644 --- a/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/IntegrationTestPlugin.java +++ b/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/IntegrationTestPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/example/android/app/src/main/java/com/example/e2e_example/EmbedderV1Activity.java b/packages/integration_test/example/android/app/src/main/java/com/example/e2e_example/EmbedderV1Activity.java index 9318e457800d..fedd3626fa80 100644 --- a/packages/integration_test/example/android/app/src/main/java/com/example/e2e_example/EmbedderV1Activity.java +++ b/packages/integration_test/example/android/app/src/main/java/com/example/e2e_example/EmbedderV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/example/ios/Runner.xcodeproj/project.pbxproj b/packages/integration_test/example/ios/Runner.xcodeproj/project.pbxproj index b96fa2fb2618..1028a7d3e995 100644 --- a/packages/integration_test/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/integration_test/example/ios/Runner.xcodeproj/project.pbxproj @@ -231,7 +231,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 769541C723A0351900E5C350 = { CreatedOnToolsVersion = 11.0; diff --git a/packages/integration_test/example/ios/Runner/AppDelegate.h b/packages/integration_test/example/ios/Runner/AppDelegate.h index b7984f089a9c..d53a2aeb21ac 100644 --- a/packages/integration_test/example/ios/Runner/AppDelegate.h +++ b/packages/integration_test/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/example/ios/Runner/AppDelegate.m b/packages/integration_test/example/ios/Runner/AppDelegate.m index 60df7408bded..a1fd21cf937c 100644 --- a/packages/integration_test/example/ios/Runner/AppDelegate.m +++ b/packages/integration_test/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/example/ios/Runner/main.m b/packages/integration_test/example/ios/Runner/main.m index 84022b1644c3..4817030ede8d 100644 --- a/packages/integration_test/example/ios/Runner/main.m +++ b/packages/integration_test/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/example/test_driver/failure.dart b/packages/integration_test/example/test_driver/failure.dart index 02fc55e94a53..a37306392321 100644 --- a/packages/integration_test/example/test_driver/failure.dart +++ b/packages/integration_test/example/test_driver/failure.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/ios/Classes/IntegrationTestIosTest.h b/packages/integration_test/ios/Classes/IntegrationTestIosTest.h index 7c09a1171267..19503385b70e 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestIosTest.h +++ b/packages/integration_test/ios/Classes/IntegrationTestIosTest.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/ios/Classes/IntegrationTestIosTest.m b/packages/integration_test/ios/Classes/IntegrationTestIosTest.m index b3a7602b74b2..78cd0c28bbfb 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestIosTest.m +++ b/packages/integration_test/ios/Classes/IntegrationTestIosTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/ios/Classes/IntegrationTestPlugin.h b/packages/integration_test/ios/Classes/IntegrationTestPlugin.h index 6a6171fd16e8..4593e31e1766 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestPlugin.h +++ b/packages/integration_test/ios/Classes/IntegrationTestPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/ios/Classes/IntegrationTestPlugin.m b/packages/integration_test/ios/Classes/IntegrationTestPlugin.m index 5c4d0e6bfb24..51ac0e34562f 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestPlugin.m +++ b/packages/integration_test/ios/Classes/IntegrationTestPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/lib/_callback_io.dart b/packages/integration_test/lib/_callback_io.dart index c1a447e27cab..fe4e400be997 100644 --- a/packages/integration_test/lib/_callback_io.dart +++ b/packages/integration_test/lib/_callback_io.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/lib/_callback_web.dart b/packages/integration_test/lib/_callback_web.dart index 036098148d99..bff8e8a9d31e 100644 --- a/packages/integration_test/lib/_callback_web.dart +++ b/packages/integration_test/lib/_callback_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/lib/_extension_io.dart b/packages/integration_test/lib/_extension_io.dart index a8e66fca1900..8f6f8ac8cad1 100644 --- a/packages/integration_test/lib/_extension_io.dart +++ b/packages/integration_test/lib/_extension_io.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/lib/_extension_web.dart b/packages/integration_test/lib/_extension_web.dart index 8bf5950ef74a..b83fc1eb292e 100644 --- a/packages/integration_test/lib/_extension_web.dart +++ b/packages/integration_test/lib/_extension_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/lib/common.dart b/packages/integration_test/lib/common.dart index da93b3b51450..15b0c5c0d0cd 100644 --- a/packages/integration_test/lib/common.dart +++ b/packages/integration_test/lib/common.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/lib/integration_test.dart b/packages/integration_test/lib/integration_test.dart index 5a37e88a3c6e..5a070a4fa9ef 100644 --- a/packages/integration_test/lib/integration_test.dart +++ b/packages/integration_test/lib/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/lib/integration_test_driver_extended.dart b/packages/integration_test/lib/integration_test_driver_extended.dart index c423f296c331..613571e26abe 100644 --- a/packages/integration_test/lib/integration_test_driver_extended.dart +++ b/packages/integration_test/lib/integration_test_driver_extended.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/test/binding_fail_test.dart b/packages/integration_test/test/binding_fail_test.dart index d0d5fd423b67..34c4e6c647df 100644 --- a/packages/integration_test/test/binding_fail_test.dart +++ b/packages/integration_test/test/binding_fail_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/test/binding_test.dart b/packages/integration_test/test/binding_test.dart index 10e3c093b140..449eab5525fc 100644 --- a/packages/integration_test/test/binding_test.dart +++ b/packages/integration_test/test/binding_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/test/data/fail_test_script.dart b/packages/integration_test/test/data/fail_test_script.dart index a495a3b3f698..3e2ac31dbd7c 100644 --- a/packages/integration_test/test/data/fail_test_script.dart +++ b/packages/integration_test/test/data/fail_test_script.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/test/data/pass_test_script.dart b/packages/integration_test/test/data/pass_test_script.dart index e31651de74ac..cb5eed12ab07 100644 --- a/packages/integration_test/test/data/pass_test_script.dart +++ b/packages/integration_test/test/data/pass_test_script.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/test/data/pass_then_fail_test_script.dart b/packages/integration_test/test/data/pass_then_fail_test_script.dart index 9116fde266e0..0b0b67821284 100644 --- a/packages/integration_test/test/data/pass_then_fail_test_script.dart +++ b/packages/integration_test/test/data/pass_then_fail_test_script.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/integration_test/test/response_serialization_test.dart b/packages/integration_test/test/response_serialization_test.dart index ee6cacc73a5e..54bd49780a5d 100644 --- a/packages/integration_test/test/response_serialization_test.dart +++ b/packages/integration_test/test/response_serialization_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/ios_platform_images/AUTHORS b/packages/ios_platform_images/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/ios_platform_images/AUTHORS +++ b/packages/ios_platform_images/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/ios_platform_images/LICENSE b/packages/ios_platform_images/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/ios_platform_images/LICENSE +++ b/packages/ios_platform_images/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/ios_platform_images/example/ios/Runner.xcodeproj/project.pbxproj b/packages/ios_platform_images/example/ios/Runner.xcodeproj/project.pbxproj index ba0b25c0015b..5cf073311353 100644 --- a/packages/ios_platform_images/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/ios_platform_images/example/ios/Runner.xcodeproj/project.pbxproj @@ -167,7 +167,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h index e53977a3d9cd..8125fb2282ba 100644 --- a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h +++ b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m index 151c418c2f6a..76c54d5c2576 100644 --- a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m +++ b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/ios_platform_images/lib/ios_platform_images.dart b/packages/ios_platform_images/lib/ios_platform_images.dart index d4599be94a64..3c30c4b8fc0c 100644 --- a/packages/ios_platform_images/lib/ios_platform_images.dart +++ b/packages/ios_platform_images/lib/ios_platform_images.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/ios_platform_images/test/ios_platform_images_test.dart b/packages/ios_platform_images/test/ios_platform_images_test.dart index 6ed7714e95c2..bbdf8de57ed5 100644 --- a/packages/ios_platform_images/test/ios_platform_images_test.dart +++ b/packages/ios_platform_images/test/ios_platform_images_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/local_auth/AUTHORS b/packages/local_auth/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/local_auth/AUTHORS +++ b/packages/local_auth/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/local_auth/LICENSE b/packages/local_auth/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/local_auth/LICENSE +++ b/packages/local_auth/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java index 3a7e2d76ca08..cf4226d4ed26 100644 --- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java +++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. package io.flutter.plugins.localauth; diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java index f4c6c168f54d..5df034650f34 100644 --- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java +++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/local_auth/example/ios/Runner.xcodeproj/project.pbxproj b/packages/local_auth/example/ios/Runner.xcodeproj/project.pbxproj index 63730d4eb2e3..8960fe4d8af3 100644 --- a/packages/local_auth/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/local_auth/example/ios/Runner.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/local_auth/example/ios/Runner/AppDelegate.h b/packages/local_auth/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/local_auth/example/ios/Runner/AppDelegate.h +++ b/packages/local_auth/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/local_auth/example/ios/Runner/AppDelegate.m b/packages/local_auth/example/ios/Runner/AppDelegate.m index f08675707182..2147d3d605ac 100644 --- a/packages/local_auth/example/ios/Runner/AppDelegate.m +++ b/packages/local_auth/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/local_auth/example/lib/main.dart b/packages/local_auth/example/lib/main.dart index 8cdad5b7eed3..7d611a4ea10f 100644 --- a/packages/local_auth/example/lib/main.dart +++ b/packages/local_auth/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/local_auth/integration_test/local_auth_test.dart b/packages/local_auth/integration_test/local_auth_test.dart index d6527c7601e4..5ebaf39cfe58 100644 --- a/packages/local_auth/integration_test/local_auth_test.dart +++ b/packages/local_auth/integration_test/local_auth_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.h b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.h index 1e9e8c3a2d24..7fc6e568a470 100644 --- a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.h +++ b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m index cda49a7d68c3..f11517ceb691 100644 --- a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m +++ b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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 diff --git a/packages/local_auth/lib/auth_strings.dart b/packages/local_auth/lib/auth_strings.dart index 855098b6aba4..c7dc6bdf09f0 100644 --- a/packages/local_auth/lib/auth_strings.dart +++ b/packages/local_auth/lib/auth_strings.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/local_auth/lib/error_codes.dart b/packages/local_auth/lib/error_codes.dart index 3b080c13baf7..4ead02005250 100644 --- a/packages/local_auth/lib/error_codes.dart +++ b/packages/local_auth/lib/error_codes.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/local_auth/lib/local_auth.dart b/packages/local_auth/lib/local_auth.dart index f8a7228bcd8d..cd32b667e140 100644 --- a/packages/local_auth/lib/local_auth.dart +++ b/packages/local_auth/lib/local_auth.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/package_info/AUTHORS b/packages/package_info/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/package_info/AUTHORS +++ b/packages/package_info/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/package_info/LICENSE b/packages/package_info/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/package_info/LICENSE +++ b/packages/package_info/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/package_info/android/src/main/java/io/flutter/plugins/packageinfo/PackageInfoPlugin.java b/packages/package_info/android/src/main/java/io/flutter/plugins/packageinfo/PackageInfoPlugin.java index 645b8dd075c6..1444b1c71148 100644 --- a/packages/package_info/android/src/main/java/io/flutter/plugins/packageinfo/PackageInfoPlugin.java +++ b/packages/package_info/android/src/main/java/io/flutter/plugins/packageinfo/PackageInfoPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/package_info/darwin/Classes/FLTPackageInfoPlugin.m b/packages/package_info/darwin/Classes/FLTPackageInfoPlugin.m index 046f15fec3ea..8207438f794b 100644 --- a/packages/package_info/darwin/Classes/FLTPackageInfoPlugin.m +++ b/packages/package_info/darwin/Classes/FLTPackageInfoPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/EmbedderV1ActivityTest.java b/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/EmbedderV1ActivityTest.java index ab1d2d29635e..aef7d0dbd264 100644 --- a/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/EmbedderV1ActivityTest.java +++ b/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/EmbedderV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/MainActivityTest.java b/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/MainActivityTest.java index 91aad52d4241..f5f95cec3ed1 100644 --- a/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/MainActivityTest.java +++ b/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java b/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java index eb669bf16109..d049ed7b4efc 100644 --- a/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java +++ b/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/package_info/example/integration_test/package_info_test.dart b/packages/package_info/example/integration_test/package_info_test.dart index 75bae13cc8f7..ecd75e2687f2 100644 --- a/packages/package_info/example/integration_test/package_info_test.dart +++ b/packages/package_info/example/integration_test/package_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/package_info/example/ios/Runner.xcodeproj/project.pbxproj b/packages/package_info/example/ios/Runner.xcodeproj/project.pbxproj index a3c977a0bf14..e1325039d44a 100644 --- a/packages/package_info/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/package_info/example/ios/Runner.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/package_info/example/ios/Runner/AppDelegate.h b/packages/package_info/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/package_info/example/ios/Runner/AppDelegate.h +++ b/packages/package_info/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/package_info/example/ios/Runner/AppDelegate.m b/packages/package_info/example/ios/Runner/AppDelegate.m index f08675707182..2147d3d605ac 100644 --- a/packages/package_info/example/ios/Runner/AppDelegate.m +++ b/packages/package_info/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/package_info/example/ios/Runner/main.m b/packages/package_info/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/package_info/example/ios/Runner/main.m +++ b/packages/package_info/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/package_info/example/lib/main.dart b/packages/package_info/example/lib/main.dart index 18620617d558..3fa7780fe9bb 100644 --- a/packages/package_info/example/lib/main.dart +++ b/packages/package_info/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/package_info/example/test_driver/integration_test.dart b/packages/package_info/example/test_driver/integration_test.dart index a2977d367f9f..9e813df086c1 100644 --- a/packages/package_info/example/test_driver/integration_test.dart +++ b/packages/package_info/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/package_info/ios/Classes/FLTPackageInfoPlugin.h b/packages/package_info/ios/Classes/FLTPackageInfoPlugin.h index 5f58c82c9446..e6a73bf164c5 100644 --- a/packages/package_info/ios/Classes/FLTPackageInfoPlugin.h +++ b/packages/package_info/ios/Classes/FLTPackageInfoPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/package_info/lib/package_info.dart b/packages/package_info/lib/package_info.dart index 5b7f4e573aa0..7bcd80619037 100644 --- a/packages/package_info/lib/package_info.dart +++ b/packages/package_info/lib/package_info.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/package_info/macos/Classes/FLTPackageInfoPlugin.h b/packages/package_info/macos/Classes/FLTPackageInfoPlugin.h index cb165ad5e41e..b8705ddfc199 100644 --- a/packages/package_info/macos/Classes/FLTPackageInfoPlugin.h +++ b/packages/package_info/macos/Classes/FLTPackageInfoPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/path_provider/path_provider/AUTHORS b/packages/path_provider/path_provider/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/path_provider/path_provider/AUTHORS +++ b/packages/path_provider/path_provider/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart index cb0b8744c84f..71c138b2dd3e 100644 --- a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/path_provider/path_provider/example/ios/Runner.xcodeproj/project.pbxproj b/packages/path_provider/path_provider/example/ios/Runner.xcodeproj/project.pbxproj index eb0222a7c9c5..475c9d8f64a4 100644 --- a/packages/path_provider/path_provider/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/path_provider/path_provider/example/ios/Runner.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.h b/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.h +++ b/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.m b/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.m index a4b51c88eb60..abfe2106b092 100644 --- a/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.m +++ b/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/path_provider/path_provider/example/ios/Runner/main.m b/packages/path_provider/path_provider/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/path_provider/path_provider/example/ios/Runner/main.m +++ b/packages/path_provider/path_provider/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/path_provider/path_provider/example/linux/my_application.h b/packages/path_provider/path_provider/example/linux/my_application.h index abbdf1213815..b3d62442a005 100644 --- a/packages/path_provider/path_provider/example/linux/my_application.h +++ b/packages/path_provider/path_provider/example/linux/my_application.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/path_provider/path_provider/example/test_driver/integration_test.dart b/packages/path_provider/path_provider/example/test_driver/integration_test.dart index a82b5fb51e77..dec1aa55d40e 100644 --- a/packages/path_provider/path_provider/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp b/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp index dd2e3cca5666..b7d078e4d4a5 100644 --- a/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/path_provider/path_provider_linux/AUTHORS b/packages/path_provider/path_provider_linux/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/path_provider/path_provider_linux/AUTHORS +++ b/packages/path_provider/path_provider_linux/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/path_provider/path_provider_linux/LICENSE b/packages/path_provider/path_provider_linux/LICENSE index d7412e0a1e0c..67c7e2c52e46 100644 --- a/packages/path_provider/path_provider_linux/LICENSE +++ b/packages/path_provider/path_provider_linux/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Chromium Authors. All rights reserved. +Copyright 2020 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart index 6cd19401cf0e..a4b254145344 100644 --- a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart index a82b5fb51e77..dec1aa55d40e 100644 --- a/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart b/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart index e35b73bf3766..0295ffa2d15a 100644 --- a/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart +++ b/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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 'dart:io'; diff --git a/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart b/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart index be831b92211f..5ec530313462 100644 --- a/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart +++ b/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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_test/flutter_test.dart'; diff --git a/packages/path_provider/path_provider_macos/AUTHORS b/packages/path_provider/path_provider_macos/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/path_provider/path_provider_macos/AUTHORS +++ b/packages/path_provider/path_provider_macos/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/path_provider/path_provider_macos/LICENSE b/packages/path_provider/path_provider_macos/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/path_provider/path_provider_macos/LICENSE +++ b/packages/path_provider/path_provider_macos/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart index 10be231d064e..21f757c86e71 100644 --- a/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart index a82b5fb51e77..dec1aa55d40e 100644 --- a/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift b/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift index a1528822893f..8081b89b2ccf 100644 --- a/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift +++ b/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/path_provider/path_provider_platform_interface/AUTHORS b/packages/path_provider/path_provider_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/path_provider/path_provider_platform_interface/AUTHORS +++ b/packages/path_provider/path_provider_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/path_provider/path_provider_platform_interface/LICENSE b/packages/path_provider/path_provider_platform_interface/LICENSE index d7412e0a1e0c..67c7e2c52e46 100644 --- a/packages/path_provider/path_provider_platform_interface/LICENSE +++ b/packages/path_provider/path_provider_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Chromium Authors. All rights reserved. +Copyright 2020 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart b/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart index 1ff2a978c5a4..5b7046bda3d8 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart b/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart index f563b5ed0b2d..fe46401501d4 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart b/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart index 728c1068f876..418d983273ea 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart b/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart index 7130d7743e69..3f44387f1b7d 100644 --- a/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart +++ b/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/path_provider/path_provider_windows/AUTHORS b/packages/path_provider/path_provider_windows/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/path_provider/path_provider_windows/AUTHORS +++ b/packages/path_provider/path_provider_windows/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/path_provider/path_provider_windows/LICENSE b/packages/path_provider/path_provider_windows/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/path_provider/path_provider_windows/LICENSE +++ b/packages/path_provider/path_provider_windows/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart index 0d521a5df247..733865b577f0 100644 --- a/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/path_provider/path_provider_windows/example/lib/main.dart b/packages/path_provider/path_provider_windows/example/lib/main.dart index 964ef3d04db1..7d4db2304259 100644 --- a/packages/path_provider/path_provider_windows/example/lib/main.dart +++ b/packages/path_provider/path_provider_windows/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart index a82b5fb51e77..dec1aa55d40e 100644 --- a/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/path_provider/path_provider_windows/lib/path_provider_windows.dart b/packages/path_provider/path_provider_windows/lib/path_provider_windows.dart index b7aeb7a6d5f6..dbb178242970 100644 --- a/packages/path_provider/path_provider_windows/lib/path_provider_windows.dart +++ b/packages/path_provider/path_provider_windows/lib/path_provider_windows.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/path_provider/path_provider_windows/lib/src/folders.dart b/packages/path_provider/path_provider_windows/lib/src/folders.dart index fc2ea8351476..d1e7ecc767f0 100644 --- a/packages/path_provider/path_provider_windows/lib/src/folders.dart +++ b/packages/path_provider/path_provider_windows/lib/src/folders.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/path_provider/path_provider_windows/lib/src/folders_stub.dart b/packages/path_provider/path_provider_windows/lib/src/folders_stub.dart index d19103602cdc..6dae052246ad 100644 --- a/packages/path_provider/path_provider_windows/lib/src/folders_stub.dart +++ b/packages/path_provider/path_provider_windows/lib/src/folders_stub.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart index db2ad9da207c..23eee59f32fb 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart index 1a0e84e8f0da..9d71d2258e04 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart index 989f3673ac63..0ca4595fa14e 100644 --- a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart +++ b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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 'dart:ffi'; diff --git a/packages/plugin_platform_interface/AUTHORS b/packages/plugin_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/plugin_platform_interface/AUTHORS +++ b/packages/plugin_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/plugin_platform_interface/LICENSE b/packages/plugin_platform_interface/LICENSE index 507569823f1b..b257ce7c224c 100644 --- a/packages/plugin_platform_interface/LICENSE +++ b/packages/plugin_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Chromium Authors. All rights reserved. +Copyright 2019 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/plugin_platform_interface/lib/plugin_platform_interface.dart b/packages/plugin_platform_interface/lib/plugin_platform_interface.dart index 6e425a19a048..187d1fa47b44 100644 --- a/packages/plugin_platform_interface/lib/plugin_platform_interface.dart +++ b/packages/plugin_platform_interface/lib/plugin_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart b/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart index 0488c20f3efb..8b5d68f00684 100644 --- a/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart +++ b/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/quick_actions/AUTHORS b/packages/quick_actions/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/quick_actions/AUTHORS +++ b/packages/quick_actions/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/quick_actions/LICENSE b/packages/quick_actions/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/quick_actions/LICENSE +++ b/packages/quick_actions/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java index dcf2390570bd..6d7f79fb7c2d 100644 --- a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java +++ b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java index 14e59951cf5e..695ff00a1a67 100644 --- a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java +++ b/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java index 4a77793da48a..db2b2f69609c 100644 --- a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java +++ b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java index e9e9401128a4..16820dfa0f39 100644 --- a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java +++ b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java index 9ce1e8dfe4ea..4eb4033a4f94 100644 --- a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java +++ b/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/quick_actions/example/integration_test/quick_actions_test.dart b/packages/quick_actions/example/integration_test/quick_actions_test.dart index bad84debefd6..f8841843b016 100644 --- a/packages/quick_actions/example/integration_test/quick_actions_test.dart +++ b/packages/quick_actions/example/integration_test/quick_actions_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj b/packages/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj index dba32819ce42..aca645880e15 100644 --- a/packages/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj @@ -214,7 +214,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 686BE82C25E58CCF00862533 = { CreatedOnToolsVersion = 12.4; diff --git a/packages/quick_actions/example/ios/Runner/AppDelegate.h b/packages/quick_actions/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/quick_actions/example/ios/Runner/AppDelegate.h +++ b/packages/quick_actions/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/quick_actions/example/ios/Runner/AppDelegate.m b/packages/quick_actions/example/ios/Runner/AppDelegate.m index f08675707182..2147d3d605ac 100644 --- a/packages/quick_actions/example/ios/Runner/AppDelegate.m +++ b/packages/quick_actions/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/quick_actions/example/ios/Runner/main.m b/packages/quick_actions/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/quick_actions/example/ios/Runner/main.m +++ b/packages/quick_actions/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/quick_actions/example/ios/RunnerUITests/RunnerUITests.m b/packages/quick_actions/example/ios/RunnerUITests/RunnerUITests.m index f78081b98a01..dfb8022529d2 100644 --- a/packages/quick_actions/example/ios/RunnerUITests/RunnerUITests.m +++ b/packages/quick_actions/example/ios/RunnerUITests/RunnerUITests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/quick_actions/example/lib/main.dart b/packages/quick_actions/example/lib/main.dart index 08d8f4a1fbce..4422a520c9ed 100644 --- a/packages/quick_actions/example/lib/main.dart +++ b/packages/quick_actions/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/quick_actions/example/test_driver/integration_test.dart b/packages/quick_actions/example/test_driver/integration_test.dart index 6332de2cfd8d..b02d7d397106 100644 --- a/packages/quick_actions/example/test_driver/integration_test.dart +++ b/packages/quick_actions/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.h b/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.h index f0ef61d445e9..d170a81a2e58 100644 --- a/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.h +++ b/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.m b/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.m index c99c016ed1ed..808d4d112b12 100644 --- a/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.m +++ b/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/quick_actions/lib/quick_actions.dart b/packages/quick_actions/lib/quick_actions.dart index 875661244a74..fe95b1d07765 100644 --- a/packages/quick_actions/lib/quick_actions.dart +++ b/packages/quick_actions/lib/quick_actions.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/quick_actions/test/quick_actions_test.dart b/packages/quick_actions/test/quick_actions_test.dart index 8066719e5113..9adcf5628a47 100644 --- a/packages/quick_actions/test/quick_actions_test.dart +++ b/packages/quick_actions/test/quick_actions_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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 'dart:async'; diff --git a/packages/sensors/AUTHORS b/packages/sensors/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/sensors/AUTHORS +++ b/packages/sensors/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/sensors/LICENSE b/packages/sensors/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/sensors/LICENSE +++ b/packages/sensors/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java index e01c80d1cdd2..4aac1a58d6bf 100644 --- a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java +++ b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java index ac0546109f96..93fd2e0fbf2b 100644 --- a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java +++ b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java index 7813e7e8e43f..23390293aeb5 100644 --- a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java +++ b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/FlutterActivityTest.java b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/FlutterActivityTest.java index 0835b0f5945a..7f2d79bab028 100644 --- a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/FlutterActivityTest.java +++ b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/sensors/example/ios/Runner.xcodeproj/project.pbxproj b/packages/sensors/example/ios/Runner.xcodeproj/project.pbxproj index 8bde68c84719..9abd66cff4d8 100644 --- a/packages/sensors/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/sensors/example/ios/Runner.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/sensors/example/lib/main.dart b/packages/sensors/example/lib/main.dart index d6f01380c534..88cc2d7a2750 100644 --- a/packages/sensors/example/lib/main.dart +++ b/packages/sensors/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/sensors/example/lib/snake.dart b/packages/sensors/example/lib/snake.dart index 72f27472dd5b..28610758ca5f 100644 --- a/packages/sensors/example/lib/snake.dart +++ b/packages/sensors/example/lib/snake.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/sensors/example/test_driver/test/integration_test.dart b/packages/sensors/example/test_driver/test/integration_test.dart index c62ef5dba800..ac2a0cf5f19b 100644 --- a/packages/sensors/example/test_driver/test/integration_test.dart +++ b/packages/sensors/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/sensors/integration_test/sensors_test.dart b/packages/sensors/integration_test/sensors_test.dart index 5ae15967d8e4..ecee934b799a 100644 --- a/packages/sensors/integration_test/sensors_test.dart +++ b/packages/sensors/integration_test/sensors_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/sensors/ios/Classes/FLTSensorsPlugin.h b/packages/sensors/ios/Classes/FLTSensorsPlugin.h index 288db1901ed2..c3eaa137d065 100644 --- a/packages/sensors/ios/Classes/FLTSensorsPlugin.h +++ b/packages/sensors/ios/Classes/FLTSensorsPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/sensors/ios/Classes/FLTSensorsPlugin.m b/packages/sensors/ios/Classes/FLTSensorsPlugin.m index ba8d542f488e..d3541337280a 100644 --- a/packages/sensors/ios/Classes/FLTSensorsPlugin.m +++ b/packages/sensors/ios/Classes/FLTSensorsPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/sensors/lib/sensors.dart b/packages/sensors/lib/sensors.dart index 8f69255bcec7..3309f1b20453 100644 --- a/packages/sensors/lib/sensors.dart +++ b/packages/sensors/lib/sensors.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/sensors/test/sensors_test.dart b/packages/sensors/test/sensors_test.dart index fe56c7e5a36f..89856279ff16 100644 --- a/packages/sensors/test/sensors_test.dart +++ b/packages/sensors/test/sensors_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/share/AUTHORS b/packages/share/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/share/AUTHORS +++ b/packages/share/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java index d14e39781c2b..32c382f656f8 100644 --- a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java +++ b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/FlutterActivityTest.java b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/FlutterActivityTest.java index 3b73737f15b2..9767b63e7799 100644 --- a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/FlutterActivityTest.java +++ b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/share/example/ios/Runner.xcodeproj/project.pbxproj b/packages/share/example/ios/Runner.xcodeproj/project.pbxproj index d03ef3e65776..956735eafeab 100644 --- a/packages/share/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/share/example/ios/Runner.xcodeproj/project.pbxproj @@ -214,7 +214,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 683426AA2538D314009B194C = { CreatedOnToolsVersion = 11.7; diff --git a/packages/share/example/ios/Runner/AppDelegate.h b/packages/share/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/share/example/ios/Runner/AppDelegate.h +++ b/packages/share/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/share/example/ios/Runner/AppDelegate.m b/packages/share/example/ios/Runner/AppDelegate.m index a4b51c88eb60..abfe2106b092 100644 --- a/packages/share/example/ios/Runner/AppDelegate.m +++ b/packages/share/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/share/example/ios/Runner/main.m b/packages/share/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/share/example/ios/Runner/main.m +++ b/packages/share/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/share/example/ios/RunnerUITests/FLTShareExampleUITests.m b/packages/share/example/ios/RunnerUITests/FLTShareExampleUITests.m index 8e18d03ba354..05966fb439f1 100644 --- a/packages/share/example/ios/RunnerUITests/FLTShareExampleUITests.m +++ b/packages/share/example/ios/RunnerUITests/FLTShareExampleUITests.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/share/example/test_driver/test/integration_test.dart b/packages/share/example/test_driver/test/integration_test.dart index c62ef5dba800..ac2a0cf5f19b 100644 --- a/packages/share/example/test_driver/test/integration_test.dart +++ b/packages/share/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/share/integration_test/share_test.dart b/packages/share/integration_test/share_test.dart index a6a2ddb4f7cd..4fdfc220c9cc 100644 --- a/packages/share/integration_test/share_test.dart +++ b/packages/share/integration_test/share_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/shared_preferences/shared_preferences/AUTHORS b/packages/shared_preferences/shared_preferences/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/shared_preferences/shared_preferences/AUTHORS +++ b/packages/shared_preferences/shared_preferences/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/shared_preferences/shared_preferences/LICENSE b/packages/shared_preferences/shared_preferences/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/shared_preferences/shared_preferences/LICENSE +++ b/packages/shared_preferences/shared_preferences/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java index 4486421e3959..7955f2f89afb 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java index 83163f82d9ec..3583f3b73cb7 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart index d36286a559b3..daa2cbba1670 100644 --- a/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.pbxproj b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.pbxproj index 2adc7021c6bf..e26da81f1166 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.h b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.h +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.m b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.m index a4b51c88eb60..abfe2106b092 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.m +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h b/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h index 0592e2dd559c..3a69a7befa44 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/main.m b/packages/shared_preferences/shared_preferences/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/main.m +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/lib/main.dart b/packages/shared_preferences/shared_preferences/example/lib/main.dart index 26e6c8eb42f8..a56deb276037 100644 --- a/packages/shared_preferences/shared_preferences/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/linux/my_application.h b/packages/shared_preferences/shared_preferences/example/linux/my_application.h index abbdf1213815..b3d62442a005 100644 --- a/packages/shared_preferences/shared_preferences/example/linux/my_application.h +++ b/packages/shared_preferences/shared_preferences/example/linux/my_application.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart index a82b5fb51e77..dec1aa55d40e 100644 --- a/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp index dd2e3cca5666..b7d078e4d4a5 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h index a9d273e419eb..9b4ef089621b 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp index 40492ac76edb..e74157ed999a 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp index 4dd13b6d1db9..ee2e2fd5eae9 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h index 12aaab42c59b..a24c47f2e55f 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp index c408cb3f7a74..9eba364025d0 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h index 2754c7a7f9ef..640587eb23ab 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp index 878b64afe276..97628170c2c2 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h index 99e24a555afa..59b78382b27d 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.h b/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.h index 6bb1d5eecbeb..d77611fde7b4 100644 --- a/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.h +++ b/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.m b/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.m index dd68fb5b98c4..77d53504b4d3 100644 --- a/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.m +++ b/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart b/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart index 2f4ebe730351..6ed771e87c53 100644 --- a/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart +++ b/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart index 7866b2e38fac..412285ed4fd3 100755 --- a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_linux/AUTHORS b/packages/shared_preferences/shared_preferences_linux/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/shared_preferences/shared_preferences_linux/AUTHORS +++ b/packages/shared_preferences/shared_preferences_linux/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/shared_preferences/shared_preferences_linux/LICENSE b/packages/shared_preferences/shared_preferences_linux/LICENSE index d7412e0a1e0c..67c7e2c52e46 100644 --- a/packages/shared_preferences/shared_preferences_linux/LICENSE +++ b/packages/shared_preferences/shared_preferences_linux/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Chromium Authors. All rights reserved. +Copyright 2020 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart index 019dc248a918..a8e52ccc3063 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart b/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart index ab664cd652ff..0f6d7fc49f7e 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h index d1c3f9c4fb0b..5d666ca73bec 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart index a82b5fb51e77..dec1aa55d40e 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart index 5a694658cdf5..6252da4668c9 100644 --- a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart +++ b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart index cf0bc80e3ec2..98260302b778 100644 --- a/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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:file/memory.dart'; diff --git a/packages/shared_preferences/shared_preferences_macos/AUTHORS b/packages/shared_preferences/shared_preferences_macos/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/shared_preferences/shared_preferences_macos/AUTHORS +++ b/packages/shared_preferences/shared_preferences_macos/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart index 94dee2d73c9d..53d3cfdf3bc5 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017, the Chromium project authors. All rights reserved. +// Copyright 2017, 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. diff --git a/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart b/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart index f1058cddd63b..388f2389bf5b 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart index a82b5fb51e77..dec1aa55d40e 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift b/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift index 8f7f58ece635..19a420d002a4 100644 --- a/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift +++ b/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/AUTHORS b/packages/shared_preferences/shared_preferences_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/AUTHORS +++ b/packages/shared_preferences/shared_preferences_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/shared_preferences/shared_preferences_platform_interface/LICENSE b/packages/shared_preferences/shared_preferences_platform_interface/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/LICENSE +++ b/packages/shared_preferences/shared_preferences_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart b/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart index c02c537adcbd..47004b198175 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart b/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart index cf194f82c267..f330b04cd30c 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart index d828126168ba..3225090e5b51 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/test/shared_preferences_platform_interface_test.dart b/packages/shared_preferences/shared_preferences_platform_interface/test/shared_preferences_platform_interface_test.dart index 9e957734d174..a1c4ca9219aa 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/test/shared_preferences_platform_interface_test.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/test/shared_preferences_platform_interface_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_web/LICENSE b/packages/shared_preferences/shared_preferences_web/LICENSE index 507569823f1b..b257ce7c224c 100644 --- a/packages/shared_preferences/shared_preferences_web/LICENSE +++ b/packages/shared_preferences/shared_preferences_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Chromium Authors. All rights reserved. +Copyright 2019 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart b/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart index 346877e8a120..7d5292a54db1 100644 --- a/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart +++ b/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart b/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart index c0cf92cc1bf0..b1275330e3a7 100644 --- a/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart +++ b/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/AUTHORS b/packages/shared_preferences/shared_preferences_windows/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/shared_preferences/shared_preferences_windows/AUTHORS +++ b/packages/shared_preferences/shared_preferences_windows/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/shared_preferences/shared_preferences_windows/LICENSE b/packages/shared_preferences/shared_preferences_windows/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/shared_preferences/shared_preferences_windows/LICENSE +++ b/packages/shared_preferences/shared_preferences_windows/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_windows/example/LICENSE b/packages/shared_preferences/shared_preferences_windows/example/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/LICENSE +++ b/packages/shared_preferences/shared_preferences_windows/example/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart index 41fc5dbf8b2a..16f17cf71094 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017, the Chromium project authors. All rights reserved. +// Copyright 2017, 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart b/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart index f0dc155aee4a..96c2490a60ee 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart index 5504f8c79080..f41cb47e07a2 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017, the Chromium project authors. All rights reserved. +// Copyright 2017, 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp index dd2e3cca5666..b7d078e4d4a5 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h index a9d273e419eb..9b4ef089621b 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp index 40492ac76edb..e74157ed999a 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp index 4dd13b6d1db9..ee2e2fd5eae9 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h index 12aaab42c59b..a24c47f2e55f 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp index c408cb3f7a74..9eba364025d0 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h index 2754c7a7f9ef..640587eb23ab 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp index 878b64afe276..97628170c2c2 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h index 99e24a555afa..59b78382b27d 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart b/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart index b2678c49782b..04efce9946d4 100644 --- a/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart +++ b/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart b/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart index 785092f6fa16..a78dce207c09 100644 --- a/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/url_launcher/url_launcher/AUTHORS b/packages/url_launcher/url_launcher/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/url_launcher/url_launcher/AUTHORS +++ b/packages/url_launcher/url_launcher/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/url_launcher/url_launcher/LICENSE b/packages/url_launcher/url_launcher/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/url_launcher/url_launcher/LICENSE +++ b/packages/url_launcher/url_launcher/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java index 7a4b37488e69..7b858fbafdb3 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java index a6f29e1af68d..b6446458322b 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java index 79198200c526..cafc7a65c04b 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java index 160e24e331d3..53b2e8a44479 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java b/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java index e9d27e3e3b01..0055659c5fc0 100644 --- a/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java +++ b/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java b/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java index 9fd4871c0711..a005c452d426 100644 --- a/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java +++ b/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart index 9e7b04b38b46..62343c6dc689 100644 --- a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher/example/ios/Runner.xcodeproj/project.pbxproj b/packages/url_launcher/url_launcher/example/ios/Runner.xcodeproj/project.pbxproj index db72809a6169..de3d24772fb4 100644 --- a/packages/url_launcher/url_launcher/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/url_launcher/url_launcher/example/ios/Runner.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.h b/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.h +++ b/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.m b/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.m index 9cf1c7796c6a..07cf6cb9b49f 100644 --- a/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.m +++ b/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/example/ios/Runner/main.m b/packages/url_launcher/url_launcher/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/url_launcher/url_launcher/example/ios/Runner/main.m +++ b/packages/url_launcher/url_launcher/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/example/lib/main.dart b/packages/url_launcher/url_launcher/example/lib/main.dart index 0b310490d0e9..8af62ed7859e 100644 --- a/packages/url_launcher/url_launcher/example/lib/main.dart +++ b/packages/url_launcher/url_launcher/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart index 3e3caf844689..f044c8de676e 100644 --- a/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.h b/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.h index 7ce28f598082..35eade666e15 100644 --- a/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.h +++ b/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m b/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m index ac05417473a3..bbcfdfdc949c 100644 --- a/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m +++ b/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/lib/link.dart b/packages/url_launcher/url_launcher/lib/link.dart index ac1d4064d10f..cdcc2ee1a016 100644 --- a/packages/url_launcher/url_launcher/lib/link.dart +++ b/packages/url_launcher/url_launcher/lib/link.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/lib/src/link.dart b/packages/url_launcher/url_launcher/lib/src/link.dart index 14fdc9055d7a..e614c2200b02 100644 --- a/packages/url_launcher/url_launcher/lib/src/link.dart +++ b/packages/url_launcher/url_launcher/lib/src/link.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/lib/url_launcher.dart b/packages/url_launcher/url_launcher/lib/url_launcher.dart index 35833de18738..1a3ac40ce5e2 100644 --- a/packages/url_launcher/url_launcher/lib/url_launcher.dart +++ b/packages/url_launcher/url_launcher/lib/url_launcher.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/test/link_test.dart b/packages/url_launcher/url_launcher/test/link_test.dart index 8da5111f5733..02678a3559dd 100644 --- a/packages/url_launcher/url_launcher/test/link_test.dart +++ b/packages/url_launcher/url_launcher/test/link_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart b/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart index 87ae99e81024..6d862844e1d0 100644 --- a/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart +++ b/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher/test/url_launcher_test.dart b/packages/url_launcher/url_launcher/test/url_launcher_test.dart index 9fb16019a543..89eb259e2fa9 100644 --- a/packages/url_launcher/url_launcher/test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/test/url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_linux/AUTHORS b/packages/url_launcher/url_launcher_linux/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/url_launcher/url_launcher_linux/AUTHORS +++ b/packages/url_launcher/url_launcher_linux/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/url_launcher/url_launcher_linux/LICENSE b/packages/url_launcher/url_launcher_linux/LICENSE index d7412e0a1e0c..67c7e2c52e46 100644 --- a/packages/url_launcher/url_launcher_linux/LICENSE +++ b/packages/url_launcher/url_launcher_linux/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Chromium Authors. All rights reserved. +Copyright 2020 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart index aa668ed747b5..b14cc943c90d 100644 --- a/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_linux/example/lib/main.dart b/packages/url_launcher/url_launcher_linux/example/lib/main.dart index f49e9fa290c5..e6e027b4a6ba 100644 --- a/packages/url_launcher/url_launcher_linux/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_linux/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart index c62ef5dba800..ac2a0cf5f19b 100644 --- a/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h b/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h index efcfe62e706a..399bde268919 100644 --- a/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h +++ b/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc b/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc index 8ef1a8aedbc2..17431d1c2f81 100644 --- a/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc +++ b/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/url_launcher/url_launcher_macos/AUTHORS b/packages/url_launcher/url_launcher_macos/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/url_launcher/url_launcher_macos/AUTHORS +++ b/packages/url_launcher/url_launcher_macos/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/url_launcher/url_launcher_macos/LICENSE b/packages/url_launcher/url_launcher_macos/LICENSE index 507569823f1b..b257ce7c224c 100644 --- a/packages/url_launcher/url_launcher_macos/LICENSE +++ b/packages/url_launcher/url_launcher_macos/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Chromium Authors. All rights reserved. +Copyright 2019 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart index 6775a637f7dc..ade3da82700d 100644 --- a/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_macos/example/lib/main.dart b/packages/url_launcher/url_launcher_macos/example/lib/main.dart index f49e9fa290c5..e6e027b4a6ba 100644 --- a/packages/url_launcher/url_launcher_macos/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_macos/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart index c62ef5dba800..ac2a0cf5f19b 100644 --- a/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_macos/macos/Classes/UrlLauncherPlugin.swift b/packages/url_launcher/url_launcher_macos/macos/Classes/UrlLauncherPlugin.swift index 916f5c9aa22f..46df87a34304 100644 --- a/packages/url_launcher/url_launcher_macos/macos/Classes/UrlLauncherPlugin.swift +++ b/packages/url_launcher/url_launcher_macos/macos/Classes/UrlLauncherPlugin.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_platform_interface/AUTHORS b/packages/url_launcher/url_launcher_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/url_launcher/url_launcher_platform_interface/AUTHORS +++ b/packages/url_launcher/url_launcher_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/url_launcher/url_launcher_platform_interface/LICENSE b/packages/url_launcher/url_launcher_platform_interface/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/url_launcher/url_launcher_platform_interface/LICENSE +++ b/packages/url_launcher/url_launcher_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/link.dart b/packages/url_launcher/url_launcher_platform_interface/lib/link.dart index a176972e06bd..6c1a13b604a8 100644 --- a/packages/url_launcher/url_launcher_platform_interface/lib/link.dart +++ b/packages/url_launcher/url_launcher_platform_interface/lib/link.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart b/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart index 7b9dfc9cc5cf..93fdaff7ea1b 100644 --- a/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart +++ b/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart b/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart index 2a4edfa8d1af..d34ce7512afb 100644 --- a/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart +++ b/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart b/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart index a01637e2f378..e60cc25f25fe 100644 --- a/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart +++ b/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart b/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart index b5a96b18c91a..3e450e83e41b 100644 --- a/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_web/AUTHORS b/packages/url_launcher/url_launcher_web/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/url_launcher/url_launcher_web/AUTHORS +++ b/packages/url_launcher/url_launcher_web/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/url_launcher/url_launcher_web/LICENSE b/packages/url_launcher/url_launcher_web/LICENSE index 46b9e8c222d7..b66343316afd 100644 --- a/packages/url_launcher/url_launcher_web/LICENSE +++ b/packages/url_launcher/url_launcher_web/LICENSE @@ -1,6 +1,6 @@ url_launcher_web -Copyright 2019 The Chromium Authors. All rights reserved. +Copyright 2019 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart b/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart index 3c1dbd8b1b89..43bd2234ec84 100644 --- a/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart +++ b/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart index f7ea35667530..f8057d5f4204 100644 --- a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart +++ b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart b/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart index 64e2248a4f9b..0dd5f694f16b 100644 --- a/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart +++ b/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_web/lib/src/link.dart b/packages/url_launcher/url_launcher_web/lib/src/link.dart index 42c711b7d818..a39dbd4edf58 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/link.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/link.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart index 27d39b528e51..ec93f431138b 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart index 7f8c2b2c0796..2a8c7f5f5c6e 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart index 16654a0fa967..b6c2f8812a1b 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart index e4d2116445cf..a2a1f2a9d863 100644 --- a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart +++ b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart b/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart index 11f9b24dc878..64d8e547e485 100644 --- a/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart +++ b/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_windows/AUTHORS b/packages/url_launcher/url_launcher_windows/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/url_launcher/url_launcher_windows/AUTHORS +++ b/packages/url_launcher/url_launcher_windows/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/url_launcher/url_launcher_windows/LICENSE b/packages/url_launcher/url_launcher_windows/LICENSE index 507569823f1b..b257ce7c224c 100644 --- a/packages/url_launcher/url_launcher_windows/LICENSE +++ b/packages/url_launcher/url_launcher_windows/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Chromium Authors. All rights reserved. +Copyright 2019 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart index aa668ed747b5..b14cc943c90d 100644 --- a/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_windows/example/lib/main.dart b/packages/url_launcher/url_launcher_windows/example/lib/main.dart index f49e9fa290c5..e6e027b4a6ba 100644 --- a/packages/url_launcher/url_launcher_windows/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_windows/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart index c62ef5dba800..ac2a0cf5f19b 100644 --- a/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h b/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h index cdd018a0924e..7ffb0f93f271 100644 --- a/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h +++ b/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. #ifndef PACKAGES_URL_LAUNCHER_URL_LAUNCHER_WINDOWS_WINDOWS_INCLUDE_URL_LAUNCHER_WINDOWS_URL_LAUNCHER_PLUGIN_H_ diff --git a/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp b/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp index dfb406385787..e6a36f76ad77 100644 --- a/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp +++ b/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. #include "include/url_launcher_windows/url_launcher_plugin.h" diff --git a/packages/video_player/video_player/AUTHORS b/packages/video_player/video_player/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/video_player/video_player/AUTHORS +++ b/packages/video_player/video_player/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/video_player/video_player/LICENSE b/packages/video_player/video_player/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/video_player/video_player/LICENSE +++ b/packages/video_player/video_player/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java index adccd2e2cdcd..0deb06b6fa08 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java index 0d108caa0597..c42abff848d5 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/QueuingEventSink.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/QueuingEventSink.java index 18835271a83a..fc1acc3250f9 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/QueuingEventSink.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/QueuingEventSink.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java index bba301666993..dae24d17ece2 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java index fa51fbf50b43..63b1896038c7 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java index 0c5854f4bc83..644c0e88c226 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/example/android/app/src/main/java/io/flutter/plugins/videoplayerexample/EmbeddingV1Activity.java b/packages/video_player/video_player/example/android/app/src/main/java/io/flutter/plugins/videoplayerexample/EmbeddingV1Activity.java index 841853dbd758..60bebe82d4df 100644 --- a/packages/video_player/video_player/example/android/app/src/main/java/io/flutter/plugins/videoplayerexample/EmbeddingV1Activity.java +++ b/packages/video_player/video_player/example/android/app/src/main/java/io/flutter/plugins/videoplayerexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/video_player/video_player/example/integration_test/video_player_test.dart b/packages/video_player/video_player/example/integration_test/video_player_test.dart index b39bb087a21c..0566ceeb01c4 100644 --- a/packages/video_player/video_player/example/integration_test/video_player_test.dart +++ b/packages/video_player/video_player/example/integration_test/video_player_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/video_player/video_player/example/ios/Runner.xcodeproj/project.pbxproj b/packages/video_player/video_player/example/ios/Runner.xcodeproj/project.pbxproj index 9f0a7ef189b9..d558ae5d68e0 100644 --- a/packages/video_player/video_player/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/video_player/video_player/example/ios/Runner.xcodeproj/project.pbxproj @@ -177,7 +177,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; diff --git a/packages/video_player/video_player/example/ios/Runner/AppDelegate.h b/packages/video_player/video_player/example/ios/Runner/AppDelegate.h index d9e18e990f2e..31fc381e7066 100644 --- a/packages/video_player/video_player/example/ios/Runner/AppDelegate.h +++ b/packages/video_player/video_player/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/example/ios/Runner/AppDelegate.m b/packages/video_player/video_player/example/ios/Runner/AppDelegate.m index f08675707182..2147d3d605ac 100644 --- a/packages/video_player/video_player/example/ios/Runner/AppDelegate.m +++ b/packages/video_player/video_player/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/example/ios/Runner/main.m b/packages/video_player/video_player/example/ios/Runner/main.m index bec320c0bee0..f451b14cb751 100644 --- a/packages/video_player/video_player/example/ios/Runner/main.m +++ b/packages/video_player/video_player/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/example/lib/main.dart b/packages/video_player/video_player/example/lib/main.dart index c874f740eab2..8ab4ff12216c 100644 --- a/packages/video_player/video_player/example/lib/main.dart +++ b/packages/video_player/video_player/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/example/test_driver/integration_test.dart b/packages/video_player/video_player/example/test_driver/integration_test.dart index ca76cd86091a..2a2476ac7a1a 100644 --- a/packages/video_player/video_player/example/test_driver/integration_test.dart +++ b/packages/video_player/video_player/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/video_player/video_player/example/test_driver/video_player.dart b/packages/video_player/video_player/example/test_driver/video_player.dart index b942d20c17ba..317632834566 100644 --- a/packages/video_player/video_player/example/test_driver/video_player.dart +++ b/packages/video_player/video_player/example/test_driver/video_player.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/video_player/video_player/example/test_driver/video_player_test.dart b/packages/video_player/video_player/example/test_driver/video_player_test.dart index 232a88d89926..63e53f0b69e9 100644 --- a/packages/video_player/video_player/example/test_driver/video_player_test.dart +++ b/packages/video_player/video_player/example/test_driver/video_player_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.h b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.h index 18fdcca6d54e..80f07014954e 100644 --- a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.h +++ b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m index c2a1a40aa4fe..ed1623f4f575 100644 --- a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m +++ b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/ios/Classes/messages.h b/packages/video_player/video_player/ios/Classes/messages.h index 8e2ae130643f..ab54e8d8048f 100644 --- a/packages/video_player/video_player/ios/Classes/messages.h +++ b/packages/video_player/video_player/ios/Classes/messages.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/ios/Classes/messages.m b/packages/video_player/video_player/ios/Classes/messages.m index 368601b9d6cb..78174d43a153 100644 --- a/packages/video_player/video_player/ios/Classes/messages.m +++ b/packages/video_player/video_player/ios/Classes/messages.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/lib/src/closed_caption_file.dart b/packages/video_player/video_player/lib/src/closed_caption_file.dart index 64ab1f6ca651..1542746e08b1 100644 --- a/packages/video_player/video_player/lib/src/closed_caption_file.dart +++ b/packages/video_player/video_player/lib/src/closed_caption_file.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/video_player/video_player/lib/src/sub_rip.dart b/packages/video_player/video_player/lib/src/sub_rip.dart index 11456db88d09..89c1d5f78b01 100644 --- a/packages/video_player/video_player/lib/src/sub_rip.dart +++ b/packages/video_player/video_player/lib/src/sub_rip.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index 96dd73d3adea..4d3e4fa2dcbc 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/pigeons/messages.dart b/packages/video_player/video_player/pigeons/messages.dart index 33ca12e7969e..43bcf4d6a3c2 100644 --- a/packages/video_player/video_player/pigeons/messages.dart +++ b/packages/video_player/video_player/pigeons/messages.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player/test/closed_caption_file_test.dart b/packages/video_player/video_player/test/closed_caption_file_test.dart index 148c082bceee..9b5ca8a11b22 100644 --- a/packages/video_player/video_player/test/closed_caption_file_test.dart +++ b/packages/video_player/video_player/test/closed_caption_file_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/video_player/video_player/test/sub_rip_file_test.dart b/packages/video_player/video_player/test/sub_rip_file_test.dart index 2b9803d8275e..5f696fa0d351 100644 --- a/packages/video_player/video_player/test/sub_rip_file_test.dart +++ b/packages/video_player/video_player/test/sub_rip_file_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/video_player/video_player/test/video_player_initialization_test.dart b/packages/video_player/video_player/test/video_player_initialization_test.dart index 1a09ed9f718c..64bbb99d09b8 100644 --- a/packages/video_player/video_player/test/video_player_initialization_test.dart +++ b/packages/video_player/video_player/test/video_player_initialization_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart index 582012097b71..bdb9dc9ec432 100644 --- a/packages/video_player/video_player/test/video_player_test.dart +++ b/packages/video_player/video_player/test/video_player_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/video_player/video_player_platform_interface/AUTHORS b/packages/video_player/video_player_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/video_player/video_player_platform_interface/AUTHORS +++ b/packages/video_player/video_player_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/video_player/video_player_platform_interface/LICENSE b/packages/video_player/video_player_platform_interface/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/video_player/video_player_platform_interface/LICENSE +++ b/packages/video_player/video_player_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/video_player/video_player_platform_interface/lib/messages.dart b/packages/video_player/video_player_platform_interface/lib/messages.dart index 96ff20ea907f..83e34ee33eb8 100644 --- a/packages/video_player/video_player_platform_interface/lib/messages.dart +++ b/packages/video_player/video_player_platform_interface/lib/messages.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart index 9b007d00d6a9..9a37d6084c0a 100644 --- a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart +++ b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player_platform_interface/lib/test.dart b/packages/video_player/video_player_platform_interface/lib/test.dart index 7365f6dfb391..fd23a61a0365 100644 --- a/packages/video_player/video_player_platform_interface/lib/test.dart +++ b/packages/video_player/video_player_platform_interface/lib/test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart index 77b34f46bc10..bf30ecc6fc93 100644 --- a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart +++ b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart index fae4b746bf05..7a5192d861c0 100644 --- a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart +++ b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player_web/AUTHORS b/packages/video_player/video_player_web/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/video_player/video_player_web/AUTHORS +++ b/packages/video_player/video_player_web/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/video_player/video_player_web/LICENSE b/packages/video_player/video_player_web/LICENSE index a6d6c0749818..bb6f2c07756f 100644 --- a/packages/video_player/video_player_web/LICENSE +++ b/packages/video_player/video_player_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart b/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart index 27d39b528e51..ec93f431138b 100644 --- a/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart +++ b/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart b/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart index 7f8c2b2c0796..2a8c7f5f5c6e 100644 --- a/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart +++ b/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart b/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart index 16654a0fa967..b6c2f8812a1b 100644 --- a/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart +++ b/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player_web/lib/video_player_web.dart b/packages/video_player/video_player_web/lib/video_player_web.dart index d22c8f4f983c..6c99e24c4feb 100644 --- a/packages/video_player/video_player_web/lib/video_player_web.dart +++ b/packages/video_player/video_player_web/lib/video_player_web.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/packages/video_player/video_player_web/test/video_player_web_test.dart b/packages/video_player/video_player_web/test/video_player_web_test.dart index aee5b0350570..4fdbc7e9d3d6 100644 --- a/packages/video_player/video_player_web/test/video_player_web_test.dart +++ b/packages/video_player/video_player_web/test/video_player_web_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/AUTHORS b/packages/webview_flutter/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/webview_flutter/AUTHORS +++ b/packages/webview_flutter/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/webview_flutter/LICENSE b/packages/webview_flutter/LICENSE index ad33cf3c3ed1..050e2c7cac4f 100644 --- a/packages/webview_flutter/LICENSE +++ b/packages/webview_flutter/LICENSE @@ -1,4 +1,4 @@ -Copyright 2018 The Chromium Authors. All rights reserved. +Copyright 2018 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java index e98c2b0fc4da..2d66da8fc918 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java index 86b4fd412a29..456d07c2d214 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java index 022f1c3597e7..f170e7267c56 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java index 3590d67eb334..30bbeafd1b68 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java index 9b81a5b7cc6b..51758d05c57a 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java index f23aae5b2b69..4b39d3bb83ef 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java index 8fbdfaff1a6d..2be6dc1f575c 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java index 6fdc36fbe545..054e68554df4 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java index 2de8fdf94bc4..23926c4577ea 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java b/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java index dbdb1d7f72f9..8eda066ea776 100644 --- a/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java +++ b/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index 20391f70d2ff..37da553b0893 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj index d651613f32dc..30ce866bcf73 100644 --- a/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/webview_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -227,7 +227,7 @@ attributes = { DefaultBuildSystemTypeForWorkspace = Original; LastUpgradeCheck = 1030; - ORGANIZATIONNAME = "The Chromium Authors"; + ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 68BDCAE823C3F7CB00D9C032 = { ProvisioningStyle = Automatic; diff --git a/packages/webview_flutter/example/ios/Runner/AppDelegate.h b/packages/webview_flutter/example/ios/Runner/AppDelegate.h index d129e6e65e7a..d0578fc417d7 100644 --- a/packages/webview_flutter/example/ios/Runner/AppDelegate.h +++ b/packages/webview_flutter/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/example/ios/Runner/AppDelegate.m b/packages/webview_flutter/example/ios/Runner/AppDelegate.m index e5b5ebef5767..f6a895ac8dd8 100644 --- a/packages/webview_flutter/example/ios/Runner/AppDelegate.m +++ b/packages/webview_flutter/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/example/ios/Runner/main.m b/packages/webview_flutter/example/ios/Runner/main.m index bc098e4e00a4..a6d55eceeb0e 100644 --- a/packages/webview_flutter/example/ios/Runner/main.m +++ b/packages/webview_flutter/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/example/lib/main.dart b/packages/webview_flutter/example/lib/main.dart index e7e7981150ca..5c9e638ee1aa 100644 --- a/packages/webview_flutter/example/lib/main.dart +++ b/packages/webview_flutter/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/example/test_driver/integration_test.dart b/packages/webview_flutter/example/test_driver/integration_test.dart index c62ef5dba800..ac2a0cf5f19b 100644 --- a/packages/webview_flutter/example/test_driver/integration_test.dart +++ b/packages/webview_flutter/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, the Chromium project authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Classes/FLTCookieManager.h b/packages/webview_flutter/ios/Classes/FLTCookieManager.h index 3ad5c7e0d9bf..29e028ced59f 100644 --- a/packages/webview_flutter/ios/Classes/FLTCookieManager.h +++ b/packages/webview_flutter/ios/Classes/FLTCookieManager.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Classes/FLTCookieManager.m b/packages/webview_flutter/ios/Classes/FLTCookieManager.m index 47948bf6b9f0..0a15c7ceb975 100644 --- a/packages/webview_flutter/ios/Classes/FLTCookieManager.m +++ b/packages/webview_flutter/ios/Classes/FLTCookieManager.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h index 1625c4999bd2..3e661ff93b3e 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h +++ b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m index 7eb08daea40e..85a5decf6e3e 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m +++ b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h index 40139ead262c..36ed108bb727 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h +++ b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m index ad864e6e1fd1..d53f132bea25 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m +++ b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.h b/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.h index fffaedbe513b..109170e9af66 100644 --- a/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.h +++ b/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.m b/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.m index a131263c9a92..3d39d96a6771 100644 --- a/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.m +++ b/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.h b/packages/webview_flutter/ios/Classes/FlutterWebView.h index 875551d3535d..555a90837da9 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.h +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index 5f2af3b8aae0..a1ea10c397f9 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.h b/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.h index 1e0a9f2fe9d6..d3b1261dae94 100644 --- a/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.h +++ b/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.m b/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.m index 5bafd8c715dd..2e9e1b864f34 100644 --- a/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.m +++ b/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m b/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m index b22f9aa9d642..af6ce0b71450 100644 --- a/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m +++ b/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/ios/Tests/FLTWebViewTests.m b/packages/webview_flutter/ios/Tests/FLTWebViewTests.m index 40b79e356389..9a886d383c22 100644 --- a/packages/webview_flutter/ios/Tests/FLTWebViewTests.m +++ b/packages/webview_flutter/ios/Tests/FLTWebViewTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/lib/platform_interface.dart index 16b529d7090e..198e07767fc5 100644 --- a/packages/webview_flutter/lib/platform_interface.dart +++ b/packages/webview_flutter/lib/platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/lib/src/webview_android.dart b/packages/webview_flutter/lib/src/webview_android.dart index cba9e1b698b8..a8b87fc52616 100644 --- a/packages/webview_flutter/lib/src/webview_android.dart +++ b/packages/webview_flutter/lib/src/webview_android.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/lib/src/webview_cupertino.dart b/packages/webview_flutter/lib/src/webview_cupertino.dart index e6816555f73b..eb1e75876d4e 100644 --- a/packages/webview_flutter/lib/src/webview_cupertino.dart +++ b/packages/webview_flutter/lib/src/webview_cupertino.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart index e26604f74628..bd042130f92a 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 56315b6692a5..af373d1bcbb7 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/test/webview_flutter_test.dart index 8ae6e625431d..afe6664a5957 100644 --- a/packages/webview_flutter/test/webview_flutter_test.dart +++ b/packages/webview_flutter/test/webview_flutter_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/AUTHORS b/packages/wifi_info_flutter/wifi_info_flutter/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/AUTHORS +++ b/packages/wifi_info_flutter/wifi_info_flutter/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/wifi_info_flutter/wifi_info_flutter/LICENSE b/packages/wifi_info_flutter/wifi_info_flutter/LICENSE index d7412e0a1e0c..67c7e2c52e46 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/LICENSE +++ b/packages/wifi_info_flutter/wifi_info_flutter/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Chromium Authors. All rights reserved. +Copyright 2020 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java index e5e33af715ca..6425b9be2909 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java +++ b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterMethodChannelHandler.java b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterMethodChannelHandler.java index b996d32255e3..77861fd4b5fa 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterMethodChannelHandler.java +++ b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterMethodChannelHandler.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java index 1346617df53b..f1b3c0e181ba 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java +++ b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart b/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart index b92e55028a45..7e25bc527b2a 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart index 6fe4737ae7a1..98f56d4e5e25 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart index d59272c77431..8997c9275a06 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart index 4760b88d9019..5b6c0ded11cf 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.h b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.h index 7cfe42df6079..05b885c7d2ac 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.h +++ b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.m b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.m index 2f237a1d3f15..331b6cca2ea8 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.m +++ b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.m @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.h b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.h index 92d843793990..66e3dd18c9b4 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.h +++ b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m index f0811dd92ef6..1db163a65766 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m +++ b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart b/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart index a2a69d161f5a..c15718bdb82d 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart index 19e84f696f7f..c0874d10aa07 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/AUTHORS b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/AUTHORS index dbf9d190931b..493a0b4ef9c2 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/AUTHORS +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/AUTHORS @@ -4,6 +4,7 @@ # Name/Organization Google Inc. +The Chromium Authors German Saprykin Benjamin Sauer larsenthomasj@gmail.com diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/LICENSE b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/LICENSE index d7412e0a1e0c..67c7e2c52e46 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/LICENSE +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Chromium Authors. All rights reserved. +Copyright 2020 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/enums.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/enums.dart index 4529938b4761..8dae9737981a 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/enums.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/enums.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart index ba422ecd7565..efd775ab7486 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart index 5115af7e56eb..7e8de96336b4 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart index 33733170c9fb..c30713a65b72 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. +// Copyright 2020 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. diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index cfd783e64d1e..864a81a85057 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2017 The Chromium Authors. All rights reserved. +# Copyright 2017 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. diff --git a/script/check_publish.sh b/script/check_publish.sh index ead4aa3b2b34..5c68806c092a 100755 --- a/script/check_publish.sh +++ b/script/check_publish.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2017 The Chromium Authors. All rights reserved. +# Copyright 2017 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. diff --git a/script/common.sh b/script/common.sh index 9668688f50b2..81fc96cbdc18 100644 --- a/script/common.sh +++ b/script/common.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2017 The Chromium Authors. All rights reserved. +# Copyright 2017 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. diff --git a/script/incremental_build.sh b/script/incremental_build.sh index b46f500ae414..d087745eb88d 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2017 The Chromium Authors. All rights reserved. +# Copyright 2017 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. diff --git a/script/tool/lib/src/analyze_command.dart b/script/tool/lib/src/analyze_command.dart index 8cd57fa0b338..7a0b47261a90 100644 --- a/script/tool/lib/src/analyze_command.dart +++ b/script/tool/lib/src/analyze_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/script/tool/lib/src/build_examples_command.dart b/script/tool/lib/src/build_examples_command.dart index bb140bd429c6..22029791f324 100644 --- a/script/tool/lib/src/build_examples_command.dart +++ b/script/tool/lib/src/build_examples_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/script/tool/lib/src/common.dart b/script/tool/lib/src/common.dart index ce4f37873b07..1228aef5b0f6 100644 --- a/script/tool/lib/src/common.dart +++ b/script/tool/lib/src/common.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/script/tool/lib/src/create_all_plugins_app_command.dart b/script/tool/lib/src/create_all_plugins_app_command.dart index 0f1431c5aee0..ec2fb7ed698e 100644 --- a/script/tool/lib/src/create_all_plugins_app_command.dart +++ b/script/tool/lib/src/create_all_plugins_app_command.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/lib/src/drive_examples_command.dart b/script/tool/lib/src/drive_examples_command.dart index 0bd531a20f8a..4b5b33ff9029 100644 --- a/script/tool/lib/src/drive_examples_command.dart +++ b/script/tool/lib/src/drive_examples_command.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/lib/src/firebase_test_lab_command.dart b/script/tool/lib/src/firebase_test_lab_command.dart index 0b4b2a471dbc..382161226987 100644 --- a/script/tool/lib/src/firebase_test_lab_command.dart +++ b/script/tool/lib/src/firebase_test_lab_command.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/script/tool/lib/src/format_command.dart b/script/tool/lib/src/format_command.dart index e1c14e04cfec..54895cbae094 100644 --- a/script/tool/lib/src/format_command.dart +++ b/script/tool/lib/src/format_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/script/tool/lib/src/java_test_command.dart b/script/tool/lib/src/java_test_command.dart index cf605bfc5ce2..07800349a37b 100644 --- a/script/tool/lib/src/java_test_command.dart +++ b/script/tool/lib/src/java_test_command.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/script/tool/lib/src/license_check_command.dart b/script/tool/lib/src/license_check_command.dart index e70e60b154d9..2df217ef78fd 100644 --- a/script/tool/lib/src/license_check_command.dart +++ b/script/tool/lib/src/license_check_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. @@ -60,13 +60,7 @@ final RegExp _workivaLicenseRegex = RegExp( multiLine: true, dotAll: true); -// TODO(stuartmorgan): Replace this with a single string once all the copyrights -// are standardized. -final List _firstPartyAuthors = [ - 'The Chromium Authors', - 'the Chromium project authors', - 'The Flutter Authors', -]; +const String _firstPartyAuthors = 'The Flutter Authors'; // The exact format of the BSD license that our license files should contain. // Slight variants are not accepted because they may prevent consolidation in @@ -129,7 +123,7 @@ class LicenseCheckCommand extends PluginCommand { p.basename(file.basename) == 'LICENSE' && !_isThirdParty(file)); final bool copyrightCheckSucceeded = await _checkCodeLicenses(codeFiles); - print('\n=======================================\n'); + _print('\n=======================================\n'); final bool licenseCheckSucceeded = await _checkLicenseFiles(firstPartyLicenseFiles); @@ -170,7 +164,7 @@ class LicenseCheckCommand extends PluginCommand { continue; } final String author = copyright.group(1); - if (!_firstPartyAuthors.contains(author) && !_isThirdParty(file)) { + if (author != _firstPartyAuthors && !_isThirdParty(file)) { misplacedThirdPartyFiles.add(file); } diff --git a/script/tool/lib/src/lint_podspecs_command.dart b/script/tool/lib/src/lint_podspecs_command.dart index 13de64415e9e..1e75eb62e4ea 100644 --- a/script/tool/lib/src/lint_podspecs_command.dart +++ b/script/tool/lib/src/lint_podspecs_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/script/tool/lib/src/list_command.dart b/script/tool/lib/src/list_command.dart index 7f94daac7096..53c1ba2f3ea3 100644 --- a/script/tool/lib/src/list_command.dart +++ b/script/tool/lib/src/list_command.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// Copyright 2018 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. diff --git a/script/tool/lib/src/main.dart b/script/tool/lib/src/main.dart index 329112931251..bb8af5d5ad58 100644 --- a/script/tool/lib/src/main.dart +++ b/script/tool/lib/src/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/script/tool/lib/src/publish_check_command.dart b/script/tool/lib/src/publish_check_command.dart index 670fedaf2fa1..53002b57897a 100644 --- a/script/tool/lib/src/publish_check_command.dart +++ b/script/tool/lib/src/publish_check_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/script/tool/lib/src/publish_plugin_command.dart b/script/tool/lib/src/publish_plugin_command.dart index f61a76947c9e..d48ed5b7fe7d 100644 --- a/script/tool/lib/src/publish_plugin_command.dart +++ b/script/tool/lib/src/publish_plugin_command.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/lib/src/test_command.dart b/script/tool/lib/src/test_command.dart index e938168cfa89..47f7ad89cb8d 100644 --- a/script/tool/lib/src/test_command.dart +++ b/script/tool/lib/src/test_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/script/tool/lib/src/version_check_command.dart b/script/tool/lib/src/version_check_command.dart index 111239f0399a..36105ad300ab 100644 --- a/script/tool/lib/src/version_check_command.dart +++ b/script/tool/lib/src/version_check_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/script/tool/lib/src/xctest_command.dart b/script/tool/lib/src/xctest_command.dart index a4d03360b292..cdc02594a192 100644 --- a/script/tool/lib/src/xctest_command.dart +++ b/script/tool/lib/src/xctest_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. diff --git a/script/tool/test/analyze_command_test.dart b/script/tool/test/analyze_command_test.dart index 63afb51c8595..6474d02f3d28 100644 --- a/script/tool/test/analyze_command_test.dart +++ b/script/tool/test/analyze_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/build_examples_command_test.dart b/script/tool/test/build_examples_command_test.dart index e0213893db38..ef959a6e251c 100644 --- a/script/tool/test/build_examples_command_test.dart +++ b/script/tool/test/build_examples_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/common_test.dart b/script/tool/test/common_test.dart index a8deacc8e483..8ee82ca2e95a 100644 --- a/script/tool/test/common_test.dart +++ b/script/tool/test/common_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/drive_examples_command_test.dart b/script/tool/test/drive_examples_command_test.dart index 7a8e9f3e9f95..63a3e69adcdc 100644 --- a/script/tool/test/drive_examples_command_test.dart +++ b/script/tool/test/drive_examples_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/firebase_test_lab_test.dart b/script/tool/test/firebase_test_lab_test.dart index d11624671523..6db4461a23a8 100644 --- a/script/tool/test/firebase_test_lab_test.dart +++ b/script/tool/test/firebase_test_lab_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/license_check_command_test.dart b/script/tool/test/license_check_command_test.dart index 8ae956740d72..69879bff8869 100644 --- a/script/tool/test/license_check_command_test.dart +++ b/script/tool/test/license_check_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. @@ -45,7 +45,7 @@ void main() { String prefix = '', String suffix = '', String copyright = - 'Copyright 2019 The Chromium Authors. All rights reserved.', + 'Copyright 2019 The Flutter Authors. All rights reserved.', List license = const [ 'Use of this source code is governed by a BSD-style license that can be', 'found in the LICENSE file.', diff --git a/script/tool/test/lint_podspecs_command_test.dart b/script/tool/test/lint_podspecs_command_test.dart index 2a3e60853d08..44e94ee873e4 100644 --- a/script/tool/test/lint_podspecs_command_test.dart +++ b/script/tool/test/lint_podspecs_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/list_command_test.dart b/script/tool/test/list_command_test.dart index d06f6d2ca464..e9b68254fb5d 100644 --- a/script/tool/test/list_command_test.dart +++ b/script/tool/test/list_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/mocks.dart b/script/tool/test/mocks.dart index 35a4eb7cbacb..d5cfe4ec4f76 100644 --- a/script/tool/test/mocks.dart +++ b/script/tool/test/mocks.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/publish_plugin_command_test.dart b/script/tool/test/publish_plugin_command_test.dart index 4f770b2054f9..b8ab1d25e532 100644 --- a/script/tool/test/publish_plugin_command_test.dart +++ b/script/tool/test/publish_plugin_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/test_command_test.dart b/script/tool/test/test_command_test.dart index 520f4c316f5c..eb9f3a9b0cf3 100644 --- a/script/tool/test/test_command_test.dart +++ b/script/tool/test/test_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/util.dart b/script/tool/test/util.dart index 63cd5defbb27..e463b88a1abb 100644 --- a/script/tool/test/util.dart +++ b/script/tool/test/util.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. diff --git a/script/tool/test/version_check_test.dart b/script/tool/test/version_check_test.dart index 400d4263357c..9e610d8a7a20 100644 --- a/script/tool/test/version_check_test.dart +++ b/script/tool/test/version_check_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. @@ -215,7 +215,7 @@ void main() { createFakePubspec(pluginDirectory, isFlutter: true, includeVersion: true, version: '1.0.1'); String changelog = ''' - + ## 1.0.1 diff --git a/script/tool/test/xctest_command_test.dart b/script/tool/test/xctest_command_test.dart index 2b75ccde4210..3b76fa6ffa19 100644 --- a/script/tool/test/xctest_command_test.dart +++ b/script/tool/test/xctest_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. +// Copyright 2017 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. From 15d4f9c4e06014225807c5fbcf681bd6ea1f765d Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 18 Mar 2021 17:05:38 -0700 Subject: [PATCH 342/924] [integration_test] Deprecate, and stop using in this repository (#3723) Updates integration_test README to note that the published version is deprecated and direct people to the SDK version. Updates all plugins here to use the SDK version. --- CODEOWNERS | 1 - CONTRIBUTING.md | 2 +- README.md | 3 +-- .../android_alarm_manager/example/pubspec.yaml | 2 +- packages/android_intent/example/pubspec.yaml | 2 +- packages/battery/battery/example/pubspec.yaml | 2 +- packages/battery/battery/pubspec.yaml | 2 +- packages/camera/camera/example/pubspec.yaml | 2 +- .../connectivity/example/pubspec.yaml | 2 +- packages/connectivity/connectivity/pubspec.yaml | 2 +- .../connectivity_macos/example/pubspec.yaml | 2 +- .../device_info/device_info/example/pubspec.yaml | 2 +- .../example/pubspec.yaml | 2 +- .../google_maps_flutter/example/pubspec.yaml | 2 +- .../google_sign_in/example/pubspec.yaml | 2 +- .../google_sign_in/google_sign_in/pubspec.yaml | 2 +- .../image_picker/example/pubspec.yaml | 2 +- packages/image_picker/image_picker/pubspec.yaml | 2 +- packages/in_app_purchase/example/pubspec.yaml | 2 +- packages/in_app_purchase/pubspec.yaml | 2 +- packages/integration_test/CHANGELOG.md | 4 ++++ packages/integration_test/README.md | 15 ++++++++++++++- packages/integration_test/pubspec.yaml | 2 +- packages/local_auth/example/pubspec.yaml | 2 +- packages/local_auth/pubspec.yaml | 2 +- packages/package_info/example/pubspec.yaml | 2 +- packages/package_info/pubspec.yaml | 2 +- .../path_provider/example/pubspec.yaml | 2 +- packages/path_provider/path_provider/pubspec.yaml | 2 +- .../path_provider_linux/example/pubspec.yaml | 2 +- .../path_provider_macos/example/pubspec.yaml | 2 +- .../path_provider_windows/example/pubspec.yaml | 2 +- packages/quick_actions/example/pubspec.yaml | 2 +- packages/quick_actions/pubspec.yaml | 2 +- packages/sensors/example/pubspec.yaml | 2 +- packages/sensors/pubspec.yaml | 2 +- packages/share/example/pubspec.yaml | 2 +- packages/share/pubspec.yaml | 2 +- .../shared_preferences/example/pubspec.yaml | 2 +- .../shared_preferences/pubspec.yaml | 2 +- .../shared_preferences_linux/example/pubspec.yaml | 2 +- .../shared_preferences_macos/example/pubspec.yaml | 2 +- .../example/pubspec.yaml | 2 +- .../url_launcher/example/pubspec.yaml | 2 +- .../url_launcher_linux/example/pubspec.yaml | 2 +- .../url_launcher_macos/example/pubspec.yaml | 2 +- .../url_launcher_windows/example/pubspec.yaml | 2 +- .../video_player/example/pubspec.yaml | 2 +- packages/webview_flutter/example/pubspec.yaml | 2 +- .../wifi_info_flutter/example/pubspec.yaml | 2 +- .../wifi_info_flutter/pubspec.yaml | 2 +- 51 files changed, 66 insertions(+), 51 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 8ab65bbb5a63..1d52dcefcbef 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -9,6 +9,5 @@ packages/camera/** @bparrishMines packages/file_selector/** @ditman packages/google_maps_flutter/** @cyanglaz packages/image_picker/** @cyanglaz -packages/integration_test/** @dnfield packages/in_app_purchase/** @cyanglaz @LHLL packages/ios_platform_images/** @gaaclarke diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d5ea4766b363..f307695b5956 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -61,7 +61,7 @@ USB and debugging enabled on that device. ## Setting up XCUITests -Sometimes, XCUITests are useful when integration testing a plugin that has native UI on iOS (e.g image_picker, in_app_purchase, camera, share, local_auth etc). Most of the time, XCUITests are not necessary, consider using [integration_test](https://pub.dev/packages/integration_test) if the tests are not focused on iOS system UI. +Sometimes, XCUITests are useful when integration testing a plugin that has native UI on iOS (e.g image_picker, in_app_purchase, camera, share, local_auth etc). Most of the time, XCUITests are not necessary, consider using `integration_test` if the tests are not focused on iOS system UI. If XCUITests has always been set up for the plugin, a RunnerUITests folder under `/example/ios` directory can be found. If XCUITests has not been set up for the plugin, follow these steps to set it up: diff --git a/README.md b/README.md index b65c10e7f381..c5c88d554df1 100644 --- a/README.md +++ b/README.md @@ -47,13 +47,12 @@ These are the available plugins in this repository. | [camera](./packages/camera/) | [![pub package](https://img.shields.io/pub/v/camera.svg)](https://pub.dev/packages/camera) | [![pub points](https://badges.bar/camera/pub%20points)](https://pub.dev/packages/camera/score) | [![popularity](https://badges.bar/camera/popularity)](https://pub.dev/packages/camera/score) | [![likes](https://badges.bar/camera/likes)](https://pub.dev/packages/camera/score) | | [connectivity](./packages/connectivity/) | [![pub package](https://img.shields.io/pub/v/connectivity.svg)](https://pub.dev/packages/connectivity) | [![pub points](https://badges.bar/connectivity/pub%20points)](https://pub.dev/packages/connectivity/score) | [![popularity](https://badges.bar/connectivity/popularity)](https://pub.dev/packages/connectivity/score) | [![likes](https://badges.bar/connectivity/likes)](https://pub.dev/packages/connectivity/score) | | [device_info](./packages/device_info/) | [![pub package](https://img.shields.io/pub/v/device_info.svg)](https://pub.dev/packages/device_info) | [![pub points](https://badges.bar/device_info/pub%20points)](https://pub.dev/packages/device_info/score) | [![popularity](https://badges.bar/device_info/popularity)](https://pub.dev/packages/device_info/score) | [![likes](https://badges.bar/device_info/likes)](https://pub.dev/packages/device_info/score) | -| [e2e (Discontinued, use integration_test)](./packages/e2e/) | [![pub package](https://img.shields.io/pub/v/e2e.svg)](https://pub.dev/packages/e2e) | [![pub points](https://badges.bar/e2e/pub%20points)](https://pub.dev/packages/e2e/score) | [![popularity](https://badges.bar/e2e/popularity)](https://pub.dev/packages/e2e/score) | [![likes](https://badges.bar/e2e/likes)](https://pub.dev/packages/e2e/score) | | [espresso](./packages/espresso/) | [![pub package](https://img.shields.io/pub/v/espresso.svg)](https://pub.dev/packages/espresso) | [![pub points](https://badges.bar/espresso/pub%20points)](https://pub.dev/packages/espresso/score) | [![popularity](https://badges.bar/espresso/popularity)](https://pub.dev/packages/espresso/score) | [![likes](https://badges.bar/espresso/likes)](https://pub.dev/packages/espresso/score) | | [flutter_plugin_android_lifecycle](./packages/flutter_plugin_android_lifecycle/) | [![pub package](https://img.shields.io/pub/v/flutter_plugin_android_lifecycle.svg)](https://pub.dev/packages/flutter_plugin_android_lifecycle) | [![pub points](https://badges.bar/flutter_plugin_android_lifecycle/pub%20points)](https://pub.dev/packages/flutter_plugin_android_lifecycle/score) | [![popularity](https://badges.bar/flutter_plugin_android_lifecycle/popularity)](https://pub.dev/packages/flutter_plugin_android_lifecycle/score) | [![likes](https://badges.bar/flutter_plugin_android_lifecycle/likes)](https://pub.dev/packages/flutter_plugin_android_lifecycle/score) | | [google_maps_flutter](./packages/google_maps_flutter) | [![pub package](https://img.shields.io/pub/v/google_maps_flutter.svg)](https://pub.dev/packages/google_maps_flutter) | [![pub points](https://badges.bar/google_maps_flutter/pub%20points)](https://pub.dev/packages/google_maps_flutter/score) | [![popularity](https://badges.bar/google_maps_flutter/popularity)](https://pub.dev/packages/google_maps_flutter/score) | [![likes](https://badges.bar/google_maps_flutter/likes)](https://pub.dev/packages/google_maps_flutter/score) | | [google_sign_in](./packages/google_sign_in/) | [![pub package](https://img.shields.io/pub/v/google_sign_in.svg)](https://pub.dev/packages/google_sign_in) | [![pub points](https://badges.bar/google_sign_in/pub%20points)](https://pub.dev/packages/google_sign_in/score) | [![popularity](https://badges.bar/google_sign_in/popularity)](https://pub.dev/packages/google_sign_in/score) | [![likes](https://badges.bar/google_sign_in/likes)](https://pub.dev/packages/google_sign_in/score) | | [image_picker](./packages/image_picker/) | [![pub package](https://img.shields.io/pub/v/image_picker.svg)](https://pub.dev/packages/image_picker) | [![pub points](https://badges.bar/image_picker/pub%20points)](https://pub.dev/packages/image_picker/score) | [![popularity](https://badges.bar/image_picker/popularity)](https://pub.dev/packages/image_picker/score) | [![likes](https://badges.bar/image_picker/likes)](https://pub.dev/packages/image_picker/score) | -| [integration_test](./packages/integration_test/) | [![pub package](https://img.shields.io/pub/v/integration_test.svg)](https://pub.dev/packages/integration_test) | [![pub points](https://badges.bar/integration_test/pub%20points)](https://pub.dev/packages/integration_test/score) | [![popularity](https://badges.bar/integration_test/popularity)](https://pub.dev/packages/integration_test/score) | [![likes](https://badges.bar/integration_test/likes)](https://pub.dev/packages/integration_test/score) | +| [integration_test (discontinued)](./packages/integration_test/) | [![pub package](https://img.shields.io/pub/v/integration_test.svg)](https://pub.dev/packages/integration_test) | [![pub points](https://badges.bar/integration_test/pub%20points)](https://pub.dev/packages/integration_test/score) | [![popularity](https://badges.bar/integration_test/popularity)](https://pub.dev/packages/integration_test/score) | [![likes](https://badges.bar/integration_test/likes)](https://pub.dev/packages/integration_test/score) | | [in_app_purchase](./packages/in_app_purchase/) | [![pub package](https://img.shields.io/pub/v/in_app_purchase.svg)](https://pub.dev/packages/in_app_purchase) | [![pub points](https://badges.bar/in_app_purchase/pub%20points)](https://pub.dev/packages/in_app_purchase/score) | [![popularity](https://badges.bar/in_app_purchase/popularity)](https://pub.dev/packages/in_app_purchase/score) | [![likes](https://badges.bar/in_app_purchase/likes)](https://pub.dev/packages/in_app_purchase/score) | | [ios_platform_images](./packages/ios_platform_images/) | [![pub package](https://img.shields.io/pub/v/ios_platform_images.svg)](https://pub.dev/packages/ios_platform_images) | [![pub points](https://badges.bar/ios_platform_images/pub%20points)](https://pub.dev/packages/ios_platform_images/score) | [![popularity](https://badges.bar/ios_platform_images/popularity)](https://pub.dev/packages/ios_platform_images/score) | [![likes](https://badges.bar/ios_platform_images/likes)](https://pub.dev/packages/ios_platform_images/score) | | [local_auth](./packages/local_auth/) | [![pub package](https://img.shields.io/pub/v/local_auth.svg)](https://pub.dev/packages/local_auth) | [![pub points](https://badges.bar/local_auth/pub%20points)](https://pub.dev/packages/local_auth/score) | [![popularity](https://badges.bar/local_auth/popularity)](https://pub.dev/packages/local_auth/score) | [![likes](https://badges.bar/local_auth/likes)](https://pub.dev/packages/local_auth/score) | diff --git a/packages/android_alarm_manager/example/pubspec.yaml b/packages/android_alarm_manager/example/pubspec.yaml index b92f45c73d35..78525345ab5c 100644 --- a/packages/android_alarm_manager/example/pubspec.yaml +++ b/packages/android_alarm_manager/example/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: path: ../ shared_preferences: ^2.0.0 integration_test: - path: ../../integration_test + sdk: flutter path_provider: ^2.0.0 dev_dependencies: diff --git a/packages/android_intent/example/pubspec.yaml b/packages/android_intent/example/pubspec.yaml index fd0e2d6b7844..fc154511dfa1 100644 --- a/packages/android_intent/example/pubspec.yaml +++ b/packages/android_intent/example/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../integration_test + sdk: flutter flutter_driver: sdk: flutter pedantic: ^1.10.0 diff --git a/packages/battery/battery/example/pubspec.yaml b/packages/battery/battery/example/pubspec.yaml index ea3d5d39ae14..648e9f578db6 100644 --- a/packages/battery/battery/example/pubspec.yaml +++ b/packages/battery/battery/example/pubspec.yaml @@ -16,7 +16,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/battery/battery/pubspec.yaml b/packages/battery/battery/pubspec.yaml index b705955efdef..4a93af02b0ea 100644 --- a/packages/battery/battery/pubspec.yaml +++ b/packages/battery/battery/pubspec.yaml @@ -24,7 +24,7 @@ dev_dependencies: sdk: flutter plugin_platform_interface: ^2.0.0 integration_test: - path: ../../integration_test + sdk: flutter pedantic: ^1.10.0 test: ^1.16.3 diff --git a/packages/camera/camera/example/pubspec.yaml b/packages/camera/camera/example/pubspec.yaml index b3ef8e497dc1..5fdaf5812d72 100644 --- a/packages/camera/camera/example/pubspec.yaml +++ b/packages/camera/camera/example/pubspec.yaml @@ -20,7 +20,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/connectivity/connectivity/example/pubspec.yaml b/packages/connectivity/connectivity/example/pubspec.yaml index 6395dc38c3ae..58d6f0ddca61 100644 --- a/packages/connectivity/connectivity/example/pubspec.yaml +++ b/packages/connectivity/connectivity/example/pubspec.yaml @@ -17,7 +17,7 @@ dev_dependencies: sdk: flutter test: ^1.16.3 integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/connectivity/connectivity/pubspec.yaml b/packages/connectivity/connectivity/pubspec.yaml index 7b4dc60eee81..85985dd45565 100644 --- a/packages/connectivity/connectivity/pubspec.yaml +++ b/packages/connectivity/connectivity/pubspec.yaml @@ -32,7 +32,7 @@ dev_dependencies: sdk: flutter test: ^1.16.3 integration_test: - path: ../../integration_test + sdk: flutter plugin_platform_interface: ^2.0.0 pedantic: ^1.10.0 diff --git a/packages/connectivity/connectivity_macos/example/pubspec.yaml b/packages/connectivity/connectivity_macos/example/pubspec.yaml index 61cf16854d8b..d130158c4364 100644 --- a/packages/connectivity/connectivity_macos/example/pubspec.yaml +++ b/packages/connectivity/connectivity_macos/example/pubspec.yaml @@ -17,7 +17,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/device_info/device_info/example/pubspec.yaml b/packages/device_info/device_info/example/pubspec.yaml index bc7d00ef87f0..36b6d6e9441c 100644 --- a/packages/device_info/device_info/example/pubspec.yaml +++ b/packages/device_info/device_info/example/pubspec.yaml @@ -16,7 +16,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml index 833c2eba4319..4506437b1180 100644 --- a/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/example/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../integration_test + sdk: flutter flutter_test: sdk: flutter pedantic: ^1.8.0 diff --git a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml index 35d0da3488be..5d553eaa3c99 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml @@ -23,7 +23,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/google_sign_in/google_sign_in/example/pubspec.yaml b/packages/google_sign_in/google_sign_in/example/pubspec.yaml index b5a1f3e1c2cc..f08a131e484a 100755 --- a/packages/google_sign_in/google_sign_in/example/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/example/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: dev_dependencies: pedantic: ^1.10.0 integration_test: - path: ../../../integration_test + sdk: flutter flutter_driver: sdk: flutter diff --git a/packages/google_sign_in/google_sign_in/pubspec.yaml b/packages/google_sign_in/google_sign_in/pubspec.yaml index 23f2588c8f90..1184d0f9af25 100644 --- a/packages/google_sign_in/google_sign_in/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in/pubspec.yaml @@ -30,7 +30,7 @@ dev_dependencies: sdk: flutter pedantic: ^1.10.0 integration_test: - path: ../../integration_test + sdk: flutter environment: sdk: ">=2.12.0-259.9.beta <3.0.0" diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml index ceafc317fa82..68b70b909162 100755 --- a/packages/image_picker/image_picker/example/pubspec.yaml +++ b/packages/image_picker/image_picker/example/pubspec.yaml @@ -19,7 +19,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index cd4089e58798..0018e87ab437 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -26,7 +26,7 @@ dev_dependencies: flutter_test: sdk: flutter integration_test: - path: ../../integration_test + sdk: flutter mockito: ^5.0.0-nullsafety.7 pedantic: ^1.10.0 plugin_platform_interface: ^2.0.0 diff --git a/packages/in_app_purchase/example/pubspec.yaml b/packages/in_app_purchase/example/pubspec.yaml index 8c9296dc98c8..8d193debb826 100644 --- a/packages/in_app_purchase/example/pubspec.yaml +++ b/packages/in_app_purchase/example/pubspec.yaml @@ -18,7 +18,7 @@ dev_dependencies: # the parent directory to use the current plugin's version. path: ../ integration_test: - path: ../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index c7582f91d8c2..2a8f56946bf2 100644 --- a/packages/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/pubspec.yaml @@ -19,7 +19,7 @@ dev_dependencies: sdk: flutter test: ^1.16.0 integration_test: - path: ../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/integration_test/CHANGELOG.md b/packages/integration_test/CHANGELOG.md index 71ab0e86266b..c5c34f49c2ab 100644 --- a/packages/integration_test/CHANGELOG.md +++ b/packages/integration_test/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.2+3 + +* Update README to reflect deprecation. + ## 1.0.2+2 * Fix tests from changes to `flutter test` machine output. diff --git a/packages/integration_test/README.md b/packages/integration_test/README.md index 676041eefae5..802fd4cafefc 100644 --- a/packages/integration_test/README.md +++ b/packages/integration_test/README.md @@ -1,4 +1,17 @@ -# integration_test +# integration_test (deprecated) + +## DEPRECATED + +This package has been moved to the Flutter SDK. Starting with Flutter 2.0, +it should be included as: + +``` +dev_dependencies: + integration_test: + sdk: flutter +``` + +## Old instructions This package enables self-driving testing of Flutter code on devices and emulators. It adapts flutter_test results into a format that is compatible with `flutter drive` diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index 33c174a9724a..daf84d6a5164 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -1,6 +1,6 @@ name: integration_test description: Runs tests that use the flutter_test API as integration tests. -version: 1.0.2+2 +version: 1.0.2+3 homepage: https://github.com/flutter/plugins/tree/master/packages/integration_test environment: diff --git a/packages/local_auth/example/pubspec.yaml b/packages/local_auth/example/pubspec.yaml index d50940f6b63c..aad68c59f930 100644 --- a/packages/local_auth/example/pubspec.yaml +++ b/packages/local_auth/example/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../integration_test + sdk: flutter flutter_driver: sdk: flutter pedantic: ^1.10.0 diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 337006aa196f..a63027728d86 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: dev_dependencies: integration_test: - path: ../integration_test + sdk: flutter flutter_driver: sdk: flutter flutter_test: diff --git a/packages/package_info/example/pubspec.yaml b/packages/package_info/example/pubspec.yaml index a4691fcba518..0e47ad232eaa 100644 --- a/packages/package_info/example/pubspec.yaml +++ b/packages/package_info/example/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: # the parent directory to use the current plugin's version. path: ../ integration_test: - path: ../../integration_test + sdk: flutter dev_dependencies: flutter_driver: diff --git a/packages/package_info/pubspec.yaml b/packages/package_info/pubspec.yaml index 2769af1f83d5..dac73571fd33 100644 --- a/packages/package_info/pubspec.yaml +++ b/packages/package_info/pubspec.yaml @@ -25,7 +25,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../integration_test + sdk: flutter pedantic: ^1.10.0 environment: diff --git a/packages/path_provider/path_provider/example/pubspec.yaml b/packages/path_provider/path_provider/example/pubspec.yaml index 68c751a81843..326c68e0e3e5 100644 --- a/packages/path_provider/path_provider/example/pubspec.yaml +++ b/packages/path_provider/path_provider/example/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../../integration_test + sdk: flutter flutter_driver: sdk: flutter pedantic: ^1.10.0 diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml index 3ee67007f97d..6cb451344a3d 100644 --- a/packages/path_provider/path_provider/pubspec.yaml +++ b/packages/path_provider/path_provider/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../integration_test + sdk: flutter flutter_test: sdk: flutter flutter_driver: diff --git a/packages/path_provider/path_provider_linux/example/pubspec.yaml b/packages/path_provider/path_provider_linux/example/pubspec.yaml index cb778ef6ac57..c9c2f47bf654 100644 --- a/packages/path_provider/path_provider_linux/example/pubspec.yaml +++ b/packages/path_provider/path_provider_linux/example/pubspec.yaml @@ -24,7 +24,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter flutter: uses-material-design: true diff --git a/packages/path_provider/path_provider_macos/example/pubspec.yaml b/packages/path_provider/path_provider_macos/example/pubspec.yaml index db7fd9a0dea6..1451dea36362 100644 --- a/packages/path_provider/path_provider_macos/example/pubspec.yaml +++ b/packages/path_provider/path_provider_macos/example/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../../integration_test + sdk: flutter flutter_driver: sdk: flutter pedantic: ^1.8.0 diff --git a/packages/path_provider/path_provider_windows/example/pubspec.yaml b/packages/path_provider/path_provider_windows/example/pubspec.yaml index 8c1f88b89cb0..29e228d0fd19 100644 --- a/packages/path_provider/path_provider_windows/example/pubspec.yaml +++ b/packages/path_provider/path_provider_windows/example/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../../integration_test + sdk: flutter flutter_driver: sdk: flutter pedantic: ^1.10.0 diff --git a/packages/quick_actions/example/pubspec.yaml b/packages/quick_actions/example/pubspec.yaml index ded88685c41b..b26f8432e9ad 100644 --- a/packages/quick_actions/example/pubspec.yaml +++ b/packages/quick_actions/example/pubspec.yaml @@ -16,7 +16,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/quick_actions/pubspec.yaml b/packages/quick_actions/pubspec.yaml index dc500e2516e1..ed6555833b83 100644 --- a/packages/quick_actions/pubspec.yaml +++ b/packages/quick_actions/pubspec.yaml @@ -23,7 +23,7 @@ dev_dependencies: flutter_test: sdk: flutter integration_test: - path: ../integration_test + sdk: flutter pedantic: ^1.10.0 environment: diff --git a/packages/sensors/example/pubspec.yaml b/packages/sensors/example/pubspec.yaml index 0cd30b12df2b..7d8effbcce87 100644 --- a/packages/sensors/example/pubspec.yaml +++ b/packages/sensors/example/pubspec.yaml @@ -16,7 +16,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/sensors/pubspec.yaml b/packages/sensors/pubspec.yaml index da45c82b7dd7..8056d99d07ed 100644 --- a/packages/sensors/pubspec.yaml +++ b/packages/sensors/pubspec.yaml @@ -22,7 +22,7 @@ dev_dependencies: flutter_test: sdk: flutter integration_test: - path: ../integration_test + sdk: flutter mockito: ^5.0.0-nullsafety.0 pedantic: ^1.10.0 diff --git a/packages/share/example/pubspec.yaml b/packages/share/example/pubspec.yaml index 2df76efb6ca2..378e25bc9c75 100644 --- a/packages/share/example/pubspec.yaml +++ b/packages/share/example/pubspec.yaml @@ -17,7 +17,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/share/pubspec.yaml b/packages/share/pubspec.yaml index dd82fb4926bf..5f2c9f0a400b 100644 --- a/packages/share/pubspec.yaml +++ b/packages/share/pubspec.yaml @@ -23,7 +23,7 @@ dev_dependencies: flutter_test: sdk: flutter integration_test: - path: ../integration_test + sdk: flutter pedantic: ^1.10.0 environment: diff --git a/packages/shared_preferences/shared_preferences/example/pubspec.yaml b/packages/shared_preferences/shared_preferences/example/pubspec.yaml index 84692d76e5a1..7a7b1ac7402f 100644 --- a/packages/shared_preferences/shared_preferences/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/example/pubspec.yaml @@ -16,7 +16,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/shared_preferences/shared_preferences/pubspec.yaml b/packages/shared_preferences/shared_preferences/pubspec.yaml index 3f8391f188d7..ad809b2564bd 100644 --- a/packages/shared_preferences/shared_preferences/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences/pubspec.yaml @@ -42,7 +42,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../integration_test + sdk: flutter pedantic: ^1.10.0 environment: diff --git a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml index dffdbd7526d2..a3a3cbced044 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_linux/example/pubspec.yaml @@ -16,7 +16,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml index 7db361fccfd5..8ad710c6b984 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_macos/example/pubspec.yaml @@ -17,7 +17,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml b/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml index 6725259c4bdc..e83598703a4b 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml +++ b/packages/shared_preferences/shared_preferences_windows/example/pubspec.yaml @@ -23,7 +23,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/url_launcher/url_launcher/example/pubspec.yaml b/packages/url_launcher/url_launcher/example/pubspec.yaml index 0bc027de90a8..4ab235328e46 100644 --- a/packages/url_launcher/url_launcher/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher/example/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../../integration_test + sdk: flutter flutter_driver: sdk: flutter pedantic: ^1.10.0 diff --git a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml index 63c920fba614..e0c59fbbde54 100644 --- a/packages/url_launcher/url_launcher_linux/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_linux/example/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../../integration_test + sdk: flutter flutter_driver: sdk: flutter pedantic: ^1.10.0 diff --git a/packages/url_launcher/url_launcher_macos/example/pubspec.yaml b/packages/url_launcher/url_launcher_macos/example/pubspec.yaml index 40bb4eaba67a..595d1bc30dae 100644 --- a/packages/url_launcher/url_launcher_macos/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_macos/example/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../../integration_test + sdk: flutter flutter_driver: sdk: flutter pedantic: ^1.10.0 diff --git a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml index 8a273ba65020..86ceeecc369f 100644 --- a/packages/url_launcher/url_launcher_windows/example/pubspec.yaml +++ b/packages/url_launcher/url_launcher_windows/example/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../../integration_test + sdk: flutter flutter_driver: sdk: flutter pedantic: ^1.10.0 diff --git a/packages/video_player/video_player/example/pubspec.yaml b/packages/video_player/video_player/example/pubspec.yaml index 4bfb3e5fefad..354f3d18df00 100644 --- a/packages/video_player/video_player/example/pubspec.yaml +++ b/packages/video_player/video_player/example/pubspec.yaml @@ -20,7 +20,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../../integration_test + sdk: flutter test: any pedantic: ^1.10.0 diff --git a/packages/webview_flutter/example/pubspec.yaml b/packages/webview_flutter/example/pubspec.yaml index d7688b720f3f..b70674197901 100644 --- a/packages/webview_flutter/example/pubspec.yaml +++ b/packages/webview_flutter/example/pubspec.yaml @@ -21,7 +21,7 @@ dev_dependencies: flutter_driver: sdk: flutter integration_test: - path: ../../integration_test + sdk: flutter pedantic: ^1.10.0 flutter: diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml index bd424859abf2..57edbe86daea 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../../integration_test + sdk: flutter flutter_test: sdk: flutter diff --git a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml index 7b58d481f6c7..1742f9b86099 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml +++ b/packages/wifi_info_flutter/wifi_info_flutter/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dev_dependencies: integration_test: - path: ../../integration_test + sdk: flutter flutter_test: sdk: flutter From aa8e61503f205a664b54e2cbcd2a62a02ce2010b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Fri, 19 Mar 2021 15:40:06 +0100 Subject: [PATCH 343/924] Moved quickactions to a subfolder (#3734) --- packages/quick_actions/example/android.iml | 12 ------------ .../example/quick_actions_example.iml | 15 --------------- .../example/quick_actions_example_android.iml | 12 ------------ .../{ => quick_actions}/CHANGELOG.md | 0 .../quick_actions/{ => quick_actions}/LICENSE | 0 .../quick_actions/{ => quick_actions}/README.md | 0 .../{ => quick_actions}/android/build.gradle | 0 .../android/gradle.properties | 0 .../{ => quick_actions}/android/settings.gradle | 0 .../android/src/main/AndroidManifest.xml | 0 .../quickactions/MethodCallHandlerImpl.java | 0 .../plugins/quickactions/QuickActionsPlugin.java | 0 .../{ => quick_actions}/example/README.md | 0 .../example/android/app/build.gradle | 0 .../app/gradle/wrapper/gradle-wrapper.properties | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../quickactionsexample/EmbeddingV1Activity.java | 0 .../EmbeddingV1ActivityTest.java | 0 .../quickactionsexample/FlutterActivityTest.java | 0 .../main/res/drawable/ic_launcher_background.xml | 0 .../app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../android/app/src/main/res/values/styles.xml | 0 .../example/android/build.gradle | 0 .../example/android/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../example/android/settings.gradle | 0 .../integration_test/quick_actions_test.dart | 0 .../example/ios/Flutter/AppFrameworkInfo.plist | 0 .../example/ios/Flutter/Debug.xcconfig | 0 .../example/ios/Flutter/Release.xcconfig | 0 .../example/ios/Runner.xcodeproj/project.pbxproj | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../xcschemes/RunnerUITests.xcscheme | 0 .../Runner.xcworkspace/contents.xcworkspacedata | 0 .../example/ios/Runner/AppDelegate.h | 0 .../example/ios/Runner/AppDelegate.m | 0 .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../AppIcon.appiconset/Icon-App-83.5x83.5@2x.png | Bin .../Runner/Base.lproj/LaunchScreen.storyboard | 0 .../ios/Runner/Base.lproj/Main.storyboard | 0 .../example/ios/Runner/Info.plist | 0 .../example/ios/Runner/main.m | 0 .../example/ios/RunnerUITests/Info.plist | 0 .../example/ios/RunnerUITests/RunnerUITests.m | 0 .../{ => quick_actions}/example/lib/main.dart | 0 .../{ => quick_actions}/example/pubspec.yaml | 0 .../example/test_driver/integration_test.dart | 0 .../{ => quick_actions}/ios/Assets/.gitkeep | 0 .../ios/Classes/FLTQuickActionsPlugin.h | 0 .../ios/Classes/FLTQuickActionsPlugin.m | 0 .../ios/quick_actions.podspec | 0 .../{ => quick_actions}/lib/quick_actions.dart | 0 .../{ => quick_actions}/pubspec.yaml | 0 .../test/quick_actions_test.dart | 0 packages/quick_actions/quick_actions_android.iml | 12 ------------ 72 files changed, 51 deletions(-) delete mode 100644 packages/quick_actions/example/android.iml delete mode 100644 packages/quick_actions/example/quick_actions_example.iml delete mode 100644 packages/quick_actions/example/quick_actions_example_android.iml rename packages/quick_actions/{ => quick_actions}/CHANGELOG.md (100%) rename packages/quick_actions/{ => quick_actions}/LICENSE (100%) rename packages/quick_actions/{ => quick_actions}/README.md (100%) rename packages/quick_actions/{ => quick_actions}/android/build.gradle (100%) rename packages/quick_actions/{ => quick_actions}/android/gradle.properties (100%) rename packages/quick_actions/{ => quick_actions}/android/settings.gradle (100%) rename packages/quick_actions/{ => quick_actions}/android/src/main/AndroidManifest.xml (100%) rename packages/quick_actions/{ => quick_actions}/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java (100%) rename packages/quick_actions/{ => quick_actions}/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java (100%) rename packages/quick_actions/{ => quick_actions}/example/README.md (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/build.gradle (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/gradle/wrapper/gradle-wrapper.properties (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/AndroidManifest.xml (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/res/drawable/ic_launcher_background.xml (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename packages/quick_actions/{ => quick_actions}/example/android/app/src/main/res/values/styles.xml (100%) rename packages/quick_actions/{ => quick_actions}/example/android/build.gradle (100%) rename packages/quick_actions/{ => quick_actions}/example/android/gradle.properties (100%) rename packages/quick_actions/{ => quick_actions}/example/android/gradle/wrapper/gradle-wrapper.properties (100%) rename packages/quick_actions/{ => quick_actions}/example/android/settings.gradle (100%) rename packages/quick_actions/{ => quick_actions}/example/integration_test/quick_actions_test.dart (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Flutter/AppFrameworkInfo.plist (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Flutter/Debug.xcconfig (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Flutter/Release.xcconfig (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner.xcodeproj/project.pbxproj (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner.xcworkspace/contents.xcworkspacedata (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/AppDelegate.h (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/AppDelegate.m (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Base.lproj/Main.storyboard (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/Info.plist (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/Runner/main.m (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/RunnerUITests/Info.plist (100%) rename packages/quick_actions/{ => quick_actions}/example/ios/RunnerUITests/RunnerUITests.m (100%) rename packages/quick_actions/{ => quick_actions}/example/lib/main.dart (100%) rename packages/quick_actions/{ => quick_actions}/example/pubspec.yaml (100%) rename packages/quick_actions/{ => quick_actions}/example/test_driver/integration_test.dart (100%) rename packages/quick_actions/{ => quick_actions}/ios/Assets/.gitkeep (100%) rename packages/quick_actions/{ => quick_actions}/ios/Classes/FLTQuickActionsPlugin.h (100%) rename packages/quick_actions/{ => quick_actions}/ios/Classes/FLTQuickActionsPlugin.m (100%) rename packages/quick_actions/{ => quick_actions}/ios/quick_actions.podspec (100%) rename packages/quick_actions/{ => quick_actions}/lib/quick_actions.dart (100%) rename packages/quick_actions/{ => quick_actions}/pubspec.yaml (100%) rename packages/quick_actions/{ => quick_actions}/test/quick_actions_test.dart (100%) delete mode 100644 packages/quick_actions/quick_actions_android.iml diff --git a/packages/quick_actions/example/android.iml b/packages/quick_actions/example/android.iml deleted file mode 100644 index 462b903e05b6..000000000000 --- a/packages/quick_actions/example/android.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/packages/quick_actions/example/quick_actions_example.iml b/packages/quick_actions/example/quick_actions_example.iml deleted file mode 100644 index 9d5dae19540c..000000000000 --- a/packages/quick_actions/example/quick_actions_example.iml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/packages/quick_actions/example/quick_actions_example_android.iml b/packages/quick_actions/example/quick_actions_example_android.iml deleted file mode 100644 index 462b903e05b6..000000000000 --- a/packages/quick_actions/example/quick_actions_example_android.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/packages/quick_actions/CHANGELOG.md b/packages/quick_actions/quick_actions/CHANGELOG.md similarity index 100% rename from packages/quick_actions/CHANGELOG.md rename to packages/quick_actions/quick_actions/CHANGELOG.md diff --git a/packages/quick_actions/LICENSE b/packages/quick_actions/quick_actions/LICENSE similarity index 100% rename from packages/quick_actions/LICENSE rename to packages/quick_actions/quick_actions/LICENSE diff --git a/packages/quick_actions/README.md b/packages/quick_actions/quick_actions/README.md similarity index 100% rename from packages/quick_actions/README.md rename to packages/quick_actions/quick_actions/README.md diff --git a/packages/quick_actions/android/build.gradle b/packages/quick_actions/quick_actions/android/build.gradle similarity index 100% rename from packages/quick_actions/android/build.gradle rename to packages/quick_actions/quick_actions/android/build.gradle diff --git a/packages/quick_actions/android/gradle.properties b/packages/quick_actions/quick_actions/android/gradle.properties similarity index 100% rename from packages/quick_actions/android/gradle.properties rename to packages/quick_actions/quick_actions/android/gradle.properties diff --git a/packages/quick_actions/android/settings.gradle b/packages/quick_actions/quick_actions/android/settings.gradle similarity index 100% rename from packages/quick_actions/android/settings.gradle rename to packages/quick_actions/quick_actions/android/settings.gradle diff --git a/packages/quick_actions/android/src/main/AndroidManifest.xml b/packages/quick_actions/quick_actions/android/src/main/AndroidManifest.xml similarity index 100% rename from packages/quick_actions/android/src/main/AndroidManifest.xml rename to packages/quick_actions/quick_actions/android/src/main/AndroidManifest.xml diff --git a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java b/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java similarity index 100% rename from packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java rename to packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java diff --git a/packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java b/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java similarity index 100% rename from packages/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java rename to packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java diff --git a/packages/quick_actions/example/README.md b/packages/quick_actions/quick_actions/example/README.md similarity index 100% rename from packages/quick_actions/example/README.md rename to packages/quick_actions/quick_actions/example/README.md diff --git a/packages/quick_actions/example/android/app/build.gradle b/packages/quick_actions/quick_actions/example/android/app/build.gradle similarity index 100% rename from packages/quick_actions/example/android/app/build.gradle rename to packages/quick_actions/quick_actions/example/android/app/build.gradle diff --git a/packages/quick_actions/example/android/app/gradle/wrapper/gradle-wrapper.properties b/packages/quick_actions/quick_actions/example/android/app/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/quick_actions/example/android/app/gradle/wrapper/gradle-wrapper.properties rename to packages/quick_actions/quick_actions/example/android/app/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/quick_actions/example/android/app/src/main/AndroidManifest.xml b/packages/quick_actions/quick_actions/example/android/app/src/main/AndroidManifest.xml similarity index 100% rename from packages/quick_actions/example/android/app/src/main/AndroidManifest.xml rename to packages/quick_actions/quick_actions/example/android/app/src/main/AndroidManifest.xml diff --git a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java b/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java similarity index 100% rename from packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java rename to packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java diff --git a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java b/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java similarity index 100% rename from packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java rename to packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java diff --git a/packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java b/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java similarity index 100% rename from packages/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java rename to packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java diff --git a/packages/quick_actions/example/android/app/src/main/res/drawable/ic_launcher_background.xml b/packages/quick_actions/quick_actions/example/android/app/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from packages/quick_actions/example/android/app/src/main/res/drawable/ic_launcher_background.xml rename to packages/quick_actions/quick_actions/example/android/app/src/main/res/drawable/ic_launcher_background.xml diff --git a/packages/quick_actions/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/quick_actions/quick_actions/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from packages/quick_actions/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to packages/quick_actions/quick_actions/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/packages/quick_actions/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/quick_actions/quick_actions/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from packages/quick_actions/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to packages/quick_actions/quick_actions/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/packages/quick_actions/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/quick_actions/quick_actions/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from packages/quick_actions/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to packages/quick_actions/quick_actions/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/packages/quick_actions/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/quick_actions/quick_actions/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from packages/quick_actions/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to packages/quick_actions/quick_actions/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/packages/quick_actions/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/quick_actions/quick_actions/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from packages/quick_actions/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to packages/quick_actions/quick_actions/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/packages/quick_actions/example/android/app/src/main/res/values/styles.xml b/packages/quick_actions/quick_actions/example/android/app/src/main/res/values/styles.xml similarity index 100% rename from packages/quick_actions/example/android/app/src/main/res/values/styles.xml rename to packages/quick_actions/quick_actions/example/android/app/src/main/res/values/styles.xml diff --git a/packages/quick_actions/example/android/build.gradle b/packages/quick_actions/quick_actions/example/android/build.gradle similarity index 100% rename from packages/quick_actions/example/android/build.gradle rename to packages/quick_actions/quick_actions/example/android/build.gradle diff --git a/packages/quick_actions/example/android/gradle.properties b/packages/quick_actions/quick_actions/example/android/gradle.properties similarity index 100% rename from packages/quick_actions/example/android/gradle.properties rename to packages/quick_actions/quick_actions/example/android/gradle.properties diff --git a/packages/quick_actions/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/quick_actions/quick_actions/example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/quick_actions/example/android/gradle/wrapper/gradle-wrapper.properties rename to packages/quick_actions/quick_actions/example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/quick_actions/example/android/settings.gradle b/packages/quick_actions/quick_actions/example/android/settings.gradle similarity index 100% rename from packages/quick_actions/example/android/settings.gradle rename to packages/quick_actions/quick_actions/example/android/settings.gradle diff --git a/packages/quick_actions/example/integration_test/quick_actions_test.dart b/packages/quick_actions/quick_actions/example/integration_test/quick_actions_test.dart similarity index 100% rename from packages/quick_actions/example/integration_test/quick_actions_test.dart rename to packages/quick_actions/quick_actions/example/integration_test/quick_actions_test.dart diff --git a/packages/quick_actions/example/ios/Flutter/AppFrameworkInfo.plist b/packages/quick_actions/quick_actions/example/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from packages/quick_actions/example/ios/Flutter/AppFrameworkInfo.plist rename to packages/quick_actions/quick_actions/example/ios/Flutter/AppFrameworkInfo.plist diff --git a/packages/quick_actions/example/ios/Flutter/Debug.xcconfig b/packages/quick_actions/quick_actions/example/ios/Flutter/Debug.xcconfig similarity index 100% rename from packages/quick_actions/example/ios/Flutter/Debug.xcconfig rename to packages/quick_actions/quick_actions/example/ios/Flutter/Debug.xcconfig diff --git a/packages/quick_actions/example/ios/Flutter/Release.xcconfig b/packages/quick_actions/quick_actions/example/ios/Flutter/Release.xcconfig similarity index 100% rename from packages/quick_actions/example/ios/Flutter/Release.xcconfig rename to packages/quick_actions/quick_actions/example/ios/Flutter/Release.xcconfig diff --git a/packages/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj b/packages/quick_actions/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from packages/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj rename to packages/quick_actions/quick_actions/example/ios/Runner.xcodeproj/project.pbxproj diff --git a/packages/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/quick_actions/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from packages/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/quick_actions/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/packages/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme b/packages/quick_actions/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme similarity index 100% rename from packages/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme rename to packages/quick_actions/quick_actions/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/RunnerUITests.xcscheme diff --git a/packages/quick_actions/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/quick_actions/quick_actions/example/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/quick_actions/example/ios/Runner.xcworkspace/contents.xcworkspacedata rename to packages/quick_actions/quick_actions/example/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/packages/quick_actions/example/ios/Runner/AppDelegate.h b/packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.h similarity index 100% rename from packages/quick_actions/example/ios/Runner/AppDelegate.h rename to packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.h diff --git a/packages/quick_actions/example/ios/Runner/AppDelegate.m b/packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.m similarity index 100% rename from packages/quick_actions/example/ios/Runner/AppDelegate.m rename to packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.m diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from packages/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to packages/quick_actions/quick_actions/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/packages/quick_actions/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/quick_actions/quick_actions/example/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from packages/quick_actions/example/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to packages/quick_actions/quick_actions/example/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/packages/quick_actions/example/ios/Runner/Base.lproj/Main.storyboard b/packages/quick_actions/quick_actions/example/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from packages/quick_actions/example/ios/Runner/Base.lproj/Main.storyboard rename to packages/quick_actions/quick_actions/example/ios/Runner/Base.lproj/Main.storyboard diff --git a/packages/quick_actions/example/ios/Runner/Info.plist b/packages/quick_actions/quick_actions/example/ios/Runner/Info.plist similarity index 100% rename from packages/quick_actions/example/ios/Runner/Info.plist rename to packages/quick_actions/quick_actions/example/ios/Runner/Info.plist diff --git a/packages/quick_actions/example/ios/Runner/main.m b/packages/quick_actions/quick_actions/example/ios/Runner/main.m similarity index 100% rename from packages/quick_actions/example/ios/Runner/main.m rename to packages/quick_actions/quick_actions/example/ios/Runner/main.m diff --git a/packages/quick_actions/example/ios/RunnerUITests/Info.plist b/packages/quick_actions/quick_actions/example/ios/RunnerUITests/Info.plist similarity index 100% rename from packages/quick_actions/example/ios/RunnerUITests/Info.plist rename to packages/quick_actions/quick_actions/example/ios/RunnerUITests/Info.plist diff --git a/packages/quick_actions/example/ios/RunnerUITests/RunnerUITests.m b/packages/quick_actions/quick_actions/example/ios/RunnerUITests/RunnerUITests.m similarity index 100% rename from packages/quick_actions/example/ios/RunnerUITests/RunnerUITests.m rename to packages/quick_actions/quick_actions/example/ios/RunnerUITests/RunnerUITests.m diff --git a/packages/quick_actions/example/lib/main.dart b/packages/quick_actions/quick_actions/example/lib/main.dart similarity index 100% rename from packages/quick_actions/example/lib/main.dart rename to packages/quick_actions/quick_actions/example/lib/main.dart diff --git a/packages/quick_actions/example/pubspec.yaml b/packages/quick_actions/quick_actions/example/pubspec.yaml similarity index 100% rename from packages/quick_actions/example/pubspec.yaml rename to packages/quick_actions/quick_actions/example/pubspec.yaml diff --git a/packages/quick_actions/example/test_driver/integration_test.dart b/packages/quick_actions/quick_actions/example/test_driver/integration_test.dart similarity index 100% rename from packages/quick_actions/example/test_driver/integration_test.dart rename to packages/quick_actions/quick_actions/example/test_driver/integration_test.dart diff --git a/packages/quick_actions/ios/Assets/.gitkeep b/packages/quick_actions/quick_actions/ios/Assets/.gitkeep similarity index 100% rename from packages/quick_actions/ios/Assets/.gitkeep rename to packages/quick_actions/quick_actions/ios/Assets/.gitkeep diff --git a/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.h b/packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.h similarity index 100% rename from packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.h rename to packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.h diff --git a/packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.m b/packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.m similarity index 100% rename from packages/quick_actions/ios/Classes/FLTQuickActionsPlugin.m rename to packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.m diff --git a/packages/quick_actions/ios/quick_actions.podspec b/packages/quick_actions/quick_actions/ios/quick_actions.podspec similarity index 100% rename from packages/quick_actions/ios/quick_actions.podspec rename to packages/quick_actions/quick_actions/ios/quick_actions.podspec diff --git a/packages/quick_actions/lib/quick_actions.dart b/packages/quick_actions/quick_actions/lib/quick_actions.dart similarity index 100% rename from packages/quick_actions/lib/quick_actions.dart rename to packages/quick_actions/quick_actions/lib/quick_actions.dart diff --git a/packages/quick_actions/pubspec.yaml b/packages/quick_actions/quick_actions/pubspec.yaml similarity index 100% rename from packages/quick_actions/pubspec.yaml rename to packages/quick_actions/quick_actions/pubspec.yaml diff --git a/packages/quick_actions/test/quick_actions_test.dart b/packages/quick_actions/quick_actions/test/quick_actions_test.dart similarity index 100% rename from packages/quick_actions/test/quick_actions_test.dart rename to packages/quick_actions/quick_actions/test/quick_actions_test.dart diff --git a/packages/quick_actions/quick_actions_android.iml b/packages/quick_actions/quick_actions_android.iml deleted file mode 100644 index 462b903e05b6..000000000000 --- a/packages/quick_actions/quick_actions_android.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - From 67bdfcb5b6f49286dcc17a58107ddd1ab2b20472 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Mar 2021 13:18:00 -0700 Subject: [PATCH 344/924] Standardize copyright year (#3737) Standardizes all first-party copyrights on a single year, as is done in flutter/flutter and flutter/engine. All code now uses 2013, which is the earliest year that was in any existing copyright notice. The script checks now enforce the exact format of first-party licenses and copyrights. Fixes flutter/flutter#78448 --- LICENSE | 2 +- packages/android_alarm_manager/LICENSE | 2 +- .../AlarmBroadcastReceiver.java | 2 +- .../androidalarmmanager/AlarmService.java | 2 +- .../AndroidAlarmManagerPlugin.java | 2 +- .../FlutterBackgroundExecutor.java | 2 +- .../PluginRegistrantException.java | 2 +- .../RebootBroadcastReceiver.java | 2 +- .../BackgroundExecutionTest.java | 2 +- .../DriverExtensionActivity.java | 2 +- .../androidalarmmanager/MainActivityTest.java | 2 +- .../Application.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../android_alarm_manager_test.dart | 2 +- .../example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../lib/android_alarm_manager.dart | 2 +- .../test/android_alarm_manager_test.dart | 2 +- packages/android_intent/LICENSE | 2 +- .../androidintent/AndroidIntentPlugin.java | 2 +- .../plugins/androidintent/IntentSender.java | 2 +- .../androidintent/MethodCallHandlerImpl.java | 2 +- .../MethodCallHandlerImplTest.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../MainActivityTest.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../integration_test/android_intent_test.dart | 2 +- packages/android_intent/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../android_intent/lib/android_intent.dart | 2 +- packages/android_intent/lib/flag.dart | 2 +- .../test/android_intent_test.dart | 2 +- packages/battery/battery/LICENSE | 2 +- .../plugins/battery/BatteryPlugin.java | 2 +- .../battery/EmbedderV1ActivityTest.java | 2 +- .../plugins/battery/FlutterActivityTest.java | 2 +- .../batteryexample/EmbedderV1Activity.java | 2 +- .../battery/example/ios/Runner/AppDelegate.h | 2 +- .../battery/example/ios/Runner/AppDelegate.m | 2 +- .../battery/battery/example/ios/Runner/main.m | 2 +- .../battery/battery/example/lib/main.dart | 2 +- .../integration_test/battery_test.dart | 2 +- .../battery/ios/Classes/FLTBatteryPlugin.h | 2 +- .../battery/ios/Classes/FLTBatteryPlugin.m | 2 +- packages/battery/battery/lib/battery.dart | 2 +- .../battery/battery/test/battery_test.dart | 2 +- .../battery_platform_interface/LICENSE | 2 +- .../lib/battery_platform_interface.dart | 2 +- .../lib/enums/battery_state.dart | 2 +- .../method_channel_battery.dart | 2 +- .../test/method_channel_battery_test.dart | 2 +- packages/camera/camera/LICENSE | 2 +- .../io/flutter/plugins/camera/Camera.java | 2 +- .../plugins/camera/CameraPermissions.java | 2 +- .../flutter/plugins/camera/CameraPlugin.java | 2 +- .../flutter/plugins/camera/CameraRegions.java | 2 +- .../flutter/plugins/camera/CameraUtils.java | 2 +- .../io/flutter/plugins/camera/CameraZoom.java | 2 +- .../flutter/plugins/camera/DartMessenger.java | 2 +- .../camera/DeviceOrientationManager.java | 2 +- .../plugins/camera/MethodCallHandlerImpl.java | 2 +- .../plugins/camera/PictureCaptureRequest.java | 2 +- .../camera/media/MediaRecorderBuilder.java | 2 +- .../plugins/camera/types/ExposureMode.java | 2 +- .../plugins/camera/types/FlashMode.java | 2 +- .../plugins/camera/types/FocusMode.java | 2 +- .../camera/types/ResolutionPreset.java | 2 +- .../plugins/camera/CameraPermissionsTest.java | 2 +- .../plugins/camera/CameraRegionsTest.java | 2 +- .../plugins/camera/CameraUtilsTest.java | 2 +- .../plugins/camera/CameraZoomTest.java | 2 +- .../plugins/camera/DartMessengerTest.java | 2 +- .../camera/PictureCaptureRequestTest.java | 2 +- .../media/MediaRecorderBuilderTest.java | 2 +- .../camera/types/ExposureModeTest.java | 2 +- .../plugins/camera/types/FlashModeTest.java | 2 +- .../plugins/camera/types/FocusModeTest.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../cameraexample/FlutterActivityTest.java | 2 +- .../cameraexample/EmbeddingV1Activity.java | 2 +- .../example/integration_test/camera_test.dart | 2 +- .../camera/example/ios/Runner/AppDelegate.h | 2 +- .../camera/example/ios/Runner/AppDelegate.m | 2 +- .../camera/camera/example/ios/Runner/main.m | 2 +- packages/camera/camera/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../camera/camera/ios/Classes/CameraPlugin.h | 2 +- .../camera/camera/ios/Classes/CameraPlugin.m | 2 +- .../camera/ios/Tests/CameraPluginTests.m | 2 +- packages/camera/camera/lib/camera.dart | 2 +- .../camera/lib/src/camera_controller.dart | 2 +- .../camera/camera/lib/src/camera_image.dart | 2 +- .../camera/camera/lib/src/camera_preview.dart | 2 +- .../camera/test/camera_image_stream_test.dart | 2 +- .../camera/camera/test/camera_image_test.dart | 2 +- packages/camera/camera/test/camera_test.dart | 2 +- .../camera/camera/test/camera_value_test.dart | 2 +- .../test/utils/method_channel_mock.dart | 2 +- .../camera/camera_platform_interface/LICENSE | 2 +- .../lib/camera_platform_interface.dart | 2 +- .../lib/src/events/camera_event.dart | 2 +- .../lib/src/events/device_event.dart | 2 +- .../method_channel/method_channel_camera.dart | 2 +- .../platform_interface/camera_platform.dart | 2 +- .../lib/src/types/camera_description.dart | 2 +- .../lib/src/types/camera_exception.dart | 2 +- .../lib/src/types/exposure_mode.dart | 2 +- .../lib/src/types/flash_mode.dart | 2 +- .../lib/src/types/focus_mode.dart | 2 +- .../lib/src/types/image_format_group.dart | 2 +- .../lib/src/types/resolution_preset.dart | 2 +- .../lib/src/types/types.dart | 2 +- .../lib/src/utils/utils.dart | 2 +- .../test/camera_platform_interface_test.dart | 2 +- .../test/events/camera_event_test.dart | 2 +- .../test/events/device_event_test.dart | 2 +- .../method_channel_camera_test.dart | 2 +- .../test/types/camera_description_test.dart | 2 +- .../test/types/camera_exception_test.dart | 2 +- .../test/types/exposure_mode_test.dart | 2 +- .../test/types/flash_mode_test.dart | 2 +- .../test/types/focus_mode_test.dart | 2 +- .../test/types/image_group_test.dart | 2 +- .../test/types/resolution_preset_test.dart | 2 +- .../test/utils/method_channel_mock.dart | 2 +- .../test/utils/utils_test.dart | 2 +- packages/connectivity/connectivity/LICENSE | 2 +- .../plugins/connectivity/Connectivity.java | 2 +- .../ConnectivityBroadcastReceiver.java | 2 +- .../ConnectivityMethodChannelHandler.java | 2 +- .../connectivity/ConnectivityPlugin.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../FlutterActivityTest.java | 2 +- .../connectivityexample/ActivityTest.java | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../connectivity/example/ios/Runner/main.m | 2 +- .../connectivity/example/lib/main.dart | 2 +- .../example/macos/Runner/AppDelegate.swift | 2 +- .../macos/Runner/MainFlutterWindow.swift | 2 +- .../integration_test/connectivity_test.dart | 2 +- .../test_driver/test/integration_test.dart | 2 +- .../connectivity/example/web/index.html | 2 +- .../integration_test/connectivity_test.dart | 2 +- .../ios/Classes/FLTConnectivityPlugin.h | 2 +- .../ios/Classes/FLTConnectivityPlugin.m | 2 +- .../connectivity/lib/connectivity.dart | 2 +- .../connectivity/test/connectivity_test.dart | 2 +- .../connectivity/connectivity_for_web/LICENSE | 2 +- .../network_information_test.dart | 2 +- .../src/connectivity_mocks.dart | 2 +- .../connectivity_for_web/example/run_test.sh | 2 +- .../test_driver/integration_driver.dart | 2 +- .../example/web/index.html | 2 +- .../lib/connectivity_for_web.dart | 2 +- .../src/dart_html_connectivity_plugin.dart | 2 +- ...k_information_api_connectivity_plugin.dart | 2 +- .../lib/src/utils/connectivity_result.dart | 2 +- .../test/tests_exist_elsewhere_test.dart | 2 +- .../connectivity/connectivity_macos/LICENSE | 2 +- .../connectivity_macos/example/lib/main.dart | 2 +- .../example/macos/Runner/AppDelegate.swift | 2 +- .../macos/Runner/MainFlutterWindow.swift | 2 +- .../integration_test/connectivity_test.dart | 2 +- .../test_driver/test/integration_test.dart | 2 +- .../macos/Classes/ConnectivityPlugin.swift | 2 +- .../macos/Classes/IPHelper.h | 2 +- .../connectivity_platform_interface/LICENSE | 2 +- .../lib/connectivity_platform_interface.dart | 2 +- .../lib/src/enums.dart | 2 +- .../lib/src/method_channel_connectivity.dart | 2 +- .../lib/src/utils.dart | 2 +- .../method_channel_connectivity_test.dart | 2 +- packages/device_info/device_info/LICENSE | 2 +- .../plugins/deviceinfo/DeviceInfoPlugin.java | 2 +- .../deviceinfo/MethodCallHandlerImpl.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../integration_test/device_info_test.dart | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../device_info/example/ios/Runner/main.m | 2 +- .../device_info/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../ios/Classes/FLTDeviceInfoPlugin.h | 2 +- .../ios/Classes/FLTDeviceInfoPlugin.m | 2 +- .../device_info/lib/device_info.dart | 2 +- .../device_info_platform_interface/LICENSE | 2 +- .../lib/device_info_platform_interface.dart | 2 +- .../method_channel_device_info.dart | 2 +- .../lib/model/android_device_info.dart | 2 +- .../lib/model/ios_device_info.dart | 2 +- .../test/method_channel_device_info_test.dart | 2 +- packages/espresso/LICENSE | 2 +- .../espresso/flutter/EspressoFlutter.java | 2 +- .../espresso/flutter/action/ActionUtil.java | 2 +- .../espresso/flutter/action/ClickAction.java | 2 +- .../flutter/action/FlutterActions.java | 2 +- .../flutter/action/FlutterScrollToAction.java | 2 +- .../flutter/action/FlutterTypeTextAction.java | 2 +- .../flutter/action/FlutterViewAction.java | 2 +- .../flutter/action/SyntheticClickAction.java | 2 +- .../flutter/action/WaitUntilIdleAction.java | 2 +- .../action/WidgetCoordinatesCalculator.java | 2 +- .../flutter/action/WidgetInfoFetcher.java | 2 +- .../espresso/flutter/api/FlutterAction.java | 2 +- .../flutter/api/FlutterTestingProtocol.java | 2 +- .../espresso/flutter/api/SyntheticAction.java | 2 +- .../espresso/flutter/api/WidgetAction.java | 2 +- .../espresso/flutter/api/WidgetAssertion.java | 2 +- .../espresso/flutter/api/WidgetMatcher.java | 2 +- .../flutter/assertion/FlutterAssertions.java | 2 +- .../assertion/FlutterViewAssertion.java | 2 +- .../espresso/flutter/common/Constants.java | 2 +- .../espresso/flutter/common/Duration.java | 2 +- .../AmbiguousWidgetMatcherException.java | 2 +- .../InvalidFlutterViewException.java | 2 +- .../exception/NoMatchingWidgetException.java | 2 +- .../internal/idgenerator/IdException.java | 2 +- .../internal/idgenerator/IdGenerator.java | 2 +- .../internal/idgenerator/IdGenerators.java | 2 +- .../internal/jsonrpc/JsonRpcClient.java | 2 +- .../internal/jsonrpc/message/ErrorObject.java | 2 +- .../jsonrpc/message/JsonRpcRequest.java | 2 +- .../jsonrpc/message/JsonRpcResponse.java | 2 +- .../internal/protocol/impl/DartVmService.java | 2 +- .../protocol/impl/DartVmServiceUtil.java | 2 +- .../impl/FlutterProtocolException.java | 2 +- .../protocol/impl/GetOffsetAction.java | 2 +- .../protocol/impl/GetOffsetResponse.java | 2 +- .../internal/protocol/impl/GetVmResponse.java | 2 +- .../impl/GetWidgetDiagnosticsAction.java | 2 +- .../impl/GetWidgetDiagnosticsResponse.java | 2 +- .../impl/NoPendingFrameCondition.java | 2 +- .../NoPendingPlatformMessagesCondition.java | 2 +- .../impl/NoTransientCallbacksCondition.java | 2 +- .../internal/protocol/impl/WaitCondition.java | 2 +- .../protocol/impl/WaitForConditionAction.java | 2 +- .../protocol/impl/WidgetInfoFactory.java | 2 +- .../flutter/matcher/FlutterMatchers.java | 2 +- .../matcher/IsDescendantOfMatcher.java | 2 +- .../flutter/matcher/IsExistingMatcher.java | 2 +- .../flutter/matcher/WithTextMatcher.java | 2 +- .../flutter/matcher/WithTooltipMatcher.java | 2 +- .../flutter/matcher/WithTypeMatcher.java | 2 +- .../flutter/matcher/WithValueKeyMatcher.java | 2 +- .../espresso/flutter/model/WidgetInfo.java | 2 +- .../flutter/model/WidgetInfoBuilder.java | 2 +- .../com/example/espresso/EspressoPlugin.java | 2 +- .../java/com/example/MainActivityTest.java | 2 +- .../espresso_example/MainActivity.java | 2 +- packages/espresso/example/lib/main.dart | 2 +- .../espresso/example/test_driver/example.dart | 2 +- packages/file_selector/file_selector/LICENSE | 2 +- .../example/lib/get_directory_page.dart | 2 +- .../file_selector/example/lib/home_page.dart | 2 +- .../file_selector/example/lib/main.dart | 2 +- .../example/lib/open_image_page.dart | 2 +- .../lib/open_multiple_images_page.dart | 2 +- .../example/lib/open_text_page.dart | 2 +- .../example/lib/save_text_page.dart | 2 +- .../file_selector/example/web/index.html | 2 +- .../file_selector/lib/file_selector.dart | 2 +- .../test/file_selector_test.dart | 2 +- .../file_selector_platform_interface/LICENSE | 2 +- .../lib/file_selector_platform_interface.dart | 2 +- .../method_channel_file_selector.dart | 2 +- .../file_selector_interface.dart | 2 +- .../lib/src/types/types.dart | 2 +- .../src/types/x_type_group/x_type_group.dart | 2 +- .../lib/src/web_helpers/web_helpers.dart | 2 +- ...file_selector_platform_interface_test.dart | 2 +- .../method_channel_file_selector_test.dart | 2 +- .../test/x_type_group_test.dart | 2 +- .../file_selector/file_selector_web/LICENSE | 2 +- .../integration_test/dom_helper_test.dart | 2 +- .../file_selector_web_test.dart | 2 +- .../file_selector_web/example/run_test.sh | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../file_selector_web/example/web/index.html | 2 +- .../lib/file_selector_web.dart | 2 +- .../file_selector_web/lib/src/dom_helper.dart | 2 +- .../file_selector_web/lib/src/utils.dart | 2 +- .../test/more_tests_exist_elsewhere_test.dart | 2 +- .../file_selector_web/test/utils_test.dart | 2 +- .../flutter_plugin_android_lifecycle/LICENSE | 2 +- .../lifecycle/FlutterLifecycleAdapter.java | 2 +- .../FlutterAndroidLifecyclePlugin.java | 2 +- .../FlutterLifecycleAdapterTest.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../MainActivityTest.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../MainActivity.java | 2 +- ...flutter_plugin_android_lifecycle_test.dart | 2 +- .../example/lib/main.dart | 2 +- .../lib/flutter_plugin_android_lifecycle.dart | 2 +- .../google_maps_flutter/LICENSE | 2 +- .../plugins/googlemaps/CircleBuilder.java | 2 +- .../plugins/googlemaps/CircleController.java | 2 +- .../plugins/googlemaps/CircleOptionsSink.java | 2 +- .../plugins/googlemaps/CirclesController.java | 2 +- .../flutter/plugins/googlemaps/Convert.java | 2 +- .../plugins/googlemaps/GoogleMapBuilder.java | 2 +- .../googlemaps/GoogleMapController.java | 2 +- .../plugins/googlemaps/GoogleMapFactory.java | 2 +- .../plugins/googlemaps/GoogleMapListener.java | 2 +- .../googlemaps/GoogleMapOptionsSink.java | 2 +- .../plugins/googlemaps/GoogleMapsPlugin.java | 2 +- .../plugins/googlemaps/LifecycleProvider.java | 2 +- .../plugins/googlemaps/MarkerBuilder.java | 2 +- .../plugins/googlemaps/MarkerController.java | 2 +- .../plugins/googlemaps/MarkerOptionsSink.java | 2 +- .../plugins/googlemaps/MarkersController.java | 2 +- .../plugins/googlemaps/PolygonBuilder.java | 2 +- .../plugins/googlemaps/PolygonController.java | 2 +- .../googlemaps/PolygonOptionsSink.java | 2 +- .../googlemaps/PolygonsController.java | 2 +- .../plugins/googlemaps/PolylineBuilder.java | 2 +- .../googlemaps/PolylineController.java | 2 +- .../googlemaps/PolylineOptionsSink.java | 2 +- .../googlemaps/PolylinesController.java | 2 +- .../googlemaps/TileOverlayBuilder.java | 2 +- .../googlemaps/TileOverlayController.java | 2 +- .../plugins/googlemaps/TileOverlaySink.java | 2 +- .../googlemaps/TileOverlaysController.java | 2 +- .../googlemaps/TileProviderController.java | 2 +- .../plugins/googlemaps/CircleBuilderTest.java | 2 +- .../googlemaps/CircleControllerTest.java | 2 +- .../googlemaps/PolygonBuilderTest.java | 2 +- .../googlemaps/PolygonControllerTest.java | 2 +- .../googlemaps/PolylineBuilderTest.java | 2 +- .../googlemaps/PolylineControllerTest.java | 2 +- .../googlemaps/EmbeddingV1ActivityTest.java | 2 +- .../plugins/googlemaps/MainActivityTest.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../googlemaps/GoogleMapControllerTest.java | 2 +- .../google_map_inspector.dart | 2 +- .../integration_test/google_maps_test.dart | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../example/ios/Runner/main.m | 2 +- .../example/lib/animate_camera.dart | 2 +- .../example/lib/lite_mode.dart | 2 +- .../google_maps_flutter/example/lib/main.dart | 2 +- .../example/lib/map_click.dart | 2 +- .../example/lib/map_coordinates.dart | 2 +- .../example/lib/map_ui.dart | 2 +- .../example/lib/marker_icons.dart | 2 +- .../example/lib/move_camera.dart | 2 +- .../example/lib/padding.dart | 2 +- .../google_maps_flutter/example/lib/page.dart | 2 +- .../example/lib/place_circle.dart | 2 +- .../example/lib/place_marker.dart | 2 +- .../example/lib/place_polygon.dart | 2 +- .../example/lib/place_polyline.dart | 2 +- .../example/lib/scrolling_map.dart | 2 +- .../example/lib/snapshot.dart | 2 +- .../example/lib/tile_overlay.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../FLTGoogleMapTileOverlayController.h | 2 +- .../FLTGoogleMapTileOverlayController.m | 2 +- .../ios/Classes/FLTGoogleMapsPlugin.h | 2 +- .../ios/Classes/FLTGoogleMapsPlugin.m | 2 +- .../ios/Classes/GoogleMapCircleController.h | 2 +- .../ios/Classes/GoogleMapCircleController.m | 2 +- .../ios/Classes/GoogleMapController.h | 2 +- .../ios/Classes/GoogleMapController.m | 2 +- .../ios/Classes/GoogleMapMarkerController.h | 2 +- .../ios/Classes/GoogleMapMarkerController.m | 2 +- .../ios/Classes/GoogleMapPolygonController.h | 2 +- .../ios/Classes/GoogleMapPolygonController.m | 2 +- .../ios/Classes/GoogleMapPolylineController.h | 2 +- .../ios/Classes/GoogleMapPolylineController.m | 2 +- .../ios/Classes/JsonConversions.h | 2 +- .../ios/Classes/JsonConversions.m | 2 +- .../lib/google_maps_flutter.dart | 2 +- .../lib/src/controller.dart | 2 +- .../lib/src/google_map.dart | 2 +- .../test/android_google_map_test.dart | 2 +- .../test/circle_updates_test.dart | 2 +- .../test/fake_maps_controllers.dart | 2 +- .../test/google_map_test.dart | 2 +- .../test/map_creation_test.dart | 2 +- .../test/marker_updates_test.dart | 2 +- .../test/polygon_updates_test.dart | 2 +- .../test/polyline_updates_test.dart | 2 +- .../test/tile_overlay_updates_test.dart | 2 +- .../LICENSE | 2 +- ...oogle_maps_flutter_platform_interface.dart | 2 +- .../lib/src/events/map_event.dart | 2 +- .../method_channel_google_maps_flutter.dart | 2 +- .../google_maps_flutter_platform.dart | 2 +- .../lib/src/types/bitmap.dart | 2 +- .../lib/src/types/callbacks.dart | 2 +- .../lib/src/types/camera.dart | 2 +- .../lib/src/types/cap.dart | 2 +- .../lib/src/types/circle.dart | 2 +- .../lib/src/types/circle_updates.dart | 2 +- .../lib/src/types/joint_type.dart | 2 +- .../lib/src/types/location.dart | 2 +- .../lib/src/types/maps_object.dart | 2 +- .../lib/src/types/maps_object_updates.dart | 2 +- .../lib/src/types/marker.dart | 2 +- .../lib/src/types/marker_updates.dart | 2 +- .../lib/src/types/pattern_item.dart | 2 +- .../lib/src/types/polygon.dart | 2 +- .../lib/src/types/polygon_updates.dart | 2 +- .../lib/src/types/polyline.dart | 2 +- .../lib/src/types/polyline_updates.dart | 2 +- .../lib/src/types/screen_coordinate.dart | 2 +- .../lib/src/types/tile.dart | 2 +- .../lib/src/types/tile_overlay.dart | 2 +- .../lib/src/types/tile_overlay_updates.dart | 2 +- .../lib/src/types/tile_provider.dart | 2 +- .../lib/src/types/types.dart | 2 +- .../lib/src/types/ui.dart | 2 +- .../lib/src/types/utils/circle.dart | 2 +- .../lib/src/types/utils/maps_object.dart | 2 +- .../lib/src/types/utils/marker.dart | 2 +- .../lib/src/types/utils/polygon.dart | 2 +- .../lib/src/types/utils/polyline.dart | 2 +- .../lib/src/types/utils/tile_overlay.dart | 2 +- .../google_maps_flutter_platform_test.dart | 2 +- .../test/types/bitmap_test.dart | 2 +- .../test/types/camera_test.dart | 2 +- .../test/types/maps_object_test.dart | 2 +- .../test/types/maps_object_updates_test.dart | 2 +- .../test/types/test_maps_object.dart | 2 +- .../test/types/tile_overlay_test.dart | 2 +- .../test/types/tile_overlay_updates_test.dart | 2 +- .../test/types/tile_test.dart | 2 +- .../google_maps_flutter_web/LICENSE | 2 +- .../google_maps_controller_test.dart | 2 +- .../google_maps_plugin_test.dart | 2 +- .../example/integration_test/marker_test.dart | 2 +- .../integration_test/markers_test.dart | 2 +- .../resources/icon_image_base64.dart | 2 +- .../example/integration_test/shape_test.dart | 2 +- .../example/integration_test/shapes_test.dart | 2 +- .../example/run_test.sh | 2 +- .../test_driver/integration_driver.dart | 2 +- .../example/web/index.html | 2 +- .../lib/google_maps_flutter_web.dart | 2 +- .../lib/src/circle.dart | 2 +- .../lib/src/circles.dart | 2 +- .../lib/src/convert.dart | 2 +- .../lib/src/google_maps_controller.dart | 2 +- .../lib/src/google_maps_flutter_web.dart | 2 +- .../lib/src/marker.dart | 2 +- .../lib/src/markers.dart | 2 +- .../lib/src/polygon.dart | 2 +- .../lib/src/polygons.dart | 2 +- .../lib/src/polyline.dart | 2 +- .../lib/src/polylines.dart | 2 +- .../lib/src/shims/dart_ui.dart | 2 +- .../lib/src/shims/dart_ui_fake.dart | 2 +- .../lib/src/shims/dart_ui_real.dart | 2 +- .../lib/src/types.dart | 2 +- .../test/tests_exist_elsewhere_test.dart | 2 +- .../google_sign_in/google_sign_in/LICENSE | 2 +- .../googlesignin/BackgroundTaskRunner.java | 2 +- .../plugins/googlesignin/Executors.java | 2 +- .../googlesignin/GoogleSignInPlugin.java | 2 +- .../googlesignin/GoogleSignInWrapper.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../FlutterActivityTest.java | 2 +- .../googlesignin/GoogleSignInPluginTests.java | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../google_sign_in/example/ios/Runner/main.m | 2 +- .../google_sign_in/example/lib/main.dart | 2 +- .../google_sign_in/example/web/index.html | 2 +- .../integration_test/google_sign_in_test.dart | 2 +- .../ios/Classes/FLTGoogleSignInPlugin.h | 2 +- .../ios/Classes/FLTGoogleSignInPlugin.m | 2 +- .../ios/Tests/GoogleSignInPluginTest.m | 2 +- .../google_sign_in/lib/google_sign_in.dart | 2 +- .../google_sign_in/lib/src/common.dart | 2 +- .../google_sign_in/lib/src/fife.dart | 2 +- .../google_sign_in/lib/testing.dart | 2 +- .../google_sign_in/lib/widgets.dart | 2 +- .../google_sign_in/test/fife_test.dart | 2 +- .../test/google_sign_in_test.dart | 2 +- .../test_driver/integration_test.dart | 2 +- .../google_sign_in_platform_interface/LICENSE | 2 +- .../google_sign_in_platform_interface.dart | 2 +- .../src/method_channel_google_sign_in.dart | 2 +- .../lib/src/types.dart | 2 +- .../lib/src/utils.dart | 2 +- ...oogle_sign_in_platform_interface_test.dart | 2 +- .../method_channel_google_sign_in_test.dart | 2 +- .../google_sign_in/google_sign_in_web/LICENSE | 2 +- .../example/integration_test/auth2_test.dart | 2 +- .../integration_test/gapi_load_test.dart | 2 +- .../gapi_mocks/gapi_mocks.dart | 2 +- .../gapi_mocks/src/auth2_init.dart | 2 +- .../integration_test/gapi_mocks/src/gapi.dart | 2 +- .../gapi_mocks/src/google_user.dart | 2 +- .../gapi_mocks/src/test_iife.dart | 2 +- .../integration_test/gapi_utils_test.dart | 2 +- .../integration_test/src/test_utils.dart | 2 +- .../google_sign_in_web/example/run_test.sh | 2 +- .../test_driver/integration_driver.dart | 2 +- .../google_sign_in_web/example/web/index.html | 2 +- .../lib/google_sign_in_web.dart | 2 +- .../lib/src/generated/gapi.dart | 2 +- .../lib/src/generated/gapiauth2.dart | 2 +- .../google_sign_in_web/lib/src/load_gapi.dart | 2 +- .../google_sign_in_web/lib/src/utils.dart | 2 +- .../test/tests_exist_elsewhere_test.dart | 2 +- packages/image_picker/image_picker/LICENSE | 2 +- .../plugins/imagepicker/ExifDataCopier.java | 2 +- .../plugins/imagepicker/FileUtils.java | 2 +- .../plugins/imagepicker/ImagePickerCache.java | 2 +- .../imagepicker/ImagePickerDelegate.java | 2 +- .../imagepicker/ImagePickerFileProvider.java | 2 +- .../imagepicker/ImagePickerPlugin.java | 2 +- .../plugins/imagepicker/ImagePickerUtils.java | 2 +- .../plugins/imagepicker/ImageResizer.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../FlutterActivityTest.java | 2 +- .../plugins/imagepicker/FileUtilTest.java | 2 +- .../imagepicker/ImagePickerCacheTest.java | 2 +- .../imagepicker/ImagePickerDelegateTest.java | 2 +- .../imagepicker/ImagePickerPluginTest.java | 2 +- .../plugins/imagepicker/ImageResizerTest.java | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../image_picker/example/ios/Runner/main.m | 2 +- .../ImagePickerFromGalleryUITests.m | 2 +- .../image_picker/example/lib/main.dart | 2 +- .../test_driver/test/integration_test.dart | 2 +- .../image_picker/example/web/index.html | 2 +- .../old_image_picker_test.dart | 2 +- .../ios/Classes/FLTImagePickerImageUtil.h | 2 +- .../ios/Classes/FLTImagePickerImageUtil.m | 2 +- .../ios/Classes/FLTImagePickerMetaDataUtil.h | 2 +- .../ios/Classes/FLTImagePickerMetaDataUtil.m | 2 +- .../Classes/FLTImagePickerPhotoAssetUtil.h | 2 +- .../Classes/FLTImagePickerPhotoAssetUtil.m | 2 +- .../ios/Classes/FLTImagePickerPlugin.h | 2 +- .../ios/Classes/FLTImagePickerPlugin.m | 2 +- .../ios/Tests/ImagePickerPluginTests.m | 2 +- .../ios/Tests/ImagePickerTestImages.h | 2 +- .../ios/Tests/ImagePickerTestImages.m | 2 +- .../image_picker/ios/Tests/ImageUtilTests.m | 2 +- .../ios/Tests/MetaDataUtilTests.m | 2 +- .../ios/Tests/PhotoAssetUtilTests.m | 2 +- .../image_picker/lib/image_picker.dart | 2 +- .../image_picker/test/image_picker_test.dart | 2 +- .../image_picker/image_picker_for_web/LICENSE | 2 +- .../lib/image_picker_for_web.dart | 2 +- .../test/image_picker_for_web_test.dart | 2 +- .../image_picker_platform_interface/LICENSE | 2 +- .../lib/image_picker_platform_interface.dart | 2 +- .../method_channel_image_picker.dart | 2 +- .../image_picker_platform.dart | 2 +- .../lib/src/types/camera_device.dart | 2 +- .../lib/src/types/image_source.dart | 2 +- .../lib/src/types/picked_file/base.dart | 2 +- .../lib/src/types/picked_file/html.dart | 2 +- .../lib/src/types/picked_file/io.dart | 2 +- .../lib/src/types/picked_file/lost_data.dart | 2 +- .../src/types/picked_file/picked_file.dart | 2 +- .../src/types/picked_file/unsupported.dart | 2 +- .../lib/src/types/retrieve_type.dart | 2 +- .../lib/src/types/types.dart | 2 +- .../new_method_channel_image_picker_test.dart | 2 +- .../test/picked_file_html_test.dart | 2 +- .../test/picked_file_io_test.dart | 2 +- packages/in_app_purchase/LICENSE | 2 +- .../inapppurchase/BillingClientFactory.java | 2 +- .../BillingClientFactoryImpl.java | 2 +- .../inapppurchase/InAppPurchasePlugin.java | 2 +- .../inapppurchase/MethodCallHandlerImpl.java | 2 +- .../inapppurchase/PluginPurchaseListener.java | 2 +- .../plugins/inapppurchase/Translator.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../FlutterActivityTest.java | 2 +- .../InAppPurchasePluginTest.java | 2 +- .../inapppurchase/MethodCallHandlerTest.java | 2 +- .../plugins/inapppurchase/TranslatorTest.java | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../in_app_purchase/example/ios/Runner/main.m | 2 +- .../example/lib/consumable_store.dart | 2 +- .../in_app_purchase/example/lib/main.dart | 2 +- .../test_driver/test/integration_test.dart | 2 +- .../in_app_purchase_test.dart | 2 +- .../ios/Classes/FIAObjectTranslator.h | 2 +- .../ios/Classes/FIAObjectTranslator.m | 2 +- .../ios/Classes/FIAPReceiptManager.h | 2 +- .../ios/Classes/FIAPReceiptManager.m | 2 +- .../ios/Classes/FIAPRequestHandler.h | 2 +- .../ios/Classes/FIAPRequestHandler.m | 2 +- .../ios/Classes/FIAPaymentQueueHandler.h | 2 +- .../ios/Classes/FIAPaymentQueueHandler.m | 2 +- .../ios/Classes/InAppPurchasePlugin.h | 2 +- .../ios/Classes/InAppPurchasePlugin.m | 2 +- .../ios/Tests/InAppPurchasePluginTest.m | 2 +- .../ios/Tests/PaymentQueueTest.m | 2 +- .../ios/Tests/ProductRequestHandlerTest.m | 2 +- packages/in_app_purchase/ios/Tests/Stubs.h | 2 +- packages/in_app_purchase/ios/Tests/Stubs.m | 2 +- .../ios/Tests/TranslatorTest.m | 2 +- .../lib/billing_client_wrappers.dart | 2 +- .../in_app_purchase/lib/in_app_purchase.dart | 2 +- .../billing_client_wrapper.dart | 2 +- .../enum_converters.dart | 2 +- .../purchase_wrapper.dart | 2 +- .../sku_details_wrapper.dart | 2 +- packages/in_app_purchase/lib/src/channel.dart | 2 +- .../in_app_purchase/app_store_connection.dart | 2 +- .../google_play_connection.dart | 2 +- .../in_app_purchase_connection.dart | 2 +- .../src/in_app_purchase/product_details.dart | 2 +- .../src/in_app_purchase/purchase_details.dart | 2 +- .../store_kit_wrappers/enum_converters.dart | 2 +- .../sk_payment_queue_wrapper.dart | 2 +- .../sk_payment_transaction_wrappers.dart | 2 +- .../sk_product_wrapper.dart | 2 +- .../sk_receipt_manager.dart | 2 +- .../store_kit_wrappers/sk_request_maker.dart | 2 +- .../lib/store_kit_wrappers.dart | 2 +- .../billing_client_wrapper_test.dart | 2 +- .../purchase_wrapper_test.dart | 2 +- .../sku_details_wrapper_test.dart | 2 +- .../app_store_connection_test.dart | 2 +- .../google_play_connection_test.dart | 2 +- .../sk_methodchannel_apis_test.dart | 2 +- .../store_kit_wrappers/sk_product_test.dart | 2 +- .../sk_test_stub_objects.dart | 2 +- .../test/stub_in_app_purchase_platform.dart | 2 +- packages/integration_test/LICENSE | 2 +- .../integration_test/FlutterTestRunner.java | 2 +- .../IntegrationTestPlugin.java | 2 +- .../e2e_example/EmbedderV1ActivityTest.java | 2 +- .../e2e_example/FlutterActivityTest.java | 2 +- .../FlutterActivityWithPermissionTest.java | 2 +- .../e2e_example/EmbedderV1Activity.java | 2 +- .../integration_test/_example_test_io.dart | 2 +- .../integration_test/_example_test_web.dart | 2 +- .../integration_test/_extended_test_io.dart | 2 +- .../integration_test/_extended_test_web.dart | 2 +- .../integration_test/example_test.dart | 2 +- .../integration_test/extended_test.dart | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../example/ios/Runner/main.m | 2 +- .../example/ios/RunnerTests/RunnerTests.m | 2 +- .../integration_test/example/lib/main.dart | 2 +- .../integration_test/example/lib/my_app.dart | 2 +- .../example/lib/my_web_app.dart | 2 +- .../example/macos/Runner/AppDelegate.swift | 2 +- .../macos/Runner/MainFlutterWindow.swift | 2 +- .../extended_integration_test.dart | 2 +- .../example/test_driver/failure.dart | 2 +- .../example/test_driver/failure_test.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../integration_test/example/web/index.html | 2 +- .../ios/Classes/IntegrationTestIosTest.h | 2 +- .../ios/Classes/IntegrationTestIosTest.m | 2 +- .../ios/Classes/IntegrationTestPlugin.h | 2 +- .../ios/Classes/IntegrationTestPlugin.m | 2 +- .../integration_test/lib/_callback_io.dart | 2 +- .../integration_test/lib/_callback_web.dart | 2 +- .../integration_test/lib/_extension_io.dart | 2 +- .../integration_test/lib/_extension_web.dart | 2 +- packages/integration_test/lib/common.dart | 2 +- .../lib/integration_test.dart | 2 +- .../lib/integration_test_driver.dart | 2 +- .../lib/integration_test_driver_extended.dart | 2 +- .../test/binding_fail_test.dart | 2 +- .../integration_test/test/binding_test.dart | 2 +- .../test/data/fail_test_script.dart | 2 +- .../test/data/pass_test_script.dart | 2 +- .../test/data/pass_then_fail_test_script.dart | 2 +- .../test/response_serialization_test.dart | 2 +- packages/ios_platform_images/LICENSE | 2 +- .../example/ios/Runner/AppDelegate.swift | 2 +- .../ios/Runner/Runner-Bridging-Header.h | 2 +- .../ios_platform_images/example/lib/main.dart | 2 +- .../example/test/widget_test.dart | 2 +- .../ios/Classes/IosPlatformImagesPlugin.h | 2 +- .../ios/Classes/IosPlatformImagesPlugin.m | 2 +- .../lib/ios_platform_images.dart | 2 +- .../test/ios_platform_images_test.dart | 2 +- packages/local_auth/LICENSE | 2 +- .../localauth/AuthenticationHelper.java | 2 +- .../plugins/localauth/LocalAuthPlugin.java | 2 +- .../localauth/EmbeddingV1ActivityTest.java | 2 +- .../FlutterFragmentActivityTest.java | 2 +- .../localauthexample/EmbeddingV1Activity.java | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- packages/local_auth/example/ios/Runner/main.m | 2 +- packages/local_auth/example/lib/main.dart | 2 +- .../integration_test/local_auth_test.dart | 2 +- .../ios/Classes/FLTLocalAuthPlugin.h | 2 +- .../ios/Classes/FLTLocalAuthPlugin.m | 2 +- packages/local_auth/lib/auth_strings.dart | 2 +- packages/local_auth/lib/error_codes.dart | 2 +- packages/local_auth/lib/local_auth.dart | 2 +- packages/local_auth/test/local_auth_test.dart | 2 +- packages/package_info/LICENSE | 2 +- .../packageinfo/PackageInfoPlugin.java | 2 +- .../darwin/Classes/FLTPackageInfoPlugin.m | 2 +- .../EmbedderV1ActivityTest.java | 2 +- .../packageinfoexample/MainActivityTest.java | 2 +- .../EmbedderV1Activity.java | 2 +- .../integration_test/package_info_test.dart | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../package_info/example/ios/Runner/main.m | 2 +- packages/package_info/example/lib/main.dart | 2 +- .../example/macos/Runner/AppDelegate.swift | 2 +- .../macos/Runner/MainFlutterWindow.swift | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../ios/Classes/FLTPackageInfoPlugin.h | 2 +- packages/package_info/lib/package_info.dart | 2 +- .../macos/Classes/FLTPackageInfoPlugin.h | 2 +- .../package_info/test/package_info_test.dart | 2 +- packages/path_provider/path_provider/LICENSE | 2 +- .../pathprovider/PathProviderPlugin.java | 2 +- .../pathprovider/StorageDirectoryMapper.java | 2 +- .../StorageDirectoryMapperTest.java | 2 +- .../java/EmbeddingV1ActivityTest.java | 2 +- .../androidTest/java/MainActivityTest.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../integration_test/path_provider_test.dart | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../path_provider/example/ios/Runner/main.m | 2 +- .../path_provider/example/lib/main.dart | 2 +- .../path_provider/example/linux/main.cc | 2 +- .../example/linux/my_application.cc | 2 +- .../example/linux/my_application.h | 2 +- .../example/macos/Runner/AppDelegate.swift | 2 +- .../macos/Runner/MainFlutterWindow.swift | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../example/windows/runner/flutter_window.cpp | 2 +- .../example/windows/runner/flutter_window.h | 2 +- .../example/windows/runner/main.cpp | 2 +- .../example/windows/runner/run_loop.cpp | 2 +- .../example/windows/runner/run_loop.h | 2 +- .../example/windows/runner/utils.cpp | 2 +- .../example/windows/runner/utils.h | 2 +- .../example/windows/runner/win32_window.cpp | 2 +- .../example/windows/runner/win32_window.h | 2 +- .../integration_test/path_provider_test.dart | 2 +- .../ios/Classes/FLTPathProviderPlugin.h | 2 +- .../ios/Classes/FLTPathProviderPlugin.m | 2 +- .../path_provider/lib/path_provider.dart | 2 +- .../test/path_provider_test.dart | 2 +- .../path_provider/path_provider_linux/LICENSE | 2 +- .../integration_test/path_provider_test.dart | 2 +- .../path_provider_linux/example/lib/main.dart | 2 +- .../path_provider_linux/example/linux/main.cc | 2 +- .../example/linux/my_application.cc | 2 +- .../example/linux/my_application.h | 2 +- .../example/test/widget_test.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../lib/path_provider_linux.dart | 2 +- .../test/path_provider_linux_test.dart | 2 +- .../path_provider/path_provider_macos/LICENSE | 2 +- .../integration_test/path_provider_test.dart | 2 +- .../path_provider_macos/example/lib/main.dart | 2 +- .../example/macos/Runner/AppDelegate.swift | 2 +- .../macos/Runner/MainFlutterWindow.swift | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../macos/Classes/PathProviderPlugin.swift | 2 +- .../path_provider_platform_interface/LICENSE | 2 +- .../lib/path_provider_platform_interface.dart | 2 +- .../lib/src/enums.dart | 2 +- .../lib/src/method_channel_path_provider.dart | 2 +- .../method_channel_path_provider_test.dart | 2 +- .../path_provider_windows/LICENSE | 2 +- .../integration_test/path_provider_test.dart | 2 +- .../example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../example/windows/runner/flutter_window.cpp | 2 +- .../example/windows/runner/flutter_window.h | 2 +- .../example/windows/runner/main.cpp | 2 +- .../example/windows/runner/run_loop.cpp | 2 +- .../example/windows/runner/run_loop.h | 2 +- .../example/windows/runner/utils.cpp | 2 +- .../example/windows/runner/utils.h | 2 +- .../example/windows/runner/win32_window.cpp | 2 +- .../example/windows/runner/win32_window.h | 2 +- .../lib/path_provider_windows.dart | 2 +- .../lib/src/folders.dart | 2 +- .../lib/src/folders_stub.dart | 2 +- .../lib/src/path_provider_windows_real.dart | 2 +- .../lib/src/path_provider_windows_stub.dart | 2 +- .../test/path_provider_windows_test.dart | 2 +- packages/plugin_platform_interface/LICENSE | 2 +- .../lib/plugin_platform_interface.dart | 2 +- .../test/plugin_platform_interface_test.dart | 2 +- packages/quick_actions/quick_actions/LICENSE | 2 +- .../quickactions/MethodCallHandlerImpl.java | 2 +- .../quickactions/QuickActionsPlugin.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../FlutterActivityTest.java | 2 +- .../integration_test/quick_actions_test.dart | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../quick_actions/example/ios/Runner/main.m | 2 +- .../example/ios/RunnerUITests/RunnerUITests.m | 2 +- .../quick_actions/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../ios/Classes/FLTQuickActionsPlugin.h | 2 +- .../ios/Classes/FLTQuickActionsPlugin.m | 2 +- .../quick_actions/lib/quick_actions.dart | 2 +- .../test/quick_actions_test.dart | 2 +- packages/sensors/LICENSE | 2 +- .../plugins/sensors/SensorsPlugin.java | 2 +- .../plugins/sensors/StreamHandlerImpl.java | 2 +- .../sensorsexample/EmbeddingV1Activity.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../sensorsexample/FlutterActivityTest.java | 2 +- .../sensors/example/ios/Runner/AppDelegate.h | 2 +- .../sensors/example/ios/Runner/AppDelegate.m | 2 +- packages/sensors/example/ios/Runner/main.m | 2 +- packages/sensors/example/lib/main.dart | 2 +- packages/sensors/example/lib/snake.dart | 2 +- .../test_driver/test/integration_test.dart | 2 +- .../integration_test/sensors_test.dart | 2 +- .../sensors/ios/Classes/FLTSensorsPlugin.h | 2 +- .../sensors/ios/Classes/FLTSensorsPlugin.m | 2 +- packages/sensors/lib/sensors.dart | 2 +- packages/sensors/test/sensors_test.dart | 2 +- packages/share/LICENSE | 2 +- .../plugins/share/MethodCallHandler.java | 2 +- .../java/io/flutter/plugins/share/Share.java | 2 +- .../plugins/share/ShareFileProvider.java | 2 +- .../io/flutter/plugins/share/SharePlugin.java | 2 +- .../shareexample/EmbeddingV1Activity.java | 2 +- .../shareexample/EmbeddingV1ActivityTest.java | 2 +- .../shareexample/FlutterActivityTest.java | 2 +- .../share/example/ios/Runner/AppDelegate.h | 2 +- .../share/example/ios/Runner/AppDelegate.m | 2 +- packages/share/example/ios/Runner/main.m | 2 +- .../RunnerUITests/FLTShareExampleUITests.m | 2 +- .../share/example/lib/image_previews.dart | 2 +- packages/share/example/lib/main.dart | 2 +- .../test_driver/test/integration_test.dart | 2 +- .../share/integration_test/share_test.dart | 2 +- packages/share/ios/Classes/FLTSharePlugin.h | 2 +- packages/share/ios/Classes/FLTSharePlugin.m | 2 +- packages/share/lib/share.dart | 2 +- packages/share/test/share_test.dart | 2 +- .../shared_preferences/LICENSE | 2 +- .../MethodCallHandlerImpl.java | 2 +- .../SharedPreferencesPlugin.java | 2 +- .../shared_preferences_test.dart | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../example/ios/Runner/AppDelegate.swift | 2 +- .../ios/Runner/Runner-Bridging-Header.h | 2 +- .../example/ios/Runner/main.m | 2 +- .../shared_preferences/example/lib/main.dart | 2 +- .../shared_preferences/example/linux/main.cc | 2 +- .../example/linux/my_application.cc | 2 +- .../example/linux/my_application.h | 2 +- .../example/macos/Runner/AppDelegate.swift | 2 +- .../macos/Runner/MainFlutterWindow.swift | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../shared_preferences/example/web/index.html | 2 +- .../example/windows/runner/flutter_window.cpp | 2 +- .../example/windows/runner/flutter_window.h | 2 +- .../example/windows/runner/main.cpp | 2 +- .../example/windows/runner/run_loop.cpp | 2 +- .../example/windows/runner/run_loop.h | 2 +- .../example/windows/runner/utils.cpp | 2 +- .../example/windows/runner/utils.h | 2 +- .../example/windows/runner/win32_window.cpp | 2 +- .../example/windows/runner/win32_window.h | 2 +- .../ios/Classes/FLTSharedPreferencesPlugin.h | 2 +- .../ios/Classes/FLTSharedPreferencesPlugin.m | 2 +- .../lib/shared_preferences.dart | 2 +- .../test/shared_preferences_test.dart | 2 +- .../shared_preferences_linux/LICENSE | 2 +- .../shared_preferences_test.dart | 2 +- .../example/lib/main.dart | 2 +- .../example/linux/main.cc | 2 +- .../example/linux/my_application.cc | 2 +- .../example/linux/my_application.h | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../lib/shared_preferences_linux.dart | 2 +- .../test/shared_preferences_linux_test.dart | 2 +- .../shared_preferences_macos/LICENSE | 2 +- .../shared_preferences_test.dart | 2 +- .../example/lib/main.dart | 2 +- .../example/macos/Runner/AppDelegate.swift | 2 +- .../macos/Runner/MainFlutterWindow.swift | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../Classes/SharedPreferencesPlugin.swift | 2 +- .../LICENSE | 2 +- .../method_channel_shared_preferences.dart | 2 +- ...shared_preferences_platform_interface.dart | 2 +- ...ethod_channel_shared_preferences_test.dart | 2 +- ...d_preferences_platform_interface_test.dart | 2 +- .../shared_preferences_web/LICENSE | 2 +- .../lib/shared_preferences_web.dart | 2 +- .../test/shared_preferences_web_test.dart | 2 +- .../shared_preferences_windows/LICENSE | 2 +- .../example/LICENSE | 2 +- .../shared_preferences_test.dart | 2 +- .../example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../example/windows/runner/flutter_window.cpp | 2 +- .../example/windows/runner/flutter_window.h | 2 +- .../example/windows/runner/main.cpp | 2 +- .../example/windows/runner/run_loop.cpp | 2 +- .../example/windows/runner/run_loop.h | 2 +- .../example/windows/runner/utils.cpp | 2 +- .../example/windows/runner/utils.h | 2 +- .../example/windows/runner/win32_window.cpp | 2 +- .../example/windows/runner/win32_window.h | 2 +- .../lib/shared_preferences_windows.dart | 2 +- .../test/shared_preferences_windows_test.dart | 2 +- packages/url_launcher/url_launcher/LICENSE | 2 +- .../urllauncher/MethodCallHandlerImpl.java | 2 +- .../plugins/urllauncher/UrlLauncher.java | 2 +- .../urllauncher/UrlLauncherPlugin.java | 2 +- .../plugins/urllauncher/WebViewActivity.java | 2 +- .../MethodCallHandlerImplTest.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../urllauncherexample/MainActivityTest.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../integration_test/url_launcher_test.dart | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../url_launcher/example/ios/Runner/main.m | 2 +- .../url_launcher/example/lib/main.dart | 2 +- .../url_launcher/example/linux/main.cc | 2 +- .../example/linux/my_application.cc | 2 +- .../example/linux/my_application.h | 2 +- .../example/macos/Runner/AppDelegate.swift | 2 +- .../macos/Runner/MainFlutterWindow.swift | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../url_launcher/example/web/index.html | 2 +- .../example/windows/runner/flutter_window.cpp | 2 +- .../example/windows/runner/flutter_window.h | 2 +- .../example/windows/runner/main.cpp | 2 +- .../example/windows/runner/run_loop.cpp | 2 +- .../example/windows/runner/run_loop.h | 2 +- .../example/windows/runner/utils.cpp | 2 +- .../example/windows/runner/utils.h | 2 +- .../example/windows/runner/win32_window.cpp | 2 +- .../example/windows/runner/win32_window.h | 2 +- .../ios/Classes/FLTURLLauncherPlugin.h | 2 +- .../ios/Classes/FLTURLLauncherPlugin.m | 2 +- .../url_launcher/url_launcher/lib/link.dart | 2 +- .../url_launcher/lib/src/link.dart | 2 +- .../url_launcher/lib/url_launcher.dart | 2 +- .../url_launcher/test/link_test.dart | 2 +- .../test/mock_url_launcher_platform.dart | 2 +- .../url_launcher/test/url_launcher_test.dart | 2 +- .../url_launcher/url_launcher_linux/LICENSE | 2 +- .../integration_test/url_launcher_test.dart | 2 +- .../url_launcher_linux/example/lib/main.dart | 2 +- .../url_launcher_linux/example/linux/main.cc | 2 +- .../example/linux/my_application.cc | 2 +- .../example/linux/my_application.h | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../url_launcher_linux/url_launcher_plugin.h | 2 +- .../linux/url_launcher_plugin.cc | 2 +- .../url_launcher/url_launcher_macos/LICENSE | 2 +- .../integration_test/url_launcher_test.dart | 2 +- .../url_launcher_macos/example/lib/main.dart | 2 +- .../example/macos/Runner/AppDelegate.swift | 2 +- .../macos/Runner/MainFlutterWindow.swift | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../macos/Classes/UrlLauncherPlugin.swift | 2 +- .../url_launcher_platform_interface/LICENSE | 2 +- .../lib/link.dart | 2 +- .../lib/method_channel_url_launcher.dart | 2 +- .../lib/url_launcher_platform_interface.dart | 2 +- .../test/link_test.dart | 2 +- .../method_channel_url_launcher_test.dart | 2 +- .../url_launcher/url_launcher_web/LICENSE | 2 +- .../integration_test/link_widget_test.dart | 2 +- .../url_launcher_web_test.dart | 2 +- .../url_launcher_web_test.mocks.dart | 2 +- .../url_launcher_web/example/run_test.sh | 2 +- .../test_driver/integration_test_driver.dart | 2 +- .../url_launcher_web/example/web/index.html | 2 +- .../url_launcher_web/lib/src/link.dart | 2 +- .../lib/src/shims/dart_ui.dart | 2 +- .../lib/src/shims/dart_ui_fake.dart | 2 +- .../lib/src/shims/dart_ui_real.dart | 2 +- .../lib/url_launcher_web.dart | 2 +- .../test/tests_exist_elsewhere_test.dart | 2 +- .../url_launcher/url_launcher_windows/LICENSE | 2 +- .../integration_test/url_launcher_test.dart | 2 +- .../example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../example/windows/runner/flutter_window.cpp | 2 +- .../example/windows/runner/flutter_window.h | 2 +- .../example/windows/runner/main.cpp | 2 +- .../example/windows/runner/run_loop.cpp | 2 +- .../example/windows/runner/run_loop.h | 2 +- .../example/windows/runner/utils.cpp | 2 +- .../example/windows/runner/utils.h | 2 +- .../example/windows/runner/win32_window.cpp | 2 +- .../example/windows/runner/win32_window.h | 2 +- .../url_launcher_plugin.h | 2 +- .../windows/url_launcher_plugin.cpp | 2 +- packages/video_player/video_player/LICENSE | 2 +- .../videoplayer/CustomSSLSocketFactory.java | 2 +- .../flutter/plugins/videoplayer/Messages.java | 2 +- .../plugins/videoplayer/QueuingEventSink.java | 2 +- .../plugins/videoplayer/VideoPlayer.java | 2 +- .../videoplayer/VideoPlayerOptions.java | 2 +- .../videoplayer/VideoPlayerPlugin.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../FlutterActivityTest.java | 2 +- .../integration_test/video_player_test.dart | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../video_player/example/ios/Runner/main.m | 2 +- .../video_player/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../example/test_driver/video_player.dart | 2 +- .../test_driver/video_player_test.dart | 2 +- .../video_player/example/web/index.html | 2 +- .../ios/Classes/FLTVideoPlayerPlugin.h | 2 +- .../ios/Classes/FLTVideoPlayerPlugin.m | 2 +- .../video_player/ios/Classes/messages.h | 2 +- .../video_player/ios/Classes/messages.m | 2 +- .../lib/src/closed_caption_file.dart | 2 +- .../video_player/lib/src/sub_rip.dart | 2 +- .../video_player/lib/video_player.dart | 2 +- .../video_player/pigeons/messages.dart | 2 +- .../test/closed_caption_file_test.dart | 2 +- .../video_player/test/sub_rip_file_test.dart | 2 +- .../video_player_initialization_test.dart | 2 +- .../video_player/test/video_player_test.dart | 2 +- .../video_player_platform_interface/LICENSE | 2 +- .../lib/messages.dart | 2 +- .../lib/method_channel_video_player.dart | 2 +- .../lib/test.dart | 2 +- .../lib/video_player_platform_interface.dart | 2 +- .../method_channel_video_player_test.dart | 2 +- .../video_player/video_player_web/LICENSE | 2 +- .../lib/src/shims/dart_ui.dart | 2 +- .../lib/src/shims/dart_ui_fake.dart | 2 +- .../lib/src/shims/dart_ui_real.dart | 2 +- .../lib/video_player_web.dart | 2 +- .../test/video_player_web_test.dart | 2 +- packages/webview_flutter/LICENSE | 2 +- .../webviewflutter/DisplayListenerProxy.java | 2 +- .../webviewflutter/FlutterCookieManager.java | 2 +- .../webviewflutter/FlutterWebView.java | 2 +- .../webviewflutter/FlutterWebViewClient.java | 2 +- .../webviewflutter/InputAwareWebView.java | 2 +- .../webviewflutter/JavaScriptChannel.java | 2 +- ...readedInputConnectionProxyAdapterView.java | 2 +- .../webviewflutter/WebViewFactory.java | 2 +- .../webviewflutter/WebViewFlutterPlugin.java | 2 +- .../EmbeddingV1ActivityTest.java | 2 +- .../MainActivityTest.java | 2 +- .../EmbeddingV1Activity.java | 2 +- .../webview_flutter_test.dart | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../webview_flutter/example/ios/Runner/main.m | 2 +- .../webview_flutter/example/lib/main.dart | 2 +- .../example/test_driver/integration_test.dart | 2 +- .../ios/Classes/FLTCookieManager.h | 2 +- .../ios/Classes/FLTCookieManager.m | 2 +- .../ios/Classes/FLTWKNavigationDelegate.h | 2 +- .../ios/Classes/FLTWKNavigationDelegate.m | 2 +- .../ios/Classes/FLTWKProgressionDelegate.h | 2 +- .../ios/Classes/FLTWKProgressionDelegate.m | 2 +- .../ios/Classes/FLTWebViewFlutterPlugin.h | 2 +- .../ios/Classes/FLTWebViewFlutterPlugin.m | 2 +- .../ios/Classes/FlutterWebView.h | 2 +- .../ios/Classes/FlutterWebView.m | 2 +- .../ios/Classes/JavaScriptChannelHandler.h | 2 +- .../ios/Classes/JavaScriptChannelHandler.m | 2 +- .../ios/Tests/FLTWKNavigationDelegateTests.m | 2 +- .../ios/Tests/FLTWebViewTests.m | 2 +- .../lib/platform_interface.dart | 2 +- .../lib/src/webview_android.dart | 2 +- .../lib/src/webview_cupertino.dart | 2 +- .../lib/src/webview_method_channel.dart | 2 +- .../webview_flutter/lib/webview_flutter.dart | 2 +- .../test/webview_flutter_test.dart | 2 +- .../wifi_info_flutter/LICENSE | 2 +- .../wifi_info_flutter/WifiInfoFlutter.java | 2 +- .../WifiInfoFlutterMethodChannelHandler.java | 2 +- .../WifiInfoFlutterPlugin.java | 2 +- .../MainActivity.java | 2 +- .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 2 +- .../example/ios/Runner/main.m | 2 +- .../wifi_info_flutter/example/lib/main.dart | 2 +- .../integration_test/wifi_info_test.dart | 2 +- .../test_driver/test/integration_test.dart | 2 +- .../integration_test/wifi_info_test.dart | 2 +- .../ios/Classes/FLTWifiInfoLocationHandler.h | 2 +- .../ios/Classes/FLTWifiInfoLocationHandler.m | 2 +- .../ios/Classes/WifiInfoFlutterPlugin.h | 2 +- .../ios/Classes/WifiInfoFlutterPlugin.m | 2 +- .../lib/wifi_info_flutter.dart | 2 +- .../test/wifi_info_flutter_test.dart | 2 +- .../LICENSE | 2 +- .../lib/src/enums.dart | 2 +- .../src/method_channel_wifi_info_flutter.dart | 2 +- .../wifi_info_flutter_platform_interface.dart | 2 +- ...method_channel_wifi_info_flutter_test.dart | 2 +- script/build_all_plugins_app.sh | 2 +- script/check_publish.sh | 2 +- script/common.sh | 2 +- script/incremental_build.sh | 2 +- script/tool/lib/src/analyze_command.dart | 2 +- .../tool/lib/src/build_examples_command.dart | 2 +- script/tool/lib/src/common.dart | 2 +- .../src/create_all_plugins_app_command.dart | 2 +- .../tool/lib/src/drive_examples_command.dart | 2 +- .../lib/src/firebase_test_lab_command.dart | 2 +- script/tool/lib/src/format_command.dart | 2 +- script/tool/lib/src/java_test_command.dart | 2 +- .../tool/lib/src/license_check_command.dart | 140 ++++++++---------- .../tool/lib/src/lint_podspecs_command.dart | 2 +- script/tool/lib/src/list_command.dart | 2 +- script/tool/lib/src/main.dart | 2 +- .../tool/lib/src/publish_check_command.dart | 2 +- .../tool/lib/src/publish_plugin_command.dart | 2 +- script/tool/lib/src/test_command.dart | 2 +- .../tool/lib/src/version_check_command.dart | 2 +- script/tool/lib/src/xctest_command.dart | 2 +- script/tool/test/analyze_command_test.dart | 2 +- .../test/build_examples_command_test.dart | 2 +- script/tool/test/common_test.dart | 2 +- .../test/drive_examples_command_test.dart | 2 +- script/tool/test/firebase_test_lab_test.dart | 2 +- .../tool/test/license_check_command_test.dart | 56 ++++--- .../tool/test/lint_podspecs_command_test.dart | 2 +- script/tool/test/list_command_test.dart | 2 +- script/tool/test/mocks.dart | 2 +- .../test/publish_plugin_command_test.dart | 2 +- script/tool/test/test_command_test.dart | 2 +- script/tool/test/util.dart | 2 +- script/tool/test/version_check_test.dart | 2 +- script/tool/test/xctest_command_test.dart | 2 +- 1153 files changed, 1248 insertions(+), 1250 deletions(-) diff --git a/LICENSE b/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/android_alarm_manager/LICENSE b/packages/android_alarm_manager/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/android_alarm_manager/LICENSE +++ b/packages/android_alarm_manager/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmBroadcastReceiver.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmBroadcastReceiver.java index 0b8a1455f9ae..c471643628bc 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmBroadcastReceiver.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmBroadcastReceiver.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmService.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmService.java index 5311911a3d7d..d333a4950026 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmService.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AlarmService.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java index 1587bca71a80..fd3a9c5e87dd 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/FlutterBackgroundExecutor.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/FlutterBackgroundExecutor.java index fc438753f3cc..d9c40bfe7181 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/FlutterBackgroundExecutor.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/FlutterBackgroundExecutor.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/PluginRegistrantException.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/PluginRegistrantException.java index f38c2b8b0461..afbc1c71bd3f 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/PluginRegistrantException.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/PluginRegistrantException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/RebootBroadcastReceiver.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/RebootBroadcastReceiver.java index 5f5c5cacd86f..9135755863a1 100644 --- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/RebootBroadcastReceiver.java +++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/RebootBroadcastReceiver.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/BackgroundExecutionTest.java b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/BackgroundExecutionTest.java index 457599b0da91..d6927232fb80 100644 --- a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/BackgroundExecutionTest.java +++ b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/BackgroundExecutionTest.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/DriverExtensionActivity.java b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/DriverExtensionActivity.java index 57c3f4122578..9a57f2c1d914 100644 --- a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/DriverExtensionActivity.java +++ b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/DriverExtensionActivity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/MainActivityTest.java b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/MainActivityTest.java index 82503c9d54c5..0272c14a8328 100644 --- a/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/MainActivityTest.java +++ b/packages/android_alarm_manager/example/android/app/src/androidTest/java/io/plugins/androidalarmmanager/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/Application.java b/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/Application.java index e2b3e8aae73d..fc83d38128c4 100644 --- a/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/Application.java +++ b/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/Application.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/EmbeddingV1Activity.java b/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/EmbeddingV1Activity.java index 8e77dbd1b46b..fa4b1422f474 100644 --- a/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/EmbeddingV1Activity.java +++ b/packages/android_alarm_manager/example/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart b/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart index 67dcb520a3a2..37b5659f09f4 100644 --- a/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart +++ b/packages/android_alarm_manager/example/integration_test/android_alarm_manager_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/example/lib/main.dart b/packages/android_alarm_manager/example/lib/main.dart index ff164a6275b3..75648b8ded5f 100644 --- a/packages/android_alarm_manager/example/lib/main.dart +++ b/packages/android_alarm_manager/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/example/test_driver/integration_test.dart b/packages/android_alarm_manager/example/test_driver/integration_test.dart index 88461d1c79a1..c08f4a817f6c 100644 --- a/packages/android_alarm_manager/example/test_driver/integration_test.dart +++ b/packages/android_alarm_manager/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/lib/android_alarm_manager.dart b/packages/android_alarm_manager/lib/android_alarm_manager.dart index e074dfb3af36..e4e3855933ca 100644 --- a/packages/android_alarm_manager/lib/android_alarm_manager.dart +++ b/packages/android_alarm_manager/lib/android_alarm_manager.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_alarm_manager/test/android_alarm_manager_test.dart b/packages/android_alarm_manager/test/android_alarm_manager_test.dart index 4b340f563fd4..908bb957c0f2 100644 --- a/packages/android_alarm_manager/test/android_alarm_manager_test.dart +++ b/packages/android_alarm_manager/test/android_alarm_manager_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/LICENSE b/packages/android_intent/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/android_intent/LICENSE +++ b/packages/android_intent/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java index ff73b6de5485..883d05922874 100644 --- a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java +++ b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/AndroidIntentPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java index 1c9aa9ac6b02..2c05a914c888 100644 --- a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java +++ b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/IntentSender.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java index 9bdcbec08465..bcd843b64228 100644 --- a/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java +++ b/packages/android_intent/android/src/main/java/io/flutter/plugins/androidintent/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java b/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java index bf3fdf976d9d..0ea03a0690f1 100644 --- a/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java +++ b/packages/android_intent/android/src/test/java/io/flutter/plugins/androidintent/MethodCallHandlerImplTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/EmbeddingV1ActivityTest.java b/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/EmbeddingV1ActivityTest.java index a370318927ba..36f8444dea62 100644 --- a/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/EmbeddingV1ActivityTest.java +++ b/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/MainActivityTest.java b/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/MainActivityTest.java index f7cddca2832f..d9ba10729001 100644 --- a/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/MainActivityTest.java +++ b/packages/android_intent/example/android/app/src/androidTestDebug/java/io/flutter/plugins/androidintentexample/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/example/android/app/src/main/java/io/flutter/plugins/androidintentexample/EmbeddingV1Activity.java b/packages/android_intent/example/android/app/src/main/java/io/flutter/plugins/androidintentexample/EmbeddingV1Activity.java index 87e822274f85..5906a8940236 100644 --- a/packages/android_intent/example/android/app/src/main/java/io/flutter/plugins/androidintentexample/EmbeddingV1Activity.java +++ b/packages/android_intent/example/android/app/src/main/java/io/flutter/plugins/androidintentexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/example/integration_test/android_intent_test.dart b/packages/android_intent/example/integration_test/android_intent_test.dart index 28de6b785c70..5ae86cba6a03 100644 --- a/packages/android_intent/example/integration_test/android_intent_test.dart +++ b/packages/android_intent/example/integration_test/android_intent_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/example/lib/main.dart b/packages/android_intent/example/lib/main.dart index 99413c1d5701..c2276d080aa4 100644 --- a/packages/android_intent/example/lib/main.dart +++ b/packages/android_intent/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/example/test_driver/integration_test.dart b/packages/android_intent/example/test_driver/integration_test.dart index 993729f6ac3d..cc91e52ef2ef 100644 --- a/packages/android_intent/example/test_driver/integration_test.dart +++ b/packages/android_intent/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/lib/android_intent.dart b/packages/android_intent/lib/android_intent.dart index 698a584ce7ea..80208833c6be 100644 --- a/packages/android_intent/lib/android_intent.dart +++ b/packages/android_intent/lib/android_intent.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/lib/flag.dart b/packages/android_intent/lib/flag.dart index 147c6a1d932c..771a89ff83a7 100644 --- a/packages/android_intent/lib/flag.dart +++ b/packages/android_intent/lib/flag.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/android_intent/test/android_intent_test.dart b/packages/android_intent/test/android_intent_test.dart index 95ff345395cf..00bcc7664908 100644 --- a/packages/android_intent/test/android_intent_test.dart +++ b/packages/android_intent/test/android_intent_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/LICENSE b/packages/battery/battery/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/battery/battery/LICENSE +++ b/packages/battery/battery/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/battery/battery/android/src/main/java/io/flutter/plugins/battery/BatteryPlugin.java b/packages/battery/battery/android/src/main/java/io/flutter/plugins/battery/BatteryPlugin.java index 92405a9900d3..7f2e1efbeede 100644 --- a/packages/battery/battery/android/src/main/java/io/flutter/plugins/battery/BatteryPlugin.java +++ b/packages/battery/battery/android/src/main/java/io/flutter/plugins/battery/BatteryPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/EmbedderV1ActivityTest.java b/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/EmbedderV1ActivityTest.java index 3c4eabeaf23f..c939be4281da 100644 --- a/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/EmbedderV1ActivityTest.java +++ b/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/EmbedderV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/FlutterActivityTest.java b/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/FlutterActivityTest.java index 2fec9365b756..267271f70f42 100644 --- a/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/FlutterActivityTest.java +++ b/packages/battery/battery/example/android/app/src/androidTest/java/io/flutter/plugins/battery/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/example/android/app/src/main/java/io/flutter/plugins/batteryexample/EmbedderV1Activity.java b/packages/battery/battery/example/android/app/src/main/java/io/flutter/plugins/batteryexample/EmbedderV1Activity.java index 6877a5013737..2b9e538bbe47 100644 --- a/packages/battery/battery/example/android/app/src/main/java/io/flutter/plugins/batteryexample/EmbedderV1Activity.java +++ b/packages/battery/battery/example/android/app/src/main/java/io/flutter/plugins/batteryexample/EmbedderV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/example/ios/Runner/AppDelegate.h b/packages/battery/battery/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/battery/battery/example/ios/Runner/AppDelegate.h +++ b/packages/battery/battery/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/example/ios/Runner/AppDelegate.m b/packages/battery/battery/example/ios/Runner/AppDelegate.m index abfe2106b092..b790a0a52635 100644 --- a/packages/battery/battery/example/ios/Runner/AppDelegate.m +++ b/packages/battery/battery/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/example/ios/Runner/main.m b/packages/battery/battery/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/battery/battery/example/ios/Runner/main.m +++ b/packages/battery/battery/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/example/lib/main.dart b/packages/battery/battery/example/lib/main.dart index 8c0edec04f74..b139d0d8e4be 100644 --- a/packages/battery/battery/example/lib/main.dart +++ b/packages/battery/battery/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/integration_test/battery_test.dart b/packages/battery/battery/integration_test/battery_test.dart index 4912f3f81fd3..24f5a5adc7f9 100644 --- a/packages/battery/battery/integration_test/battery_test.dart +++ b/packages/battery/battery/integration_test/battery_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/ios/Classes/FLTBatteryPlugin.h b/packages/battery/battery/ios/Classes/FLTBatteryPlugin.h index b555de48ebf4..fd6a3e964d83 100644 --- a/packages/battery/battery/ios/Classes/FLTBatteryPlugin.h +++ b/packages/battery/battery/ios/Classes/FLTBatteryPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/ios/Classes/FLTBatteryPlugin.m b/packages/battery/battery/ios/Classes/FLTBatteryPlugin.m index 151dbda1ce32..558d395bb9c0 100644 --- a/packages/battery/battery/ios/Classes/FLTBatteryPlugin.m +++ b/packages/battery/battery/ios/Classes/FLTBatteryPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/lib/battery.dart b/packages/battery/battery/lib/battery.dart index 8781979a7eac..92e54be095fe 100644 --- a/packages/battery/battery/lib/battery.dart +++ b/packages/battery/battery/lib/battery.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery/test/battery_test.dart b/packages/battery/battery/test/battery_test.dart index 5db0798d906e..8870acb775de 100644 --- a/packages/battery/battery/test/battery_test.dart +++ b/packages/battery/battery/test/battery_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery_platform_interface/LICENSE b/packages/battery/battery_platform_interface/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/battery/battery_platform_interface/LICENSE +++ b/packages/battery/battery_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart b/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart index c839b02bc18d..548edf8257f5 100644 --- a/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart +++ b/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery_platform_interface/lib/enums/battery_state.dart b/packages/battery/battery_platform_interface/lib/enums/battery_state.dart index b8458224df4a..a525e78ccdf5 100644 --- a/packages/battery/battery_platform_interface/lib/enums/battery_state.dart +++ b/packages/battery/battery_platform_interface/lib/enums/battery_state.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart b/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart index 8f38b6616702..1d0a8329c257 100644 --- a/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart +++ b/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart b/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart index 0e36e0a1fbba..6a312ee73ef2 100644 --- a/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart +++ b/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/LICENSE b/packages/camera/camera/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/camera/camera/LICENSE +++ b/packages/camera/camera/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 4faedf3aa0c2..4c1370f2f3cb 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java index 4442fce9b2fd..7d60e0fffa5c 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java index 849ca3ccc489..75730ab41711 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java index 67030ebe9667..60c866cd82d5 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java index 4ad260f7347f..b4d4689f2b4e 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java index ff3f04ade0fd..42ad6d76dcfc 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraZoom.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java index 8e7be0937000..164a529ffa8b 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java index af1a0c2082c5..634596dde8bb 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index c1afd64febec..040225ed5ff3 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java index 4a6fafff50c8..4c11e2d40e62 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java index 9873a3c12972..a78c2b47b7ad 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/media/MediaRecorderBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java index fd2475649b89..0bd23945e3f7 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ExposureMode.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java index 3880874779be..d7b661380098 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java index d4e8348ab8ed..c879593d4f21 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FocusMode.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java index 1c2ce8b0c8aa..a70d85688037 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/ResolutionPreset.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java index 930b5ad08ab3..ecb96a88f31a 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java index d0074d295ca2..6a04b14fe21e 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionsTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java index aa89669459bb..b97192b889cf 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java index 445174b3b357..1385c2e36949 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java index ff77b32cd1d0..ed6fd56a3c34 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java index 8542fc615c35..f257a7f7fd4b 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java index 04eb3e031cca..9b8b54cc959c 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java index 600c426063e2..5f4bd9f89ec7 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java index 8b812b4b011d..5a53648bc51e 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java index 114aaa342e9b..58e6d7ce3306 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java b/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java index 08ae8e4274af..9cd4ef60991b 100644 --- a/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java +++ b/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java b/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java index 4f30e83a138c..32acc1ba9c15 100644 --- a/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java +++ b/packages/camera/camera/example/android/app/src/androidTestDebug/java/io/flutter/plugins/cameraexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java b/packages/camera/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java index e30d5ec7b07b..406e1417e3af 100644 --- a/packages/camera/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java +++ b/packages/camera/camera/example/android/app/src/main/java/io/flutter/plugins/cameraexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/example/integration_test/camera_test.dart b/packages/camera/camera/example/integration_test/camera_test.dart index 1b08200ed68d..7767ac0c6979 100644 --- a/packages/camera/camera/example/integration_test/camera_test.dart +++ b/packages/camera/camera/example/integration_test/camera_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/example/ios/Runner/AppDelegate.h b/packages/camera/camera/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/camera/camera/example/ios/Runner/AppDelegate.h +++ b/packages/camera/camera/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/example/ios/Runner/AppDelegate.m b/packages/camera/camera/example/ios/Runner/AppDelegate.m index 2147d3d605ac..30b87969f44a 100644 --- a/packages/camera/camera/example/ios/Runner/AppDelegate.m +++ b/packages/camera/camera/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/example/ios/Runner/main.m b/packages/camera/camera/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/camera/camera/example/ios/Runner/main.m +++ b/packages/camera/camera/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 0148ce41d725..536e95de9c8b 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/example/test_driver/integration_test.dart b/packages/camera/camera/example/test_driver/integration_test.dart index 0ad951cb063d..fac399066292 100644 --- a/packages/camera/camera/example/test_driver/integration_test.dart +++ b/packages/camera/camera/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.h b/packages/camera/camera/ios/Classes/CameraPlugin.h index f42084125e6c..f13d810445bc 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.h +++ b/packages/camera/camera/ios/Classes/CameraPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index 308ca886a45f..e867491fcf8f 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/ios/Tests/CameraPluginTests.m b/packages/camera/camera/ios/Tests/CameraPluginTests.m index 3d8443901672..25496d539dc8 100644 --- a/packages/camera/camera/ios/Tests/CameraPluginTests.m +++ b/packages/camera/camera/ios/Tests/CameraPluginTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/lib/camera.dart b/packages/camera/camera/lib/camera.dart index daab70128ada..1e24efbd3dc6 100644 --- a/packages/camera/camera/lib/camera.dart +++ b/packages/camera/camera/lib/camera.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index f7710d45c7fd..3284a9b01fa2 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/lib/src/camera_image.dart b/packages/camera/camera/lib/src/camera_image.dart index fd551082bc83..411c7e86db41 100644 --- a/packages/camera/camera/lib/src/camera_image.dart +++ b/packages/camera/camera/lib/src/camera_image.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/lib/src/camera_preview.dart b/packages/camera/camera/lib/src/camera_preview.dart index caa8c04885c7..517751b7bf64 100644 --- a/packages/camera/camera/lib/src/camera_preview.dart +++ b/packages/camera/camera/lib/src/camera_preview.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/test/camera_image_stream_test.dart b/packages/camera/camera/test/camera_image_stream_test.dart index 6832466a25ba..d971103b3636 100644 --- a/packages/camera/camera/test/camera_image_stream_test.dart +++ b/packages/camera/camera/test/camera_image_stream_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/test/camera_image_test.dart b/packages/camera/camera/test/camera_image_test.dart index 40d7194e36d1..2d827d983f3a 100644 --- a/packages/camera/camera/test/camera_image_test.dart +++ b/packages/camera/camera/test/camera_image_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 272587e9955b..26382a9b7d60 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/test/camera_value_test.dart b/packages/camera/camera/test/camera_value_test.dart index f1809fc61167..e0378cca2cb9 100644 --- a/packages/camera/camera/test/camera_value_test.dart +++ b/packages/camera/camera/test/camera_value_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera/test/utils/method_channel_mock.dart b/packages/camera/camera/test/utils/method_channel_mock.dart index 6e0b28e224d8..60d8def6a2e3 100644 --- a/packages/camera/camera/test/utils/method_channel_mock.dart +++ b/packages/camera/camera/test/utils/method_channel_mock.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/LICENSE b/packages/camera/camera_platform_interface/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/camera/camera_platform_interface/LICENSE +++ b/packages/camera/camera_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart b/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart index b7a7b2ff29b8..3ec66dd54894 100644 --- a/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart +++ b/packages/camera/camera_platform_interface/lib/camera_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart index 137a0002ef17..591d5a336356 100644 --- a/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart +++ b/packages/camera/camera_platform_interface/lib/src/events/camera_event.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/events/device_event.dart b/packages/camera/camera_platform_interface/lib/src/events/device_event.dart index a4edbef0d317..c6cedd135fed 100644 --- a/packages/camera/camera_platform_interface/lib/src/events/device_event.dart +++ b/packages/camera/camera_platform_interface/lib/src/events/device_event.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index 321104e695e9..c6c363a56d65 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 92e3587ee04b..4437d3b0593a 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart b/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart index dffb5d1bff01..98a39fd6c65e 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/camera_description.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart b/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart index f8da81392b43..d112f9f6f6e3 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart index a1cfbfcc08a5..1debd19b3a26 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/exposure_mode.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart index e851857a26d6..b9f146d373d3 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/flash_mode.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart index 76d429463a29..60a419155149 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/focus_mode.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart b/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart index 3c07dfe0faca..edbf7d24098c 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/image_format_group.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart b/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart index cabeb6a0b9cc..1724f6c97517 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/types/types.dart b/packages/camera/camera_platform_interface/lib/src/types/types.dart index 5b9999ece037..0927458299df 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/types.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/types.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/lib/src/utils/utils.dart b/packages/camera/camera_platform_interface/lib/src/utils/utils.dart index b8703d603801..8c455867762f 100644 --- a/packages/camera/camera_platform_interface/lib/src/utils/utils.dart +++ b/packages/camera/camera_platform_interface/lib/src/utils/utils.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart index b3d61a467373..c8f38efc4e2d 100644 --- a/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart +++ b/packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/events/camera_event_test.dart b/packages/camera/camera_platform_interface/test/events/camera_event_test.dart index 120cafc238c3..637358f557c3 100644 --- a/packages/camera/camera_platform_interface/test/events/camera_event_test.dart +++ b/packages/camera/camera_platform_interface/test/events/camera_event_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/events/device_event_test.dart b/packages/camera/camera_platform_interface/test/events/device_event_test.dart index 950a12e21484..f7cb657725a9 100644 --- a/packages/camera/camera_platform_interface/test/events/device_event_test.dart +++ b/packages/camera/camera_platform_interface/test/events/device_event_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index ea7e9787a817..8a618545535b 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/types/camera_description_test.dart b/packages/camera/camera_platform_interface/test/types/camera_description_test.dart index a098df07b094..11a5210e831b 100644 --- a/packages/camera/camera_platform_interface/test/types/camera_description_test.dart +++ b/packages/camera/camera_platform_interface/test/types/camera_description_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart b/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart index 338238e0bb75..5fb753fb3616 100644 --- a/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart +++ b/packages/camera/camera_platform_interface/test/types/camera_exception_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart b/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart index b8e77fe5df80..659b75e017f1 100644 --- a/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart +++ b/packages/camera/camera_platform_interface/test/types/exposure_mode_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart b/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart index 8c6903087fdd..d313bcf52b77 100644 --- a/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart +++ b/packages/camera/camera_platform_interface/test/types/flash_mode_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart b/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart index 5ce379400e37..866f8ce07909 100644 --- a/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart +++ b/packages/camera/camera_platform_interface/test/types/focus_mode_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/types/image_group_test.dart b/packages/camera/camera_platform_interface/test/types/image_group_test.dart index 9ae4b9bb4c3c..89585cc1ae35 100644 --- a/packages/camera/camera_platform_interface/test/types/image_group_test.dart +++ b/packages/camera/camera_platform_interface/test/types/image_group_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart b/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart index 4da08cf2f0b7..55a4ac56cd9d 100644 --- a/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart +++ b/packages/camera/camera_platform_interface/test/types/resolution_preset_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart b/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart index 6e0b28e224d8..60d8def6a2e3 100644 --- a/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart +++ b/packages/camera/camera_platform_interface/test/utils/method_channel_mock.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/camera/camera_platform_interface/test/utils/utils_test.dart b/packages/camera/camera_platform_interface/test/utils/utils_test.dart index d99f9ab01443..f1960eeb2e72 100644 --- a/packages/camera/camera_platform_interface/test/utils/utils_test.dart +++ b/packages/camera/camera_platform_interface/test/utils/utils_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/LICENSE b/packages/connectivity/connectivity/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/connectivity/connectivity/LICENSE +++ b/packages/connectivity/connectivity/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java index f2f16ae61629..d7e254e84595 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/Connectivity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java index e44e7b4e8f5d..fbda187bd188 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityBroadcastReceiver.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityMethodChannelHandler.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityMethodChannelHandler.java index 3f8541ed1c54..06275498c4a9 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityMethodChannelHandler.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityMethodChannelHandler.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityPlugin.java b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityPlugin.java index 91d00839145f..2287a0a30b86 100644 --- a/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityPlugin.java +++ b/packages/connectivity/connectivity/android/src/main/java/io/flutter/plugins/connectivity/ConnectivityPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1Activity.java b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1Activity.java index 89438471ace3..8329fa29e431 100644 --- a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1Activity.java +++ b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1ActivityTest.java b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1ActivityTest.java index 1667a7317c68..e2bd59408d4b 100644 --- a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1ActivityTest.java +++ b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/FlutterActivityTest.java b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/FlutterActivityTest.java index 8d7f9d0c460f..330f0050a1d8 100644 --- a/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/FlutterActivityTest.java +++ b/packages/connectivity/connectivity/example/android/app/src/main/java/io/flutter/plugins/connectivityexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java b/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java index b531a2db2897..2cf03dd3c2f5 100644 --- a/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java +++ b/packages/connectivity/connectivity/example/android/app/src/test/java/io/flutter/plugins/connectivityexample/ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.h b/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.h +++ b/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.m b/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.m index 2147d3d605ac..30b87969f44a 100644 --- a/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.m +++ b/packages/connectivity/connectivity/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/ios/Runner/main.m b/packages/connectivity/connectivity/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/connectivity/connectivity/example/ios/Runner/main.m +++ b/packages/connectivity/connectivity/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/lib/main.dart b/packages/connectivity/connectivity/example/lib/main.dart index 6f6356f0fc2b..b6a6882cb12e 100644 --- a/packages/connectivity/connectivity/example/lib/main.dart +++ b/packages/connectivity/connectivity/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/macos/Runner/AppDelegate.swift b/packages/connectivity/connectivity/example/macos/Runner/AppDelegate.swift index ca19fe95f8cf..5cec4c48f620 100644 --- a/packages/connectivity/connectivity/example/macos/Runner/AppDelegate.swift +++ b/packages/connectivity/connectivity/example/macos/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/macos/Runner/MainFlutterWindow.swift b/packages/connectivity/connectivity/example/macos/Runner/MainFlutterWindow.swift index 2ce11b78604b..32aaeedceb1f 100644 --- a/packages/connectivity/connectivity/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/connectivity/connectivity/example/macos/Runner/MainFlutterWindow.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart b/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart index 13c9d4b5e8fb..454ddd4c351b 100644 --- a/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart +++ b/packages/connectivity/connectivity/example/test_driver/integration_test/connectivity_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart b/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart index 9887033fc5dd..79c1875f85d2 100644 --- a/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart +++ b/packages/connectivity/connectivity/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/example/web/index.html b/packages/connectivity/connectivity/example/web/index.html index 97b1100c4244..c6fa1623be95 100644 --- a/packages/connectivity/connectivity/example/web/index.html +++ b/packages/connectivity/connectivity/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/connectivity/connectivity/integration_test/connectivity_test.dart b/packages/connectivity/connectivity/integration_test/connectivity_test.dart index 13c9d4b5e8fb..454ddd4c351b 100644 --- a/packages/connectivity/connectivity/integration_test/connectivity_test.dart +++ b/packages/connectivity/connectivity/integration_test/connectivity_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.h b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.h index bb0ff07dc712..aec76adc0b58 100644 --- a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.h +++ b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m index 241d01c1b007..ac37c2359137 100644 --- a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m +++ b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/lib/connectivity.dart b/packages/connectivity/connectivity/lib/connectivity.dart index e4199d55f699..1b819d7470d2 100644 --- a/packages/connectivity/connectivity/lib/connectivity.dart +++ b/packages/connectivity/connectivity/lib/connectivity.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity/test/connectivity_test.dart b/packages/connectivity/connectivity/test/connectivity_test.dart index cde833c9d71e..e6c253e0d49a 100644 --- a/packages/connectivity/connectivity/test/connectivity_test.dart +++ b/packages/connectivity/connectivity/test/connectivity_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_for_web/LICENSE b/packages/connectivity/connectivity_for_web/LICENSE index 1d7bbaf70add..c6823b81eb84 100644 --- a/packages/connectivity/connectivity_for_web/LICENSE +++ b/packages/connectivity/connectivity_for_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2016 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart b/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart index 1f4a1d5d8f60..e6faa30da4dc 100644 --- a/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart +++ b/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart b/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart index 390a66556d10..556b6fe6fca0 100644 --- a/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart +++ b/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_for_web/example/run_test.sh b/packages/connectivity/connectivity_for_web/example/run_test.sh index 9bfce94f63b2..dbf0ec55fd8f 100755 --- a/packages/connectivity/connectivity_for_web/example/run_test.sh +++ b/packages/connectivity/connectivity_for_web/example/run_test.sh @@ -1,5 +1,5 @@ #!/usr/bin/bash -# Copyright 2017 The Flutter Authors. All rights reserved. +# Copyright 2013 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. diff --git a/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart b/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart index 0dd5f694f16b..f26b6a310cfe 100644 --- a/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart +++ b/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_for_web/example/web/index.html b/packages/connectivity/connectivity_for_web/example/web/index.html index 27464c33811a..7fb138cc90fa 100644 --- a/packages/connectivity/connectivity_for_web/example/web/index.html +++ b/packages/connectivity/connectivity_for_web/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart b/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart index 14de31db1125..d1c6811f5349 100644 --- a/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart +++ b/packages/connectivity/connectivity_for_web/lib/connectivity_for_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart index 09fbeaf7fd0d..475ec0d675b7 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart index 2b319b1fb5ab..6554f7a8c124 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart index 9f1b111eccd3..691bd6da3bfb 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart b/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart index 64d8e547e485..442c50144727 100644 --- a/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart +++ b/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_macos/LICENSE b/packages/connectivity/connectivity_macos/LICENSE index b257ce7c224c..c6823b81eb84 100644 --- a/packages/connectivity/connectivity_macos/LICENSE +++ b/packages/connectivity/connectivity_macos/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/connectivity/connectivity_macos/example/lib/main.dart b/packages/connectivity/connectivity_macos/example/lib/main.dart index 97baf2678fd3..d0e07341fe92 100644 --- a/packages/connectivity/connectivity_macos/example/lib/main.dart +++ b/packages/connectivity/connectivity_macos/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_macos/example/macos/Runner/AppDelegate.swift b/packages/connectivity/connectivity_macos/example/macos/Runner/AppDelegate.swift index ca19fe95f8cf..5cec4c48f620 100644 --- a/packages/connectivity/connectivity_macos/example/macos/Runner/AppDelegate.swift +++ b/packages/connectivity/connectivity_macos/example/macos/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_macos/example/macos/Runner/MainFlutterWindow.swift b/packages/connectivity/connectivity_macos/example/macos/Runner/MainFlutterWindow.swift index 2ce11b78604b..32aaeedceb1f 100644 --- a/packages/connectivity/connectivity_macos/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/connectivity/connectivity_macos/example/macos/Runner/MainFlutterWindow.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart b/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart index d38614076190..c6b05c73cde9 100644 --- a/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart +++ b/packages/connectivity/connectivity_macos/example/test_driver/integration_test/connectivity_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart b/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart index 49af1cbb81a5..9647a12d77ce 100644 --- a/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart +++ b/packages/connectivity/connectivity_macos/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_macos/macos/Classes/ConnectivityPlugin.swift b/packages/connectivity/connectivity_macos/macos/Classes/ConnectivityPlugin.swift index 302c6d7d55e3..69efe80df5ac 100644 --- a/packages/connectivity/connectivity_macos/macos/Classes/ConnectivityPlugin.swift +++ b/packages/connectivity/connectivity_macos/macos/Classes/ConnectivityPlugin.swift @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_macos/macos/Classes/IPHelper.h b/packages/connectivity/connectivity_macos/macos/Classes/IPHelper.h index a1bc4ce12179..e5370fb349c3 100644 --- a/packages/connectivity/connectivity_macos/macos/Classes/IPHelper.h +++ b/packages/connectivity/connectivity_macos/macos/Classes/IPHelper.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_platform_interface/LICENSE b/packages/connectivity/connectivity_platform_interface/LICENSE index 67c7e2c52e46..c6823b81eb84 100644 --- a/packages/connectivity/connectivity_platform_interface/LICENSE +++ b/packages/connectivity/connectivity_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart b/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart index b137509f650a..6667b353a4aa 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/connectivity_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart b/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart index 9c8398f2f67a..b77f54cf60b2 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/src/enums.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart b/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart index f04eb9193fb5..bdf820ac3ba7 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/src/method_channel_connectivity.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart b/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart index 5c62c61220ec..3b5b753f6c29 100644 --- a/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart +++ b/packages/connectivity/connectivity_platform_interface/lib/src/utils.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart b/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart index 5ae66acabc36..38f4ac38b156 100644 --- a/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart +++ b/packages/connectivity/connectivity_platform_interface/test/method_channel_connectivity_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/LICENSE b/packages/device_info/device_info/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/device_info/device_info/LICENSE +++ b/packages/device_info/device_info/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java b/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java index 28fdc888560b..9b766d7f8381 100644 --- a/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java +++ b/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java b/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java index fb44bc821e6d..531e5db0c237 100644 --- a/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java +++ b/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1Activity.java b/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1Activity.java index 6be74796a0b6..86966cd137bb 100644 --- a/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1Activity.java +++ b/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1ActivityTest.java b/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1ActivityTest.java index ca680684e3ea..a9babfe803ae 100644 --- a/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1ActivityTest.java +++ b/packages/device_info/device_info/example/android/app/src/main/java/io/flutter/plugins/deviceinfoexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/example/integration_test/device_info_test.dart b/packages/device_info/device_info/example/integration_test/device_info_test.dart index 9fbb682df2e8..abb2b5ea0b03 100644 --- a/packages/device_info/device_info/example/integration_test/device_info_test.dart +++ b/packages/device_info/device_info/example/integration_test/device_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/example/ios/Runner/AppDelegate.h b/packages/device_info/device_info/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/device_info/device_info/example/ios/Runner/AppDelegate.h +++ b/packages/device_info/device_info/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/example/ios/Runner/AppDelegate.m b/packages/device_info/device_info/example/ios/Runner/AppDelegate.m index 2147d3d605ac..30b87969f44a 100644 --- a/packages/device_info/device_info/example/ios/Runner/AppDelegate.m +++ b/packages/device_info/device_info/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/example/ios/Runner/main.m b/packages/device_info/device_info/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/device_info/device_info/example/ios/Runner/main.m +++ b/packages/device_info/device_info/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/example/lib/main.dart b/packages/device_info/device_info/example/lib/main.dart index 24129aa04b1c..44e3fb4ee2f7 100644 --- a/packages/device_info/device_info/example/lib/main.dart +++ b/packages/device_info/device_info/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/example/test_driver/integration_test.dart b/packages/device_info/device_info/example/test_driver/integration_test.dart index 29b5b21a5941..156ecae508c1 100644 --- a/packages/device_info/device_info/example/test_driver/integration_test.dart +++ b/packages/device_info/device_info/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.h b/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.h index e4e287c584d5..511b5b893fcb 100644 --- a/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.h +++ b/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.m b/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.m index bc2d172c576e..3d4d25ad9c6e 100644 --- a/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.m +++ b/packages/device_info/device_info/ios/Classes/FLTDeviceInfoPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info/lib/device_info.dart b/packages/device_info/device_info/lib/device_info.dart index a357844cf2d9..1153ac6f7da6 100644 --- a/packages/device_info/device_info/lib/device_info.dart +++ b/packages/device_info/device_info/lib/device_info.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info_platform_interface/LICENSE b/packages/device_info/device_info_platform_interface/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/device_info/device_info_platform_interface/LICENSE +++ b/packages/device_info/device_info_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart b/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart index 676207ba07fe..a40363b2dcb6 100644 --- a/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart +++ b/packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart b/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart index d9eb455684e7..3c19e57f66a8 100644 --- a/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/method_channel/method_channel_device_info.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart index 00195a8f42b2..961d373e2dea 100644 --- a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart index e779ddc8a129..17c96a3e250a 100644 --- a/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart index cc0b4b4d10a7..14ed7c0aefb4 100644 --- a/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart +++ b/packages/device_info/device_info_platform_interface/test/method_channel_device_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/LICENSE b/packages/espresso/LICENSE index b257ce7c224c..c6823b81eb84 100644 --- a/packages/espresso/LICENSE +++ b/packages/espresso/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java index 89233e64799f..3ba1762117c3 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/EspressoFlutter.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ActionUtil.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ActionUtil.java index 8ab4c4a137cf..73f8c111b6cf 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ActionUtil.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ActionUtil.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ClickAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ClickAction.java index 949c1e1cffbd..d2e251e887e3 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ClickAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/ClickAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterActions.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterActions.java index 3fdcb08eb525..2f0c171e780d 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterActions.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterActions.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterScrollToAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterScrollToAction.java index 4462ff6d6646..04692155fc80 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterScrollToAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterScrollToAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterTypeTextAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterTypeTextAction.java index b0b744773066..3de8aec56622 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterTypeTextAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterTypeTextAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java index 0d8d94844d97..7031915f1ca1 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/FlutterViewAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/SyntheticClickAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/SyntheticClickAction.java index ddc347defa55..fa238cbe76c0 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/SyntheticClickAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/SyntheticClickAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WaitUntilIdleAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WaitUntilIdleAction.java index 054c00e86d60..a4c2c95bade4 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WaitUntilIdleAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WaitUntilIdleAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetCoordinatesCalculator.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetCoordinatesCalculator.java index 0ef5a5761dc3..13de56e5a616 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetCoordinatesCalculator.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetCoordinatesCalculator.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetInfoFetcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetInfoFetcher.java index 3e5f48d56983..d922b1fb33ae 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetInfoFetcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/action/WidgetInfoFetcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterAction.java index 3f1d3a23d99a..71e851d2a959 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterTestingProtocol.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterTestingProtocol.java index 54be97652157..68429bfbdcd0 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterTestingProtocol.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/FlutterTestingProtocol.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/SyntheticAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/SyntheticAction.java index 0d2f0cbf49cf..41af3e99dfda 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/SyntheticAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/SyntheticAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAction.java index b04cb0cb1d8a..012066cc3f80 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAssertion.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAssertion.java index d69972b09b3f..9cd36f1df363 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAssertion.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetAssertion.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetMatcher.java index a8e0b6a07c75..5c983c118ede 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/api/WidgetMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterAssertions.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterAssertions.java index 6573f2a2a705..0a6b2b791545 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterAssertions.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterAssertions.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterViewAssertion.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterViewAssertion.java index 6bc81b5862e4..1233e9f35edf 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterViewAssertion.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/assertion/FlutterViewAssertion.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Constants.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Constants.java index 170830fc7abb..359d50ae4fba 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Constants.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Constants.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Duration.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Duration.java index 1d7bac224ec6..086ee47ad52c 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Duration.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/common/Duration.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/AmbiguousWidgetMatcherException.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/AmbiguousWidgetMatcherException.java index adf2e39db0b8..c0f1a06f5733 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/AmbiguousWidgetMatcherException.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/AmbiguousWidgetMatcherException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/InvalidFlutterViewException.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/InvalidFlutterViewException.java index 16c49220e0b9..d2d32869dd66 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/InvalidFlutterViewException.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/InvalidFlutterViewException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/NoMatchingWidgetException.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/NoMatchingWidgetException.java index 55ce0f4e3935..756710f790c5 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/NoMatchingWidgetException.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/exception/NoMatchingWidgetException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdException.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdException.java index 5be422184fe6..94c2d86db922 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdException.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerator.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerator.java index ee6d693d97ee..23d02373e856 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerator.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerator.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerators.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerators.java index 28d6816b7306..d14d8c50eaac 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerators.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/idgenerator/IdGenerators.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/JsonRpcClient.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/JsonRpcClient.java index 7b5f8458a8f5..743c138fbf09 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/JsonRpcClient.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/JsonRpcClient.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java index bf31679d7b3b..877dffbe9ade 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/ErrorObject.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcRequest.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcRequest.java index 6eff736b5434..09bc7bbfe770 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcRequest.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcRequest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcResponse.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcResponse.java index 45b376a3f793..460aaa48a17c 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcResponse.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/jsonrpc/message/JsonRpcResponse.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java index 7e3b277558c9..a1cdd977066c 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmService.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java index 2534cc4d4736..63c62c4f5046 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/DartVmServiceUtil.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/FlutterProtocolException.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/FlutterProtocolException.java index b2b182f10640..26865a31098f 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/FlutterProtocolException.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/FlutterProtocolException.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetAction.java index 4dbf78836223..d668d4a303f7 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetResponse.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetResponse.java index 202f774f5d6b..a86cccbf1b6d 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetResponse.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetOffsetResponse.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetVmResponse.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetVmResponse.java index e3f97afb97fa..94cac364ddc7 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetVmResponse.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetVmResponse.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsAction.java index 4753dd3dc451..6aa030a1d669 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsResponse.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsResponse.java index 6ee27de06705..b0c8b4246b8a 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsResponse.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/GetWidgetDiagnosticsResponse.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingFrameCondition.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingFrameCondition.java index 64c37d31a782..2051f947f619 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingFrameCondition.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingFrameCondition.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingPlatformMessagesCondition.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingPlatformMessagesCondition.java index 7969ef851b3e..9145e5cd4aac 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingPlatformMessagesCondition.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoPendingPlatformMessagesCondition.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoTransientCallbacksCondition.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoTransientCallbacksCondition.java index d4eb77810d0b..35aa5385fba9 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoTransientCallbacksCondition.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/NoTransientCallbacksCondition.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitCondition.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitCondition.java index 5baba66b89cb..868a877bbb1c 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitCondition.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitCondition.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitForConditionAction.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitForConditionAction.java index 2880130e8438..b8ca1846c8c3 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitForConditionAction.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WaitForConditionAction.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WidgetInfoFactory.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WidgetInfoFactory.java index 264f6cb77e5d..46269678b97b 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WidgetInfoFactory.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/internal/protocol/impl/WidgetInfoFactory.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java index 634e2197ee94..9db88665f8e7 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/FlutterMatchers.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsDescendantOfMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsDescendantOfMatcher.java index 947a0f79cad4..81c33d9b2fdb 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsDescendantOfMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsDescendantOfMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsExistingMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsExistingMatcher.java index 843d331d10a3..f077254be8f6 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsExistingMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/IsExistingMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTextMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTextMatcher.java index 711a835a45a5..99d630bbb1c4 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTextMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTextMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTooltipMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTooltipMatcher.java index fde9cd805ce8..78c14673a55d 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTooltipMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTooltipMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTypeMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTypeMatcher.java index b30fdf38674c..cea0572ed1b6 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTypeMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithTypeMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithValueKeyMatcher.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithValueKeyMatcher.java index 719f8adcab4d..fba9ec5dc5ac 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithValueKeyMatcher.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/matcher/WithValueKeyMatcher.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfo.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfo.java index 5b90a0002b53..9d8671fbcf2e 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfo.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfo.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfoBuilder.java b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfoBuilder.java index c119278af645..029111a6cb9b 100644 --- a/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfoBuilder.java +++ b/packages/espresso/android/src/main/java/androidx/test/espresso/flutter/model/WidgetInfoBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/android/src/main/java/com/example/espresso/EspressoPlugin.java b/packages/espresso/android/src/main/java/com/example/espresso/EspressoPlugin.java index 634b5fe53ad7..6c8620b3ca14 100644 --- a/packages/espresso/android/src/main/java/com/example/espresso/EspressoPlugin.java +++ b/packages/espresso/android/src/main/java/com/example/espresso/EspressoPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/example/android/app/src/androidTest/java/com/example/MainActivityTest.java b/packages/espresso/example/android/app/src/androidTest/java/com/example/MainActivityTest.java index 8a432809e9cb..739d49c1f9b0 100644 --- a/packages/espresso/example/android/app/src/androidTest/java/com/example/MainActivityTest.java +++ b/packages/espresso/example/android/app/src/androidTest/java/com/example/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/example/android/app/src/main/java/com/example/espresso_example/MainActivity.java b/packages/espresso/example/android/app/src/main/java/com/example/espresso_example/MainActivity.java index ff62ed2521d5..7b2675e21399 100644 --- a/packages/espresso/example/android/app/src/main/java/com/example/espresso_example/MainActivity.java +++ b/packages/espresso/example/android/app/src/main/java/com/example/espresso_example/MainActivity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/example/lib/main.dart b/packages/espresso/example/lib/main.dart index 2ab6632113d5..de9387ee2fd9 100644 --- a/packages/espresso/example/lib/main.dart +++ b/packages/espresso/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/espresso/example/test_driver/example.dart b/packages/espresso/example/test_driver/example.dart index 42acdeb61a2c..630db5e25420 100644 --- a/packages/espresso/example/test_driver/example.dart +++ b/packages/espresso/example/test_driver/example.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector/LICENSE b/packages/file_selector/file_selector/LICENSE index 67c7e2c52e46..c6823b81eb84 100644 --- a/packages/file_selector/file_selector/LICENSE +++ b/packages/file_selector/file_selector/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/file_selector/file_selector/example/lib/get_directory_page.dart b/packages/file_selector/file_selector/example/lib/get_directory_page.dart index be278f374fa8..6022559ce40e 100644 --- a/packages/file_selector/file_selector/example/lib/get_directory_page.dart +++ b/packages/file_selector/file_selector/example/lib/get_directory_page.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector/example/lib/home_page.dart b/packages/file_selector/file_selector/example/lib/home_page.dart index 842094c9acaa..ab0b5c32187c 100644 --- a/packages/file_selector/file_selector/example/lib/home_page.dart +++ b/packages/file_selector/file_selector/example/lib/home_page.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector/example/lib/main.dart b/packages/file_selector/file_selector/example/lib/main.dart index e355109d1799..bd4c9b7ab853 100644 --- a/packages/file_selector/file_selector/example/lib/main.dart +++ b/packages/file_selector/file_selector/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector/example/lib/open_image_page.dart b/packages/file_selector/file_selector/example/lib/open_image_page.dart index da11ead1c09f..ae0d5ad4eefb 100644 --- a/packages/file_selector/file_selector/example/lib/open_image_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_image_page.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart index d91d126c940f..5bf080eff450 100644 --- a/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_multiple_images_page.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector/example/lib/open_text_page.dart b/packages/file_selector/file_selector/example/lib/open_text_page.dart index 52296abd4379..8451378f7baa 100644 --- a/packages/file_selector/file_selector/example/lib/open_text_page.dart +++ b/packages/file_selector/file_selector/example/lib/open_text_page.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector/example/lib/save_text_page.dart b/packages/file_selector/file_selector/example/lib/save_text_page.dart index 982692bc40f8..1610fc05164d 100644 --- a/packages/file_selector/file_selector/example/lib/save_text_page.dart +++ b/packages/file_selector/file_selector/example/lib/save_text_page.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector/example/web/index.html b/packages/file_selector/file_selector/example/web/index.html index 97b1100c4244..c6fa1623be95 100644 --- a/packages/file_selector/file_selector/example/web/index.html +++ b/packages/file_selector/file_selector/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/file_selector/file_selector/lib/file_selector.dart b/packages/file_selector/file_selector/lib/file_selector.dart index cdb2bf9c726d..c2803d60c972 100644 --- a/packages/file_selector/file_selector/lib/file_selector.dart +++ b/packages/file_selector/file_selector/lib/file_selector.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector/test/file_selector_test.dart b/packages/file_selector/file_selector/test/file_selector_test.dart index b16f234bb3b8..6d5e215eeb01 100644 --- a/packages/file_selector/file_selector/test/file_selector_test.dart +++ b/packages/file_selector/file_selector/test/file_selector_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_platform_interface/LICENSE b/packages/file_selector/file_selector_platform_interface/LICENSE index 67c7e2c52e46..c6823b81eb84 100644 --- a/packages/file_selector/file_selector_platform_interface/LICENSE +++ b/packages/file_selector/file_selector_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/file_selector/file_selector_platform_interface/lib/file_selector_platform_interface.dart b/packages/file_selector/file_selector_platform_interface/lib/file_selector_platform_interface.dart index dcd87aaed4a7..5e9a9fefa0bc 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/file_selector_platform_interface.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/file_selector_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart b/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart index e14239f51690..34017acc90e0 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/method_channel/method_channel_file_selector.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart b/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart index 0be02c2185dd..54a6557c4428 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/platform_interface/file_selector_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart index 65a0bdcd1583..9caee27c3e35 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/types/types.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart index 7b3cb12be9f1..3e3326379610 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/types/x_type_group/x_type_group.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart b/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart index f9e33aed1389..0f157ed0be5a 100644 --- a/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart +++ b/packages/file_selector/file_selector_platform_interface/lib/src/web_helpers/web_helpers.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_platform_interface/test/file_selector_platform_interface_test.dart b/packages/file_selector/file_selector_platform_interface/test/file_selector_platform_interface_test.dart index 56f6ae91bf28..f5b609c93ed3 100644 --- a/packages/file_selector/file_selector_platform_interface/test/file_selector_platform_interface_test.dart +++ b/packages/file_selector/file_selector_platform_interface/test/file_selector_platform_interface_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_platform_interface/test/method_channel_file_selector_test.dart b/packages/file_selector/file_selector_platform_interface/test/method_channel_file_selector_test.dart index c863ad361112..96a3c2d4f4c9 100644 --- a/packages/file_selector/file_selector_platform_interface/test/method_channel_file_selector_test.dart +++ b/packages/file_selector/file_selector_platform_interface/test/method_channel_file_selector_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart b/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart index 21bbac5d0f90..e85a4929e411 100644 --- a/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart +++ b/packages/file_selector/file_selector_platform_interface/test/x_type_group_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_web/LICENSE b/packages/file_selector/file_selector_web/LICENSE index 67c7e2c52e46..c6823b81eb84 100644 --- a/packages/file_selector/file_selector_web/LICENSE +++ b/packages/file_selector/file_selector_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart index 274aed93659e..f000574861ab 100644 --- a/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart index ea9569bf00a9..c16aa1cf454e 100644 --- a/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_web/example/run_test.sh b/packages/file_selector/file_selector_web/example/run_test.sh index a381127c2716..0542b53cd6c9 100755 --- a/packages/file_selector/file_selector_web/example/run_test.sh +++ b/packages/file_selector/file_selector_web/example/run_test.sh @@ -1,5 +1,5 @@ #!/usr/bin/bash -# Copyright 2017 The Flutter Authors. All rights reserved. +# Copyright 2013 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. diff --git a/packages/file_selector/file_selector_web/example/test_driver/integration_test.dart b/packages/file_selector/file_selector_web/example/test_driver/integration_test.dart index 44d6ed9c64bc..4f10f2a522f3 100644 --- a/packages/file_selector/file_selector_web/example/test_driver/integration_test.dart +++ b/packages/file_selector/file_selector_web/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_web/example/web/index.html b/packages/file_selector/file_selector_web/example/web/index.html index dc8d0cfe0428..dc9f89762aec 100644 --- a/packages/file_selector/file_selector_web/example/web/index.html +++ b/packages/file_selector/file_selector_web/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/file_selector/file_selector_web/lib/file_selector_web.dart b/packages/file_selector/file_selector_web/lib/file_selector_web.dart index cf95e403effc..f7c10b36a186 100644 --- a/packages/file_selector/file_selector_web/lib/file_selector_web.dart +++ b/packages/file_selector/file_selector_web/lib/file_selector_web.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart index 5c578b6f4639..0d251af9cc7f 100644 --- a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart +++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_web/lib/src/utils.dart b/packages/file_selector/file_selector_web/lib/src/utils.dart index 6be58c2aa0ec..e52c00d1c223 100644 --- a/packages/file_selector/file_selector_web/lib/src/utils.dart +++ b/packages/file_selector/file_selector_web/lib/src/utils.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart b/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart index 6aaf4475d537..37c6eb644c9b 100644 --- a/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart +++ b/packages/file_selector/file_selector_web/test/more_tests_exist_elsewhere_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/file_selector/file_selector_web/test/utils_test.dart b/packages/file_selector/file_selector_web/test/utils_test.dart index e3e47c00f176..2951af24dff9 100644 --- a/packages/file_selector/file_selector_web/test/utils_test.dart +++ b/packages/file_selector/file_selector_web/test/utils_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/flutter_plugin_android_lifecycle/LICENSE b/packages/flutter_plugin_android_lifecycle/LICENSE index b257ce7c224c..c6823b81eb84 100644 --- a/packages/flutter_plugin_android_lifecycle/LICENSE +++ b/packages/flutter_plugin_android_lifecycle/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapter.java b/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapter.java index 3c91bb744d5c..05490eb93e46 100644 --- a/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapter.java +++ b/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapter.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle/FlutterAndroidLifecyclePlugin.java b/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle/FlutterAndroidLifecyclePlugin.java index fa90a210ffd2..e3b8ea2a6318 100644 --- a/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle/FlutterAndroidLifecyclePlugin.java +++ b/packages/flutter_plugin_android_lifecycle/android/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle/FlutterAndroidLifecyclePlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. // diff --git a/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java b/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java index c184b1ad88db..08bb3d7266e8 100644 --- a/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java +++ b/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/EmbeddingV1ActivityTest.java b/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/EmbeddingV1ActivityTest.java index 89b9192c1676..84173f4a9c0f 100644 --- a/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/EmbeddingV1ActivityTest.java +++ b/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/MainActivityTest.java b/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/MainActivityTest.java index 22bc3fe68d46..66a606ca00a9 100644 --- a/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/MainActivityTest.java +++ b/packages/flutter_plugin_android_lifecycle/example/android/app/src/androidTest/java/io/flutter/plugins/flutter_plugin_android_lifecycle/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/EmbeddingV1Activity.java b/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/EmbeddingV1Activity.java index 5859e177b2fc..e6ab004fccf6 100644 --- a/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/EmbeddingV1Activity.java +++ b/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/MainActivity.java b/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/MainActivity.java index a05da9ebb71a..1726aecbeddb 100644 --- a/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/MainActivity.java +++ b/packages/flutter_plugin_android_lifecycle/example/android/app/src/main/java/io/flutter/plugins/flutter_plugin_android_lifecycle_example/MainActivity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart b/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart index 8890f14925ab..b9861166147c 100644 --- a/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart +++ b/packages/flutter_plugin_android_lifecycle/example/integration_test/flutter_plugin_android_lifecycle_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/flutter_plugin_android_lifecycle/example/lib/main.dart b/packages/flutter_plugin_android_lifecycle/example/lib/main.dart index d9ee842364a6..c019590b2a7c 100644 --- a/packages/flutter_plugin_android_lifecycle/example/lib/main.dart +++ b/packages/flutter_plugin_android_lifecycle/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart b/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart index 38bb867225d1..340b06832f19 100644 --- a/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart +++ b/packages/flutter_plugin_android_lifecycle/lib/flutter_plugin_android_lifecycle.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/LICENSE b/packages/google_maps_flutter/google_maps_flutter/LICENSE index 050e2c7cac4f..c6823b81eb84 100644 --- a/packages/google_maps_flutter/google_maps_flutter/LICENSE +++ b/packages/google_maps_flutter/google_maps_flutter/LICENSE @@ -1,4 +1,4 @@ -Copyright 2018 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleBuilder.java index 230659d2bf71..b52017523e3c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleController.java index 27accafd9bd9..6ecc86220c0d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleOptionsSink.java index 51e6c2194ab7..719fc77660ae 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CircleOptionsSink.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java index d9661e9e80f8..d128d9544b1f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 30e7339f3de5..72c6959fe55e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java index 8d3414edfc4c..ad5179a69a45 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index 92d0e044e577..05e016c32e27 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java index 96cfee088ad3..ca9ac184a76e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java index c240f89deddb..0a5c3ec67e27 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java index 4ed31fabdab0..17f0d970a4ef 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java index 0a0a17a05f47..763cd9e3e72e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/LifecycleProvider.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/LifecycleProvider.java index 0e06321e7267..a3b6c0a3adf0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/LifecycleProvider.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/LifecycleProvider.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java index 69637a12bff0..ecc5f01bc87c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java index 667254ea9d7f..5c568a1c9a1e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java index 25ed42927189..88c970c1f14b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java index 8a9897886f11..189cba03c1cd 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java index 149c1246f596..072fa746958f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java index 3fe58f2fb900..e66f05e18f93 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java index 6b4aea89efc1..e9b0ec1413a2 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonOptionsSink.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java index 734525b2b0a3..6f855db07996 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineBuilder.java index 2a8718710262..9120a1618237 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineController.java index 172c807eb2a2..8bd84f5906f2 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineOptionsSink.java index d05059860d68..5b3f193617cb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylineOptionsSink.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java index b6f3a90f4745..399634933dc9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java index cbe6cfbd5e51..ecbc2f8f9ee1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java index 9f07d7e6859f..7405b5fcc496 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlayController.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java index b32ae8fb6f67..d167af7d4a6d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaySink.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java index f72dd7d6c1af..82a3edcb32c0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java index e760fafca8b7..f05d04550994 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/TileProviderController.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java index 5b24902e17f1..269c35ebd864 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java index 33765e71e7a1..72a8cab626b5 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/CircleControllerTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java index 0d167a5dbe1e..c781afc0ede9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java index f4a0248240a4..29234b6adb42 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolygonControllerTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java index bca2ebe5b8ce..9e2e9e81b829 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java index 7cfa33acbd7c..bb7653aa2293 100644 --- a/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/android/src/test/java/io/flutter/plugins/googlemaps/PolylineControllerTest.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/EmbeddingV1ActivityTest.java b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/EmbeddingV1ActivityTest.java index 5ade4367835a..9da7185b8ace 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/EmbeddingV1ActivityTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/MainActivityTest.java b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/MainActivityTest.java index 7c624bb556a9..fccd4c95c3ac 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/MainActivityTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/androidTest/java/io/flutter/plugins/googlemaps/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/main/java/io/flutter/plugins/googlemapsexample/EmbeddingV1Activity.java b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/main/java/io/flutter/plugins/googlemapsexample/EmbeddingV1Activity.java index 9924fa03e3aa..cecf76a690e0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/main/java/io/flutter/plugins/googlemapsexample/EmbeddingV1Activity.java +++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/main/java/io/flutter/plugins/googlemapsexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java index 7b81f287a9d1..2a81479988e0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart index 02e1ac430e2e..fa19705d8287 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_map_inspector.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. // @dart=2.9 diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart index 0230a2157297..e50231293775 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/google_maps_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. // @dart=2.9 diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.h b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.h index 8e973d51585b..9bc6c56e34f9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.h +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.m b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.m index b22c283d4704..d050cf771c8f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.m +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/main.m b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/main.m +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart index 6581bc0af7b8..cc5fd257dfd3 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/animate_camera.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart index cb7fe0b861d8..f6d6f54e135a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart index 9a6cf91a987d..15b14db0357a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart index cea5c3ee3d35..a46fc5fba420 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_click.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart index 4819fcbd577b..99ab16802fea 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_coordinates.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart index 703523efc2ec..2e0d2d188a3f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart index d37fe5fb2203..da57b83a7e4f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart index add70fbdd7a8..f8274196770d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/move_camera.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart index fa35ae0c90f3..d90005fa6998 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/padding.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/page.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/page.dart index 536cbbc361d3..fb6eb3260f6d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/page.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/page.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart index 9885747e7cba..a4953428f088 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_circle.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart index 8ba85eff1b37..4e9f4c14ebd0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart index 192416a92e01..476084defa75 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polygon.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart index 7f24979b5ed1..aeb9bf1b11eb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_polyline.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart index 684a66b993ef..9611d36bc8e8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/scrolling_map.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart index fadfc1775f31..c85048f5b5aa 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/snapshot.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart index a8cb34133dcf..a367511cb72f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart index 80715b0ee874..ab30698581d0 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. // @dart=2.9 diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h index 5ef5eb86dfbb..356a13faba62 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m index 68884c650ecb..fb391380c92c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h index ca815956de9a..953c0557ff20 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m index 2b345a1ddee2..7ce2cf1c204d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h index 2a8022a3ef2a..2e7a9967ebd3 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m index 25c0f37b427b..bdf36484aaf7 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h index f261722cf7e1..a8cebb983347 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m index a823c4bbe660..bf47dfab12b7 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h index 468c399e808f..d3e835435ed9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m index a6d395b0c505..6a9fb885afac 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h index ad611a759548..b123ac0a3d68 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m index 445e4aebde1d..5ad8d4d3bc0e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h index c0f46070c945..f7fafc2f065f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m index 0d54cf13c458..8c70d2c161ba 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h index a0e09f7b6fe2..6ede4dbaf8b4 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m index d2fd2c1c82eb..592d7e825b38 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart index 11f674b197a3..93bb0566dd1f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart index 529950566ccc..ba18c5ffc17b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart index 82549c3b491a..26b9d6b83c84 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart index e6ac4331a935..8ee845469e25 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart index d39173197d31..e0d1180a0abb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/circle_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart index 5871745fc1da..37270ea34d29 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart index 0718d59a674b..2b754afbd359 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart index c90c47d0a038..6e0f5ed3e4f5 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/map_creation_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart index ec3a89b72886..e295393fe15a 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/marker_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart index f4df8ac137ad..79c63c1c5459 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/polygon_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart index c82693cad9c8..01eb2e2ce724 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/polyline_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart index c7f5ef8e8286..35732da29726 100644 --- a/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter/test/tile_overlay_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/LICENSE b/packages/google_maps_flutter/google_maps_flutter_platform_interface/LICENSE index 050e2c7cac4f..c6823b81eb84 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/LICENSE +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2018 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/google_maps_flutter_platform_interface.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/google_maps_flutter_platform_interface.dart index 3b01002e8d92..650a839cb676 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/google_maps_flutter_platform_interface.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/google_maps_flutter_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart index 9afc6db8cb94..be426483193d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index dee04c92db14..80a71b4edd2b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart index c38a87f5a5c0..425e040ee812 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart index 0f2192fda1db..d3dc37e327fe 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/callbacks.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/callbacks.dart index 62b535bec08e..3b484c1feb05 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/callbacks.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/callbacks.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart index a4d762e87f48..7cb6369e7f59 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/camera.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart index 9580a89189b8..f5f43209d828 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/cap.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart index 8d1d9ac7dbb6..1845195b31c6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart index b063a6bec0d6..f3fdbb447c94 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/circle_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/joint_type.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/joint_type.dart index 5dc15b394fd8..64e7a3d8cbdc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/joint_type.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/joint_type.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart index cd9d0ee6993f..42c66e036fd7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart index d8cdfdce9f48..77d958be01e2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart index 0d94b77b48f4..2e2eefa3d32e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/maps_object_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart index 014e5515e6cb..0d1b780c24d2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart index 8c0a1336ad32..27257c628033 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/marker_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart index 89422a3423ec..89f29d25e4cc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/pattern_item.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart index 78e25c1f91cf..569bd4c1f553 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart index cb5b2a1faf6a..8b62141ce03c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polygon_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart index f4d70dc1dcf8..c324aeb5f492 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart index 2fddcfe26619..30cd99f73229 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/polyline_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart index efbd77942a46..8c9c083913ce 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/screen_coordinate.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart index 4aa07669c2e7..d602b127f06c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart index d430623cdafe..55dca55f9d8e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart index 914aacdc8393..e40db7da10fe 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart index eb87bb6bb15d..dfe6937e24a4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_provider.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart index c49ad7c47171..5e2e4c234ccf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart index 3490c121acbc..38c34fcfd27f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ui.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart index e0374269daea..bf1754fdf399 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/circle.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart index 4418638353ce..da5a49825c7f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/maps_object.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart index 1c112a68ceb9..4be3f2a2f9a4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/marker.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart index 53e946e11943..ba4ce7d6f55f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polygon.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart index 0b163f7b84ee..8c188b021b2f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/polyline.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart index 9f8c51906abd..fae61a4b4433 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/tile_overlay.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart index be20335e834b..73cea10ec2d9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart index 81ca300a6955..6d02b2c630df 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart index aa48b7b74760..11665d904556 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/camera_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart index 4f9fc7cca2dd..c2ca2bdda5b7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart index 252303076a04..f09f70fd769e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/maps_object_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart index 077f823a1e05..b95ae50a8f08 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/test_maps_object.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart index ddcb693cc217..a17f86d4f19a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart index f2054c676d41..05be14e1ba0b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_updates_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart index f7f0c285168a..653958474185 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/LICENSE b/packages/google_maps_flutter/google_maps_flutter_web/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/LICENSE +++ b/packages/google_maps_flutter/google_maps_flutter_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart index 11d054a64c42..fd4df2ee4fd8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart index b33d8ae69205..dee37618c940 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart index a8858bedcdab..1a85f3bb28e1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart index e8526d9f314a..e9e458c85685 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/resources/icon_image_base64.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/resources/icon_image_base64.dart index 66814d8df7ca..6010f0107031 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/resources/icon_image_base64.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/resources/icon_image_base64.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart index 91ad7dfac90f..0c351971af7c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart index 3735bd06a5c8..9bb3599311d2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh index 9bfce94f63b2..dbf0ec55fd8f 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh @@ -1,5 +1,5 @@ #!/usr/bin/bash -# Copyright 2017 The Flutter Authors. All rights reserved. +# Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart index dba91905cd68..f26b6a310cfe 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html b/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html index 03feba172d74..d48ebfe62c37 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart index df2d04853c8a..0aa563ccb889 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart index ea24d4d6ab15..84bae1b98e2e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart index 6463c9e11ba1..659d8ac823a6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index ca15df56cbd0..c875bf782474 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart index 7ccce3bde370..cc8d79a6226d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart index 92ee16ad3d49..5e95a538c07a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart index c0efc6b5bdda..62238fc2d86b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart index a3128043d575..bc9827a20270 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart index 3cb5638846df..4ce1f022e586 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart index bb232d0d94a7..4671e6d77a87 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart index cf9de5b36d33..bf1dbb222555 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart index 9fbcf119100e..e91b82fd1947 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart index ec93f431138b..5eacec5fe867 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart index 2a8c7f5f5c6e..f2862af8b704 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_fake.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart index b6c2f8812a1b..276b768c76c5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/shims/dart_ui_real.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart index 0393cb205200..10b5199a894e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart index ab69a33ba215..442c50144727 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/tests_exist_elsewhere_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/LICENSE b/packages/google_sign_in/google_sign_in/LICENSE index 1d7bbaf70add..c6823b81eb84 100644 --- a/packages/google_sign_in/google_sign_in/LICENSE +++ b/packages/google_sign_in/google_sign_in/LICENSE @@ -1,4 +1,4 @@ -Copyright 2016 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java index 95bc0153e41a..b13ec7e3412a 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/BackgroundTaskRunner.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java index 008a33c30052..824c6da8ec9f 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/Executors.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index 351ed731cccd..3a63f785aa9f 100755 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java index 3c84968f986c..5af0b50136ce 100644 --- a/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java +++ b/packages/google_sign_in/google_sign_in/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInWrapper.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java index 215136625dc2..f61bb72ba9da 100644 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java index 893a13d2379b..cfd2fcec9ec3 100644 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java index 6ab856eca8bd..36787ffd9910 100644 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/main/java/io/flutter/plugins/googlesigninexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java index b2a13a712823..f1058760e2de 100644 --- a/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java +++ b/packages/google_sign_in/google_sign_in/example/android/app/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInPluginTests.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.h b/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.h +++ b/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.m b/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.m index 2147d3d605ac..30b87969f44a 100644 --- a/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.m +++ b/packages/google_sign_in/google_sign_in/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/example/ios/Runner/main.m b/packages/google_sign_in/google_sign_in/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/google_sign_in/google_sign_in/example/ios/Runner/main.m +++ b/packages/google_sign_in/google_sign_in/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/example/lib/main.dart b/packages/google_sign_in/google_sign_in/example/lib/main.dart index c87063297373..c677d4e75bc3 100755 --- a/packages/google_sign_in/google_sign_in/example/lib/main.dart +++ b/packages/google_sign_in/google_sign_in/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/example/web/index.html b/packages/google_sign_in/google_sign_in/example/web/index.html index 187eeb5ff8ff..5710c936c2ed 100644 --- a/packages/google_sign_in/google_sign_in/example/web/index.html +++ b/packages/google_sign_in/google_sign_in/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart index d3896b57174c..7a1522346e37 100644 --- a/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/integration_test/google_sign_in_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h index 6447e9243483..cb6b51aab1bf 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m index 23584fd36922..757578bb3a50 100644 --- a/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in/ios/Classes/FLTGoogleSignInPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m index d00ef82237c0..adbf61326c8d 100644 --- a/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m +++ b/packages/google_sign_in/google_sign_in/ios/Tests/GoogleSignInPluginTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart index 2e094a8b1575..6584156cc070 100644 --- a/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in/lib/google_sign_in.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/lib/src/common.dart b/packages/google_sign_in/google_sign_in/lib/src/common.dart index e341a27a740d..068403e74629 100644 --- a/packages/google_sign_in/google_sign_in/lib/src/common.dart +++ b/packages/google_sign_in/google_sign_in/lib/src/common.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/lib/src/fife.dart b/packages/google_sign_in/google_sign_in/lib/src/fife.dart index 14ecf5fd6083..ff048e249590 100644 --- a/packages/google_sign_in/google_sign_in/lib/src/fife.dart +++ b/packages/google_sign_in/google_sign_in/lib/src/fife.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/lib/testing.dart b/packages/google_sign_in/google_sign_in/lib/testing.dart index ed0ca4f2de7c..c4d2da3089a5 100644 --- a/packages/google_sign_in/google_sign_in/lib/testing.dart +++ b/packages/google_sign_in/google_sign_in/lib/testing.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/lib/widgets.dart b/packages/google_sign_in/google_sign_in/lib/widgets.dart index c3537ab90394..18f9973454f6 100644 --- a/packages/google_sign_in/google_sign_in/lib/widgets.dart +++ b/packages/google_sign_in/google_sign_in/lib/widgets.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/test/fife_test.dart b/packages/google_sign_in/google_sign_in/test/fife_test.dart index bfc4937a7c64..c81454ef0a8c 100644 --- a/packages/google_sign_in/google_sign_in/test/fife_test.dart +++ b/packages/google_sign_in/google_sign_in/test/fife_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart index 4eb45a5dc38e..f642bcd2eaf8 100755 --- a/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in/test/google_sign_in_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart b/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart index c85665696a0f..257b0d3c0930 100644 --- a/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart +++ b/packages/google_sign_in/google_sign_in/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/LICENSE b/packages/google_sign_in/google_sign_in_platform_interface/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/LICENSE +++ b/packages/google_sign_in/google_sign_in_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart index 560b72088978..42038879e90b 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/google_sign_in_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart index b2718d0f08b0..23c35ac240b9 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart index e20d44fae473..61231d1b70b9 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/types.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart index 14701897933a..4a70ec4d25ef 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/lib/src/utils.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart b/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart index e49f6a1074e2..b3ac51b7fa52 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/test/google_sign_in_platform_interface_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart index dbc5bb00f17f..390c12583a79 100644 --- a/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart +++ b/packages/google_sign_in/google_sign_in_platform_interface/test/method_channel_google_sign_in_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/LICENSE b/packages/google_sign_in/google_sign_in_web/LICENSE index 1d7bbaf70add..c6823b81eb84 100644 --- a/packages/google_sign_in/google_sign_in_web/LICENSE +++ b/packages/google_sign_in/google_sign_in_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2016 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart index 0df203f2f4d8..e1a97cee6cf7 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/auth2_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart index 0e0363bdd760..5da42283367f 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_load_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart index eb77900d27b6..43eb9a55d06b 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/gapi_mocks.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart index acda5d525a91..2a085ccf3588 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/auth2_init.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart index 587920494692..0e652c647a38 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/gapi.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart index 98e978641d3d..e5e6eb262502 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/google_user.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart index 277dfa39104a..c5aac367c1de 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_mocks/src/test_iife.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart index 2b439c9c74fb..1447093d4115 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/gapi_utils_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart b/packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart index f01c801dcb14..89f9b55f3ddf 100644 --- a/packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart +++ b/packages/google_sign_in/google_sign_in_web/example/integration_test/src/test_utils.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/run_test.sh b/packages/google_sign_in/google_sign_in_web/example/run_test.sh index d6b5dbb18ae9..fe30bc8652d0 100755 --- a/packages/google_sign_in/google_sign_in_web/example/run_test.sh +++ b/packages/google_sign_in/google_sign_in_web/example/run_test.sh @@ -1,5 +1,5 @@ #!/usr/bin/bash -# Copyright 2017 The Flutter Authors. All rights reserved. +# Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart b/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart index dba91905cd68..f26b6a310cfe 100644 --- a/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart +++ b/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/example/web/index.html b/packages/google_sign_in/google_sign_in_web/example/web/index.html index 59a832b5de4c..9e1284771b82 100644 --- a/packages/google_sign_in/google_sign_in_web/example/web/index.html +++ b/packages/google_sign_in/google_sign_in_web/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart index 320dad4ea220..f40b42b1881e 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/google_sign_in_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart index d2c00a840597..a7ee1cdd3314 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart index b42486b9fd7f..0dec17dbd19c 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart b/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart index 5aad2d9c52ba..6d8c566f0412 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/load_gapi.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart b/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart index 12cdd0a3162b..bcfefc2054b4 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/utils.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart b/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart index 64d8e547e485..442c50144727 100644 --- a/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart +++ b/packages/google_sign_in/google_sign_in_web/test/tests_exist_elsewhere_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/LICENSE b/packages/image_picker/image_picker/LICENSE index 7cd0a6f3b98f..0be8bbc3e68d 100644 --- a/packages/image_picker/image_picker/LICENSE +++ b/packages/image_picker/image_picker/LICENSE @@ -1,6 +1,6 @@ image_picker -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ExifDataCopier.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ExifDataCopier.java index 08b010072585..eada546f029a 100644 --- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ExifDataCopier.java +++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ExifDataCopier.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java index 19e304ea9eee..1f51a226c7e2 100644 --- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java +++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/FileUtils.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java index 45ba6de0ee6b..3df0a4108b5c 100644 --- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java +++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java index ff7f1534a586..29d7c8529a99 100644 --- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java +++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerFileProvider.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerFileProvider.java index ca7f6b064b39..7416665c49c1 100644 --- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerFileProvider.java +++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerFileProvider.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java index 74556f9cd6cc..98b64101bed7 100644 --- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java +++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java index 65b05e7ac3cc..ba9878925575 100644 --- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java +++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java index 27a145567a31..2a93785678af 100644 --- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java +++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1Activity.java b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1Activity.java index 215fcfdb9212..b9d2808a4486 100644 --- a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1Activity.java +++ b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1ActivityTest.java b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1ActivityTest.java index 34a827eed3ae..7d790563abae 100644 --- a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1ActivityTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/FlutterActivityTest.java b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/FlutterActivityTest.java index cfe112e39cb2..1ca37ce5feb7 100644 --- a/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/FlutterActivityTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/main/java/io/flutter/plugins/imagepickerexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java index bd705d2374e5..32e3ebc6183d 100644 --- a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/FileUtilTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java index 51733a503a92..92070e7a65c5 100644 --- a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java index 858d929dbc5d..a6858f2bd3b0 100644 --- a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java index 27bc57bd2dcd..2e50a220c752 100644 --- a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java index 4968d844f824..73cfef9e88ea 100644 --- a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.h b/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.h +++ b/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.m b/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.m index abfe2106b092..b790a0a52635 100644 --- a/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.m +++ b/packages/image_picker/image_picker/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/ios/Runner/main.m b/packages/image_picker/image_picker/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/image_picker/image_picker/example/ios/Runner/main.m +++ b/packages/image_picker/image_picker/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m index 68ca6304e17e..a3ca1a1f8892 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/lib/main.dart b/packages/image_picker/image_picker/example/lib/main.dart index 54e3a1ae4cd2..ff9f4a03cebc 100755 --- a/packages/image_picker/image_picker/example/lib/main.dart +++ b/packages/image_picker/image_picker/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart b/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart index b02d7d397106..4c4c006068b8 100644 --- a/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart +++ b/packages/image_picker/image_picker/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/example/web/index.html b/packages/image_picker/image_picker/example/web/index.html index a692cdb87e02..b05fdf840323 100644 --- a/packages/image_picker/image_picker/example/web/index.html +++ b/packages/image_picker/image_picker/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart b/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart index 953acd1a8da3..528c8b9f127a 100644 --- a/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart +++ b/packages/image_picker/image_picker/integration_test/old_image_picker_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerImageUtil.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerImageUtil.h index e809744f76d9..02b58d38a12e 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerImageUtil.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerImageUtil.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerImageUtil.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerImageUtil.m index ab765208d0bc..2f6ead7317b9 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerImageUtil.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerImageUtil.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerMetaDataUtil.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerMetaDataUtil.h index 9f7c19aae1b4..d5a20ffc6d2e 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerMetaDataUtil.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerMetaDataUtil.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerMetaDataUtil.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerMetaDataUtil.m index 9786f61e1e67..1419584a4675 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerMetaDataUtil.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerMetaDataUtil.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h index 1e6fda2cf786..ce37ff715caf 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m index f6727334060a..caadc8ba4864 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h index b6d8687a32e3..3b3551d53461 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 8d260f31b055..9159ea4c990b 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m b/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m index f34fa7049616..04ba4b98e241 100644 --- a/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m +++ b/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.h b/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.h index 8ba64a4d03b6..1074a5c62455 100644 --- a/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.h +++ b/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.m b/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.m index 536e3b3cba8e..a0bae7b8f91c 100644 --- a/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.m +++ b/packages/image_picker/image_picker/ios/Tests/ImagePickerTestImages.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Tests/ImageUtilTests.m b/packages/image_picker/image_picker/ios/Tests/ImageUtilTests.m index 87c8249e78a4..958c99f9c651 100644 --- a/packages/image_picker/image_picker/ios/Tests/ImageUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/ImageUtilTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Tests/MetaDataUtilTests.m b/packages/image_picker/image_picker/ios/Tests/MetaDataUtilTests.m index 505ccbfecab8..e1dbfad77b5d 100644 --- a/packages/image_picker/image_picker/ios/Tests/MetaDataUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/MetaDataUtilTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m index ac408b22c387..2a1ba75b0608 100644 --- a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/lib/image_picker.dart b/packages/image_picker/image_picker/lib/image_picker.dart index 22315100c961..77c26d40346a 100755 --- a/packages/image_picker/image_picker/lib/image_picker.dart +++ b/packages/image_picker/image_picker/lib/image_picker.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker/test/image_picker_test.dart b/packages/image_picker/image_picker/test/image_picker_test.dart index 0508d257016d..f56d47ff262b 100644 --- a/packages/image_picker/image_picker/test/image_picker_test.dart +++ b/packages/image_picker/image_picker/test/image_picker_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker_for_web/LICENSE b/packages/image_picker/image_picker_for_web/LICENSE index b257ce7c224c..c6823b81eb84 100644 --- a/packages/image_picker/image_picker_for_web/LICENSE +++ b/packages/image_picker/image_picker_for_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart index 75e185470d60..2fb66380e1d8 100644 --- a/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart +++ b/packages/image_picker/image_picker_for_web/lib/image_picker_for_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart index aa97170bf800..fbdd1d38bee6 100644 --- a/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart +++ b/packages/image_picker/image_picker_for_web/test/image_picker_for_web_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker_platform_interface/LICENSE b/packages/image_picker/image_picker_platform_interface/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/image_picker/image_picker_platform_interface/LICENSE +++ b/packages/image_picker/image_picker_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart b/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart index e04027cbd744..b384e3845c4b 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/image_picker_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. 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 272a018a3e35..429c51bc8923 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. 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 66986d35719f..3bbf4221ff50 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/camera_device.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/camera_device.dart index 658adc5f2c7f..45dfe3ac96aa 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/camera_device.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/camera_device.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/image_source.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/image_source.dart index 6676a9dab30b..ed907dc54c48 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/image_source.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/image_source.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. 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 a6cbeeed5c97..de259e0611dd 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. 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 8e757774042b..24e1931008b6 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. 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 08c172a98a05..7037b6b7121a 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. 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 3bd9a696d035..64f6a1f27538 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 @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart index 34fa2f624f0d..c8c9e5a0ac79 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart index 25a0a73d49a9..ad3ed6a4f86a 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/unsupported.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/retrieve_type.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/retrieve_type.dart index 3090513b5b8d..445445e5d7fb 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/retrieve_type.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/retrieve_type.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. 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 c07ac524335e..10e7745f2741 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,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. 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 df35f8fd96b8..26217334aeb3 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 @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. 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 00d6e99ec0bf..7721f66148e0 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 @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart index c721326e17a4..d366204c36bf 100644 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_io_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/LICENSE b/packages/in_app_purchase/LICENSE index 050e2c7cac4f..c6823b81eb84 100644 --- a/packages/in_app_purchase/LICENSE +++ b/packages/in_app_purchase/LICENSE @@ -1,4 +1,4 @@ -Copyright 2018 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java index 915a18eee7ac..7b21cbf2e6f5 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java index 38e59321ce8a..c256d2c59551 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java index f412b517cf1c..e4719f030d53 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java index 1663c39cfa0f..cfcb81ae05b5 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java index 04f980429eaf..54c775d0ad0f 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java index c7e7e9029ebd..37e30cbfed06 100644 --- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java +++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java index dd4ad6db07a7..c74ad9447e81 100644 --- a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java +++ b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java index 165bc4b42c67..55d97a658ec0 100644 --- a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java +++ b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java index eaacdf16282d..a60599573d57 100644 --- a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java +++ b/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java index 248e4105b200..bcee5428eac9 100644 --- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java +++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java index 374dc3297e9e..4d7a02220cf5 100644 --- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java +++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java index 63f670dc26e1..47147e772bce 100644 --- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java +++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/ios/Runner/AppDelegate.h b/packages/in_app_purchase/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/in_app_purchase/example/ios/Runner/AppDelegate.h +++ b/packages/in_app_purchase/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/ios/Runner/AppDelegate.m b/packages/in_app_purchase/example/ios/Runner/AppDelegate.m index 2147d3d605ac..30b87969f44a 100644 --- a/packages/in_app_purchase/example/ios/Runner/AppDelegate.m +++ b/packages/in_app_purchase/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/ios/Runner/main.m b/packages/in_app_purchase/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/in_app_purchase/example/ios/Runner/main.m +++ b/packages/in_app_purchase/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/lib/consumable_store.dart b/packages/in_app_purchase/example/lib/consumable_store.dart index 271291ca6eee..4d10a50e1ee8 100644 --- a/packages/in_app_purchase/example/lib/consumable_store.dart +++ b/packages/in_app_purchase/example/lib/consumable_store.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/lib/main.dart b/packages/in_app_purchase/example/lib/main.dart index 2172ca3480f5..58cca9162b17 100644 --- a/packages/in_app_purchase/example/lib/main.dart +++ b/packages/in_app_purchase/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/example/test_driver/test/integration_test.dart b/packages/in_app_purchase/example/test_driver/test/integration_test.dart index b02d7d397106..4c4c006068b8 100644 --- a/packages/in_app_purchase/example/test_driver/test/integration_test.dart +++ b/packages/in_app_purchase/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/integration_test/in_app_purchase_test.dart b/packages/in_app_purchase/integration_test/in_app_purchase_test.dart index f7edfb71412c..ca1eea640655 100644 --- a/packages/in_app_purchase/integration_test/in_app_purchase_test.dart +++ b/packages/in_app_purchase/integration_test/in_app_purchase_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.h b/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.h index 383e5440509a..2d0187e88aed 100644 --- a/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.h +++ b/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.m b/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.m index e54504a67218..5d6e0a244a96 100644 --- a/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.m +++ b/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.h b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.h index 797e4a6f4216..94020ff2348b 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.h +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m index deeed2873b30..526364020ad3 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m +++ b/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.h b/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.h index 6c75a9fcdf44..cbf21d6e161f 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.h +++ b/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.m b/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.m index 7172687956bf..8767265d8544 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.m +++ b/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h index 4776062aa04c..fddeb07e01a3 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h +++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m index 8eed06ce022c..eb3348e4b3c9 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m +++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h index 6974b33fd230..8cb42f3fe8c2 100644 --- a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h +++ b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m index b254e622e69f..650cd812d470 100644 --- a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m +++ b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m index 7ef757b7c4c5..cb00cbc2a43e 100644 --- a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m +++ b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m b/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m index f5248da74635..c335fa3ef307 100644 --- a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m +++ b/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m b/packages/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m index 25d11de5f6ad..19f5848b7168 100644 --- a/packages/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m +++ b/packages/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Tests/Stubs.h b/packages/in_app_purchase/ios/Tests/Stubs.h index f93d41325199..e07cc3f5a147 100644 --- a/packages/in_app_purchase/ios/Tests/Stubs.h +++ b/packages/in_app_purchase/ios/Tests/Stubs.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Tests/Stubs.m b/packages/in_app_purchase/ios/Tests/Stubs.m index 640352a82146..66610a88a77d 100644 --- a/packages/in_app_purchase/ios/Tests/Stubs.m +++ b/packages/in_app_purchase/ios/Tests/Stubs.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/ios/Tests/TranslatorTest.m b/packages/in_app_purchase/ios/Tests/TranslatorTest.m index e1db3d154310..550d1fc341c6 100644 --- a/packages/in_app_purchase/ios/Tests/TranslatorTest.m +++ b/packages/in_app_purchase/ios/Tests/TranslatorTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/billing_client_wrappers.dart b/packages/in_app_purchase/lib/billing_client_wrappers.dart index e8d13e7d2315..1dac19f825b8 100644 --- a/packages/in_app_purchase/lib/billing_client_wrappers.dart +++ b/packages/in_app_purchase/lib/billing_client_wrappers.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/in_app_purchase.dart b/packages/in_app_purchase/lib/in_app_purchase.dart index b197583614a6..928f860daa4b 100644 --- a/packages/in_app_purchase/lib/in_app_purchase.dart +++ b/packages/in_app_purchase/lib/in_app_purchase.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart index 909c4d70b101..1f43b3a8fbdd 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart index 0b1e96a19d53..1f5e2a286d6a 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart index 2353175b15b4..7ef089f4af8d 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart index bfaafb7faf08..e3d13df2262a 100644 --- a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart +++ b/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/channel.dart b/packages/in_app_purchase/lib/src/channel.dart index 9976ea6e23d1..f8ab4d48be7e 100644 --- a/packages/in_app_purchase/lib/src/channel.dart +++ b/packages/in_app_purchase/lib/src/channel.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index cf0b4df2fbbe..069cf7800599 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart index 044144e04f24..069dad5f40f3 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart index c53d40914874..a5db8e5d4206 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart b/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart index 0f23c3a8e557..151086d90f92 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart b/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart index e346c7f42e42..fc286d404de1 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart index 2a20b21eabb7..5a4438913338 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart index f4a766a9f4c6..2ba61b0a5d44 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart index edf0708b8041..01cd6db0dda1 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart index 045c2fcd5b07..ef0e6671d177 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart index 5cab368558a5..429cbf032812 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart index 6f143edd50da..88f3ac5835b5 100644 --- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart +++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/lib/store_kit_wrappers.dart b/packages/in_app_purchase/lib/store_kit_wrappers.dart index 3b94a17f9ad9..b687d238083c 100644 --- a/packages/in_app_purchase/lib/store_kit_wrappers.dart +++ b/packages/in_app_purchase/lib/store_kit_wrappers.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart index b1bfa7f3b6dd..9a5d262923f1 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart index 8aeef23cda3b..b6755262cf1c 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart b/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart index 46ec9c602e23..74af47266447 100644 --- a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart +++ b/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index 9b979e6ef021..dfab31906231 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart index d29c0e43d9bc..25feb89fed45 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart index 57932cd44af6..5bc3d92d735e 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart index 6508c83bceb1..e2db6ba7dde8 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart index 7c92a11962fb..09c730ec75b4 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart b/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart index 325b48931896..11a3426335d5 100644 --- a/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart +++ b/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/LICENSE b/packages/integration_test/LICENSE index b257ce7c224c..c6823b81eb84 100644 --- a/packages/integration_test/LICENSE +++ b/packages/integration_test/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterTestRunner.java b/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterTestRunner.java index 3cada2f44a58..25cd2a1f5521 100644 --- a/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterTestRunner.java +++ b/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterTestRunner.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/IntegrationTestPlugin.java b/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/IntegrationTestPlugin.java index 01adf98ad90d..7793b10f2db5 100644 --- a/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/IntegrationTestPlugin.java +++ b/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/IntegrationTestPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/EmbedderV1ActivityTest.java b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/EmbedderV1ActivityTest.java index 2ae8cbb37db2..18ac43ee9b39 100644 --- a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/EmbedderV1ActivityTest.java +++ b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/EmbedderV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityTest.java b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityTest.java index b84b290f175b..a607c06f9ce5 100644 --- a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityTest.java +++ b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityWithPermissionTest.java b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityWithPermissionTest.java index a8e868a76838..4752d2fcbcc3 100644 --- a/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityWithPermissionTest.java +++ b/packages/integration_test/example/android/app/src/androidTest/java/com/example/e2e_example/FlutterActivityWithPermissionTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/android/app/src/main/java/com/example/e2e_example/EmbedderV1Activity.java b/packages/integration_test/example/android/app/src/main/java/com/example/e2e_example/EmbedderV1Activity.java index fedd3626fa80..9dbed6e01e8b 100644 --- a/packages/integration_test/example/android/app/src/main/java/com/example/e2e_example/EmbedderV1Activity.java +++ b/packages/integration_test/example/android/app/src/main/java/com/example/e2e_example/EmbedderV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/integration_test/_example_test_io.dart b/packages/integration_test/example/integration_test/_example_test_io.dart index 01bcfe2928b1..eed73218bc3e 100644 --- a/packages/integration_test/example/integration_test/_example_test_io.dart +++ b/packages/integration_test/example/integration_test/_example_test_io.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/integration_test/_example_test_web.dart b/packages/integration_test/example/integration_test/_example_test_web.dart index f0fd6212615a..cfc5b90e180d 100644 --- a/packages/integration_test/example/integration_test/_example_test_web.dart +++ b/packages/integration_test/example/integration_test/_example_test_web.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/integration_test/_extended_test_io.dart b/packages/integration_test/example/integration_test/_extended_test_io.dart index ee0618a5adbc..1a727ee0552d 100644 --- a/packages/integration_test/example/integration_test/_extended_test_io.dart +++ b/packages/integration_test/example/integration_test/_extended_test_io.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/integration_test/_extended_test_web.dart b/packages/integration_test/example/integration_test/_extended_test_web.dart index 878d9949af20..cb0819fd5071 100644 --- a/packages/integration_test/example/integration_test/_extended_test_web.dart +++ b/packages/integration_test/example/integration_test/_extended_test_web.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/integration_test/example_test.dart b/packages/integration_test/example/integration_test/example_test.dart index 382094b9232f..9db52436de88 100644 --- a/packages/integration_test/example/integration_test/example_test.dart +++ b/packages/integration_test/example/integration_test/example_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/integration_test/extended_test.dart b/packages/integration_test/example/integration_test/extended_test.dart index b2a42ffafc00..6e3a40af0032 100644 --- a/packages/integration_test/example/integration_test/extended_test.dart +++ b/packages/integration_test/example/integration_test/extended_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/ios/Runner/AppDelegate.h b/packages/integration_test/example/ios/Runner/AppDelegate.h index d53a2aeb21ac..0681d288bb70 100644 --- a/packages/integration_test/example/ios/Runner/AppDelegate.h +++ b/packages/integration_test/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/ios/Runner/AppDelegate.m b/packages/integration_test/example/ios/Runner/AppDelegate.m index a1fd21cf937c..30b87969f44a 100644 --- a/packages/integration_test/example/ios/Runner/AppDelegate.m +++ b/packages/integration_test/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/ios/Runner/main.m b/packages/integration_test/example/ios/Runner/main.m index 4817030ede8d..f97b9ef5c8a1 100644 --- a/packages/integration_test/example/ios/Runner/main.m +++ b/packages/integration_test/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/ios/RunnerTests/RunnerTests.m b/packages/integration_test/example/ios/RunnerTests/RunnerTests.m index 15cc596a22cb..6b9c5a3cf5a8 100644 --- a/packages/integration_test/example/ios/RunnerTests/RunnerTests.m +++ b/packages/integration_test/example/ios/RunnerTests/RunnerTests.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/lib/main.dart b/packages/integration_test/example/lib/main.dart index 76d2378b32e1..796384bead77 100644 --- a/packages/integration_test/example/lib/main.dart +++ b/packages/integration_test/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/lib/my_app.dart b/packages/integration_test/example/lib/my_app.dart index bfcee0911064..8d497866bbb8 100644 --- a/packages/integration_test/example/lib/my_app.dart +++ b/packages/integration_test/example/lib/my_app.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/lib/my_web_app.dart b/packages/integration_test/example/lib/my_web_app.dart index b3efb24a54a8..c0ea09da24e4 100644 --- a/packages/integration_test/example/lib/my_web_app.dart +++ b/packages/integration_test/example/lib/my_web_app.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/macos/Runner/AppDelegate.swift b/packages/integration_test/example/macos/Runner/AppDelegate.swift index ca19fe95f8cf..5cec4c48f620 100644 --- a/packages/integration_test/example/macos/Runner/AppDelegate.swift +++ b/packages/integration_test/example/macos/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/macos/Runner/MainFlutterWindow.swift b/packages/integration_test/example/macos/Runner/MainFlutterWindow.swift index 2ce11b78604b..32aaeedceb1f 100644 --- a/packages/integration_test/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/integration_test/example/macos/Runner/MainFlutterWindow.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/test_driver/extended_integration_test.dart b/packages/integration_test/example/test_driver/extended_integration_test.dart index 059a3d13a2eb..22d93aa7b157 100644 --- a/packages/integration_test/example/test_driver/extended_integration_test.dart +++ b/packages/integration_test/example/test_driver/extended_integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/test_driver/failure.dart b/packages/integration_test/example/test_driver/failure.dart index a37306392321..72b7bab57ca7 100644 --- a/packages/integration_test/example/test_driver/failure.dart +++ b/packages/integration_test/example/test_driver/failure.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/test_driver/failure_test.dart b/packages/integration_test/example/test_driver/failure_test.dart index c90eaafa7090..21dfb08241fc 100644 --- a/packages/integration_test/example/test_driver/failure_test.dart +++ b/packages/integration_test/example/test_driver/failure_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/test_driver/integration_test.dart b/packages/integration_test/example/test_driver/integration_test.dart index 8c650ee9f293..4f10f2a522f3 100644 --- a/packages/integration_test/example/test_driver/integration_test.dart +++ b/packages/integration_test/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/example/web/index.html b/packages/integration_test/example/web/index.html index 492b9fd4cefc..3d58580ac205 100644 --- a/packages/integration_test/example/web/index.html +++ b/packages/integration_test/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/integration_test/ios/Classes/IntegrationTestIosTest.h b/packages/integration_test/ios/Classes/IntegrationTestIosTest.h index 19503385b70e..553cdbe2cd87 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestIosTest.h +++ b/packages/integration_test/ios/Classes/IntegrationTestIosTest.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/ios/Classes/IntegrationTestIosTest.m b/packages/integration_test/ios/Classes/IntegrationTestIosTest.m index 78cd0c28bbfb..55aebe9f3ff4 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestIosTest.m +++ b/packages/integration_test/ios/Classes/IntegrationTestIosTest.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/ios/Classes/IntegrationTestPlugin.h b/packages/integration_test/ios/Classes/IntegrationTestPlugin.h index 4593e31e1766..918aa8c51f4f 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestPlugin.h +++ b/packages/integration_test/ios/Classes/IntegrationTestPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/ios/Classes/IntegrationTestPlugin.m b/packages/integration_test/ios/Classes/IntegrationTestPlugin.m index 51ac0e34562f..081135e5f4e4 100644 --- a/packages/integration_test/ios/Classes/IntegrationTestPlugin.m +++ b/packages/integration_test/ios/Classes/IntegrationTestPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/lib/_callback_io.dart b/packages/integration_test/lib/_callback_io.dart index fe4e400be997..e6b5fd37004e 100644 --- a/packages/integration_test/lib/_callback_io.dart +++ b/packages/integration_test/lib/_callback_io.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/lib/_callback_web.dart b/packages/integration_test/lib/_callback_web.dart index bff8e8a9d31e..80bb4ad4ab5a 100644 --- a/packages/integration_test/lib/_callback_web.dart +++ b/packages/integration_test/lib/_callback_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/lib/_extension_io.dart b/packages/integration_test/lib/_extension_io.dart index 8f6f8ac8cad1..c3b95ff06618 100644 --- a/packages/integration_test/lib/_extension_io.dart +++ b/packages/integration_test/lib/_extension_io.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/lib/_extension_web.dart b/packages/integration_test/lib/_extension_web.dart index b83fc1eb292e..2f4be0cf0034 100644 --- a/packages/integration_test/lib/_extension_web.dart +++ b/packages/integration_test/lib/_extension_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/lib/common.dart b/packages/integration_test/lib/common.dart index 15b0c5c0d0cd..b523224e32b3 100644 --- a/packages/integration_test/lib/common.dart +++ b/packages/integration_test/lib/common.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/lib/integration_test.dart b/packages/integration_test/lib/integration_test.dart index 5a070a4fa9ef..d807b603c085 100644 --- a/packages/integration_test/lib/integration_test.dart +++ b/packages/integration_test/lib/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/lib/integration_test_driver.dart b/packages/integration_test/lib/integration_test_driver.dart index 3b0e756000d0..e06340d67f52 100644 --- a/packages/integration_test/lib/integration_test_driver.dart +++ b/packages/integration_test/lib/integration_test_driver.dart @@ -1,4 +1,4 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/lib/integration_test_driver_extended.dart b/packages/integration_test/lib/integration_test_driver_extended.dart index 613571e26abe..18514f12a102 100644 --- a/packages/integration_test/lib/integration_test_driver_extended.dart +++ b/packages/integration_test/lib/integration_test_driver_extended.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/test/binding_fail_test.dart b/packages/integration_test/test/binding_fail_test.dart index 34c4e6c647df..f5ff21f0cb86 100644 --- a/packages/integration_test/test/binding_fail_test.dart +++ b/packages/integration_test/test/binding_fail_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/test/binding_test.dart b/packages/integration_test/test/binding_test.dart index 449eab5525fc..500d65766da1 100644 --- a/packages/integration_test/test/binding_test.dart +++ b/packages/integration_test/test/binding_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/test/data/fail_test_script.dart b/packages/integration_test/test/data/fail_test_script.dart index 3e2ac31dbd7c..a3055d865049 100644 --- a/packages/integration_test/test/data/fail_test_script.dart +++ b/packages/integration_test/test/data/fail_test_script.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/test/data/pass_test_script.dart b/packages/integration_test/test/data/pass_test_script.dart index cb5eed12ab07..289af70e0005 100644 --- a/packages/integration_test/test/data/pass_test_script.dart +++ b/packages/integration_test/test/data/pass_test_script.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/test/data/pass_then_fail_test_script.dart b/packages/integration_test/test/data/pass_then_fail_test_script.dart index 0b0b67821284..d7de6e6c59f6 100644 --- a/packages/integration_test/test/data/pass_then_fail_test_script.dart +++ b/packages/integration_test/test/data/pass_then_fail_test_script.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/integration_test/test/response_serialization_test.dart b/packages/integration_test/test/response_serialization_test.dart index 54bd49780a5d..3ce6c05a53d6 100644 --- a/packages/integration_test/test/response_serialization_test.dart +++ b/packages/integration_test/test/response_serialization_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/ios_platform_images/LICENSE b/packages/ios_platform_images/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/ios_platform_images/LICENSE +++ b/packages/ios_platform_images/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/ios_platform_images/example/ios/Runner/AppDelegate.swift b/packages/ios_platform_images/example/ios/Runner/AppDelegate.swift index f26669f6bd4f..caf998393333 100644 --- a/packages/ios_platform_images/example/ios/Runner/AppDelegate.swift +++ b/packages/ios_platform_images/example/ios/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/ios_platform_images/example/ios/Runner/Runner-Bridging-Header.h b/packages/ios_platform_images/example/ios/Runner/Runner-Bridging-Header.h index 3a69a7befa44..eb7e8ba8052f 100644 --- a/packages/ios_platform_images/example/ios/Runner/Runner-Bridging-Header.h +++ b/packages/ios_platform_images/example/ios/Runner/Runner-Bridging-Header.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/ios_platform_images/example/lib/main.dart b/packages/ios_platform_images/example/lib/main.dart index aa4392243785..d1b07b0a5fee 100644 --- a/packages/ios_platform_images/example/lib/main.dart +++ b/packages/ios_platform_images/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/ios_platform_images/example/test/widget_test.dart b/packages/ios_platform_images/example/test/widget_test.dart index 66d964302180..09fa35c27a6b 100644 --- a/packages/ios_platform_images/example/test/widget_test.dart +++ b/packages/ios_platform_images/example/test/widget_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h index 8125fb2282ba..f3c8efe9bd6a 100644 --- a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h +++ b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m index 76c54d5c2576..abd331e5d0cb 100644 --- a/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m +++ b/packages/ios_platform_images/ios/Classes/IosPlatformImagesPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/ios_platform_images/lib/ios_platform_images.dart b/packages/ios_platform_images/lib/ios_platform_images.dart index 3c30c4b8fc0c..e9bc0b342239 100644 --- a/packages/ios_platform_images/lib/ios_platform_images.dart +++ b/packages/ios_platform_images/lib/ios_platform_images.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/ios_platform_images/test/ios_platform_images_test.dart b/packages/ios_platform_images/test/ios_platform_images_test.dart index bbdf8de57ed5..a896e3d835af 100644 --- a/packages/ios_platform_images/test/ios_platform_images_test.dart +++ b/packages/ios_platform_images/test/ios_platform_images_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/LICENSE b/packages/local_auth/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/local_auth/LICENSE +++ b/packages/local_auth/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java index cf4226d4ed26..2b825c6d1f31 100644 --- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java +++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. package io.flutter.plugins.localauth; diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java index 5df034650f34..7ed9a7ea324d 100644 --- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java +++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/EmbeddingV1ActivityTest.java b/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/EmbeddingV1ActivityTest.java index dc28926caa08..696fc493c6b8 100644 --- a/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/EmbeddingV1ActivityTest.java +++ b/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java b/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java index ebaf3ccf92ba..e5ece3edd50d 100644 --- a/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java +++ b/packages/local_auth/example/android/app/src/androidTest/java/io/flutter/plugins/localauth/FlutterFragmentActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/example/android/app/src/main/java/io/flutter/plugins/localauthexample/EmbeddingV1Activity.java b/packages/local_auth/example/android/app/src/main/java/io/flutter/plugins/localauthexample/EmbeddingV1Activity.java index 83af839a9fbb..c3fc8d47b3a4 100644 --- a/packages/local_auth/example/android/app/src/main/java/io/flutter/plugins/localauthexample/EmbeddingV1Activity.java +++ b/packages/local_auth/example/android/app/src/main/java/io/flutter/plugins/localauthexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/example/ios/Runner/AppDelegate.h b/packages/local_auth/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/local_auth/example/ios/Runner/AppDelegate.h +++ b/packages/local_auth/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/example/ios/Runner/AppDelegate.m b/packages/local_auth/example/ios/Runner/AppDelegate.m index 2147d3d605ac..30b87969f44a 100644 --- a/packages/local_auth/example/ios/Runner/AppDelegate.m +++ b/packages/local_auth/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/example/ios/Runner/main.m b/packages/local_auth/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/local_auth/example/ios/Runner/main.m +++ b/packages/local_auth/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/example/lib/main.dart b/packages/local_auth/example/lib/main.dart index 7d611a4ea10f..d00a5b1e9ac2 100644 --- a/packages/local_auth/example/lib/main.dart +++ b/packages/local_auth/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/integration_test/local_auth_test.dart b/packages/local_auth/integration_test/local_auth_test.dart index 5ebaf39cfe58..436d6b9effcf 100644 --- a/packages/local_auth/integration_test/local_auth_test.dart +++ b/packages/local_auth/integration_test/local_auth_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.h b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.h index 7fc6e568a470..1a1446fb27bd 100644 --- a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.h +++ b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m index f11517ceb691..40a14b9f4b47 100644 --- a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m +++ b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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 diff --git a/packages/local_auth/lib/auth_strings.dart b/packages/local_auth/lib/auth_strings.dart index c7dc6bdf09f0..537340b79d4e 100644 --- a/packages/local_auth/lib/auth_strings.dart +++ b/packages/local_auth/lib/auth_strings.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/lib/error_codes.dart b/packages/local_auth/lib/error_codes.dart index 4ead02005250..bcf15b7b2154 100644 --- a/packages/local_auth/lib/error_codes.dart +++ b/packages/local_auth/lib/error_codes.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/lib/local_auth.dart b/packages/local_auth/lib/local_auth.dart index cd32b667e140..3f332592a4dd 100644 --- a/packages/local_auth/lib/local_auth.dart +++ b/packages/local_auth/lib/local_auth.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/local_auth/test/local_auth_test.dart b/packages/local_auth/test/local_auth_test.dart index f4bf9fe0314d..d0a4dc8fc594 100644 --- a/packages/local_auth/test/local_auth_test.dart +++ b/packages/local_auth/test/local_auth_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/LICENSE b/packages/package_info/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/package_info/LICENSE +++ b/packages/package_info/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/package_info/android/src/main/java/io/flutter/plugins/packageinfo/PackageInfoPlugin.java b/packages/package_info/android/src/main/java/io/flutter/plugins/packageinfo/PackageInfoPlugin.java index 1444b1c71148..4611f70951f9 100644 --- a/packages/package_info/android/src/main/java/io/flutter/plugins/packageinfo/PackageInfoPlugin.java +++ b/packages/package_info/android/src/main/java/io/flutter/plugins/packageinfo/PackageInfoPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/darwin/Classes/FLTPackageInfoPlugin.m b/packages/package_info/darwin/Classes/FLTPackageInfoPlugin.m index 8207438f794b..ab686fa08676 100644 --- a/packages/package_info/darwin/Classes/FLTPackageInfoPlugin.m +++ b/packages/package_info/darwin/Classes/FLTPackageInfoPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/EmbedderV1ActivityTest.java b/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/EmbedderV1ActivityTest.java index aef7d0dbd264..8d3b0b6c6cad 100644 --- a/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/EmbedderV1ActivityTest.java +++ b/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/EmbedderV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/MainActivityTest.java b/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/MainActivityTest.java index f5f95cec3ed1..cf7252ce19de 100644 --- a/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/MainActivityTest.java +++ b/packages/package_info/example/android/app/src/androidTest/java/io/flutter/plugins/packageinfoexample/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java b/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java index d049ed7b4efc..ded5f348c506 100644 --- a/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java +++ b/packages/package_info/example/android/app/src/main/java/io/flutter/plugins/packageinfoexample/EmbedderV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/integration_test/package_info_test.dart b/packages/package_info/example/integration_test/package_info_test.dart index ecd75e2687f2..10db8d0caf57 100644 --- a/packages/package_info/example/integration_test/package_info_test.dart +++ b/packages/package_info/example/integration_test/package_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/ios/Runner/AppDelegate.h b/packages/package_info/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/package_info/example/ios/Runner/AppDelegate.h +++ b/packages/package_info/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/ios/Runner/AppDelegate.m b/packages/package_info/example/ios/Runner/AppDelegate.m index 2147d3d605ac..30b87969f44a 100644 --- a/packages/package_info/example/ios/Runner/AppDelegate.m +++ b/packages/package_info/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/ios/Runner/main.m b/packages/package_info/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/package_info/example/ios/Runner/main.m +++ b/packages/package_info/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/lib/main.dart b/packages/package_info/example/lib/main.dart index 3fa7780fe9bb..60e4a16f7817 100644 --- a/packages/package_info/example/lib/main.dart +++ b/packages/package_info/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/macos/Runner/AppDelegate.swift b/packages/package_info/example/macos/Runner/AppDelegate.swift index ca19fe95f8cf..5cec4c48f620 100644 --- a/packages/package_info/example/macos/Runner/AppDelegate.swift +++ b/packages/package_info/example/macos/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/macos/Runner/MainFlutterWindow.swift b/packages/package_info/example/macos/Runner/MainFlutterWindow.swift index 2ce11b78604b..32aaeedceb1f 100644 --- a/packages/package_info/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/package_info/example/macos/Runner/MainFlutterWindow.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/example/test_driver/integration_test.dart b/packages/package_info/example/test_driver/integration_test.dart index 9e813df086c1..1bcccae039d6 100644 --- a/packages/package_info/example/test_driver/integration_test.dart +++ b/packages/package_info/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/ios/Classes/FLTPackageInfoPlugin.h b/packages/package_info/ios/Classes/FLTPackageInfoPlugin.h index e6a73bf164c5..65be5f99d569 100644 --- a/packages/package_info/ios/Classes/FLTPackageInfoPlugin.h +++ b/packages/package_info/ios/Classes/FLTPackageInfoPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/lib/package_info.dart b/packages/package_info/lib/package_info.dart index 7bcd80619037..69246813873a 100644 --- a/packages/package_info/lib/package_info.dart +++ b/packages/package_info/lib/package_info.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/macos/Classes/FLTPackageInfoPlugin.h b/packages/package_info/macos/Classes/FLTPackageInfoPlugin.h index b8705ddfc199..590e8263d951 100644 --- a/packages/package_info/macos/Classes/FLTPackageInfoPlugin.h +++ b/packages/package_info/macos/Classes/FLTPackageInfoPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/package_info/test/package_info_test.dart b/packages/package_info/test/package_info_test.dart index cb6967155ca0..91661de72103 100644 --- a/packages/package_info/test/package_info_test.dart +++ b/packages/package_info/test/package_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/LICENSE b/packages/path_provider/path_provider/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/path_provider/path_provider/LICENSE +++ b/packages/path_provider/path_provider/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java b/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java index 9a0c76232fb3..49360809e892 100644 --- a/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java +++ b/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java b/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java index c41b81deaff6..1a77560623a2 100644 --- a/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java +++ b/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java b/packages/path_provider/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java index 2df4497332b3..7469c545b817 100644 --- a/packages/path_provider/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java +++ b/packages/path_provider/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/android/app/src/androidTest/java/EmbeddingV1ActivityTest.java b/packages/path_provider/path_provider/example/android/app/src/androidTest/java/EmbeddingV1ActivityTest.java index 9292edb43dd7..b6a39a8260ce 100644 --- a/packages/path_provider/path_provider/example/android/app/src/androidTest/java/EmbeddingV1ActivityTest.java +++ b/packages/path_provider/path_provider/example/android/app/src/androidTest/java/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/android/app/src/androidTest/java/MainActivityTest.java b/packages/path_provider/path_provider/example/android/app/src/androidTest/java/MainActivityTest.java index 986e3a439b0f..0380a4397ae6 100644 --- a/packages/path_provider/path_provider/example/android/app/src/androidTest/java/MainActivityTest.java +++ b/packages/path_provider/path_provider/example/android/app/src/androidTest/java/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/android/app/src/main/java/io/flutter/plugins/pathproviderexample/EmbeddingV1Activity.java b/packages/path_provider/path_provider/example/android/app/src/main/java/io/flutter/plugins/pathproviderexample/EmbeddingV1Activity.java index 2853fb394179..997cd1081a0a 100644 --- a/packages/path_provider/path_provider/example/android/app/src/main/java/io/flutter/plugins/pathproviderexample/EmbeddingV1Activity.java +++ b/packages/path_provider/path_provider/example/android/app/src/main/java/io/flutter/plugins/pathproviderexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart index 71c138b2dd3e..2613b45a8574 100644 --- a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.h b/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.h +++ b/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.m b/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.m index abfe2106b092..b790a0a52635 100644 --- a/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.m +++ b/packages/path_provider/path_provider/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/ios/Runner/main.m b/packages/path_provider/path_provider/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/path_provider/path_provider/example/ios/Runner/main.m +++ b/packages/path_provider/path_provider/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/lib/main.dart b/packages/path_provider/path_provider/example/lib/main.dart index ddc1f8a6e2d5..7b1d6a73a2f5 100644 --- a/packages/path_provider/path_provider/example/lib/main.dart +++ b/packages/path_provider/path_provider/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/linux/main.cc b/packages/path_provider/path_provider/example/linux/main.cc index a15afa068a7b..88a5fd45ce1b 100644 --- a/packages/path_provider/path_provider/example/linux/main.cc +++ b/packages/path_provider/path_provider/example/linux/main.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/linux/my_application.cc b/packages/path_provider/path_provider/example/linux/my_application.cc index 3843c07aaf04..9cb411ba475b 100644 --- a/packages/path_provider/path_provider/example/linux/my_application.cc +++ b/packages/path_provider/path_provider/example/linux/my_application.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/linux/my_application.h b/packages/path_provider/path_provider/example/linux/my_application.h index b3d62442a005..6e9f0c3ff665 100644 --- a/packages/path_provider/path_provider/example/linux/my_application.h +++ b/packages/path_provider/path_provider/example/linux/my_application.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/macos/Runner/AppDelegate.swift b/packages/path_provider/path_provider/example/macos/Runner/AppDelegate.swift index ca19fe95f8cf..5cec4c48f620 100644 --- a/packages/path_provider/path_provider/example/macos/Runner/AppDelegate.swift +++ b/packages/path_provider/path_provider/example/macos/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/macos/Runner/MainFlutterWindow.swift b/packages/path_provider/path_provider/example/macos/Runner/MainFlutterWindow.swift index 2ce11b78604b..32aaeedceb1f 100644 --- a/packages/path_provider/path_provider/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/path_provider/path_provider/example/macos/Runner/MainFlutterWindow.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/test_driver/integration_test.dart b/packages/path_provider/path_provider/example/test_driver/integration_test.dart index dec1aa55d40e..18ed3cff3ee8 100644 --- a/packages/path_provider/path_provider/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp b/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp index b7d078e4d4a5..8e415602cf3b 100644 --- a/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/flutter_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/windows/runner/flutter_window.h b/packages/path_provider/path_provider/example/windows/runner/flutter_window.h index 9b4ef089621b..8e9c12bbe022 100644 --- a/packages/path_provider/path_provider/example/windows/runner/flutter_window.h +++ b/packages/path_provider/path_provider/example/windows/runner/flutter_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/windows/runner/main.cpp b/packages/path_provider/path_provider/example/windows/runner/main.cpp index e74157ed999a..126302b0be18 100644 --- a/packages/path_provider/path_provider/example/windows/runner/main.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/windows/runner/run_loop.cpp b/packages/path_provider/path_provider/example/windows/runner/run_loop.cpp index ee2e2fd5eae9..1916500e6440 100644 --- a/packages/path_provider/path_provider/example/windows/runner/run_loop.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/run_loop.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/windows/runner/run_loop.h b/packages/path_provider/path_provider/example/windows/runner/run_loop.h index a24c47f2e55f..819ed3ed4995 100644 --- a/packages/path_provider/path_provider/example/windows/runner/run_loop.h +++ b/packages/path_provider/path_provider/example/windows/runner/run_loop.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/windows/runner/utils.cpp b/packages/path_provider/path_provider/example/windows/runner/utils.cpp index 9eba364025d0..537728149601 100644 --- a/packages/path_provider/path_provider/example/windows/runner/utils.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/utils.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/windows/runner/utils.h b/packages/path_provider/path_provider/example/windows/runner/utils.h index 640587eb23ab..16b3f0794597 100644 --- a/packages/path_provider/path_provider/example/windows/runner/utils.h +++ b/packages/path_provider/path_provider/example/windows/runner/utils.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/windows/runner/win32_window.cpp b/packages/path_provider/path_provider/example/windows/runner/win32_window.cpp index 97628170c2c2..a609a2002bb3 100644 --- a/packages/path_provider/path_provider/example/windows/runner/win32_window.cpp +++ b/packages/path_provider/path_provider/example/windows/runner/win32_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/example/windows/runner/win32_window.h b/packages/path_provider/path_provider/example/windows/runner/win32_window.h index 59b78382b27d..d2a730052223 100644 --- a/packages/path_provider/path_provider/example/windows/runner/win32_window.h +++ b/packages/path_provider/path_provider/example/windows/runner/win32_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/integration_test/path_provider_test.dart b/packages/path_provider/path_provider/integration_test/path_provider_test.dart index da368d52b832..1383099a0f16 100644 --- a/packages/path_provider/path_provider/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider/integration_test/path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/ios/Classes/FLTPathProviderPlugin.h b/packages/path_provider/path_provider/ios/Classes/FLTPathProviderPlugin.h index 394f8c070632..8f9fd4597f9d 100644 --- a/packages/path_provider/path_provider/ios/Classes/FLTPathProviderPlugin.h +++ b/packages/path_provider/path_provider/ios/Classes/FLTPathProviderPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/ios/Classes/FLTPathProviderPlugin.m b/packages/path_provider/path_provider/ios/Classes/FLTPathProviderPlugin.m index 705b371b4586..4d3dfeb6e6e6 100644 --- a/packages/path_provider/path_provider/ios/Classes/FLTPathProviderPlugin.m +++ b/packages/path_provider/path_provider/ios/Classes/FLTPathProviderPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/lib/path_provider.dart b/packages/path_provider/path_provider/lib/path_provider.dart index da9c0b3d48a3..d63887a60267 100644 --- a/packages/path_provider/path_provider/lib/path_provider.dart +++ b/packages/path_provider/path_provider/lib/path_provider.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider/test/path_provider_test.dart b/packages/path_provider/path_provider/test/path_provider_test.dart index 759e9c09ffc2..7232a74a1253 100644 --- a/packages/path_provider/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/path_provider/test/path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_linux/LICENSE b/packages/path_provider/path_provider_linux/LICENSE index 67c7e2c52e46..c6823b81eb84 100644 --- a/packages/path_provider/path_provider_linux/LICENSE +++ b/packages/path_provider/path_provider_linux/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart index a4b254145344..8776e84e8b3b 100644 --- a/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_linux/example/integration_test/path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_linux/example/lib/main.dart b/packages/path_provider/path_provider_linux/example/lib/main.dart index bd1c80a12fb7..104c998bc61a 100644 --- a/packages/path_provider/path_provider_linux/example/lib/main.dart +++ b/packages/path_provider/path_provider_linux/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_linux/example/linux/main.cc b/packages/path_provider/path_provider_linux/example/linux/main.cc index a15afa068a7b..88a5fd45ce1b 100644 --- a/packages/path_provider/path_provider_linux/example/linux/main.cc +++ b/packages/path_provider/path_provider_linux/example/linux/main.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_linux/example/linux/my_application.cc b/packages/path_provider/path_provider_linux/example/linux/my_application.cc index 3843c07aaf04..9cb411ba475b 100644 --- a/packages/path_provider/path_provider_linux/example/linux/my_application.cc +++ b/packages/path_provider/path_provider_linux/example/linux/my_application.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_linux/example/linux/my_application.h b/packages/path_provider/path_provider_linux/example/linux/my_application.h index b3d62442a005..6e9f0c3ff665 100644 --- a/packages/path_provider/path_provider_linux/example/linux/my_application.h +++ b/packages/path_provider/path_provider_linux/example/linux/my_application.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_linux/example/test/widget_test.dart b/packages/path_provider/path_provider_linux/example/test/widget_test.dart index e25ebe36fb08..4d5da3e4e330 100644 --- a/packages/path_provider/path_provider_linux/example/test/widget_test.dart +++ b/packages/path_provider/path_provider_linux/example/test/widget_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart index dec1aa55d40e..18ed3cff3ee8 100644 --- a/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart b/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart index 0295ffa2d15a..cf8d12436429 100644 --- a/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart +++ b/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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 'dart:io'; diff --git a/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart b/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart index 5ec530313462..81329fb7c3cb 100644 --- a/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart +++ b/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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_test/flutter_test.dart'; diff --git a/packages/path_provider/path_provider_macos/LICENSE b/packages/path_provider/path_provider_macos/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/path_provider/path_provider_macos/LICENSE +++ b/packages/path_provider/path_provider_macos/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart index 21f757c86e71..734caa9ac7a2 100644 --- a/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_macos/example/integration_test/path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_macos/example/lib/main.dart b/packages/path_provider/path_provider_macos/example/lib/main.dart index f19807f1c273..19ba86e31cf5 100644 --- a/packages/path_provider/path_provider_macos/example/lib/main.dart +++ b/packages/path_provider/path_provider_macos/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_macos/example/macos/Runner/AppDelegate.swift b/packages/path_provider/path_provider_macos/example/macos/Runner/AppDelegate.swift index ca19fe95f8cf..5cec4c48f620 100644 --- a/packages/path_provider/path_provider_macos/example/macos/Runner/AppDelegate.swift +++ b/packages/path_provider/path_provider_macos/example/macos/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_macos/example/macos/Runner/MainFlutterWindow.swift b/packages/path_provider/path_provider_macos/example/macos/Runner/MainFlutterWindow.swift index 2ce11b78604b..32aaeedceb1f 100644 --- a/packages/path_provider/path_provider_macos/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/path_provider/path_provider_macos/example/macos/Runner/MainFlutterWindow.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart index dec1aa55d40e..18ed3cff3ee8 100644 --- a/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift b/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift index 8081b89b2ccf..b308793be355 100644 --- a/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift +++ b/packages/path_provider/path_provider_macos/macos/Classes/PathProviderPlugin.swift @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_platform_interface/LICENSE b/packages/path_provider/path_provider_platform_interface/LICENSE index 67c7e2c52e46..c6823b81eb84 100644 --- a/packages/path_provider/path_provider_platform_interface/LICENSE +++ b/packages/path_provider/path_provider_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart b/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart index 5b7046bda3d8..3eb1580711ef 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart b/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart index fe46401501d4..e355d7d1a5be 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/src/enums.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart b/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart index 418d983273ea..7889e004126f 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart b/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart index 3f44387f1b7d..71d55861c7b1 100644 --- a/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart +++ b/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/LICENSE b/packages/path_provider/path_provider_windows/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/path_provider/path_provider_windows/LICENSE +++ b/packages/path_provider/path_provider_windows/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart index 733865b577f0..f99b830b163d 100644 --- a/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider_windows/example/integration_test/path_provider_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/lib/main.dart b/packages/path_provider/path_provider_windows/example/lib/main.dart index 7d4db2304259..b4b0f999d937 100644 --- a/packages/path_provider/path_provider_windows/example/lib/main.dart +++ b/packages/path_provider/path_provider_windows/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart index dec1aa55d40e..18ed3cff3ee8 100644 --- a/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.cpp b/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.cpp index b7d078e4d4a5..8e415602cf3b 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.cpp +++ b/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.h b/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.h index 9b4ef089621b..8e9c12bbe022 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.h +++ b/packages/path_provider/path_provider_windows/example/windows/runner/flutter_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/main.cpp b/packages/path_provider/path_provider_windows/example/windows/runner/main.cpp index e74157ed999a..126302b0be18 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/main.cpp +++ b/packages/path_provider/path_provider_windows/example/windows/runner/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.cpp b/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.cpp index ee2e2fd5eae9..1916500e6440 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.cpp +++ b/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.h b/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.h index a24c47f2e55f..819ed3ed4995 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.h +++ b/packages/path_provider/path_provider_windows/example/windows/runner/run_loop.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/utils.cpp b/packages/path_provider/path_provider_windows/example/windows/runner/utils.cpp index 9eba364025d0..537728149601 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/utils.cpp +++ b/packages/path_provider/path_provider_windows/example/windows/runner/utils.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/utils.h b/packages/path_provider/path_provider_windows/example/windows/runner/utils.h index 640587eb23ab..16b3f0794597 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/utils.h +++ b/packages/path_provider/path_provider_windows/example/windows/runner/utils.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.cpp b/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.cpp index 97628170c2c2..a609a2002bb3 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.cpp +++ b/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.h b/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.h index 59b78382b27d..d2a730052223 100644 --- a/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.h +++ b/packages/path_provider/path_provider_windows/example/windows/runner/win32_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/lib/path_provider_windows.dart b/packages/path_provider/path_provider_windows/lib/path_provider_windows.dart index dbb178242970..9af55ac2616c 100644 --- a/packages/path_provider/path_provider_windows/lib/path_provider_windows.dart +++ b/packages/path_provider/path_provider_windows/lib/path_provider_windows.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/lib/src/folders.dart b/packages/path_provider/path_provider_windows/lib/src/folders.dart index d1e7ecc767f0..e8112c1a953a 100644 --- a/packages/path_provider/path_provider_windows/lib/src/folders.dart +++ b/packages/path_provider/path_provider_windows/lib/src/folders.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/lib/src/folders_stub.dart b/packages/path_provider/path_provider_windows/lib/src/folders_stub.dart index 6dae052246ad..34e9e6118f7d 100644 --- a/packages/path_provider/path_provider_windows/lib/src/folders_stub.dart +++ b/packages/path_provider/path_provider_windows/lib/src/folders_stub.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart index 23eee59f32fb..5fef0dba32ed 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart index 9d71d2258e04..69094af9eafa 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart index 0ca4595fa14e..22683d721e7c 100644 --- a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart +++ b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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 'dart:ffi'; diff --git a/packages/plugin_platform_interface/LICENSE b/packages/plugin_platform_interface/LICENSE index b257ce7c224c..c6823b81eb84 100644 --- a/packages/plugin_platform_interface/LICENSE +++ b/packages/plugin_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/plugin_platform_interface/lib/plugin_platform_interface.dart b/packages/plugin_platform_interface/lib/plugin_platform_interface.dart index 187d1fa47b44..d9bd88168422 100644 --- a/packages/plugin_platform_interface/lib/plugin_platform_interface.dart +++ b/packages/plugin_platform_interface/lib/plugin_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart b/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart index 8b5d68f00684..0079765f0b09 100644 --- a/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart +++ b/packages/plugin_platform_interface/test/plugin_platform_interface_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/LICENSE b/packages/quick_actions/quick_actions/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/quick_actions/quick_actions/LICENSE +++ b/packages/quick_actions/quick_actions/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java b/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java index 6d7f79fb7c2d..465283053442 100644 --- a/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java +++ b/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java b/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java index 695ff00a1a67..ab3431325503 100644 --- a/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java +++ b/packages/quick_actions/quick_actions/android/src/main/java/io/flutter/plugins/quickactions/QuickActionsPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java b/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java index db2b2f69609c..d85ead3b4e36 100644 --- a/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java +++ b/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java b/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java index 16820dfa0f39..a7fab3f052a4 100644 --- a/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java +++ b/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java b/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java index 4eb4033a4f94..0b60dfa53e1f 100644 --- a/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java +++ b/packages/quick_actions/quick_actions/example/android/app/src/main/java/io/flutter/plugins/quickactionsexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/example/integration_test/quick_actions_test.dart b/packages/quick_actions/quick_actions/example/integration_test/quick_actions_test.dart index f8841843b016..4b0ec7584243 100644 --- a/packages/quick_actions/quick_actions/example/integration_test/quick_actions_test.dart +++ b/packages/quick_actions/quick_actions/example/integration_test/quick_actions_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.h b/packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.h +++ b/packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.m b/packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.m index 2147d3d605ac..30b87969f44a 100644 --- a/packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.m +++ b/packages/quick_actions/quick_actions/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/example/ios/Runner/main.m b/packages/quick_actions/quick_actions/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/quick_actions/quick_actions/example/ios/Runner/main.m +++ b/packages/quick_actions/quick_actions/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/example/ios/RunnerUITests/RunnerUITests.m b/packages/quick_actions/quick_actions/example/ios/RunnerUITests/RunnerUITests.m index dfb8022529d2..45791864d239 100644 --- a/packages/quick_actions/quick_actions/example/ios/RunnerUITests/RunnerUITests.m +++ b/packages/quick_actions/quick_actions/example/ios/RunnerUITests/RunnerUITests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/example/lib/main.dart b/packages/quick_actions/quick_actions/example/lib/main.dart index 4422a520c9ed..3ff6528f3565 100644 --- a/packages/quick_actions/quick_actions/example/lib/main.dart +++ b/packages/quick_actions/quick_actions/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/example/test_driver/integration_test.dart b/packages/quick_actions/quick_actions/example/test_driver/integration_test.dart index b02d7d397106..4c4c006068b8 100644 --- a/packages/quick_actions/quick_actions/example/test_driver/integration_test.dart +++ b/packages/quick_actions/quick_actions/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.h b/packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.h index d170a81a2e58..8f98cc35e8ba 100644 --- a/packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.h +++ b/packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.m b/packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.m index 808d4d112b12..0025795744f9 100644 --- a/packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.m +++ b/packages/quick_actions/quick_actions/ios/Classes/FLTQuickActionsPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/lib/quick_actions.dart b/packages/quick_actions/quick_actions/lib/quick_actions.dart index fe95b1d07765..23dd15302d57 100644 --- a/packages/quick_actions/quick_actions/lib/quick_actions.dart +++ b/packages/quick_actions/quick_actions/lib/quick_actions.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/quick_actions/quick_actions/test/quick_actions_test.dart b/packages/quick_actions/quick_actions/test/quick_actions_test.dart index 9adcf5628a47..f2b9a9aefc8d 100644 --- a/packages/quick_actions/quick_actions/test/quick_actions_test.dart +++ b/packages/quick_actions/quick_actions/test/quick_actions_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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 'dart:async'; diff --git a/packages/sensors/LICENSE b/packages/sensors/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/sensors/LICENSE +++ b/packages/sensors/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java index 4aac1a58d6bf..c643edce3401 100644 --- a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java +++ b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/SensorsPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java index 93fd2e0fbf2b..7e6da156386d 100644 --- a/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java +++ b/packages/sensors/android/src/main/java/io/flutter/plugins/sensors/StreamHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java index 23390293aeb5..128768a097aa 100644 --- a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java +++ b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java index 9760ef098572..c96ab243a778 100644 --- a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java +++ b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/FlutterActivityTest.java b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/FlutterActivityTest.java index 7f2d79bab028..c1584aab107c 100644 --- a/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/FlutterActivityTest.java +++ b/packages/sensors/example/android/app/src/main/java/io/flutter/plugins/sensorsexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/example/ios/Runner/AppDelegate.h b/packages/sensors/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/sensors/example/ios/Runner/AppDelegate.h +++ b/packages/sensors/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/example/ios/Runner/AppDelegate.m b/packages/sensors/example/ios/Runner/AppDelegate.m index 2147d3d605ac..30b87969f44a 100644 --- a/packages/sensors/example/ios/Runner/AppDelegate.m +++ b/packages/sensors/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/example/ios/Runner/main.m b/packages/sensors/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/sensors/example/ios/Runner/main.m +++ b/packages/sensors/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/example/lib/main.dart b/packages/sensors/example/lib/main.dart index 88cc2d7a2750..0946a8e8421b 100644 --- a/packages/sensors/example/lib/main.dart +++ b/packages/sensors/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/example/lib/snake.dart b/packages/sensors/example/lib/snake.dart index 28610758ca5f..47177681020f 100644 --- a/packages/sensors/example/lib/snake.dart +++ b/packages/sensors/example/lib/snake.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/example/test_driver/test/integration_test.dart b/packages/sensors/example/test_driver/test/integration_test.dart index ac2a0cf5f19b..257b0d3c0930 100644 --- a/packages/sensors/example/test_driver/test/integration_test.dart +++ b/packages/sensors/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/integration_test/sensors_test.dart b/packages/sensors/integration_test/sensors_test.dart index ecee934b799a..3b8f614d2dcb 100644 --- a/packages/sensors/integration_test/sensors_test.dart +++ b/packages/sensors/integration_test/sensors_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/ios/Classes/FLTSensorsPlugin.h b/packages/sensors/ios/Classes/FLTSensorsPlugin.h index c3eaa137d065..8c3176b42a44 100644 --- a/packages/sensors/ios/Classes/FLTSensorsPlugin.h +++ b/packages/sensors/ios/Classes/FLTSensorsPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/ios/Classes/FLTSensorsPlugin.m b/packages/sensors/ios/Classes/FLTSensorsPlugin.m index d3541337280a..110fd305f14b 100644 --- a/packages/sensors/ios/Classes/FLTSensorsPlugin.m +++ b/packages/sensors/ios/Classes/FLTSensorsPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/lib/sensors.dart b/packages/sensors/lib/sensors.dart index 3309f1b20453..8db29e017ad0 100644 --- a/packages/sensors/lib/sensors.dart +++ b/packages/sensors/lib/sensors.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/sensors/test/sensors_test.dart b/packages/sensors/test/sensors_test.dart index 89856279ff16..659c658c3604 100644 --- a/packages/sensors/test/sensors_test.dart +++ b/packages/sensors/test/sensors_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/LICENSE b/packages/share/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/share/LICENSE +++ b/packages/share/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/MethodCallHandler.java b/packages/share/android/src/main/java/io/flutter/plugins/share/MethodCallHandler.java index 99baabeab6b7..7f162e883c32 100644 --- a/packages/share/android/src/main/java/io/flutter/plugins/share/MethodCallHandler.java +++ b/packages/share/android/src/main/java/io/flutter/plugins/share/MethodCallHandler.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/Share.java b/packages/share/android/src/main/java/io/flutter/plugins/share/Share.java index be7280eea673..fced7bb7f87c 100644 --- a/packages/share/android/src/main/java/io/flutter/plugins/share/Share.java +++ b/packages/share/android/src/main/java/io/flutter/plugins/share/Share.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/ShareFileProvider.java b/packages/share/android/src/main/java/io/flutter/plugins/share/ShareFileProvider.java index 87e4e42a03d4..fff48a6bad14 100644 --- a/packages/share/android/src/main/java/io/flutter/plugins/share/ShareFileProvider.java +++ b/packages/share/android/src/main/java/io/flutter/plugins/share/ShareFileProvider.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java index af4a02eaba47..6807851caf6b 100644 --- a/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java +++ b/packages/share/android/src/main/java/io/flutter/plugins/share/SharePlugin.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java index 32c382f656f8..85f4efb208af 100644 --- a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java +++ b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java index 77bc7cedcfa5..cbe6c064371d 100644 --- a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java +++ b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/FlutterActivityTest.java b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/FlutterActivityTest.java index 9767b63e7799..070749dcff20 100644 --- a/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/FlutterActivityTest.java +++ b/packages/share/example/android/app/src/main/java/io/flutter/plugins/shareexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/example/ios/Runner/AppDelegate.h b/packages/share/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/share/example/ios/Runner/AppDelegate.h +++ b/packages/share/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/example/ios/Runner/AppDelegate.m b/packages/share/example/ios/Runner/AppDelegate.m index abfe2106b092..b790a0a52635 100644 --- a/packages/share/example/ios/Runner/AppDelegate.m +++ b/packages/share/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/example/ios/Runner/main.m b/packages/share/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/share/example/ios/Runner/main.m +++ b/packages/share/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/example/ios/RunnerUITests/FLTShareExampleUITests.m b/packages/share/example/ios/RunnerUITests/FLTShareExampleUITests.m index 05966fb439f1..c099cb946b92 100644 --- a/packages/share/example/ios/RunnerUITests/FLTShareExampleUITests.m +++ b/packages/share/example/ios/RunnerUITests/FLTShareExampleUITests.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/example/lib/image_previews.dart b/packages/share/example/lib/image_previews.dart index 7298ed4348b1..9b5b807c77c6 100644 --- a/packages/share/example/lib/image_previews.dart +++ b/packages/share/example/lib/image_previews.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/example/lib/main.dart b/packages/share/example/lib/main.dart index 8d6a78305db9..f802b492df6d 100644 --- a/packages/share/example/lib/main.dart +++ b/packages/share/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/example/test_driver/test/integration_test.dart b/packages/share/example/test_driver/test/integration_test.dart index ac2a0cf5f19b..257b0d3c0930 100644 --- a/packages/share/example/test_driver/test/integration_test.dart +++ b/packages/share/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/integration_test/share_test.dart b/packages/share/integration_test/share_test.dart index 4fdfc220c9cc..54d553bbb5a0 100644 --- a/packages/share/integration_test/share_test.dart +++ b/packages/share/integration_test/share_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/ios/Classes/FLTSharePlugin.h b/packages/share/ios/Classes/FLTSharePlugin.h index b06f1d0be606..8f6a6a538e2a 100644 --- a/packages/share/ios/Classes/FLTSharePlugin.h +++ b/packages/share/ios/Classes/FLTSharePlugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/ios/Classes/FLTSharePlugin.m b/packages/share/ios/Classes/FLTSharePlugin.m index 024ede9cb2f3..b8a3a7ffa316 100644 --- a/packages/share/ios/Classes/FLTSharePlugin.m +++ b/packages/share/ios/Classes/FLTSharePlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/lib/share.dart b/packages/share/lib/share.dart index f15566714857..6a3f5a317e31 100644 --- a/packages/share/lib/share.dart +++ b/packages/share/lib/share.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/share/test/share_test.dart b/packages/share/test/share_test.dart index 7e72fc4dc012..d0049cef94ab 100644 --- a/packages/share/test/share_test.dart +++ b/packages/share/test/share_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/LICENSE b/packages/shared_preferences/shared_preferences/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/shared_preferences/shared_preferences/LICENSE +++ b/packages/shared_preferences/shared_preferences/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java index 7955f2f89afb..71ec14e7d06b 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java index 3583f3b73cb7..d41328ee6202 100644 --- a/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java +++ b/packages/shared_preferences/shared_preferences/android/src/main/java/io/flutter/plugins/sharedpreferences/SharedPreferencesPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart index daa2cbba1670..f844d453b743 100644 --- a/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences/example/integration_test/shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.h b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.h +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.m b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.m index abfe2106b092..b790a0a52635 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.m +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift index f26669f6bd4f..caf998393333 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h b/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h index 3a69a7befa44..eb7e8ba8052f 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/Runner-Bridging-Header.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/ios/Runner/main.m b/packages/shared_preferences/shared_preferences/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/shared_preferences/shared_preferences/example/ios/Runner/main.m +++ b/packages/shared_preferences/shared_preferences/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/lib/main.dart b/packages/shared_preferences/shared_preferences/example/lib/main.dart index a56deb276037..103481a2d295 100644 --- a/packages/shared_preferences/shared_preferences/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/linux/main.cc b/packages/shared_preferences/shared_preferences/example/linux/main.cc index a15afa068a7b..88a5fd45ce1b 100644 --- a/packages/shared_preferences/shared_preferences/example/linux/main.cc +++ b/packages/shared_preferences/shared_preferences/example/linux/main.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/linux/my_application.cc b/packages/shared_preferences/shared_preferences/example/linux/my_application.cc index 3843c07aaf04..9cb411ba475b 100644 --- a/packages/shared_preferences/shared_preferences/example/linux/my_application.cc +++ b/packages/shared_preferences/shared_preferences/example/linux/my_application.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/linux/my_application.h b/packages/shared_preferences/shared_preferences/example/linux/my_application.h index b3d62442a005..6e9f0c3ff665 100644 --- a/packages/shared_preferences/shared_preferences/example/linux/my_application.h +++ b/packages/shared_preferences/shared_preferences/example/linux/my_application.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/macos/Runner/AppDelegate.swift b/packages/shared_preferences/shared_preferences/example/macos/Runner/AppDelegate.swift index ca19fe95f8cf..5cec4c48f620 100644 --- a/packages/shared_preferences/shared_preferences/example/macos/Runner/AppDelegate.swift +++ b/packages/shared_preferences/shared_preferences/example/macos/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/macos/Runner/MainFlutterWindow.swift b/packages/shared_preferences/shared_preferences/example/macos/Runner/MainFlutterWindow.swift index 2ce11b78604b..32aaeedceb1f 100644 --- a/packages/shared_preferences/shared_preferences/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/shared_preferences/shared_preferences/example/macos/Runner/MainFlutterWindow.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart index dec1aa55d40e..18ed3cff3ee8 100644 --- a/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/web/index.html b/packages/shared_preferences/shared_preferences/example/web/index.html index 27464c33811a..7fb138cc90fa 100644 --- a/packages/shared_preferences/shared_preferences/example/web/index.html +++ b/packages/shared_preferences/shared_preferences/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp index b7d078e4d4a5..8e415602cf3b 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h index 9b4ef089621b..8e9c12bbe022 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/flutter_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp index e74157ed999a..126302b0be18 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp index ee2e2fd5eae9..1916500e6440 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h index a24c47f2e55f..819ed3ed4995 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/run_loop.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp index 9eba364025d0..537728149601 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h index 640587eb23ab..16b3f0794597 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/utils.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp index 97628170c2c2..a609a2002bb3 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h index 59b78382b27d..d2a730052223 100644 --- a/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h +++ b/packages/shared_preferences/shared_preferences/example/windows/runner/win32_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.h b/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.h index d77611fde7b4..d2d04aee3b64 100644 --- a/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.h +++ b/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.m b/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.m index 77d53504b4d3..09308d42d762 100644 --- a/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.m +++ b/packages/shared_preferences/shared_preferences/ios/Classes/FLTSharedPreferencesPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart b/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart index 6ed771e87c53..493e38901ddf 100644 --- a/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart +++ b/packages/shared_preferences/shared_preferences/lib/shared_preferences.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart index 412285ed4fd3..878021a03361 100755 --- a/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_linux/LICENSE b/packages/shared_preferences/shared_preferences_linux/LICENSE index 67c7e2c52e46..c6823b81eb84 100644 --- a/packages/shared_preferences/shared_preferences_linux/LICENSE +++ b/packages/shared_preferences/shared_preferences_linux/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart index a8e52ccc3063..ab32552b4918 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/integration_test/shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart b/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart index 0f6d7fc49f7e..aee71d00d44d 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc b/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc index 612325f29cd7..1507d02825e7 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/main.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc index a8f67ccc9a86..878cd973d997 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.cc @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h index 5d666ca73bec..6e9f0c3ff665 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h +++ b/packages/shared_preferences/shared_preferences_linux/example/linux/my_application.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart index dec1aa55d40e..18ed3cff3ee8 100644 --- a/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart index 6252da4668c9..e4fc24e78cff 100644 --- a/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart +++ b/packages/shared_preferences/shared_preferences_linux/lib/shared_preferences_linux.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart index 98260302b778..11e52dd6037f 100644 --- a/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart +++ b/packages/shared_preferences/shared_preferences_linux/test/shared_preferences_linux_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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:file/memory.dart'; diff --git a/packages/shared_preferences/shared_preferences_macos/LICENSE b/packages/shared_preferences/shared_preferences_macos/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/shared_preferences/shared_preferences_macos/LICENSE +++ b/packages/shared_preferences/shared_preferences_macos/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart index 53d3cfdf3bc5..722aee3da50a 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/integration_test/shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart b/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart index 388f2389bf5b..fb85c301f623 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/AppDelegate.swift b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/AppDelegate.swift index ca19fe95f8cf..5cec4c48f620 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/AppDelegate.swift +++ b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/MainFlutterWindow.swift b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/MainFlutterWindow.swift index 2ce11b78604b..32aaeedceb1f 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/shared_preferences/shared_preferences_macos/example/macos/Runner/MainFlutterWindow.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart index dec1aa55d40e..18ed3cff3ee8 100644 --- a/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_macos/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift b/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift index 19a420d002a4..2cf345cf0b04 100644 --- a/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift +++ b/packages/shared_preferences/shared_preferences_macos/macos/Classes/SharedPreferencesPlugin.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/LICENSE b/packages/shared_preferences/shared_preferences_platform_interface/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/LICENSE +++ b/packages/shared_preferences/shared_preferences_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart b/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart index 47004b198175..fa1bdc097b8d 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/lib/method_channel_shared_preferences.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart b/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart index f330b04cd30c..8023c864a399 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/lib/shared_preferences_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart index 3225090e5b51..3b43062c2be3 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/test/method_channel_shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_platform_interface/test/shared_preferences_platform_interface_test.dart b/packages/shared_preferences/shared_preferences_platform_interface/test/shared_preferences_platform_interface_test.dart index a1c4ca9219aa..8efe885c122c 100644 --- a/packages/shared_preferences/shared_preferences_platform_interface/test/shared_preferences_platform_interface_test.dart +++ b/packages/shared_preferences/shared_preferences_platform_interface/test/shared_preferences_platform_interface_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_web/LICENSE b/packages/shared_preferences/shared_preferences_web/LICENSE index b257ce7c224c..c6823b81eb84 100644 --- a/packages/shared_preferences/shared_preferences_web/LICENSE +++ b/packages/shared_preferences/shared_preferences_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart b/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart index 7d5292a54db1..9cff1d448896 100644 --- a/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart +++ b/packages/shared_preferences/shared_preferences_web/lib/shared_preferences_web.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart b/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart index b1275330e3a7..6e49fb47f755 100644 --- a/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart +++ b/packages/shared_preferences/shared_preferences_web/test/shared_preferences_web_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/LICENSE b/packages/shared_preferences/shared_preferences_windows/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/shared_preferences/shared_preferences_windows/LICENSE +++ b/packages/shared_preferences/shared_preferences_windows/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_windows/example/LICENSE b/packages/shared_preferences/shared_preferences_windows/example/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/LICENSE +++ b/packages/shared_preferences/shared_preferences_windows/example/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart index 16f17cf71094..6b3e9e76fffd 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/integration_test/shared_preferences_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart b/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart index 96c2490a60ee..0cdd37394706 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart b/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart index f41cb47e07a2..18ed3cff3ee8 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp index b7d078e4d4a5..8e415602cf3b 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h index 9b4ef089621b..8e9c12bbe022 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/flutter_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp index e74157ed999a..126302b0be18 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp index ee2e2fd5eae9..1916500e6440 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h index a24c47f2e55f..819ed3ed4995 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/run_loop.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp index 9eba364025d0..537728149601 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h index 640587eb23ab..16b3f0794597 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/utils.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp index 97628170c2c2..a609a2002bb3 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h index 59b78382b27d..d2a730052223 100644 --- a/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h +++ b/packages/shared_preferences/shared_preferences_windows/example/windows/runner/win32_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart b/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart index 04efce9946d4..8bbda6ec139a 100644 --- a/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart +++ b/packages/shared_preferences/shared_preferences_windows/lib/shared_preferences_windows.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart b/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart index a78dce207c09..e577b9f76e48 100644 --- a/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart +++ b/packages/shared_preferences/shared_preferences_windows/test/shared_preferences_windows_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/LICENSE b/packages/url_launcher/url_launcher/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/url_launcher/url_launcher/LICENSE +++ b/packages/url_launcher/url_launcher/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java index 7b858fbafdb3..9e798abcdbb5 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java index b6446458322b..07f7ef3ee7dc 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java index cafc7a65c04b..3c9db478e14b 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncherPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java index 53b2e8a44479..7f26c18740ec 100644 --- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java +++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/WebViewActivity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java b/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java index 0055659c5fc0..5e0811399ac6 100644 --- a/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java +++ b/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java index 9002012ce18c..4fb52708b9eb 100644 --- a/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java +++ b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java index 7760741b2127..9e343b82a193 100644 --- a/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java +++ b/packages/url_launcher/url_launcher/example/android/app/src/androidTestDebug/java/io/flutter/plugins/urllauncherexample/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java b/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java index a005c452d426..969b4713dc16 100644 --- a/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java +++ b/packages/url_launcher/url_launcher/example/android/app/src/main/java/io/flutter/plugins/urllauncherexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart index 62343c6dc689..933a3c0ed851 100644 --- a/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/example/integration_test/url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.h b/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.h +++ b/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.m b/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.m index 07cf6cb9b49f..83f0621aceba 100644 --- a/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.m +++ b/packages/url_launcher/url_launcher/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/ios/Runner/main.m b/packages/url_launcher/url_launcher/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/url_launcher/url_launcher/example/ios/Runner/main.m +++ b/packages/url_launcher/url_launcher/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/lib/main.dart b/packages/url_launcher/url_launcher/example/lib/main.dart index 8af62ed7859e..7faf2a895c98 100644 --- a/packages/url_launcher/url_launcher/example/lib/main.dart +++ b/packages/url_launcher/url_launcher/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/linux/main.cc b/packages/url_launcher/url_launcher/example/linux/main.cc index 612325f29cd7..1507d02825e7 100644 --- a/packages/url_launcher/url_launcher/example/linux/main.cc +++ b/packages/url_launcher/url_launcher/example/linux/main.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/linux/my_application.cc b/packages/url_launcher/url_launcher/example/linux/my_application.cc index 1a873cdf7b19..878cd973d997 100644 --- a/packages/url_launcher/url_launcher/example/linux/my_application.cc +++ b/packages/url_launcher/url_launcher/example/linux/my_application.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/linux/my_application.h b/packages/url_launcher/url_launcher/example/linux/my_application.h index b3d62442a005..6e9f0c3ff665 100644 --- a/packages/url_launcher/url_launcher/example/linux/my_application.h +++ b/packages/url_launcher/url_launcher/example/linux/my_application.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/macos/Runner/AppDelegate.swift b/packages/url_launcher/url_launcher/example/macos/Runner/AppDelegate.swift index ca19fe95f8cf..5cec4c48f620 100644 --- a/packages/url_launcher/url_launcher/example/macos/Runner/AppDelegate.swift +++ b/packages/url_launcher/url_launcher/example/macos/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/macos/Runner/MainFlutterWindow.swift b/packages/url_launcher/url_launcher/example/macos/Runner/MainFlutterWindow.swift index 2ce11b78604b..32aaeedceb1f 100644 --- a/packages/url_launcher/url_launcher/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/url_launcher/url_launcher/example/macos/Runner/MainFlutterWindow.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart index f044c8de676e..053e985a78ce 100644 --- a/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/web/index.html b/packages/url_launcher/url_launcher/example/web/index.html index 1127c04820dd..c3d22621fc4f 100644 --- a/packages/url_launcher/url_launcher/example/web/index.html +++ b/packages/url_launcher/url_launcher/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.cpp b/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.cpp index b7d078e4d4a5..8e415602cf3b 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.cpp +++ b/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.h b/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.h index 9b4ef089621b..8e9c12bbe022 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.h +++ b/packages/url_launcher/url_launcher/example/windows/runner/flutter_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/windows/runner/main.cpp b/packages/url_launcher/url_launcher/example/windows/runner/main.cpp index e74157ed999a..126302b0be18 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/main.cpp +++ b/packages/url_launcher/url_launcher/example/windows/runner/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/windows/runner/run_loop.cpp b/packages/url_launcher/url_launcher/example/windows/runner/run_loop.cpp index ee2e2fd5eae9..1916500e6440 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/run_loop.cpp +++ b/packages/url_launcher/url_launcher/example/windows/runner/run_loop.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/windows/runner/run_loop.h b/packages/url_launcher/url_launcher/example/windows/runner/run_loop.h index a24c47f2e55f..819ed3ed4995 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/run_loop.h +++ b/packages/url_launcher/url_launcher/example/windows/runner/run_loop.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/windows/runner/utils.cpp b/packages/url_launcher/url_launcher/example/windows/runner/utils.cpp index 9eba364025d0..537728149601 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/utils.cpp +++ b/packages/url_launcher/url_launcher/example/windows/runner/utils.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/windows/runner/utils.h b/packages/url_launcher/url_launcher/example/windows/runner/utils.h index 640587eb23ab..16b3f0794597 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/utils.h +++ b/packages/url_launcher/url_launcher/example/windows/runner/utils.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/windows/runner/win32_window.cpp b/packages/url_launcher/url_launcher/example/windows/runner/win32_window.cpp index 97628170c2c2..a609a2002bb3 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/win32_window.cpp +++ b/packages/url_launcher/url_launcher/example/windows/runner/win32_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/example/windows/runner/win32_window.h b/packages/url_launcher/url_launcher/example/windows/runner/win32_window.h index 59b78382b27d..d2a730052223 100644 --- a/packages/url_launcher/url_launcher/example/windows/runner/win32_window.h +++ b/packages/url_launcher/url_launcher/example/windows/runner/win32_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.h b/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.h index 35eade666e15..73589d2a0b7d 100644 --- a/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.h +++ b/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m b/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m index bbcfdfdc949c..6fbc3a522f36 100644 --- a/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m +++ b/packages/url_launcher/url_launcher/ios/Classes/FLTURLLauncherPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/lib/link.dart b/packages/url_launcher/url_launcher/lib/link.dart index cdcc2ee1a016..12a213b62761 100644 --- a/packages/url_launcher/url_launcher/lib/link.dart +++ b/packages/url_launcher/url_launcher/lib/link.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/lib/src/link.dart b/packages/url_launcher/url_launcher/lib/src/link.dart index e614c2200b02..259ac8dd1c66 100644 --- a/packages/url_launcher/url_launcher/lib/src/link.dart +++ b/packages/url_launcher/url_launcher/lib/src/link.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/lib/url_launcher.dart b/packages/url_launcher/url_launcher/lib/url_launcher.dart index 1a3ac40ce5e2..b59c91d02a1a 100644 --- a/packages/url_launcher/url_launcher/lib/url_launcher.dart +++ b/packages/url_launcher/url_launcher/lib/url_launcher.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/test/link_test.dart b/packages/url_launcher/url_launcher/test/link_test.dart index 02678a3559dd..833797409c8a 100644 --- a/packages/url_launcher/url_launcher/test/link_test.dart +++ b/packages/url_launcher/url_launcher/test/link_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart b/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart index 6d862844e1d0..789c1435df80 100644 --- a/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart +++ b/packages/url_launcher/url_launcher/test/mock_url_launcher_platform.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher/test/url_launcher_test.dart b/packages/url_launcher/url_launcher/test/url_launcher_test.dart index 89eb259e2fa9..9b2d167483cd 100644 --- a/packages/url_launcher/url_launcher/test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher/test/url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_linux/LICENSE b/packages/url_launcher/url_launcher_linux/LICENSE index 67c7e2c52e46..c6823b81eb84 100644 --- a/packages/url_launcher/url_launcher_linux/LICENSE +++ b/packages/url_launcher/url_launcher_linux/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart index b14cc943c90d..7cc90885129b 100644 --- a/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_linux/example/integration_test/url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_linux/example/lib/main.dart b/packages/url_launcher/url_launcher_linux/example/lib/main.dart index e6e027b4a6ba..86e06f3fafed 100644 --- a/packages/url_launcher/url_launcher_linux/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_linux/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_linux/example/linux/main.cc b/packages/url_launcher/url_launcher_linux/example/linux/main.cc index 612325f29cd7..1507d02825e7 100644 --- a/packages/url_launcher/url_launcher_linux/example/linux/main.cc +++ b/packages/url_launcher/url_launcher_linux/example/linux/main.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc b/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc index 1a873cdf7b19..878cd973d997 100644 --- a/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc +++ b/packages/url_launcher/url_launcher_linux/example/linux/my_application.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_linux/example/linux/my_application.h b/packages/url_launcher/url_launcher_linux/example/linux/my_application.h index b3d62442a005..6e9f0c3ff665 100644 --- a/packages/url_launcher/url_launcher_linux/example/linux/my_application.h +++ b/packages/url_launcher/url_launcher_linux/example/linux/my_application.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart index ac2a0cf5f19b..257b0d3c0930 100644 --- a/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_linux/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h b/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h index 399bde268919..f4d19395e37f 100644 --- a/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h +++ b/packages/url_launcher/url_launcher_linux/linux/include/url_launcher_linux/url_launcher_plugin.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc b/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc index 17431d1c2f81..6e10607dd14e 100644 --- a/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc +++ b/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_macos/LICENSE b/packages/url_launcher/url_launcher_macos/LICENSE index b257ce7c224c..c6823b81eb84 100644 --- a/packages/url_launcher/url_launcher_macos/LICENSE +++ b/packages/url_launcher/url_launcher_macos/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart index ade3da82700d..6d31d6ea0aa3 100644 --- a/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_macos/example/integration_test/url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_macos/example/lib/main.dart b/packages/url_launcher/url_launcher_macos/example/lib/main.dart index e6e027b4a6ba..86e06f3fafed 100644 --- a/packages/url_launcher/url_launcher_macos/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_macos/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_macos/example/macos/Runner/AppDelegate.swift b/packages/url_launcher/url_launcher_macos/example/macos/Runner/AppDelegate.swift index ca19fe95f8cf..5cec4c48f620 100644 --- a/packages/url_launcher/url_launcher_macos/example/macos/Runner/AppDelegate.swift +++ b/packages/url_launcher/url_launcher_macos/example/macos/Runner/AppDelegate.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_macos/example/macos/Runner/MainFlutterWindow.swift b/packages/url_launcher/url_launcher_macos/example/macos/Runner/MainFlutterWindow.swift index 2ce11b78604b..32aaeedceb1f 100644 --- a/packages/url_launcher/url_launcher_macos/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/url_launcher/url_launcher_macos/example/macos/Runner/MainFlutterWindow.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart index ac2a0cf5f19b..257b0d3c0930 100644 --- a/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_macos/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_macos/macos/Classes/UrlLauncherPlugin.swift b/packages/url_launcher/url_launcher_macos/macos/Classes/UrlLauncherPlugin.swift index 46df87a34304..ab89038fa01d 100644 --- a/packages/url_launcher/url_launcher_macos/macos/Classes/UrlLauncherPlugin.swift +++ b/packages/url_launcher/url_launcher_macos/macos/Classes/UrlLauncherPlugin.swift @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_platform_interface/LICENSE b/packages/url_launcher/url_launcher_platform_interface/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/url_launcher/url_launcher_platform_interface/LICENSE +++ b/packages/url_launcher/url_launcher_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/link.dart b/packages/url_launcher/url_launcher_platform_interface/lib/link.dart index 6c1a13b604a8..9784a3d9ec79 100644 --- a/packages/url_launcher/url_launcher_platform_interface/lib/link.dart +++ b/packages/url_launcher/url_launcher_platform_interface/lib/link.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart b/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart index 93fdaff7ea1b..e75e283eeca7 100644 --- a/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart +++ b/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart b/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart index d34ce7512afb..e9435b8dc4e3 100644 --- a/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart +++ b/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart b/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart index e60cc25f25fe..638a65547dc4 100644 --- a/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart +++ b/packages/url_launcher/url_launcher_platform_interface/test/link_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart b/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart index 3e450e83e41b..5bfc78c5c5a2 100644 --- a/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_platform_interface/test/method_channel_url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/LICENSE b/packages/url_launcher/url_launcher_web/LICENSE index b66343316afd..dd4ac737fc37 100644 --- a/packages/url_launcher/url_launcher_web/LICENSE +++ b/packages/url_launcher/url_launcher_web/LICENSE @@ -1,6 +1,6 @@ url_launcher_web -Copyright 2019 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart b/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart index 43bd2234ec84..7bbc889d9d4c 100644 --- a/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart +++ b/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart index f8057d5f4204..0b53a1ffb1dd 100644 --- a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart +++ b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart index 7e72b5ff1da3..5c55ec779c9c 100644 --- a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart +++ b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/example/run_test.sh b/packages/url_launcher/url_launcher_web/example/run_test.sh index 5d235967ac3d..1960bde25d17 100755 --- a/packages/url_launcher/url_launcher_web/example/run_test.sh +++ b/packages/url_launcher/url_launcher_web/example/run_test.sh @@ -1,5 +1,5 @@ #!/usr/bin/bash -# Copyright 2017 The Flutter Authors. All rights reserved. +# Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart b/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart index 0dd5f694f16b..f26b6a310cfe 100644 --- a/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart +++ b/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/example/web/index.html b/packages/url_launcher/url_launcher_web/example/web/index.html index dc8d0cfe0428..dc9f89762aec 100644 --- a/packages/url_launcher/url_launcher_web/example/web/index.html +++ b/packages/url_launcher/url_launcher_web/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/url_launcher/url_launcher_web/lib/src/link.dart b/packages/url_launcher/url_launcher_web/lib/src/link.dart index a39dbd4edf58..fcbbaaec4e56 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/link.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/link.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart index ec93f431138b..5eacec5fe867 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart index 2a8c7f5f5c6e..f2862af8b704 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_fake.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart index b6c2f8812a1b..276b768c76c5 100644 --- a/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart +++ b/packages/url_launcher/url_launcher_web/lib/src/shims/dart_ui_real.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart index a2a1f2a9d863..9249837bd46b 100644 --- a/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart +++ b/packages/url_launcher/url_launcher_web/lib/url_launcher_web.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart b/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart index 64d8e547e485..442c50144727 100644 --- a/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart +++ b/packages/url_launcher/url_launcher_web/test/tests_exist_elsewhere_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/LICENSE b/packages/url_launcher/url_launcher_windows/LICENSE index b257ce7c224c..c6823b81eb84 100644 --- a/packages/url_launcher/url_launcher_windows/LICENSE +++ b/packages/url_launcher/url_launcher_windows/LICENSE @@ -1,4 +1,4 @@ -Copyright 2019 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart b/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart index b14cc943c90d..7cc90885129b 100644 --- a/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart +++ b/packages/url_launcher/url_launcher_windows/example/integration_test/url_launcher_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/lib/main.dart b/packages/url_launcher/url_launcher_windows/example/lib/main.dart index e6e027b4a6ba..86e06f3fafed 100644 --- a/packages/url_launcher/url_launcher_windows/example/lib/main.dart +++ b/packages/url_launcher/url_launcher_windows/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart b/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart index ac2a0cf5f19b..257b0d3c0930 100644 --- a/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart +++ b/packages/url_launcher/url_launcher_windows/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.cpp b/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.cpp index b7d078e4d4a5..8e415602cf3b 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.cpp +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.h b/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.h index 9b4ef089621b..8e9c12bbe022 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.h +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/flutter_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/main.cpp b/packages/url_launcher/url_launcher_windows/example/windows/runner/main.cpp index e74157ed999a..126302b0be18 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/main.cpp +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/main.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.cpp b/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.cpp index ee2e2fd5eae9..1916500e6440 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.cpp +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.h b/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.h index a24c47f2e55f..819ed3ed4995 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.h +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/run_loop.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.cpp b/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.cpp index 9eba364025d0..537728149601 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.cpp +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.h b/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.h index 640587eb23ab..16b3f0794597 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.h +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/utils.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.cpp b/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.cpp index 97628170c2c2..a609a2002bb3 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.cpp +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.h b/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.h index 59b78382b27d..d2a730052223 100644 --- a/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.h +++ b/packages/url_launcher/url_launcher_windows/example/windows/runner/win32_window.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h b/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h index 7ffb0f93f271..8af3924ded81 100644 --- a/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h +++ b/packages/url_launcher/url_launcher_windows/windows/include/url_launcher_windows/url_launcher_plugin.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. #ifndef PACKAGES_URL_LAUNCHER_URL_LAUNCHER_WINDOWS_WINDOWS_INCLUDE_URL_LAUNCHER_WINDOWS_URL_LAUNCHER_PLUGIN_H_ diff --git a/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp b/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp index e6a36f76ad77..51740a3a4b04 100644 --- a/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp +++ b/packages/url_launcher/url_launcher_windows/windows/url_launcher_plugin.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. #include "include/url_launcher_windows/url_launcher_plugin.h" diff --git a/packages/video_player/video_player/LICENSE b/packages/video_player/video_player/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/video_player/video_player/LICENSE +++ b/packages/video_player/video_player/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java index 0deb06b6fa08..fb6d2d4108cd 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/CustomSSLSocketFactory.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java index c42abff848d5..f1a909534d58 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/QueuingEventSink.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/QueuingEventSink.java index fc1acc3250f9..981389583d2d 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/QueuingEventSink.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/QueuingEventSink.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java index dae24d17ece2..840b1464b4d4 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java index 63b1896038c7..85ad892f9e19 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerOptions.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java index 644c0e88c226..2895db2acd6a 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/android/app/src/main/java/io/flutter/plugins/videoplayerexample/EmbeddingV1Activity.java b/packages/video_player/video_player/example/android/app/src/main/java/io/flutter/plugins/videoplayerexample/EmbeddingV1Activity.java index 60bebe82d4df..87c39ca07117 100644 --- a/packages/video_player/video_player/example/android/app/src/main/java/io/flutter/plugins/videoplayerexample/EmbeddingV1Activity.java +++ b/packages/video_player/video_player/example/android/app/src/main/java/io/flutter/plugins/videoplayerexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java b/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java index e62e70cd54ad..434861f4b754 100644 --- a/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java +++ b/packages/video_player/video_player/example/android/app/src/test/java/io/flutter/plugins/videoplayerexample/FlutterActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/integration_test/video_player_test.dart b/packages/video_player/video_player/example/integration_test/video_player_test.dart index 0566ceeb01c4..f04dad5711a2 100644 --- a/packages/video_player/video_player/example/integration_test/video_player_test.dart +++ b/packages/video_player/video_player/example/integration_test/video_player_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/ios/Runner/AppDelegate.h b/packages/video_player/video_player/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/video_player/video_player/example/ios/Runner/AppDelegate.h +++ b/packages/video_player/video_player/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/ios/Runner/AppDelegate.m b/packages/video_player/video_player/example/ios/Runner/AppDelegate.m index 2147d3d605ac..30b87969f44a 100644 --- a/packages/video_player/video_player/example/ios/Runner/AppDelegate.m +++ b/packages/video_player/video_player/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/ios/Runner/main.m b/packages/video_player/video_player/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/video_player/video_player/example/ios/Runner/main.m +++ b/packages/video_player/video_player/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/lib/main.dart b/packages/video_player/video_player/example/lib/main.dart index 8ab4ff12216c..eef23197ef50 100644 --- a/packages/video_player/video_player/example/lib/main.dart +++ b/packages/video_player/video_player/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/test_driver/integration_test.dart b/packages/video_player/video_player/example/test_driver/integration_test.dart index 2a2476ac7a1a..6a3ccada0232 100644 --- a/packages/video_player/video_player/example/test_driver/integration_test.dart +++ b/packages/video_player/video_player/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/test_driver/video_player.dart b/packages/video_player/video_player/example/test_driver/video_player.dart index 317632834566..824b59922ca3 100644 --- a/packages/video_player/video_player/example/test_driver/video_player.dart +++ b/packages/video_player/video_player/example/test_driver/video_player.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/test_driver/video_player_test.dart b/packages/video_player/video_player/example/test_driver/video_player_test.dart index 63e53f0b69e9..ddb088a6dac3 100644 --- a/packages/video_player/video_player/example/test_driver/video_player_test.dart +++ b/packages/video_player/video_player/example/test_driver/video_player_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/example/web/index.html b/packages/video_player/video_player/example/web/index.html index 763ea662e8e3..0df50f1192dc 100644 --- a/packages/video_player/video_player/example/web/index.html +++ b/packages/video_player/video_player/example/web/index.html @@ -1,5 +1,5 @@ - diff --git a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.h b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.h index 80f07014954e..6c9d91468d6b 100644 --- a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.h +++ b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m index ed1623f4f575..83144a9cb378 100644 --- a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m +++ b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/ios/Classes/messages.h b/packages/video_player/video_player/ios/Classes/messages.h index ab54e8d8048f..9717f65b23c3 100644 --- a/packages/video_player/video_player/ios/Classes/messages.h +++ b/packages/video_player/video_player/ios/Classes/messages.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/ios/Classes/messages.m b/packages/video_player/video_player/ios/Classes/messages.m index 78174d43a153..0993c947c2cb 100644 --- a/packages/video_player/video_player/ios/Classes/messages.m +++ b/packages/video_player/video_player/ios/Classes/messages.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/lib/src/closed_caption_file.dart b/packages/video_player/video_player/lib/src/closed_caption_file.dart index 1542746e08b1..3c7d69b89598 100644 --- a/packages/video_player/video_player/lib/src/closed_caption_file.dart +++ b/packages/video_player/video_player/lib/src/closed_caption_file.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/lib/src/sub_rip.dart b/packages/video_player/video_player/lib/src/sub_rip.dart index 89c1d5f78b01..73cd8266c2e9 100644 --- a/packages/video_player/video_player/lib/src/sub_rip.dart +++ b/packages/video_player/video_player/lib/src/sub_rip.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index 4d3e4fa2dcbc..08bd1d499c36 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/pigeons/messages.dart b/packages/video_player/video_player/pigeons/messages.dart index 43bcf4d6a3c2..c0a76dd301af 100644 --- a/packages/video_player/video_player/pigeons/messages.dart +++ b/packages/video_player/video_player/pigeons/messages.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/test/closed_caption_file_test.dart b/packages/video_player/video_player/test/closed_caption_file_test.dart index 9b5ca8a11b22..369a3b362557 100644 --- a/packages/video_player/video_player/test/closed_caption_file_test.dart +++ b/packages/video_player/video_player/test/closed_caption_file_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/test/sub_rip_file_test.dart b/packages/video_player/video_player/test/sub_rip_file_test.dart index 5f696fa0d351..5808e0b9d2e3 100644 --- a/packages/video_player/video_player/test/sub_rip_file_test.dart +++ b/packages/video_player/video_player/test/sub_rip_file_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/test/video_player_initialization_test.dart b/packages/video_player/video_player/test/video_player_initialization_test.dart index 64bbb99d09b8..74973294d13a 100644 --- a/packages/video_player/video_player/test/video_player_initialization_test.dart +++ b/packages/video_player/video_player/test/video_player_initialization_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart index bdb9dc9ec432..580c9ad914dd 100644 --- a/packages/video_player/video_player/test/video_player_test.dart +++ b/packages/video_player/video_player/test/video_player_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player_platform_interface/LICENSE b/packages/video_player/video_player_platform_interface/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/video_player/video_player_platform_interface/LICENSE +++ b/packages/video_player/video_player_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/video_player/video_player_platform_interface/lib/messages.dart b/packages/video_player/video_player_platform_interface/lib/messages.dart index 83e34ee33eb8..2b7d8821a0cc 100644 --- a/packages/video_player/video_player_platform_interface/lib/messages.dart +++ b/packages/video_player/video_player_platform_interface/lib/messages.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart index 9a37d6084c0a..bd9708a117be 100644 --- a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart +++ b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player_platform_interface/lib/test.dart b/packages/video_player/video_player_platform_interface/lib/test.dart index fd23a61a0365..b4fd81f44f41 100644 --- a/packages/video_player/video_player_platform_interface/lib/test.dart +++ b/packages/video_player/video_player_platform_interface/lib/test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart index bf30ecc6fc93..1960253af193 100644 --- a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart +++ b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart index 7a5192d861c0..00ec64305a31 100644 --- a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart +++ b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player_web/LICENSE b/packages/video_player/video_player_web/LICENSE index bb6f2c07756f..c6823b81eb84 100644 --- a/packages/video_player/video_player_web/LICENSE +++ b/packages/video_player/video_player_web/LICENSE @@ -1,4 +1,4 @@ -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart b/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart index ec93f431138b..5eacec5fe867 100644 --- a/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart +++ b/packages/video_player/video_player_web/lib/src/shims/dart_ui.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart b/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart index 2a8c7f5f5c6e..f2862af8b704 100644 --- a/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart +++ b/packages/video_player/video_player_web/lib/src/shims/dart_ui_fake.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart b/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart index b6c2f8812a1b..276b768c76c5 100644 --- a/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart +++ b/packages/video_player/video_player_web/lib/src/shims/dart_ui_real.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player_web/lib/video_player_web.dart b/packages/video_player/video_player_web/lib/video_player_web.dart index 6c99e24c4feb..a61e01071b0f 100644 --- a/packages/video_player/video_player_web/lib/video_player_web.dart +++ b/packages/video_player/video_player_web/lib/video_player_web.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/video_player/video_player_web/test/video_player_web_test.dart b/packages/video_player/video_player_web/test/video_player_web_test.dart index 4fdbc7e9d3d6..18272662fccf 100644 --- a/packages/video_player/video_player_web/test/video_player_web_test.dart +++ b/packages/video_player/video_player_web/test/video_player_web_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/LICENSE b/packages/webview_flutter/LICENSE index 050e2c7cac4f..c6823b81eb84 100644 --- a/packages/webview_flutter/LICENSE +++ b/packages/webview_flutter/LICENSE @@ -1,4 +1,4 @@ -Copyright 2018 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java index 2d66da8fc918..31e3fe08c057 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java index 456d07c2d214..df3f21daadeb 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java index f170e7267c56..ebc7c31987f4 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebView.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java index 30bbeafd1b68..148be952db6e 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterWebViewClient.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java index 51758d05c57a..51b2a3809fff 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/InputAwareWebView.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java index 4b39d3bb83ef..4d596351b3d0 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java index 2be6dc1f575c..1c865c9444e2 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/ThreadedInputConnectionProxyAdapterView.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java index 054e68554df4..22de668e0126 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFactory.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java index 23926c4577ea..dc329e2273d0 100644 --- a/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java +++ b/packages/webview_flutter/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java index aebeb6d0a3b0..56691d2fc82a 100644 --- a/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java +++ b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1ActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java index e3d794e52dcc..b18308ab2feb 100644 --- a/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java +++ b/packages/webview_flutter/example/android/app/src/androidTestDebug/java/io/flutter/plugins/webviewflutterexample/MainActivityTest.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java b/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java index 8eda066ea776..88c023a35fc8 100644 --- a/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java +++ b/packages/webview_flutter/example/android/app/src/main/java/io/flutter/plugins/webviewflutterexample/EmbeddingV1Activity.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index 37da553b0893..2c7c765f34bf 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/example/ios/Runner/AppDelegate.h b/packages/webview_flutter/example/ios/Runner/AppDelegate.h index d0578fc417d7..0681d288bb70 100644 --- a/packages/webview_flutter/example/ios/Runner/AppDelegate.h +++ b/packages/webview_flutter/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/example/ios/Runner/AppDelegate.m b/packages/webview_flutter/example/ios/Runner/AppDelegate.m index f6a895ac8dd8..30b87969f44a 100644 --- a/packages/webview_flutter/example/ios/Runner/AppDelegate.m +++ b/packages/webview_flutter/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/example/ios/Runner/main.m b/packages/webview_flutter/example/ios/Runner/main.m index a6d55eceeb0e..f97b9ef5c8a1 100644 --- a/packages/webview_flutter/example/ios/Runner/main.m +++ b/packages/webview_flutter/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/example/lib/main.dart b/packages/webview_flutter/example/lib/main.dart index 5c9e638ee1aa..88256cc66287 100644 --- a/packages/webview_flutter/example/lib/main.dart +++ b/packages/webview_flutter/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/example/test_driver/integration_test.dart b/packages/webview_flutter/example/test_driver/integration_test.dart index ac2a0cf5f19b..257b0d3c0930 100644 --- a/packages/webview_flutter/example/test_driver/integration_test.dart +++ b/packages/webview_flutter/example/test_driver/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019, The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/FLTCookieManager.h b/packages/webview_flutter/ios/Classes/FLTCookieManager.h index 29e028ced59f..8fe331875250 100644 --- a/packages/webview_flutter/ios/Classes/FLTCookieManager.h +++ b/packages/webview_flutter/ios/Classes/FLTCookieManager.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/FLTCookieManager.m b/packages/webview_flutter/ios/Classes/FLTCookieManager.m index 0a15c7ceb975..f4783ffb4123 100644 --- a/packages/webview_flutter/ios/Classes/FLTCookieManager.m +++ b/packages/webview_flutter/ios/Classes/FLTCookieManager.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h index 3e661ff93b3e..31edadc8cc05 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h +++ b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m index 85a5decf6e3e..8b7ee7d0cfb7 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m +++ b/packages/webview_flutter/ios/Classes/FLTWKNavigationDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h index 36ed108bb727..96af4ef6c578 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h +++ b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m index d53f132bea25..b65d557aa427 100644 --- a/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m +++ b/packages/webview_flutter/ios/Classes/FLTWKProgressionDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.h b/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.h index 109170e9af66..2a80c7d886f2 100644 --- a/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.h +++ b/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.m b/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.m index 3d39d96a6771..9f01416acc6a 100644 --- a/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.m +++ b/packages/webview_flutter/ios/Classes/FLTWebViewFlutterPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.h b/packages/webview_flutter/ios/Classes/FlutterWebView.h index 555a90837da9..6e795f7d1528 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.h +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.h @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index a1ea10c397f9..7ca36e33031c 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.h b/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.h index d3b1261dae94..a0a5ec657295 100644 --- a/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.h +++ b/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.h @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.m b/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.m index 2e9e1b864f34..ec9a363a4b2e 100644 --- a/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.m +++ b/packages/webview_flutter/ios/Classes/JavaScriptChannelHandler.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m b/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m index af6ce0b71450..9d3a2aed64eb 100644 --- a/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m +++ b/packages/webview_flutter/ios/Tests/FLTWKNavigationDelegateTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/ios/Tests/FLTWebViewTests.m b/packages/webview_flutter/ios/Tests/FLTWebViewTests.m index 9a886d383c22..f8229935cbe6 100644 --- a/packages/webview_flutter/ios/Tests/FLTWebViewTests.m +++ b/packages/webview_flutter/ios/Tests/FLTWebViewTests.m @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/lib/platform_interface.dart index 198e07767fc5..92aa87b7480f 100644 --- a/packages/webview_flutter/lib/platform_interface.dart +++ b/packages/webview_flutter/lib/platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/lib/src/webview_android.dart b/packages/webview_flutter/lib/src/webview_android.dart index a8b87fc52616..8850c7977e9c 100644 --- a/packages/webview_flutter/lib/src/webview_android.dart +++ b/packages/webview_flutter/lib/src/webview_android.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/lib/src/webview_cupertino.dart b/packages/webview_flutter/lib/src/webview_cupertino.dart index eb1e75876d4e..8d4be3800a28 100644 --- a/packages/webview_flutter/lib/src/webview_cupertino.dart +++ b/packages/webview_flutter/lib/src/webview_cupertino.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart index bd042130f92a..05831a9d8794 100644 --- a/packages/webview_flutter/lib/src/webview_method_channel.dart +++ b/packages/webview_flutter/lib/src/webview_method_channel.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index af373d1bcbb7..92ff8e00a50e 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/test/webview_flutter_test.dart index afe6664a5957..4360484408b5 100644 --- a/packages/webview_flutter/test/webview_flutter_test.dart +++ b/packages/webview_flutter/test/webview_flutter_test.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/LICENSE b/packages/wifi_info_flutter/wifi_info_flutter/LICENSE index 67c7e2c52e46..c6823b81eb84 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/LICENSE +++ b/packages/wifi_info_flutter/wifi_info_flutter/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java index 6425b9be2909..bd4c8f10ce3b 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java +++ b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutter.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterMethodChannelHandler.java b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterMethodChannelHandler.java index 77861fd4b5fa..9ceed5968e63 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterMethodChannelHandler.java +++ b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterMethodChannelHandler.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java index f1b3c0e181ba..7757688bc9fa 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java +++ b/packages/wifi_info_flutter/wifi_info_flutter/android/src/main/java/io/flutter/plugins/wifi_info_flutter/WifiInfoFlutterPlugin.java @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/java/io/flutter/plugins/wifi_info_flutter_example/MainActivity.java b/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/java/io/flutter/plugins/wifi_info_flutter_example/MainActivity.java index f3747669929d..b52123be65d4 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/java/io/flutter/plugins/wifi_info_flutter_example/MainActivity.java +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/android/app/src/main/java/io/flutter/plugins/wifi_info_flutter_example/MainActivity.java @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.h b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.h index 31fc381e7066..0681d288bb70 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.h +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.h @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.m b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.m index 558d1adc9a4a..442514aaecbe 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.m +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/AppDelegate.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/main.m b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/main.m index f451b14cb751..f97b9ef5c8a1 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/main.m +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Runner/main.m @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart b/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart index 7e25bc527b2a..8258815b0c09 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart index 98f56d4e5e25..103be52aa56b 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/integration_test/wifi_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart index 8997c9275a06..9647a12d77ce 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/test_driver/test/integration_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart index 5b6c0ded11cf..e72db0a9f7b0 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/integration_test/wifi_info_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.h b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.h index 05b885c7d2ac..359562b7761c 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.h +++ b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.m b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.m index 331b6cca2ea8..2fe19c5e70e9 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.m +++ b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/FLTWifiInfoLocationHandler.m @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.h b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.h index 66e3dd18c9b4..41f165717809 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.h +++ b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.h @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m index 1db163a65766..47bd90c4429b 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m +++ b/packages/wifi_info_flutter/wifi_info_flutter/ios/Classes/WifiInfoFlutterPlugin.m @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart b/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart index c15718bdb82d..1c89ee82fc3e 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/lib/wifi_info_flutter.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart b/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart index c0874d10aa07..93cf378de437 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter/test/wifi_info_flutter_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/LICENSE b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/LICENSE index 67c7e2c52e46..c6823b81eb84 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/LICENSE +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2020 The Flutter Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/enums.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/enums.dart index 8dae9737981a..d5f05e6121a9 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/enums.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/enums.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart index efd775ab7486..79f27e8cde44 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/src/method_channel_wifi_info_flutter.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart index 7e8de96336b4..62330d4261a0 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/lib/wifi_info_flutter_platform_interface.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart index c30713a65b72..875f2ab4089a 100644 --- a/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart +++ b/packages/wifi_info_flutter/wifi_info_flutter_platform_interface/test/method_channel_wifi_info_flutter_test.dart @@ -1,4 +1,4 @@ -// Copyright 2020 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 864a81a85057..ab15a7d64249 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2017 The Flutter Authors. All rights reserved. +# Copyright 2013 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. diff --git a/script/check_publish.sh b/script/check_publish.sh index 5c68806c092a..a08df7a0b5d8 100755 --- a/script/check_publish.sh +++ b/script/check_publish.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2017 The Flutter Authors. All rights reserved. +# Copyright 2013 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. diff --git a/script/common.sh b/script/common.sh index 81fc96cbdc18..52eeefa6e9ff 100644 --- a/script/common.sh +++ b/script/common.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2017 The Flutter Authors. All rights reserved. +# Copyright 2013 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. diff --git a/script/incremental_build.sh b/script/incremental_build.sh index d087745eb88d..c14197c85ae7 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2017 The Flutter Authors. All rights reserved. +# Copyright 2013 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. diff --git a/script/tool/lib/src/analyze_command.dart b/script/tool/lib/src/analyze_command.dart index 7a0b47261a90..b2586c4b0fcf 100644 --- a/script/tool/lib/src/analyze_command.dart +++ b/script/tool/lib/src/analyze_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/build_examples_command.dart b/script/tool/lib/src/build_examples_command.dart index 22029791f324..966fdc9b99df 100644 --- a/script/tool/lib/src/build_examples_command.dart +++ b/script/tool/lib/src/build_examples_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/common.dart b/script/tool/lib/src/common.dart index 1228aef5b0f6..7d3063a20f53 100644 --- a/script/tool/lib/src/common.dart +++ b/script/tool/lib/src/common.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/create_all_plugins_app_command.dart b/script/tool/lib/src/create_all_plugins_app_command.dart index ec2fb7ed698e..f1f11d15ca95 100644 --- a/script/tool/lib/src/create_all_plugins_app_command.dart +++ b/script/tool/lib/src/create_all_plugins_app_command.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/drive_examples_command.dart b/script/tool/lib/src/drive_examples_command.dart index 4b5b33ff9029..529268ab4eb2 100644 --- a/script/tool/lib/src/drive_examples_command.dart +++ b/script/tool/lib/src/drive_examples_command.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/firebase_test_lab_command.dart b/script/tool/lib/src/firebase_test_lab_command.dart index 382161226987..8e0abd507464 100644 --- a/script/tool/lib/src/firebase_test_lab_command.dart +++ b/script/tool/lib/src/firebase_test_lab_command.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/format_command.dart b/script/tool/lib/src/format_command.dart index 54895cbae094..d849dc9aa9d2 100644 --- a/script/tool/lib/src/format_command.dart +++ b/script/tool/lib/src/format_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/java_test_command.dart b/script/tool/lib/src/java_test_command.dart index 07800349a37b..45042c3c7006 100644 --- a/script/tool/lib/src/java_test_command.dart +++ b/script/tool/lib/src/java_test_command.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/license_check_command.dart b/script/tool/lib/src/license_check_command.dart index 2df217ef78fd..4f78e4e96639 100644 --- a/script/tool/lib/src/license_check_command.dart +++ b/script/tool/lib/src/license_check_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. @@ -41,34 +41,30 @@ const Set _ignoredFullBasenameList = { 'resource.h', // Generated by VS. }; -// Copyright and license regexes. +// Copyright and license regexes for third-party code. // -// These are intentionally very simple, since almost all source in this -// repository should be using the same license text, comment style, etc., so -// they shouldn't need to be very flexible. Complexity can be added as-needed -// on a case-by-case basis. -final RegExp _copyrightRegex = - RegExp(r'^(?://|#|'), + final Map firstPartyLicenseBlockByExtension = + { + '.sh': _generateLicenseBlock('# '), + '.html': _generateLicenseBlock('', prefix: ''), }; for (final File file in codeFiles) { _print('Checking ${file.path}'); final String content = await file.readAsString(); - final RegExpMatch copyright = _copyrightRegex.firstMatch(content); - if (copyright == null) { - filesWithoutDetectedCopyright.add(file); - continue; - } - final String author = copyright.group(1); - if (author != _firstPartyAuthors && !_isThirdParty(file)) { - misplacedThirdPartyFiles.add(file); - } - - final String bsdLicense = - bsdLicenseBlockByExtension[p.extension(file.path)] ?? - defaultBsdLicenseBlock; - if (!content.contains(bsdLicense) && - !_workivaLicenseRegex.hasMatch(content)) { - filesWithoutDetectedLicense.add(file); + if (_isThirdParty(file)) { + if (!_thirdPartyLicenseBlockRegexes + .any((regex) => regex.hasMatch(content))) { + unrecognizedThirdPartyFiles.add(file); + } + } else { + final String license = + firstPartyLicenseBlockByExtension[p.extension(file.path)] ?? + defaultFirstParyLicenseBlock; + if (!content.contains(license)) { + incorrectFirstPartyFiles.add(file); + } } } _print('\n'); // Sort by path for more usable output. final pathCompare = (File a, File b) => a.path.compareTo(b.path); - filesWithoutDetectedCopyright.sort(pathCompare); - filesWithoutDetectedLicense.sort(pathCompare); - misplacedThirdPartyFiles.sort(pathCompare); + incorrectFirstPartyFiles.sort(pathCompare); + unrecognizedThirdPartyFiles.sort(pathCompare); - if (filesWithoutDetectedCopyright.isNotEmpty) { - _print('No copyright line was found for the following files:'); - for (final File file in filesWithoutDetectedCopyright) { + if (incorrectFirstPartyFiles.isNotEmpty) { + _print('The license block for these files is missing or incorrect:'); + for (final File file in incorrectFirstPartyFiles) { _print(' ${file.path}'); } - _print('Please check that they have a copyright and license block. ' - 'If they do, the license check may need to be updated to recognize its ' - 'format.\n'); + _print('If this third-party code, move it to a "third_party/" directory, ' + 'otherwise ensure that you are using the exact copyright and license ' + 'text used by all first-party files in this repository.\n'); } - if (filesWithoutDetectedLicense.isNotEmpty) { - _print('No recognized license was found for the following files:'); - for (final File file in filesWithoutDetectedLicense) { + if (unrecognizedThirdPartyFiles.isNotEmpty) { + _print( + 'No recognized license was found for the following third-party files:'); + for (final File file in unrecognizedThirdPartyFiles) { _print(' ${file.path}'); } _print('Please check that they have a license at the top of the file. ' - 'If they do, the license check may need to be updated to recognize ' - 'either the license or the specific format of the license ' - 'block.\n'); - } - - if (misplacedThirdPartyFiles.isNotEmpty) { - _print('The following files do not have a recognized first-party author ' - 'but are not in a "third_party/" directory:'); - for (final File file in misplacedThirdPartyFiles) { - _print(' ${file.path}'); - } - _print('Please move these files to "third_party/".\n'); + 'If they do, the license check needs to be updated to recognize ' + 'the new third-party license block.\n'); } - bool succeeded = filesWithoutDetectedCopyright.isEmpty && - filesWithoutDetectedLicense.isEmpty && - misplacedThirdPartyFiles.isEmpty; + bool succeeded = + incorrectFirstPartyFiles.isEmpty && unrecognizedThirdPartyFiles.isEmpty; if (succeeded) { _print('All source files passed validation!'); } @@ -241,7 +226,8 @@ class LicenseCheckCommand extends PluginCommand { for (final File file in incorrectLicenseFiles) { _print(' ${file.path}'); } - _print('Please ensure that they use the exact format used in this repository".\n'); + _print( + 'Please ensure that they use the exact format used in this repository".\n'); } bool succeeded = incorrectLicenseFiles.isEmpty; diff --git a/script/tool/lib/src/lint_podspecs_command.dart b/script/tool/lib/src/lint_podspecs_command.dart index 1e75eb62e4ea..3261072d71a1 100644 --- a/script/tool/lib/src/lint_podspecs_command.dart +++ b/script/tool/lib/src/lint_podspecs_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/list_command.dart b/script/tool/lib/src/list_command.dart index 53c1ba2f3ea3..3571786ab7f8 100644 --- a/script/tool/lib/src/list_command.dart +++ b/script/tool/lib/src/list_command.dart @@ -1,4 +1,4 @@ -// Copyright 2018 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/main.dart b/script/tool/lib/src/main.dart index bb8af5d5ad58..2e29aac1e784 100644 --- a/script/tool/lib/src/main.dart +++ b/script/tool/lib/src/main.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/publish_check_command.dart b/script/tool/lib/src/publish_check_command.dart index 53002b57897a..dcd28d9a89f3 100644 --- a/script/tool/lib/src/publish_check_command.dart +++ b/script/tool/lib/src/publish_check_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/publish_plugin_command.dart b/script/tool/lib/src/publish_plugin_command.dart index d48ed5b7fe7d..eb59091db34a 100644 --- a/script/tool/lib/src/publish_plugin_command.dart +++ b/script/tool/lib/src/publish_plugin_command.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/test_command.dart b/script/tool/lib/src/test_command.dart index 47f7ad89cb8d..10ded4621ab5 100644 --- a/script/tool/lib/src/test_command.dart +++ b/script/tool/lib/src/test_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/version_check_command.dart b/script/tool/lib/src/version_check_command.dart index 36105ad300ab..fb939a71e38a 100644 --- a/script/tool/lib/src/version_check_command.dart +++ b/script/tool/lib/src/version_check_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/lib/src/xctest_command.dart b/script/tool/lib/src/xctest_command.dart index cdc02594a192..41974713f99b 100644 --- a/script/tool/lib/src/xctest_command.dart +++ b/script/tool/lib/src/xctest_command.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/analyze_command_test.dart b/script/tool/test/analyze_command_test.dart index 6474d02f3d28..7b4ef81e0fc2 100644 --- a/script/tool/test/analyze_command_test.dart +++ b/script/tool/test/analyze_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/build_examples_command_test.dart b/script/tool/test/build_examples_command_test.dart index ef959a6e251c..f9ee6dcf25db 100644 --- a/script/tool/test/build_examples_command_test.dart +++ b/script/tool/test/build_examples_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/common_test.dart b/script/tool/test/common_test.dart index 8ee82ca2e95a..6f51ade64e83 100644 --- a/script/tool/test/common_test.dart +++ b/script/tool/test/common_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/drive_examples_command_test.dart b/script/tool/test/drive_examples_command_test.dart index 63a3e69adcdc..2b20f23d7da9 100644 --- a/script/tool/test/drive_examples_command_test.dart +++ b/script/tool/test/drive_examples_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/firebase_test_lab_test.dart b/script/tool/test/firebase_test_lab_test.dart index 6db4461a23a8..f1141ae19d80 100644 --- a/script/tool/test/firebase_test_lab_test.dart +++ b/script/tool/test/firebase_test_lab_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/license_check_command_test.dart b/script/tool/test/license_check_command_test.dart index 69879bff8869..f8646da5d83a 100644 --- a/script/tool/test/license_check_command_test.dart +++ b/script/tool/test/license_check_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. @@ -45,7 +45,7 @@ void main() { String prefix = '', String suffix = '', String copyright = - 'Copyright 2019 The Flutter Authors. All rights reserved.', + 'Copyright 2013 The Flutter Authors. All rights reserved.', List license = const [ 'Use of this source code is governed by a BSD-style license that can be', 'found in the LICENSE file.', @@ -171,8 +171,10 @@ void main() { throwsA(const TypeMatcher())); // Failure should give information about the problematic files. - expect(printedMessages, - contains('No copyright line was found for the following files:')); + expect( + printedMessages, + contains( + 'The license block for these files is missing or incorrect:')); expect(printedMessages, contains(' bad.cc')); expect(printedMessages, contains(' bad.h')); // Failure shouldn't print the success message. @@ -192,8 +194,10 @@ void main() { throwsA(const TypeMatcher())); // Failure should give information about the problematic files. - expect(printedMessages, - contains('No copyright line was found for the following files:')); + expect( + printedMessages, + contains( + 'The license block for these files is missing or incorrect:')); expect(printedMessages, contains(' bad.cc')); // Failure shouldn't print the success message. expect(printedMessages, @@ -212,8 +216,10 @@ void main() { throwsA(const TypeMatcher())); // Failure should give information about the problematic files. - expect(printedMessages, - contains('No recognized license was found for the following files:')); + expect( + printedMessages, + contains( + 'The license block for these files is missing or incorrect:')); expect(printedMessages, contains(' bad.cc')); // Failure shouldn't print the success message. expect(printedMessages, @@ -233,8 +239,7 @@ void main() { expect( printedMessages, contains( - 'The following files do not have a recognized first-party author ' - 'but are not in a "third_party/" directory:')); + 'The license block for these files is missing or incorrect:')); expect(printedMessages, contains(' third_party.cc')); // Failure shouldn't print the success message. expect(printedMessages, @@ -249,7 +254,12 @@ void main() { .childDirectory('third_party') .childFile('file.cc'); thirdPartyFile.createSync(recursive: true); - _writeLicense(thirdPartyFile, copyright: 'Copyright 2017 Someone Else'); + _writeLicense(thirdPartyFile, + copyright: 'Copyright 2017 Workiva Inc.', + license: [ + 'Licensed under the Apache License, Version 2.0 (the "License");', + 'you may not use this file except in compliance with the License.' + ]); await runner.run(['license-check']); @@ -274,8 +284,10 @@ void main() { throwsA(const TypeMatcher())); // Failure should give information about the problematic files. - expect(printedMessages, - contains('No recognized license was found for the following files:')); + expect( + printedMessages, + contains( + 'No recognized license was found for the following third-party files:')); expect(printedMessages, contains(' third_party/bad.cc')); // Failure shouldn't print the success message. expect(printedMessages, @@ -291,10 +303,11 @@ void main() { bad.createSync(recursive: true); _writeLicense( bad, - copyright: 'Copyright 2017 Some New Authors', - license: [ - 'Licensed under the Apache License, Version 2.0', - ], + copyright: 'Copyright 2017 Some New Authors.', + license: [ + 'Licensed under the Apache License, Version 2.0 (the "License");', + 'you may not use this file except in compliance with the License.' + ], ); await expectLater(() => runner.run(['license-check']), @@ -302,7 +315,7 @@ void main() { // Failure should give information about the problematic files. expect(printedMessages, - contains('No recognized license was found for the following files:')); + contains('No recognized license was found for the following third-party files:')); expect(printedMessages, contains(' third_party/bad.cc')); // Failure shouldn't print the success message. expect(printedMessages, @@ -335,8 +348,7 @@ void main() { isNot(contains('All LICENSE files passed validation!'))); }); - test('ignores third-party LICENSE format', - () async { + test('ignores third-party LICENSE format', () async { File license = root.childDirectory('third_party').childFile('LICENSE'); license.createSync(recursive: true); license.writeAsStringSync(_incorrectLicenseFileText); @@ -351,7 +363,7 @@ void main() { } const String _correctLicenseFileText = - '''Copyright 2017 The Flutter Authors. All rights reserved. + '''Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -381,7 +393,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // A common incorrect version created by copying text intended for a code file, // with comment markers. const String _incorrectLicenseFileText = - '''// Copyright 2017 The Flutter Authors. All rights reserved. + '''// Copyright 2013 The Flutter Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are diff --git a/script/tool/test/lint_podspecs_command_test.dart b/script/tool/test/lint_podspecs_command_test.dart index 44e94ee873e4..5475641cba93 100644 --- a/script/tool/test/lint_podspecs_command_test.dart +++ b/script/tool/test/lint_podspecs_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/list_command_test.dart b/script/tool/test/list_command_test.dart index e9b68254fb5d..19e9df0dd38d 100644 --- a/script/tool/test/list_command_test.dart +++ b/script/tool/test/list_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/mocks.dart b/script/tool/test/mocks.dart index d5cfe4ec4f76..2ef9d72e3637 100644 --- a/script/tool/test/mocks.dart +++ b/script/tool/test/mocks.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/publish_plugin_command_test.dart b/script/tool/test/publish_plugin_command_test.dart index b8ab1d25e532..9a0f1d6b6e63 100644 --- a/script/tool/test/publish_plugin_command_test.dart +++ b/script/tool/test/publish_plugin_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/test_command_test.dart b/script/tool/test/test_command_test.dart index eb9f3a9b0cf3..66471263f661 100644 --- a/script/tool/test/test_command_test.dart +++ b/script/tool/test/test_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/util.dart b/script/tool/test/util.dart index e463b88a1abb..908b67b3cf75 100644 --- a/script/tool/test/util.dart +++ b/script/tool/test/util.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/version_check_test.dart b/script/tool/test/version_check_test.dart index 9e610d8a7a20..dc36c6c32284 100644 --- a/script/tool/test/version_check_test.dart +++ b/script/tool/test/version_check_test.dart @@ -1,4 +1,4 @@ -// Copyright 2019 The Flutter Authors. All rights reserved. +// Copyright 2013 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. diff --git a/script/tool/test/xctest_command_test.dart b/script/tool/test/xctest_command_test.dart index 3b76fa6ffa19..aa71c25835c8 100644 --- a/script/tool/test/xctest_command_test.dart +++ b/script/tool/test/xctest_command_test.dart @@ -1,4 +1,4 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2013 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. From 2068cce1d06c7cbbc6e241f83af24e67dc72863d Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 19 Mar 2021 14:11:06 -0700 Subject: [PATCH 345/924] Enable web integration tests in CI (#3738) --- .ci/Dockerfile-LegacyChrome | 29 ------ .cirrus.yml | 59 +++++-------- .../tool/lib/src/drive_examples_command.dart | 38 +++++--- .../test/drive_examples_command_test.dart | 88 ++++++++++++++++++- 4 files changed, 134 insertions(+), 80 deletions(-) delete mode 100644 .ci/Dockerfile-LegacyChrome diff --git a/.ci/Dockerfile-LegacyChrome b/.ci/Dockerfile-LegacyChrome deleted file mode 100644 index 13ac087498d1..000000000000 --- a/.ci/Dockerfile-LegacyChrome +++ /dev/null @@ -1,29 +0,0 @@ -FROM cirrusci/flutter:stable - -RUN sudo apt-get update -y - -RUN sudo apt-get install -y --no-install-recommends gnupg - -# Add repo for gcloud sdk and install it -RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | \ - sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list - -RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \ - sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - - -RUN sudo apt-get update && sudo apt-get install -y google-cloud-sdk && \ - gcloud config set core/disable_usage_reporting true && \ - gcloud config set component_manager/disable_update_check true - -RUN yes | sdkmanager \ - "platforms;android-27" \ - "build-tools;27.0.3" \ - "extras;google;m2repository" \ - "extras;android;m2repository" - -RUN yes | sdkmanager --licenses - -# Add repo for Google Chrome and install it -RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - -RUN echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee /etc/apt/sources.list.d/google-chrome.list -RUN sudo apt-get update && sudo apt-get install -y --no-install-recommends google-chrome-stable diff --git a/.cirrus.yml b/.cirrus.yml index 26264b3fb926..c2bbd35e15e7 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -93,13 +93,6 @@ task: CHANNEL: "stable" script: - ./script/build_all_plugins_app.sh web - - name: build-web-examples - env: - matrix: - CHANNEL: "master" - build_script: - - ./script/incremental_build.sh build-examples --web - # TODO: Add driving examples (and move to heavy-workload group). ### Linux desktop tasks ### - name: build_all_plugins_linux env: @@ -117,35 +110,8 @@ task: build_script: - flutter config --enable-linux-desktop - ./script/incremental_build.sh build-examples --linux - - xvfb-run ./script/incremental_build.sh drive-examples --linux - -# Legacy Dockerfile configuration for web integration tests. -# https://github.com/flutter/web_installers doesn't yet support the current -# stable version of Chrome, so newly-generated Docker images don't work. -# TODO: Merge this task into the "Web tasks" section of the "Light-workload -# tasks" block above once web_installers has been updated to support Chrome 89 -# (which is what the current image generated from .ci/Dockerfile has). -task: - << : *FLUTTER_UPGRADE_TEMPLATE - container: - dockerfile: .ci/Dockerfile-LegacyChrome - matrix: - - name: integration_web_smoke_test - env: - matrix: - CHANNEL: "master" - CHANNEL: "stable" - # Tests integration example test in web. - only_if: "changesInclude('.cirrus.yml', 'packages/integration_test/**') || $CIRRUS_PR == ''" - install_script: - - git clone https://github.com/flutter/web_installers.git - - cd web_installers/packages/web_drivers/ - - pub get - - dart lib/web_driver_installer.dart chromedriver --install-only - - ./chromedriver/chromedriver --port=4444 & test_script: - - cd $INTEGRATION_TEST_PATH/example/ - - flutter drive -v --driver=test_driver/integration_test.dart --target=integration_test/example_test.dart -d web-server --release --browser-name=chrome + - xvfb-run ./script/incremental_build.sh drive-examples --linux # Heavy-workload Linux tasks. # These use machines with more CPUs and memory, so will reduce parallelization @@ -191,6 +157,27 @@ task: - fi - export CIRRUS_CHANGE_MESSAGE=`cat /tmp/cirrus_change_message.txt` - export CIRRUS_COMMIT_MESSAGE=`cat /tmp/cirrus_commit_message.txt` + ### Web tasks ### + - name: build-web+drive-examples + env: + matrix: + CHANNEL: "master" + CHANNEL: "stable" + install_script: + - git clone https://github.com/flutter/web_installers.git + - cd web_installers/packages/web_drivers/ + - pub get + - dart lib/web_driver_installer.dart chromedriver --install-only + - ./chromedriver/chromedriver --port=4444 & + build_script: + - ./script/incremental_build.sh build-examples --web + test_script: + # TODO(stuartmorgan): Eliminate this check once 2.1 reaches stable. + - if [[ "$CHANNEL" == "master" ]]; then + - ./script/incremental_build.sh drive-examples --web + - else + - echo "Requires null-safe integration_test; skipping." + - fi # macOS tasks. task: @@ -223,6 +210,7 @@ task: - xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-11 com.apple.CoreSimulator.SimRuntime.iOS-14-3 | xargs xcrun simctl boot build_script: - ./script/incremental_build.sh build-examples --ipa + test_script: - ./script/incremental_build.sh xctest --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=latest" # `drive-examples` contains integration tests, which changes the UI of the application. # This UI change sometimes affects `xctest`. @@ -246,6 +234,7 @@ task: build_script: - flutter config --enable-macos-desktop - ./script/incremental_build.sh build-examples --macos --no-ipa + test_script: - ./script/incremental_build.sh drive-examples --macos task: diff --git a/script/tool/lib/src/drive_examples_command.dart b/script/tool/lib/src/drive_examples_command.dart index 529268ab4eb2..de5dc9ebfc62 100644 --- a/script/tool/lib/src/drive_examples_command.dart +++ b/script/tool/lib/src/drive_examples_command.dart @@ -14,16 +14,18 @@ class DriveExamplesCommand extends PluginCommand { FileSystem fileSystem, { ProcessRunner processRunner = const ProcessRunner(), }) : super(packagesDir, fileSystem, processRunner: processRunner) { + argParser.addFlag(kAndroid, + help: 'Runs the Android implementation of the examples'); + argParser.addFlag(kIos, + help: 'Runs the iOS implementation of the examples'); argParser.addFlag(kLinux, help: 'Runs the Linux implementation of the examples'); argParser.addFlag(kMacos, help: 'Runs the macOS implementation of the examples'); + argParser.addFlag(kWeb, + help: 'Runs the web implementation of the examples'); argParser.addFlag(kWindows, help: 'Runs the Windows implementation of the examples'); - argParser.addFlag(kIos, - help: 'Runs the iOS implementation of the examples'); - argParser.addFlag(kAndroid, - help: 'Runs the Android implementation of the examples'); argParser.addOption( kEnableExperiment, defaultsTo: '', @@ -51,6 +53,7 @@ class DriveExamplesCommand extends PluginCommand { final List failingTests = []; final bool isLinux = argResults[kLinux]; final bool isMacos = argResults[kMacos]; + final bool isWeb = argResults[kWeb]; final bool isWindows = argResults[kWindows]; await for (Directory plugin in getPlugins()) { final String flutterCommand = @@ -139,6 +142,13 @@ Tried searching for the following: 'macos', ]); } + if (isWeb && isWebPlugin(plugin, fileSystem)) { + driveArgs.addAll([ + '-d', + 'web-server', + '--browser-name=chrome', + ]); + } if (isWindows && isWindowsPlugin(plugin, fileSystem)) { driveArgs.addAll([ '-d', @@ -180,26 +190,30 @@ Tried searching for the following: Future pluginSupportedOnCurrentPlatform( FileSystemEntity plugin, FileSystem fileSystem) async { + final bool isAndroid = argResults[kAndroid]; + final bool isIOS = argResults[kIos]; final bool isLinux = argResults[kLinux]; final bool isMacos = argResults[kMacos]; + final bool isWeb = argResults[kWeb]; final bool isWindows = argResults[kWindows]; - final bool isIOS = argResults[kIos]; - final bool isAndroid = argResults[kAndroid]; + if (isAndroid) { + return (isAndroidPlugin(plugin, fileSystem)); + } + if (isIOS) { + return isIosPlugin(plugin, fileSystem); + } if (isLinux) { return isLinuxPlugin(plugin, fileSystem); } if (isMacos) { return isMacOsPlugin(plugin, fileSystem); } + if (isWeb) { + return isWebPlugin(plugin, fileSystem); + } if (isWindows) { return isWindowsPlugin(plugin, fileSystem); } - if (isIOS) { - return isIosPlugin(plugin, fileSystem); - } - if (isAndroid) { - return (isAndroidPlugin(plugin, fileSystem)); - } // When we are here, no flags are specified. Only return true if the plugin // supports Android for legacy command support. TODO(cyanglaz): Make Android // flag also required like other platforms (breaking change). diff --git a/script/tool/test/drive_examples_command_test.dart b/script/tool/test/drive_examples_command_test.dart index 2b20f23d7da9..65bdf99c165d 100644 --- a/script/tool/test/drive_examples_command_test.dart +++ b/script/tool/test/drive_examples_command_test.dart @@ -357,13 +357,13 @@ void main() { ])); }); - test('driving when plugin does not suppport windows is a no-op', () async { + test('driving when plugin does not suppport web is a no-op', () async { createFakePlugin('plugin', withExtraFiles: >[ ['example', 'test_driver', 'plugin_test.dart'], ['example', 'test_driver', 'plugin.dart'], ], - isMacOsPlugin: false); + isWebPlugin: false); final Directory pluginExampleDirectory = mockPackagesDir.childDirectory('plugin').childDirectory('example'); @@ -372,7 +372,7 @@ void main() { final List output = await runCapturingPrint(runner, [ 'drive-examples', - '--windows', + '--web', ]); expect( @@ -384,11 +384,91 @@ void main() { ); print(processRunner.recordedCalls); - // Output should be empty since running drive-examples --windows on a non-windows + // Output should be empty since running drive-examples --web on a non-web // plugin is a no-op. expect(processRunner.recordedCalls, []); }); + test('driving a web plugin', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test_driver', 'plugin.dart'], + ], + isWebPlugin: true); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--web', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + String deviceTestPath = p.join('test_driver', 'plugin.dart'); + String driverTestPath = p.join('test_driver', 'plugin_test.dart'); + print(processRunner.recordedCalls); + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + flutterCommand, + [ + 'drive', + '-d', + 'web-server', + '--browser-name=chrome', + '--driver', + driverTestPath, + '--target', + deviceTestPath + ], + pluginExampleDirectory.path), + ])); + }); + + test('driving when plugin does not suppport Windows is a no-op', () async { + createFakePlugin('plugin', + withExtraFiles: >[ + ['example', 'test_driver', 'plugin_test.dart'], + ['example', 'test_driver', 'plugin.dart'], + ], + isWindowsPlugin: false); + + final Directory pluginExampleDirectory = + mockPackagesDir.childDirectory('plugin').childDirectory('example'); + + createFakePubspec(pluginExampleDirectory, isFlutter: true); + + final List output = await runCapturingPrint(runner, [ + 'drive-examples', + '--windows', + ]); + + expect( + output, + orderedEquals([ + '\n\n', + 'All driver tests successful!', + ]), + ); + + print(processRunner.recordedCalls); + // Output should be empty since running drive-examples --windows on a + // non-Windows plugin is a no-op. + expect(processRunner.recordedCalls, []); + }); + test('driving on a Windows plugin', () async { createFakePlugin('plugin', withExtraFiles: >[ From a85f397e760817b4fe1bb38f84cf3a0cea30c6fa Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Fri, 19 Mar 2021 16:34:20 -0700 Subject: [PATCH 346/924] [ci] Run more web tests (#3739) This change enables the integration_tests of the following packages to run in Cirrus CI: * google_sign_in_web * connectivity_for_web * google_maps_flutter_web * url_launcher_web --- .../connectivity_for_web/example/run_test.sh | 4 +- ...tion_driver.dart => integration_test.dart} | 0 .../example/run_test.sh | 4 +- ...tion_driver.dart => integration_test.dart} | 0 .../example/web/index.html | 3 +- .../google_sign_in_web/example/run_test.sh | 4 +- ...tion_driver.dart => integration_test.dart} | 0 .../url_launcher_web_test.mocks.dart | 854 ++++++++++-------- .../url_launcher_web/example/run_test.sh | 4 +- ...test_driver.dart => integration_test.dart} | 0 .../tool/lib/src/drive_examples_command.dart | 1 + .../test/drive_examples_command_test.dart | 1 + 12 files changed, 470 insertions(+), 405 deletions(-) rename packages/connectivity/connectivity_for_web/example/test_driver/{integration_driver.dart => integration_test.dart} (100%) rename packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/{integration_driver.dart => integration_test.dart} (100%) rename packages/google_sign_in/google_sign_in_web/example/test_driver/{integration_driver.dart => integration_test.dart} (100%) rename packages/url_launcher/url_launcher_web/example/test_driver/{integration_test_driver.dart => integration_test.dart} (100%) diff --git a/packages/connectivity/connectivity_for_web/example/run_test.sh b/packages/connectivity/connectivity_for_web/example/run_test.sh index dbf0ec55fd8f..aa52974f310e 100755 --- a/packages/connectivity/connectivity_for_web/example/run_test.sh +++ b/packages/connectivity/connectivity_for_web/example/run_test.sh @@ -8,11 +8,11 @@ if pgrep -lf chromedriver > /dev/null; then if [ $# -eq 0 ]; then echo "No target specified, running all tests..." - find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target='{}' + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' else echo "Running test target: $1..." set -x - flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target=$1 + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target=$1 fi else diff --git a/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart b/packages/connectivity/connectivity_for_web/example/test_driver/integration_test.dart similarity index 100% rename from packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart rename to packages/connectivity/connectivity_for_web/example/test_driver/integration_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh index dbf0ec55fd8f..aa52974f310e 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh @@ -8,11 +8,11 @@ if pgrep -lf chromedriver > /dev/null; then if [ $# -eq 0 ]; then echo "No target specified, running all tests..." - find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target='{}' + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' else echo "Running test target: $1..." set -x - flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target=$1 + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target=$1 fi else diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_test.dart similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_driver.dart rename to packages/google_maps_flutter/google_maps_flutter_web/example/test_driver/integration_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html b/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html index d48ebfe62c37..f324d1c7538f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html @@ -5,7 +5,8 @@ Browser Tests - + + diff --git a/packages/google_sign_in/google_sign_in_web/example/run_test.sh b/packages/google_sign_in/google_sign_in_web/example/run_test.sh index fe30bc8652d0..28877dce8d6e 100755 --- a/packages/google_sign_in/google_sign_in_web/example/run_test.sh +++ b/packages/google_sign_in/google_sign_in_web/example/run_test.sh @@ -8,11 +8,11 @@ if pgrep -lf chromedriver > /dev/null; then if [ $# -eq 0 ]; then echo "No target specified, running all tests..." - find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target='{}' + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' else echo "Running test target: $1..." set -x - flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target=$1 + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target=$1 fi else diff --git a/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart b/packages/google_sign_in/google_sign_in_web/example/test_driver/integration_test.dart similarity index 100% rename from packages/google_sign_in/google_sign_in_web/example/test_driver/integration_driver.dart rename to packages/google_sign_in/google_sign_in_web/example/test_driver/integration_test.dart diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart index 5c55ec779c9c..9cd0196f51db 100644 --- a/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart +++ b/packages/url_launcher/url_launcher_web/example/integration_test/url_launcher_web_test.mocks.dart @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Mocks generated by Mockito 5.0.2 from annotations +// in regular_integration_tests/integration_test/url_launcher_web_test.dart. +// Do not manually edit this file. + import 'dart:async' as _i4; import 'dart:html' as _i2; import 'dart:math' as _i5; @@ -10,7 +14,6 @@ import 'dart:web_sql' as _i3; import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: comment_references - // ignore_for_file: unnecessary_parenthesis class _FakeDocument extends _i1.Fake implements _i2.Document {} @@ -61,415 +64,450 @@ class MockWindow extends _i1.Mock implements _i2.Window { @override _i4.Future get animationFrame => - (super.noSuchMethod(Invocation.getter(#animationFrame), Future.value(0)) - as _i4.Future); + (super.noSuchMethod(Invocation.getter(#animationFrame), + returnValue: Future.value(0)) as _i4.Future); @override - _i2.Document get document => - (super.noSuchMethod(Invocation.getter(#document), _FakeDocument()) - as _i2.Document); + _i2.Document get document => (super.noSuchMethod(Invocation.getter(#document), + returnValue: _FakeDocument()) as _i2.Document); @override - _i2.Location get location => - (super.noSuchMethod(Invocation.getter(#location), _FakeLocation()) - as _i2.Location); + _i2.Location get location => (super.noSuchMethod(Invocation.getter(#location), + returnValue: _FakeLocation()) as _i2.Location); @override set location(_i2.LocationBase? value) => - super.noSuchMethod(Invocation.setter(#location, value)); + super.noSuchMethod(Invocation.setter(#location, value), + returnValueForMissingStub: null); @override - _i2.Console get console => - (super.noSuchMethod(Invocation.getter(#console), _FakeConsole()) - as _i2.Console); + _i2.Console get console => (super.noSuchMethod(Invocation.getter(#console), + returnValue: _FakeConsole()) as _i2.Console); @override num get devicePixelRatio => - (super.noSuchMethod(Invocation.getter(#devicePixelRatio), 0) as num); + (super.noSuchMethod(Invocation.getter(#devicePixelRatio), returnValue: 0) + as num); @override - _i2.History get history => - (super.noSuchMethod(Invocation.getter(#history), _FakeHistory()) - as _i2.History); + _i2.History get history => (super.noSuchMethod(Invocation.getter(#history), + returnValue: _FakeHistory()) as _i2.History); @override _i2.Storage get localStorage => - (super.noSuchMethod(Invocation.getter(#localStorage), _FakeStorage()) - as _i2.Storage); + (super.noSuchMethod(Invocation.getter(#localStorage), + returnValue: _FakeStorage()) as _i2.Storage); @override _i2.Navigator get navigator => - (super.noSuchMethod(Invocation.getter(#navigator), _FakeNavigator()) - as _i2.Navigator); + (super.noSuchMethod(Invocation.getter(#navigator), + returnValue: _FakeNavigator()) as _i2.Navigator); @override int get outerHeight => - (super.noSuchMethod(Invocation.getter(#outerHeight), 0) as int); + (super.noSuchMethod(Invocation.getter(#outerHeight), returnValue: 0) + as int); @override int get outerWidth => - (super.noSuchMethod(Invocation.getter(#outerWidth), 0) as int); + (super.noSuchMethod(Invocation.getter(#outerWidth), returnValue: 0) + as int); @override _i2.Performance get performance => - (super.noSuchMethod(Invocation.getter(#performance), _FakePerformance()) - as _i2.Performance); + (super.noSuchMethod(Invocation.getter(#performance), + returnValue: _FakePerformance()) as _i2.Performance); @override _i2.Storage get sessionStorage => - (super.noSuchMethod(Invocation.getter(#sessionStorage), _FakeStorage()) - as _i2.Storage); + (super.noSuchMethod(Invocation.getter(#sessionStorage), + returnValue: _FakeStorage()) as _i2.Storage); @override - _i4.Stream<_i2.Event> get onContentLoaded => (super.noSuchMethod( - Invocation.getter(#onContentLoaded), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); + _i4.Stream<_i2.Event> get onContentLoaded => + (super.noSuchMethod(Invocation.getter(#onContentLoaded), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); @override - _i4.Stream<_i2.Event> get onAbort => (super - .noSuchMethod(Invocation.getter(#onAbort), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); + _i4.Stream<_i2.Event> get onAbort => + (super.noSuchMethod(Invocation.getter(#onAbort), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); @override _i4.Stream<_i2.Event> get onBlur => - (super.noSuchMethod(Invocation.getter(#onBlur), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); + (super.noSuchMethod(Invocation.getter(#onBlur), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); @override - _i4.Stream<_i2.Event> get onCanPlay => (super.noSuchMethod( - Invocation.getter(#onCanPlay), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); + _i4.Stream<_i2.Event> get onCanPlay => + (super.noSuchMethod(Invocation.getter(#onCanPlay), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); @override - _i4.Stream<_i2.Event> get onCanPlayThrough => (super.noSuchMethod( - Invocation.getter(#onCanPlayThrough), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); + _i4.Stream<_i2.Event> get onCanPlayThrough => + (super.noSuchMethod(Invocation.getter(#onCanPlayThrough), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); @override - _i4.Stream<_i2.Event> get onChange => (super - .noSuchMethod(Invocation.getter(#onChange), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); + _i4.Stream<_i2.Event> get onChange => + (super.noSuchMethod(Invocation.getter(#onChange), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); @override - _i4.Stream<_i2.MouseEvent> get onClick => (super.noSuchMethod( - Invocation.getter(#onClick), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); + _i4.Stream<_i2.MouseEvent> get onClick => + (super.noSuchMethod(Invocation.getter(#onClick), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); @override - _i4.Stream<_i2.MouseEvent> get onContextMenu => (super.noSuchMethod( - Invocation.getter(#onContextMenu), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); + _i4.Stream<_i2.MouseEvent> get onContextMenu => + (super.noSuchMethod(Invocation.getter(#onContextMenu), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); @override - _i4.Stream<_i2.Event> get onDoubleClick => (super.noSuchMethod( - Invocation.getter(#onDoubleClick), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); + _i4.Stream<_i2.Event> get onDoubleClick => + (super.noSuchMethod(Invocation.getter(#onDoubleClick), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); @override - _i4.Stream<_i2.DeviceMotionEvent> get onDeviceMotion => (super.noSuchMethod( - Invocation.getter(#onDeviceMotion), - Stream<_i2.DeviceMotionEvent>.empty()) - as _i4.Stream<_i2.DeviceMotionEvent>); + _i4.Stream<_i2.DeviceMotionEvent> get onDeviceMotion => + (super.noSuchMethod(Invocation.getter(#onDeviceMotion), + returnValue: Stream<_i2.DeviceMotionEvent>.empty()) + as _i4.Stream<_i2.DeviceMotionEvent>); @override _i4.Stream<_i2.DeviceOrientationEvent> get onDeviceOrientation => (super.noSuchMethod(Invocation.getter(#onDeviceOrientation), - Stream<_i2.DeviceOrientationEvent>.empty()) + returnValue: Stream<_i2.DeviceOrientationEvent>.empty()) as _i4.Stream<_i2.DeviceOrientationEvent>); @override - _i4.Stream<_i2.MouseEvent> get onDrag => (super.noSuchMethod( - Invocation.getter(#onDrag), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onDragEnd => (super.noSuchMethod( - Invocation.getter(#onDragEnd), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onDragEnter => (super.noSuchMethod( - Invocation.getter(#onDragEnter), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onDragLeave => (super.noSuchMethod( - Invocation.getter(#onDragLeave), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onDragOver => (super.noSuchMethod( - Invocation.getter(#onDragOver), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onDragStart => (super.noSuchMethod( - Invocation.getter(#onDragStart), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onDrop => (super.noSuchMethod( - Invocation.getter(#onDrop), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.Event> get onDurationChange => (super.noSuchMethod( - Invocation.getter(#onDurationChange), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onEmptied => (super.noSuchMethod( - Invocation.getter(#onEmptied), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onEnded => (super - .noSuchMethod(Invocation.getter(#onEnded), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onError => (super - .noSuchMethod(Invocation.getter(#onError), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onFocus => (super - .noSuchMethod(Invocation.getter(#onFocus), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onHashChange => (super.noSuchMethod( - Invocation.getter(#onHashChange), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onInput => (super - .noSuchMethod(Invocation.getter(#onInput), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onInvalid => (super.noSuchMethod( - Invocation.getter(#onInvalid), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.KeyboardEvent> get onKeyDown => (super.noSuchMethod( - Invocation.getter(#onKeyDown), Stream<_i2.KeyboardEvent>.empty()) - as _i4.Stream<_i2.KeyboardEvent>); - @override - _i4.Stream<_i2.KeyboardEvent> get onKeyPress => (super.noSuchMethod( - Invocation.getter(#onKeyPress), Stream<_i2.KeyboardEvent>.empty()) - as _i4.Stream<_i2.KeyboardEvent>); - @override - _i4.Stream<_i2.KeyboardEvent> get onKeyUp => (super.noSuchMethod( - Invocation.getter(#onKeyUp), Stream<_i2.KeyboardEvent>.empty()) - as _i4.Stream<_i2.KeyboardEvent>); + _i4.Stream<_i2.MouseEvent> get onDrag => + (super.noSuchMethod(Invocation.getter(#onDrag), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDragEnd => + (super.noSuchMethod(Invocation.getter(#onDragEnd), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDragEnter => + (super.noSuchMethod(Invocation.getter(#onDragEnter), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDragLeave => + (super.noSuchMethod(Invocation.getter(#onDragLeave), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDragOver => + (super.noSuchMethod(Invocation.getter(#onDragOver), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDragStart => + (super.noSuchMethod(Invocation.getter(#onDragStart), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onDrop => + (super.noSuchMethod(Invocation.getter(#onDrop), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.Event> get onDurationChange => + (super.noSuchMethod(Invocation.getter(#onDurationChange), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onEmptied => + (super.noSuchMethod(Invocation.getter(#onEmptied), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onEnded => + (super.noSuchMethod(Invocation.getter(#onEnded), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onError => + (super.noSuchMethod(Invocation.getter(#onError), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onFocus => + (super.noSuchMethod(Invocation.getter(#onFocus), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onHashChange => + (super.noSuchMethod(Invocation.getter(#onHashChange), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onInput => + (super.noSuchMethod(Invocation.getter(#onInput), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onInvalid => + (super.noSuchMethod(Invocation.getter(#onInvalid), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.KeyboardEvent> get onKeyDown => + (super.noSuchMethod(Invocation.getter(#onKeyDown), + returnValue: Stream<_i2.KeyboardEvent>.empty()) + as _i4.Stream<_i2.KeyboardEvent>); + @override + _i4.Stream<_i2.KeyboardEvent> get onKeyPress => + (super.noSuchMethod(Invocation.getter(#onKeyPress), + returnValue: Stream<_i2.KeyboardEvent>.empty()) + as _i4.Stream<_i2.KeyboardEvent>); + @override + _i4.Stream<_i2.KeyboardEvent> get onKeyUp => + (super.noSuchMethod(Invocation.getter(#onKeyUp), + returnValue: Stream<_i2.KeyboardEvent>.empty()) + as _i4.Stream<_i2.KeyboardEvent>); @override _i4.Stream<_i2.Event> get onLoad => - (super.noSuchMethod(Invocation.getter(#onLoad), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onLoadedData => (super.noSuchMethod( - Invocation.getter(#onLoadedData), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onLoadedMetadata => (super.noSuchMethod( - Invocation.getter(#onLoadedMetadata), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onLoadStart => (super.noSuchMethod( - Invocation.getter(#onLoadStart), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.MessageEvent> get onMessage => (super.noSuchMethod( - Invocation.getter(#onMessage), Stream<_i2.MessageEvent>.empty()) - as _i4.Stream<_i2.MessageEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onMouseDown => (super.noSuchMethod( - Invocation.getter(#onMouseDown), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onMouseEnter => (super.noSuchMethod( - Invocation.getter(#onMouseEnter), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onMouseLeave => (super.noSuchMethod( - Invocation.getter(#onMouseLeave), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onMouseMove => (super.noSuchMethod( - Invocation.getter(#onMouseMove), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onMouseOut => (super.noSuchMethod( - Invocation.getter(#onMouseOut), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onMouseOver => (super.noSuchMethod( - Invocation.getter(#onMouseOver), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.MouseEvent> get onMouseUp => (super.noSuchMethod( - Invocation.getter(#onMouseUp), Stream<_i2.MouseEvent>.empty()) - as _i4.Stream<_i2.MouseEvent>); - @override - _i4.Stream<_i2.WheelEvent> get onMouseWheel => (super.noSuchMethod( - Invocation.getter(#onMouseWheel), Stream<_i2.WheelEvent>.empty()) - as _i4.Stream<_i2.WheelEvent>); - @override - _i4.Stream<_i2.Event> get onOffline => (super.noSuchMethod( - Invocation.getter(#onOffline), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onOnline => (super - .noSuchMethod(Invocation.getter(#onOnline), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onPageHide => (super.noSuchMethod( - Invocation.getter(#onPageHide), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onPageShow => (super.noSuchMethod( - Invocation.getter(#onPageShow), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onPause => (super - .noSuchMethod(Invocation.getter(#onPause), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); + (super.noSuchMethod(Invocation.getter(#onLoad), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onLoadedData => + (super.noSuchMethod(Invocation.getter(#onLoadedData), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onLoadedMetadata => + (super.noSuchMethod(Invocation.getter(#onLoadedMetadata), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onLoadStart => + (super.noSuchMethod(Invocation.getter(#onLoadStart), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.MessageEvent> get onMessage => + (super.noSuchMethod(Invocation.getter(#onMessage), + returnValue: Stream<_i2.MessageEvent>.empty()) + as _i4.Stream<_i2.MessageEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseDown => + (super.noSuchMethod(Invocation.getter(#onMouseDown), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseEnter => + (super.noSuchMethod(Invocation.getter(#onMouseEnter), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseLeave => + (super.noSuchMethod(Invocation.getter(#onMouseLeave), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseMove => + (super.noSuchMethod(Invocation.getter(#onMouseMove), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseOut => + (super.noSuchMethod(Invocation.getter(#onMouseOut), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseOver => + (super.noSuchMethod(Invocation.getter(#onMouseOver), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.MouseEvent> get onMouseUp => + (super.noSuchMethod(Invocation.getter(#onMouseUp), + returnValue: Stream<_i2.MouseEvent>.empty()) + as _i4.Stream<_i2.MouseEvent>); + @override + _i4.Stream<_i2.WheelEvent> get onMouseWheel => + (super.noSuchMethod(Invocation.getter(#onMouseWheel), + returnValue: Stream<_i2.WheelEvent>.empty()) + as _i4.Stream<_i2.WheelEvent>); + @override + _i4.Stream<_i2.Event> get onOffline => + (super.noSuchMethod(Invocation.getter(#onOffline), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onOnline => + (super.noSuchMethod(Invocation.getter(#onOnline), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onPageHide => + (super.noSuchMethod(Invocation.getter(#onPageHide), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onPageShow => + (super.noSuchMethod(Invocation.getter(#onPageShow), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onPause => + (super.noSuchMethod(Invocation.getter(#onPause), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); @override _i4.Stream<_i2.Event> get onPlay => - (super.noSuchMethod(Invocation.getter(#onPlay), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onPlaying => (super.noSuchMethod( - Invocation.getter(#onPlaying), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.PopStateEvent> get onPopState => (super.noSuchMethod( - Invocation.getter(#onPopState), Stream<_i2.PopStateEvent>.empty()) - as _i4.Stream<_i2.PopStateEvent>); - @override - _i4.Stream<_i2.Event> get onProgress => (super.noSuchMethod( - Invocation.getter(#onProgress), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onRateChange => (super.noSuchMethod( - Invocation.getter(#onRateChange), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onReset => (super - .noSuchMethod(Invocation.getter(#onReset), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onResize => (super - .noSuchMethod(Invocation.getter(#onResize), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onScroll => (super - .noSuchMethod(Invocation.getter(#onScroll), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onSearch => (super - .noSuchMethod(Invocation.getter(#onSearch), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onSeeked => (super - .noSuchMethod(Invocation.getter(#onSeeked), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onSeeking => (super.noSuchMethod( - Invocation.getter(#onSeeking), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onSelect => (super - .noSuchMethod(Invocation.getter(#onSelect), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onStalled => (super.noSuchMethod( - Invocation.getter(#onStalled), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.StorageEvent> get onStorage => (super.noSuchMethod( - Invocation.getter(#onStorage), Stream<_i2.StorageEvent>.empty()) - as _i4.Stream<_i2.StorageEvent>); - @override - _i4.Stream<_i2.Event> get onSubmit => (super - .noSuchMethod(Invocation.getter(#onSubmit), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onSuspend => (super.noSuchMethod( - Invocation.getter(#onSuspend), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onTimeUpdate => (super.noSuchMethod( - Invocation.getter(#onTimeUpdate), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.TouchEvent> get onTouchCancel => (super.noSuchMethod( - Invocation.getter(#onTouchCancel), Stream<_i2.TouchEvent>.empty()) - as _i4.Stream<_i2.TouchEvent>); - @override - _i4.Stream<_i2.TouchEvent> get onTouchEnd => (super.noSuchMethod( - Invocation.getter(#onTouchEnd), Stream<_i2.TouchEvent>.empty()) - as _i4.Stream<_i2.TouchEvent>); - @override - _i4.Stream<_i2.TouchEvent> get onTouchMove => (super.noSuchMethod( - Invocation.getter(#onTouchMove), Stream<_i2.TouchEvent>.empty()) - as _i4.Stream<_i2.TouchEvent>); - @override - _i4.Stream<_i2.TouchEvent> get onTouchStart => (super.noSuchMethod( - Invocation.getter(#onTouchStart), Stream<_i2.TouchEvent>.empty()) - as _i4.Stream<_i2.TouchEvent>); - @override - _i4.Stream<_i2.TransitionEvent> get onTransitionEnd => (super.noSuchMethod( - Invocation.getter(#onTransitionEnd), - Stream<_i2.TransitionEvent>.empty()) as _i4.Stream<_i2.TransitionEvent>); - @override - _i4.Stream<_i2.Event> get onUnload => (super - .noSuchMethod(Invocation.getter(#onUnload), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onVolumeChange => (super.noSuchMethod( - Invocation.getter(#onVolumeChange), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.Event> get onWaiting => (super.noSuchMethod( - Invocation.getter(#onWaiting), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); - @override - _i4.Stream<_i2.AnimationEvent> get onAnimationEnd => (super.noSuchMethod( - Invocation.getter(#onAnimationEnd), - Stream<_i2.AnimationEvent>.empty()) as _i4.Stream<_i2.AnimationEvent>); + (super.noSuchMethod(Invocation.getter(#onPlay), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onPlaying => + (super.noSuchMethod(Invocation.getter(#onPlaying), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.PopStateEvent> get onPopState => + (super.noSuchMethod(Invocation.getter(#onPopState), + returnValue: Stream<_i2.PopStateEvent>.empty()) + as _i4.Stream<_i2.PopStateEvent>); + @override + _i4.Stream<_i2.Event> get onProgress => + (super.noSuchMethod(Invocation.getter(#onProgress), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onRateChange => + (super.noSuchMethod(Invocation.getter(#onRateChange), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onReset => + (super.noSuchMethod(Invocation.getter(#onReset), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onResize => + (super.noSuchMethod(Invocation.getter(#onResize), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onScroll => + (super.noSuchMethod(Invocation.getter(#onScroll), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onSearch => + (super.noSuchMethod(Invocation.getter(#onSearch), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onSeeked => + (super.noSuchMethod(Invocation.getter(#onSeeked), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onSeeking => + (super.noSuchMethod(Invocation.getter(#onSeeking), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onSelect => + (super.noSuchMethod(Invocation.getter(#onSelect), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onStalled => + (super.noSuchMethod(Invocation.getter(#onStalled), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.StorageEvent> get onStorage => + (super.noSuchMethod(Invocation.getter(#onStorage), + returnValue: Stream<_i2.StorageEvent>.empty()) + as _i4.Stream<_i2.StorageEvent>); + @override + _i4.Stream<_i2.Event> get onSubmit => + (super.noSuchMethod(Invocation.getter(#onSubmit), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onSuspend => + (super.noSuchMethod(Invocation.getter(#onSuspend), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onTimeUpdate => + (super.noSuchMethod(Invocation.getter(#onTimeUpdate), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.TouchEvent> get onTouchCancel => + (super.noSuchMethod(Invocation.getter(#onTouchCancel), + returnValue: Stream<_i2.TouchEvent>.empty()) + as _i4.Stream<_i2.TouchEvent>); + @override + _i4.Stream<_i2.TouchEvent> get onTouchEnd => + (super.noSuchMethod(Invocation.getter(#onTouchEnd), + returnValue: Stream<_i2.TouchEvent>.empty()) + as _i4.Stream<_i2.TouchEvent>); + @override + _i4.Stream<_i2.TouchEvent> get onTouchMove => + (super.noSuchMethod(Invocation.getter(#onTouchMove), + returnValue: Stream<_i2.TouchEvent>.empty()) + as _i4.Stream<_i2.TouchEvent>); + @override + _i4.Stream<_i2.TouchEvent> get onTouchStart => + (super.noSuchMethod(Invocation.getter(#onTouchStart), + returnValue: Stream<_i2.TouchEvent>.empty()) + as _i4.Stream<_i2.TouchEvent>); + @override + _i4.Stream<_i2.TransitionEvent> get onTransitionEnd => + (super.noSuchMethod(Invocation.getter(#onTransitionEnd), + returnValue: Stream<_i2.TransitionEvent>.empty()) + as _i4.Stream<_i2.TransitionEvent>); + @override + _i4.Stream<_i2.Event> get onUnload => + (super.noSuchMethod(Invocation.getter(#onUnload), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onVolumeChange => + (super.noSuchMethod(Invocation.getter(#onVolumeChange), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.Event> get onWaiting => + (super.noSuchMethod(Invocation.getter(#onWaiting), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); + @override + _i4.Stream<_i2.AnimationEvent> get onAnimationEnd => + (super.noSuchMethod(Invocation.getter(#onAnimationEnd), + returnValue: Stream<_i2.AnimationEvent>.empty()) + as _i4.Stream<_i2.AnimationEvent>); @override _i4.Stream<_i2.AnimationEvent> get onAnimationIteration => (super.noSuchMethod(Invocation.getter(#onAnimationIteration), - Stream<_i2.AnimationEvent>.empty()) + returnValue: Stream<_i2.AnimationEvent>.empty()) as _i4.Stream<_i2.AnimationEvent>); @override - _i4.Stream<_i2.AnimationEvent> get onAnimationStart => (super.noSuchMethod( - Invocation.getter(#onAnimationStart), - Stream<_i2.AnimationEvent>.empty()) as _i4.Stream<_i2.AnimationEvent>); + _i4.Stream<_i2.AnimationEvent> get onAnimationStart => + (super.noSuchMethod(Invocation.getter(#onAnimationStart), + returnValue: Stream<_i2.AnimationEvent>.empty()) + as _i4.Stream<_i2.AnimationEvent>); @override - _i4.Stream<_i2.Event> get onBeforeUnload => (super.noSuchMethod( - Invocation.getter(#onBeforeUnload), Stream<_i2.Event>.empty()) - as _i4.Stream<_i2.Event>); + _i4.Stream<_i2.Event> get onBeforeUnload => + (super.noSuchMethod(Invocation.getter(#onBeforeUnload), + returnValue: Stream<_i2.Event>.empty()) as _i4.Stream<_i2.Event>); @override - _i4.Stream<_i2.WheelEvent> get onWheel => (super.noSuchMethod( - Invocation.getter(#onWheel), Stream<_i2.WheelEvent>.empty()) - as _i4.Stream<_i2.WheelEvent>); + _i4.Stream<_i2.WheelEvent> get onWheel => + (super.noSuchMethod(Invocation.getter(#onWheel), + returnValue: Stream<_i2.WheelEvent>.empty()) + as _i4.Stream<_i2.WheelEvent>); @override int get pageXOffset => - (super.noSuchMethod(Invocation.getter(#pageXOffset), 0) as int); + (super.noSuchMethod(Invocation.getter(#pageXOffset), returnValue: 0) + as int); @override int get pageYOffset => - (super.noSuchMethod(Invocation.getter(#pageYOffset), 0) as int); + (super.noSuchMethod(Invocation.getter(#pageYOffset), returnValue: 0) + as int); @override int get scrollX => - (super.noSuchMethod(Invocation.getter(#scrollX), 0) as int); + (super.noSuchMethod(Invocation.getter(#scrollX), returnValue: 0) as int); @override int get scrollY => - (super.noSuchMethod(Invocation.getter(#scrollY), 0) as int); + (super.noSuchMethod(Invocation.getter(#scrollY), returnValue: 0) as int); @override _i2.Events get on => - (super.noSuchMethod(Invocation.getter(#on), _FakeEvents()) as _i2.Events); + (super.noSuchMethod(Invocation.getter(#on), returnValue: _FakeEvents()) + as _i2.Events); @override int get hashCode => - (super.noSuchMethod(Invocation.getter(#hashCode), 0) as int); + (super.noSuchMethod(Invocation.getter(#hashCode), returnValue: 0) as int); @override - Type get runtimeType => - (super.noSuchMethod(Invocation.getter(#runtimeType), _FakeType()) - as Type); + Type get runtimeType => (super.noSuchMethod(Invocation.getter(#runtimeType), + returnValue: _FakeType()) as Type); @override _i2.WindowBase open(String? url, String? name, [String? options]) => - (super.noSuchMethod( - Invocation.method(#open, [url, name, options]), _FakeWindowBase()) - as _i2.WindowBase); + (super.noSuchMethod(Invocation.method(#open, [url, name, options]), + returnValue: _FakeWindowBase()) as _i2.WindowBase); @override int requestAnimationFrame(_i2.FrameRequestCallback? callback) => - (super.noSuchMethod( - Invocation.method(#requestAnimationFrame, [callback]), 0) as int); + (super.noSuchMethod(Invocation.method(#requestAnimationFrame, [callback]), + returnValue: 0) as int); @override void cancelAnimationFrame(int? id) => - super.noSuchMethod(Invocation.method(#cancelAnimationFrame, [id])); + super.noSuchMethod(Invocation.method(#cancelAnimationFrame, [id]), + returnValueForMissingStub: null); @override - _i4.Future<_i2.FileSystem> requestFileSystem(int? size, {bool? persistent}) => + _i4.Future<_i2.FileSystem> requestFileSystem(int? size, + {bool? persistent = false}) => (super.noSuchMethod( - Invocation.method( - #requestFileSystem, [size], {#persistent: persistent}), - Future.value(_FakeFileSystem())) as _i4.Future<_i2.FileSystem>); + Invocation.method( + #requestFileSystem, [size], {#persistent: persistent}), + returnValue: Future.value(_FakeFileSystem())) + as _i4.Future<_i2.FileSystem>); @override void cancelIdleCallback(int? handle) => - super.noSuchMethod(Invocation.method(#cancelIdleCallback, [handle])); + super.noSuchMethod(Invocation.method(#cancelIdleCallback, [handle]), + returnValueForMissingStub: null); @override bool confirm([String? message]) => - (super.noSuchMethod(Invocation.method(#confirm, [message]), false) - as bool); + (super.noSuchMethod(Invocation.method(#confirm, [message]), + returnValue: false) as bool); @override _i4.Future fetch(dynamic input, [Map? init]) => - (super.noSuchMethod( - Invocation.method(#fetch, [input, init]), Future.value(null)) - as _i4.Future); + (super.noSuchMethod(Invocation.method(#fetch, [input, init]), + returnValue: Future.value(null)) as _i4.Future); @override bool find(String? string, bool? caseSensitive, bool? backwards, bool? wrap, bool? wholeWord, bool? searchInFrames, bool? showDialog) => @@ -483,56 +521,64 @@ class MockWindow extends _i1.Mock implements _i2.Window { searchInFrames, showDialog ]), - false) as bool); + returnValue: false) as bool); @override _i2.StylePropertyMapReadonly getComputedStyleMap( _i2.Element? element, String? pseudoElement) => (super.noSuchMethod( - Invocation.method(#getComputedStyleMap, [element, pseudoElement]), - _FakeStylePropertyMapReadonly()) as _i2.StylePropertyMapReadonly); + Invocation.method(#getComputedStyleMap, [element, pseudoElement]), + returnValue: _FakeStylePropertyMapReadonly()) + as _i2.StylePropertyMapReadonly); @override List<_i2.CssRule> getMatchedCssRules( _i2.Element? element, String? pseudoElement) => (super.noSuchMethod( Invocation.method(#getMatchedCssRules, [element, pseudoElement]), - <_i2.CssRule>[]) as List<_i2.CssRule>); + returnValue: <_i2.CssRule>[]) as List<_i2.CssRule>); @override - _i2.MediaQueryList matchMedia(String? query) => (super.noSuchMethod( - Invocation.method(#matchMedia, [query]), _FakeMediaQueryList()) - as _i2.MediaQueryList); + _i2.MediaQueryList matchMedia(String? query) => + (super.noSuchMethod(Invocation.method(#matchMedia, [query]), + returnValue: _FakeMediaQueryList()) as _i2.MediaQueryList); @override void moveBy(int? x, int? y) => - super.noSuchMethod(Invocation.method(#moveBy, [x, y])); + super.noSuchMethod(Invocation.method(#moveBy, [x, y]), + returnValueForMissingStub: null); @override void postMessage(dynamic message, String? targetOrigin, [List? transfer]) => super.noSuchMethod( - Invocation.method(#postMessage, [message, targetOrigin, transfer])); + Invocation.method(#postMessage, [message, targetOrigin, transfer]), + returnValueForMissingStub: null); @override int requestIdleCallback(_i2.IdleRequestCallback? callback, [Map? options]) => (super.noSuchMethod( - Invocation.method(#requestIdleCallback, [callback, options]), 0) - as int); + Invocation.method(#requestIdleCallback, [callback, options]), + returnValue: 0) as int); @override void resizeBy(int? x, int? y) => - super.noSuchMethod(Invocation.method(#resizeBy, [x, y])); + super.noSuchMethod(Invocation.method(#resizeBy, [x, y]), + returnValueForMissingStub: null); @override void resizeTo(int? x, int? y) => - super.noSuchMethod(Invocation.method(#resizeTo, [x, y])); + super.noSuchMethod(Invocation.method(#resizeTo, [x, y]), + returnValueForMissingStub: null); @override _i4.Future<_i2.Entry> resolveLocalFileSystemUrl(String? url) => (super.noSuchMethod(Invocation.method(#resolveLocalFileSystemUrl, [url]), - Future.value(_FakeEntry())) as _i4.Future<_i2.Entry>); + returnValue: Future.value(_FakeEntry())) as _i4.Future<_i2.Entry>); @override String atob(String? atob) => - (super.noSuchMethod(Invocation.method(#atob, [atob]), '') as String); + (super.noSuchMethod(Invocation.method(#atob, [atob]), returnValue: '') + as String); @override String btoa(String? btoa) => - (super.noSuchMethod(Invocation.method(#btoa, [btoa]), '') as String); + (super.noSuchMethod(Invocation.method(#btoa, [btoa]), returnValue: '') + as String); @override void moveTo(_i5.Point? p) => - super.noSuchMethod(Invocation.method(#moveTo, [p])); + super.noSuchMethod(Invocation.method(#moveTo, [p]), + returnValueForMissingStub: null); @override _i3.SqlDatabase openDatabase(String? name, String? version, String? displayName, int? estimatedSize, @@ -540,27 +586,31 @@ class MockWindow extends _i1.Mock implements _i2.Window { (super.noSuchMethod( Invocation.method(#openDatabase, [name, version, displayName, estimatedSize, creationCallback]), - _FakeSqlDatabase()) as _i3.SqlDatabase); + returnValue: _FakeSqlDatabase()) as _i3.SqlDatabase); @override void addEventListener(String? type, _i2.EventListener? listener, [bool? useCapture]) => super.noSuchMethod( - Invocation.method(#addEventListener, [type, listener, useCapture])); + Invocation.method(#addEventListener, [type, listener, useCapture]), + returnValueForMissingStub: null); @override void removeEventListener(String? type, _i2.EventListener? listener, [bool? useCapture]) => - super.noSuchMethod(Invocation.method( - #removeEventListener, [type, listener, useCapture])); + super.noSuchMethod( + Invocation.method(#removeEventListener, [type, listener, useCapture]), + returnValueForMissingStub: null); @override bool dispatchEvent(_i2.Event? event) => - (super.noSuchMethod(Invocation.method(#dispatchEvent, [event]), false) - as bool); + (super.noSuchMethod(Invocation.method(#dispatchEvent, [event]), + returnValue: false) as bool); @override bool operator ==(Object? other) => - (super.noSuchMethod(Invocation.method(#==, [other]), false) as bool); + (super.noSuchMethod(Invocation.method(#==, [other]), returnValue: false) + as bool); @override String toString() => - (super.noSuchMethod(Invocation.method(#toString, []), '') as String); + (super.noSuchMethod(Invocation.method(#toString, []), returnValue: '') + as String); } /// A class which mocks [Navigator]. @@ -573,92 +623,104 @@ class MockNavigator extends _i1.Mock implements _i2.Navigator { @override String get language => - (super.noSuchMethod(Invocation.getter(#language), '') as String); + (super.noSuchMethod(Invocation.getter(#language), returnValue: '') + as String); @override _i2.Geolocation get geolocation => - (super.noSuchMethod(Invocation.getter(#geolocation), _FakeGeolocation()) - as _i2.Geolocation); + (super.noSuchMethod(Invocation.getter(#geolocation), + returnValue: _FakeGeolocation()) as _i2.Geolocation); @override String get vendor => - (super.noSuchMethod(Invocation.getter(#vendor), '') as String); + (super.noSuchMethod(Invocation.getter(#vendor), returnValue: '') + as String); @override String get vendorSub => - (super.noSuchMethod(Invocation.getter(#vendorSub), '') as String); + (super.noSuchMethod(Invocation.getter(#vendorSub), returnValue: '') + as String); @override String get appCodeName => - (super.noSuchMethod(Invocation.getter(#appCodeName), '') as String); + (super.noSuchMethod(Invocation.getter(#appCodeName), returnValue: '') + as String); @override String get appName => - (super.noSuchMethod(Invocation.getter(#appName), '') as String); + (super.noSuchMethod(Invocation.getter(#appName), returnValue: '') + as String); @override String get appVersion => - (super.noSuchMethod(Invocation.getter(#appVersion), '') as String); + (super.noSuchMethod(Invocation.getter(#appVersion), returnValue: '') + as String); @override String get product => - (super.noSuchMethod(Invocation.getter(#product), '') as String); + (super.noSuchMethod(Invocation.getter(#product), returnValue: '') + as String); @override String get userAgent => - (super.noSuchMethod(Invocation.getter(#userAgent), '') as String); + (super.noSuchMethod(Invocation.getter(#userAgent), returnValue: '') + as String); @override int get hashCode => - (super.noSuchMethod(Invocation.getter(#hashCode), 0) as int); + (super.noSuchMethod(Invocation.getter(#hashCode), returnValue: 0) as int); @override - Type get runtimeType => - (super.noSuchMethod(Invocation.getter(#runtimeType), _FakeType()) - as Type); + Type get runtimeType => (super.noSuchMethod(Invocation.getter(#runtimeType), + returnValue: _FakeType()) as Type); @override List<_i2.Gamepad?> getGamepads() => - (super.noSuchMethod(Invocation.method(#getGamepads, []), <_i2.Gamepad?>[]) - as List<_i2.Gamepad?>); + (super.noSuchMethod(Invocation.method(#getGamepads, []), + returnValue: <_i2.Gamepad?>[]) as List<_i2.Gamepad?>); @override - _i4.Future<_i2.MediaStream> getUserMedia({dynamic audio, dynamic video}) => + _i4.Future<_i2.MediaStream> getUserMedia( + {dynamic audio = false, dynamic video = false}) => (super.noSuchMethod( Invocation.method(#getUserMedia, [], {#audio: audio, #video: video}), - Future.value(_FakeMediaStream())) as _i4.Future<_i2.MediaStream>); + returnValue: + Future.value(_FakeMediaStream())) as _i4.Future<_i2.MediaStream>); @override - _i4.Future getBattery() => (super - .noSuchMethod(Invocation.method(#getBattery, []), Future.value(null)) - as _i4.Future); + _i4.Future getBattery() => + (super.noSuchMethod(Invocation.method(#getBattery, []), + returnValue: Future.value(null)) as _i4.Future); @override _i4.Future<_i2.RelatedApplication> getInstalledRelatedApps() => (super.noSuchMethod(Invocation.method(#getInstalledRelatedApps, []), - Future.value(_FakeRelatedApplication())) + returnValue: Future.value(_FakeRelatedApplication())) as _i4.Future<_i2.RelatedApplication>); @override - _i4.Future getVRDisplays() => (super.noSuchMethod( - Invocation.method(#getVRDisplays, []), Future.value(null)) - as _i4.Future); + _i4.Future getVRDisplays() => + (super.noSuchMethod(Invocation.method(#getVRDisplays, []), + returnValue: Future.value(null)) as _i4.Future); @override void registerProtocolHandler(String? scheme, String? url, String? title) => super.noSuchMethod( - Invocation.method(#registerProtocolHandler, [scheme, url, title])); + Invocation.method(#registerProtocolHandler, [scheme, url, title]), + returnValueForMissingStub: null); @override _i4.Future requestKeyboardLock([List? keyCodes]) => (super.noSuchMethod(Invocation.method(#requestKeyboardLock, [keyCodes]), - Future.value(null)) as _i4.Future); + returnValue: Future.value(null)) as _i4.Future); @override _i4.Future requestMidiAccess([Map? options]) => (super.noSuchMethod(Invocation.method(#requestMidiAccess, [options]), - Future.value(null)) as _i4.Future); + returnValue: Future.value(null)) as _i4.Future); @override _i4.Future requestMediaKeySystemAccess(String? keySystem, List>? supportedConfigurations) => (super.noSuchMethod( Invocation.method(#requestMediaKeySystemAccess, [keySystem, supportedConfigurations]), - Future.value(null)) as _i4.Future); + returnValue: Future.value(null)) as _i4.Future); @override bool sendBeacon(String? url, Object? data) => - (super.noSuchMethod(Invocation.method(#sendBeacon, [url, data]), false) - as bool); + (super.noSuchMethod(Invocation.method(#sendBeacon, [url, data]), + returnValue: false) as bool); @override _i4.Future share([Map? data]) => - (super.noSuchMethod(Invocation.method(#share, [data]), Future.value(null)) - as _i4.Future); + (super.noSuchMethod(Invocation.method(#share, [data]), + returnValue: Future.value(null)) as _i4.Future); @override bool operator ==(Object? other) => - (super.noSuchMethod(Invocation.method(#==, [other]), false) as bool); + (super.noSuchMethod(Invocation.method(#==, [other]), returnValue: false) + as bool); @override String toString() => - (super.noSuchMethod(Invocation.method(#toString, []), '') as String); + (super.noSuchMethod(Invocation.method(#toString, []), returnValue: '') + as String); } diff --git a/packages/url_launcher/url_launcher_web/example/run_test.sh b/packages/url_launcher/url_launcher_web/example/run_test.sh index 1960bde25d17..dabf9a8630e6 100755 --- a/packages/url_launcher/url_launcher_web/example/run_test.sh +++ b/packages/url_launcher/url_launcher_web/example/run_test.sh @@ -13,11 +13,11 @@ if pgrep -lf chromedriver > /dev/null; then if [ $# -eq 0 ]; then echo "No target specified, running all tests..." - find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test_driver.dart --target='{}' + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' else echo "Running test target: $1..." set -x - flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test_driver.dart --target=$1 + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target=$1 fi else diff --git a/packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart b/packages/url_launcher/url_launcher_web/example/test_driver/integration_test.dart similarity index 100% rename from packages/url_launcher/url_launcher_web/example/test_driver/integration_test_driver.dart rename to packages/url_launcher/url_launcher_web/example/test_driver/integration_test.dart diff --git a/script/tool/lib/src/drive_examples_command.dart b/script/tool/lib/src/drive_examples_command.dart index de5dc9ebfc62..54e0eee26425 100644 --- a/script/tool/lib/src/drive_examples_command.dart +++ b/script/tool/lib/src/drive_examples_command.dart @@ -146,6 +146,7 @@ Tried searching for the following: driveArgs.addAll([ '-d', 'web-server', + '--web-port=7357', '--browser-name=chrome', ]); } diff --git a/script/tool/test/drive_examples_command_test.dart b/script/tool/test/drive_examples_command_test.dart index 65bdf99c165d..58b8fb0d087d 100644 --- a/script/tool/test/drive_examples_command_test.dart +++ b/script/tool/test/drive_examples_command_test.dart @@ -427,6 +427,7 @@ void main() { 'drive', '-d', 'web-server', + '--web-port=7357', '--browser-name=chrome', '--driver', driverTestPath, From 7b9ac6b0c20da2ae3cdbaf4f2a06a9b9eb6e1474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Sat, 20 Mar 2021 17:28:14 +0100 Subject: [PATCH 347/924] [quick_actions] 2/3 Quick actions federated platform interface (#3735) * Moved quickactions to a subfolder * Added platform interface with tests * Added exports * Formatted, made initialize return Future instead of void * Fixed formatting * formatting * Fixed analyze issue with import * Fixed formatting * Fixed formatting * Added license in files * Removed accidental \\\ * changed license to Flutter 2017 * Moved quickactions to a subfolder * Added platform interface with tests * Added exports * Formatted, made initialize return Future instead of void * Fixed formatting * formatting * Fixed analyze issue with import * Fixed formatting * Fixed formatting * Added license in files * Removed accidental \\\ * changed license to Flutter 2017 * Implemented feedback * Changed 2017 to 2013 * Changed 2017 to 2013 * Implemented feedback. --- packages/quick_actions/AUTHORS | 66 -------- .../test/quick_actions_test.dart | 1 + .../CHANGELOG.md | 3 + .../quick_actions_platform_interface/LICENSE | 25 +++ .../README.md | 26 +++ .../method_channel_quick_actions.dart | 52 ++++++ .../quick_actions_platform.dart | 55 +++++++ .../lib/quick_actions_platform_interface.dart | 6 + .../lib/types/quick_action_handler.dart | 8 + .../lib/types/shortcut_item.dart | 26 +++ .../lib/types/types.dart | 6 + .../pubspec.yaml | 22 +++ .../method_channel_quick_actions_test.dart | 155 ++++++++++++++++++ ...quick_actions_platform_interface_test.dart | 73 +++++++++ 14 files changed, 458 insertions(+), 66 deletions(-) delete mode 100644 packages/quick_actions/AUTHORS create mode 100644 packages/quick_actions/quick_actions_platform_interface/CHANGELOG.md create mode 100644 packages/quick_actions/quick_actions_platform_interface/LICENSE create mode 100644 packages/quick_actions/quick_actions_platform_interface/README.md create mode 100644 packages/quick_actions/quick_actions_platform_interface/lib/method_channel/method_channel_quick_actions.dart create mode 100644 packages/quick_actions/quick_actions_platform_interface/lib/platform_interface/quick_actions_platform.dart create mode 100644 packages/quick_actions/quick_actions_platform_interface/lib/quick_actions_platform_interface.dart create mode 100644 packages/quick_actions/quick_actions_platform_interface/lib/types/quick_action_handler.dart create mode 100644 packages/quick_actions/quick_actions_platform_interface/lib/types/shortcut_item.dart create mode 100644 packages/quick_actions/quick_actions_platform_interface/lib/types/types.dart create mode 100644 packages/quick_actions/quick_actions_platform_interface/pubspec.yaml create mode 100644 packages/quick_actions/quick_actions_platform_interface/test/method_channel_quick_actions_test.dart create mode 100644 packages/quick_actions/quick_actions_platform_interface/test/quick_actions_platform_interface_test.dart diff --git a/packages/quick_actions/AUTHORS b/packages/quick_actions/AUTHORS deleted file mode 100644 index 493a0b4ef9c2..000000000000 --- a/packages/quick_actions/AUTHORS +++ /dev/null @@ -1,66 +0,0 @@ -# Below is a list of people and organizations that have contributed -# to the Flutter project. Names should be added to the list like so: -# -# Name/Organization - -Google Inc. -The Chromium Authors -German Saprykin -Benjamin Sauer -larsenthomasj@gmail.com -Ali Bitek -Pol Batlló -Anatoly Pulyaevskiy -Hayden Flinner -Stefano Rodriguez -Salvatore Giordano -Brian Armstrong -Paul DeMarco -Fabricio Nogueira -Simon Lightfoot -Ashton Thomas -Thomas Danner -Diego Velásquez -Hajime Nakamura -Tuyển Vũ Xuân -Miguel Ruivo -Sarthak Verma -Mike Diarmid -Invertase -Elliot Hesp -Vince Varga -Aawaz Gyawali -EUI Limited -Katarina Sheremet -Thomas Stockx -Sarbagya Dhaubanjar -Ozkan Eksi -Rishab Nayak -ko2ic -Jonathan Younger -Jose Sanchez -Debkanchan Samadder -Audrius Karosevicius -Lukasz Piliszczuk -SoundReply Solutions GmbH -Rafal Wachol -Pau Picas -Christian Weder -Alexandru Tuca -Christian Weder -Rhodes Davis Jr. -Luigi Agosti -Quentin Le Guennec -Koushik Ravikumar -Nissim Dsilva -Giancarlo Rocha -Ryo Miyake -Théo Champion -Kazuki Yamaguchi -Eitan Schwartz -Chris Rutkowski -Juan Alvarez -Aleksandr Yurkovskiy -Anton Borries -Alex Li -Rahul Raj <64.rahulraj@gmail.com> diff --git a/packages/quick_actions/quick_actions/test/quick_actions_test.dart b/packages/quick_actions/quick_actions/test/quick_actions_test.dart index f2b9a9aefc8d..ccb593f149fb 100644 --- a/packages/quick_actions/quick_actions/test/quick_actions_test.dart +++ b/packages/quick_actions/quick_actions/test/quick_actions_test.dart @@ -1,6 +1,7 @@ // Copyright 2013 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 'dart:async'; import 'package:flutter/services.dart'; diff --git a/packages/quick_actions/quick_actions_platform_interface/CHANGELOG.md b/packages/quick_actions/quick_actions_platform_interface/CHANGELOG.md new file mode 100644 index 000000000000..4b63991e9c4a --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/CHANGELOG.md @@ -0,0 +1,3 @@ +# 1.0.0 + +* Initial release of quick_actions_platform_interface diff --git a/packages/quick_actions/quick_actions_platform_interface/LICENSE b/packages/quick_actions/quick_actions_platform_interface/LICENSE new file mode 100644 index 000000000000..4c99d1dcb85e --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/LICENSE @@ -0,0 +1,25 @@ +Copyright 2013 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/quick_actions/quick_actions_platform_interface/README.md b/packages/quick_actions/quick_actions_platform_interface/README.md new file mode 100644 index 000000000000..ce8136ee9614 --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/README.md @@ -0,0 +1,26 @@ +# quick_actions_platform_interface + +A common platform interface for the [`quick_actions`][1] plugin. + +This interface allows platform-specific implementations of the `quick_actions` +plugin, as well as the plugin itself, to ensure they are supporting the +same interface. + +# Usage + +To implement a new platform-specific implementation of `quick_actions`, extend +[`QuickActionsPlatform`][2] with an implementation that performs the +platform-specific behavior, and when you register your plugin, set the default +`QuickActionsPlatform` by calling +`QuickActionsPlatform.instance = MyPlatformQuickActions()`. + +# Note on breaking changes + +Strongly prefer non-breaking changes (such as adding a method to the interface) +over breaking changes for this package. + +See https://flutter.dev/go/platform-interface-breaking-changes for a discussion +on why a less-clean interface is preferable to a breaking change. + +[1]: ../quick_actions +[2]: lib/quick_actions_platform_interface.dart diff --git a/packages/quick_actions/quick_actions_platform_interface/lib/method_channel/method_channel_quick_actions.dart b/packages/quick_actions/quick_actions_platform_interface/lib/method_channel/method_channel_quick_actions.dart new file mode 100644 index 000000000000..8172fe017a4d --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/lib/method_channel/method_channel_quick_actions.dart @@ -0,0 +1,52 @@ +// Copyright 2013 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/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show visibleForTesting; +import 'package:quick_actions_platform_interface/types/types.dart'; + +import '../platform_interface/quick_actions_platform.dart'; + +final MethodChannel _channel = + MethodChannel('plugins.flutter.io/quick_actions'); + +/// An implementation of [QuickActionsPlatform] that uses method channels. +class MethodChannelQuickActions extends QuickActionsPlatform { + /// The MethodChannel that is being used by this implementation of the plugin. + @visibleForTesting + MethodChannel get channel => _channel; + + @override + Future initialize(QuickActionHandler handler) async { + channel.setMethodCallHandler((MethodCall call) async { + assert(call.method == 'launch'); + handler(call.arguments); + }); + final String? action = + await channel.invokeMethod('getLaunchAction'); + if (action != null) { + handler(action); + } + } + + @override + Future setShortcutItems(List items) async { + final List> itemsList = + items.map(_serializeItem).toList(); + await channel.invokeMethod('setShortcutItems', itemsList); + } + + @override + Future clearShortcutItems() => + channel.invokeMethod('clearShortcutItems'); + + Map _serializeItem(ShortcutItem item) { + return { + 'type': item.type, + 'localizedTitle': item.localizedTitle, + 'icon': item.icon, + }; + } +} diff --git a/packages/quick_actions/quick_actions_platform_interface/lib/platform_interface/quick_actions_platform.dart b/packages/quick_actions/quick_actions_platform_interface/lib/platform_interface/quick_actions_platform.dart new file mode 100644 index 000000000000..b15fb8b43233 --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/lib/platform_interface/quick_actions_platform.dart @@ -0,0 +1,55 @@ +// Copyright 2013 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:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:quick_actions_platform_interface/types/types.dart'; + +import '../method_channel/method_channel_quick_actions.dart'; + +/// The interface that implementations of quick_actions must implement. +/// +/// Platform implementations should extend this class rather than implement it as `quick_actions` +/// does not consider newly added methods to be breaking changes. Extending this class +/// (using `extends`) ensures that the subclass will get the default implementation, while +/// platform implementations that `implements` this interface will be broken by newly added +/// [QuickActionsPlatform] methods. +abstract class QuickActionsPlatform extends PlatformInterface { + /// Constructs a QuickActionsPlatform. + QuickActionsPlatform() : super(token: _token); + + static final Object _token = Object(); + + static QuickActionsPlatform _instance = MethodChannelQuickActions(); + + /// The default instance of [QuickActionsPlatform] to use. + /// + /// Defaults to [MethodChannelQuickActions]. + static QuickActionsPlatform get instance => _instance; + + /// Platform-specific plugins should set this with their own platform-specific + /// class that extends [QuickActionsPlatform] when they register themselves. + // TODO(amirh): Extract common platform interface logic. + // https://github.com/flutter/flutter/issues/43368 + static set instance(QuickActionsPlatform instance) { + PlatformInterface.verifyToken(instance, _token); + _instance = instance; + } + + /// Initializes this plugin. + /// + /// Call this once before any further interaction with the the plugin. + Future initialize(QuickActionHandler handler) async { + throw UnimplementedError("initialize() has not been implemented."); + } + + /// Sets the [ShortcutItem]s to become the app's quick actions. + Future setShortcutItems(List items) async { + throw UnimplementedError("setShortcutItems() has not been implemented."); + } + + /// Removes all [ShortcutItem]s registered for the app. + Future clearShortcutItems() { + throw UnimplementedError("clearShortcutItems() has not been implemented."); + } +} diff --git a/packages/quick_actions/quick_actions_platform_interface/lib/quick_actions_platform_interface.dart b/packages/quick_actions/quick_actions_platform_interface/lib/quick_actions_platform_interface.dart new file mode 100644 index 000000000000..51bed8f230a8 --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/lib/quick_actions_platform_interface.dart @@ -0,0 +1,6 @@ +// Copyright 2013 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. + +export 'package:quick_actions_platform_interface/platform_interface/quick_actions_platform.dart'; +export 'package:quick_actions_platform_interface/types/types.dart'; diff --git a/packages/quick_actions/quick_actions_platform_interface/lib/types/quick_action_handler.dart b/packages/quick_actions/quick_actions_platform_interface/lib/types/quick_action_handler.dart new file mode 100644 index 000000000000..27c6bb494dfd --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/lib/types/quick_action_handler.dart @@ -0,0 +1,8 @@ +// Copyright 2013 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. + +/// Handler for a quick action launch event. +/// +/// The argument [type] corresponds to the [ShortcutItem]'s field. +typedef void QuickActionHandler(String type); diff --git a/packages/quick_actions/quick_actions_platform_interface/lib/types/shortcut_item.dart b/packages/quick_actions/quick_actions_platform_interface/lib/types/shortcut_item.dart new file mode 100644 index 000000000000..1d84e16ac996 --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/lib/types/shortcut_item.dart @@ -0,0 +1,26 @@ +// Copyright 2013 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. + +/// Home screen quick-action shortcut item. +class ShortcutItem { + /// Constructs an instance with the given [type], [localizedTitle], and + /// [icon]. + /// + /// Only [icon] should be nullable. It will remain `null` if unset. + const ShortcutItem({ + required this.type, + required this.localizedTitle, + this.icon, + }); + + /// The identifier of this item; should be unique within the app. + final String type; + + /// Localized title of the item. + final String localizedTitle; + + /// Name of native resource (xcassets etc; NOT a Flutter asset) to be + /// displayed as the icon for this item. + final String? icon; +} diff --git a/packages/quick_actions/quick_actions_platform_interface/lib/types/types.dart b/packages/quick_actions/quick_actions_platform_interface/lib/types/types.dart new file mode 100644 index 000000000000..ab85ca8260ce --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/lib/types/types.dart @@ -0,0 +1,6 @@ +// Copyright 2013 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. + +export 'quick_action_handler.dart'; +export 'shortcut_item.dart'; diff --git a/packages/quick_actions/quick_actions_platform_interface/pubspec.yaml b/packages/quick_actions/quick_actions_platform_interface/pubspec.yaml new file mode 100644 index 000000000000..eb1ff40bb4a4 --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/pubspec.yaml @@ -0,0 +1,22 @@ +name: quick_actions_platform_interface +description: A common platform interface for the quick_actions plugin. +homepage: https://github.com/flutter/plugins/tree/master/packages/quick_actions/quick_actions_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.0.0 + +dependencies: + flutter: + sdk: flutter + meta: ^1.3.0 + plugin_platform_interface: ^2.0.0 + +dev_dependencies: + flutter_test: + sdk: flutter + mockito: ^5.0.1 + pedantic: ^1.11.0 + +environment: + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.22.0" diff --git a/packages/quick_actions/quick_actions_platform_interface/test/method_channel_quick_actions_test.dart b/packages/quick_actions/quick_actions_platform_interface/test/method_channel_quick_actions_test.dart new file mode 100644 index 000000000000..f3e172e207fe --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/test/method_channel_quick_actions_test.dart @@ -0,0 +1,155 @@ +// Copyright 2013 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 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quick_actions_platform_interface/method_channel/method_channel_quick_actions.dart'; +import 'package:quick_actions_platform_interface/types/shortcut_item.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$MethodChannelQuickActions', () { + MethodChannelQuickActions quickActions = MethodChannelQuickActions(); + + final List log = []; + + setUp(() { + quickActions.channel + .setMockMethodCallHandler((MethodCall methodCall) async { + log.add(methodCall); + return ''; + }); + + log.clear(); + }); + + group('#initialize', () { + test('passes getLaunchAction on launch method', () { + quickActions.initialize((type) { + 'launch'; + }); + + expect( + log, + [ + isMethodCall('getLaunchAction', arguments: null), + ], + ); + }); + + test('initialize', () async { + final Completer quickActionsHandler = Completer(); + await quickActions + .initialize((_) => quickActionsHandler.complete(true)); + expect( + log, + [ + isMethodCall('getLaunchAction', arguments: null), + ], + ); + log.clear(); + + expect(quickActionsHandler.future, completion(isTrue)); + }); + }); + + group('#setShortCutItems', () { + test('passes shortcutItem through channel', () { + quickActions.initialize((type) { + 'launch'; + }); + quickActions.setShortcutItems([ + ShortcutItem(type: 'test', localizedTitle: 'title', icon: 'icon.svg') + ]); + + expect( + log, + [ + isMethodCall('getLaunchAction', arguments: null), + isMethodCall('setShortcutItems', arguments: [ + { + 'type': 'test', + 'localizedTitle': 'title', + 'icon': 'icon.svg', + } + ]), + ], + ); + }); + + test('setShortcutItems with demo data', () async { + const String type = 'type'; + const String localizedTitle = 'localizedTitle'; + const String icon = 'icon'; + await quickActions.setShortcutItems( + const [ + ShortcutItem(type: type, localizedTitle: localizedTitle, icon: icon) + ], + ); + expect( + log, + [ + isMethodCall( + 'setShortcutItems', + arguments: >[ + { + 'type': type, + 'localizedTitle': localizedTitle, + 'icon': icon, + } + ], + ), + ], + ); + log.clear(); + }); + }); + + group('#clearShortCutItems', () { + test('send clearShortcutItems through channel', () { + quickActions.initialize((type) { + 'launch'; + }); + quickActions.clearShortcutItems(); + + expect( + log, + [ + isMethodCall('getLaunchAction', arguments: null), + isMethodCall('clearShortcutItems', arguments: null), + ], + ); + }); + + test('clearShortcutItems', () { + quickActions.clearShortcutItems(); + expect( + log, + [ + isMethodCall('clearShortcutItems', arguments: null), + ], + ); + log.clear(); + }); + }); + }); + + group('$ShortcutItem', () { + test('Shortcut item can be constructed', () { + const String type = 'type'; + const String localizedTitle = 'title'; + const String icon = 'foo'; + + const ShortcutItem item = + ShortcutItem(type: type, localizedTitle: localizedTitle, icon: icon); + + expect(item.type, type); + expect(item.localizedTitle, localizedTitle); + expect(item.icon, icon); + }); + }); +} diff --git a/packages/quick_actions/quick_actions_platform_interface/test/quick_actions_platform_interface_test.dart b/packages/quick_actions/quick_actions_platform_interface/test/quick_actions_platform_interface_test.dart new file mode 100644 index 000000000000..8ce40816217f --- /dev/null +++ b/packages/quick_actions/quick_actions_platform_interface/test/quick_actions_platform_interface_test.dart @@ -0,0 +1,73 @@ +// Copyright 2013 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_test/flutter_test.dart'; +import 'package:quick_actions_platform_interface/method_channel/method_channel_quick_actions.dart'; +import 'package:quick_actions_platform_interface/platform_interface/quick_actions_platform.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$QuickActionsPlatform', () { + test('$MethodChannelQuickActions is the default instance', () { + expect(QuickActionsPlatform.instance, isA()); + }); + + test('Cannot be implemented with `implements`', () { + expect(() { + QuickActionsPlatform.instance = ImplementsQuickActionsPlatform(); + }, throwsNoSuchMethodError); + }); + + test('Can be extended', () { + QuickActionsPlatform.instance = ExtendsQuickActionsPlatform(); + }); + + test( + 'Default implementation of initialize() should throw unimplemented error', + () { + // Arrange + final QuickActionsPlatform = ExtendsQuickActionsPlatform(); + + // Act & Assert + expect( + () => QuickActionsPlatform.initialize((type) {}), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of setShortcutItems() should throw unimplemented error', + () { + // Arrange + final QuickActionsPlatform = ExtendsQuickActionsPlatform(); + + // Act & Assert + expect( + () => QuickActionsPlatform.setShortcutItems([]), + throwsUnimplementedError, + ); + }); + + test( + 'Default implementation of clearShortcutItems() should throw unimplemented error', + () { + // Arrange + final QuickActionsPlatform = ExtendsQuickActionsPlatform(); + + // Act & Assert + expect( + () => QuickActionsPlatform.clearShortcutItems(), + throwsUnimplementedError, + ); + }); + }); +} + +class ImplementsQuickActionsPlatform implements QuickActionsPlatform { + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +class ExtendsQuickActionsPlatform extends QuickActionsPlatform {} From 8621694430d0a164c358ab590519742af88cc2f4 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Mon, 22 Mar 2021 11:49:45 +0100 Subject: [PATCH 348/924] Update LICENSE (#3741) --- packages/quick_actions/quick_actions_platform_interface/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/quick_actions/quick_actions_platform_interface/LICENSE b/packages/quick_actions/quick_actions_platform_interface/LICENSE index 4c99d1dcb85e..c6823b81eb84 100644 --- a/packages/quick_actions/quick_actions_platform_interface/LICENSE +++ b/packages/quick_actions/quick_actions_platform_interface/LICENSE @@ -1,4 +1,4 @@ -Copyright 2013 The Chromium Authors. All rights reserved. +Copyright 2013 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From 7173380dd3f573877c0acd2b4f56e3df5a9c7c25 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Tue, 23 Mar 2021 20:46:03 +0200 Subject: [PATCH 349/924] [url_launcher] Update readme for URL schemes on iOS (#3252) --- .../url_launcher/url_launcher/CHANGELOG.md | 4 ++++ packages/url_launcher/url_launcher/README.md | 18 +++++++++++++++++- .../url_launcher/url_launcher/pubspec.yaml | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md index 9741f53ed329..f732fa58f8c6 100644 --- a/packages/url_launcher/url_launcher/CHANGELOG.md +++ b/packages/url_launcher/url_launcher/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.0.3 + +* Updat README notes about URL schemes on iOS + ## 6.0.2 * Update platform_plugin_interface version requirement. diff --git a/packages/url_launcher/url_launcher/README.md b/packages/url_launcher/url_launcher/README.md index daf21738d9b7..31fed9a833f1 100644 --- a/packages/url_launcher/url_launcher/README.md +++ b/packages/url_launcher/url_launcher/README.md @@ -8,6 +8,22 @@ iOS, Android, web, Windows, macOS, and Linux. ## Usage To use this plugin, add `url_launcher` as a [dependency in your pubspec.yaml file](https://flutter.dev/platform-plugins/). +## Installation + +### iOS +Add any URL schemes passed to `canLaunch` as `LSApplicationQueriesSchemes` entries in your Info.plist file. + +Example: +``` +LSApplicationQueriesSchemes + + https + http + +``` + +See [`-[UIApplication canOpenURL:]`](https://developer.apple.com/documentation/uikit/uiapplication/1622952-canopenurl) for more details. + ### Example ``` dart @@ -97,4 +113,4 @@ By default, Android opens up a browser when handling URLs. You can pass If you do this for a URL of a page containing JavaScript, make sure to pass in `enableJavaScript: true`, or else the launch method will not work properly. On iOS, the default behavior is to open all web URLs within the app. Everything -else is redirected to the app handler. +else is redirected to the app handler. \ No newline at end of file diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml index 7a4d1820fb1f..c8c5163d0e97 100644 --- a/packages/url_launcher/url_launcher/pubspec.yaml +++ b/packages/url_launcher/url_launcher/pubspec.yaml @@ -2,7 +2,7 @@ name: url_launcher description: Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes. homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher -version: 6.0.2 +version: 6.0.3 flutter: plugin: From 9548bc27af5da89544e8b1d8c31d12aaa9d673ca Mon Sep 17 00:00:00 2001 From: godofredoc <54371434+godofredoc@users.noreply.github.com> Date: Tue, 23 Mar 2021 13:48:22 -0700 Subject: [PATCH 350/924] Use flutter gcp project for linux tasks. (#3733) * Use flutter gcp project for linux tasks. Bug: https://github.com/flutter/flutter/issues/77624 * Merge upstream changes and change cluster. * Add test_script back. --- .cirrus.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index c2bbd35e15e7..e9db1b7b6bf8 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,7 +1,8 @@ +gcp_credentials: ENCRYPTED[ec898795b6f1b54f9cc2ab4104909f1053651f65fcab96397cfdc33dae6df5fd0fa972e29ba19f4f95125de844ab1641] + # Don't run on release tags since it creates O(n^2) tasks where n is the # number of plugins only_if: $CIRRUS_TAG == '' -use_compute_credits: $CIRRUS_USER_COLLABORATOR == 'true' && $CIRRUS_PR == '' env: INTEGRATION_TEST_PATH: "./packages/integration_test" CHANNEL: "master" # Default to master when not explicitly set by a task. @@ -32,8 +33,13 @@ macos_template: &MACOS_TEMPLATE # concurrency limits. task: << : *FLUTTER_UPGRADE_TEMPLATE - container: + gke_container: dockerfile: .ci/Dockerfile + builder_image_name: docker-builder # gce vm image + builder_image_project: flutter-cirrus + cluster_name: test-cluster + zone: us-central1-a + namespace: default matrix: ### Platform-agnostic tasks ### - name: plugin_tools_tests @@ -118,8 +124,13 @@ task: # for non-credit runs. task: << : *FLUTTER_UPGRADE_TEMPLATE - container: + gke_container: dockerfile: .ci/Dockerfile + builder_image_name: docker-builder # gce vm image + builder_image_project: flutter-cirrus + cluster_name: test-cluster + zone: us-central1-a + namespace: default cpu: 4 memory: 12G matrix: From 9cd84bdba7fcb18750f9916e3cad70963950709b Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Wed, 24 Mar 2021 15:35:57 +0100 Subject: [PATCH 351/924] [camera] Fix iOS rotation issue (#3591) * Fix iOS rotation issue * Fix orientation issues on iOS * Merged with master and added test * Test RotationBox turns according to device orientation * Fix formatting * Removed merge conflict tags from CHANGELOG * Fix license header in test --- packages/camera/camera/CHANGELOG.md | 4 + .../camera/camera/ios/Classes/CameraPlugin.m | 104 +++++--- .../camera/camera/lib/src/camera_preview.dart | 31 ++- packages/camera/camera/pubspec.yaml | 2 +- .../camera/test/camera_preview_test.dart | 239 ++++++++++++++++++ 5 files changed, 324 insertions(+), 56 deletions(-) create mode 100644 packages/camera/camera/test/camera_preview_test.dart diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index f1d771496dde..eb88683bee8f 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.1 + +* Solved a rotation issue on iOS which caused the default preview to be displayed as landscape right instead of portrait. + ## 0.8.0 * Stable null safety release. diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index e867491fcf8f..5c43f78a8c4b 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -345,6 +345,7 @@ @interface FLTCam : NSObject _videoWriter.status == AVAssetWriterStatusCompleted) { + [self updateOrientation]; result(self->_videoRecordingPath); self->_videoRecordingPath = nil; } else { @@ -854,12 +884,18 @@ - (void)lockCaptureOrientationWithResult:(FlutterResult)result result(getFlutterError(e)); return; } - _lockedCaptureOrientation = orientation; + + if (_lockedCaptureOrientation != orientation) { + _lockedCaptureOrientation = orientation; + [self updateOrientation]; + } + result(nil); } - (void)unlockCaptureOrientationWithResult:(FlutterResult)result { _lockedCaptureOrientation = UIDeviceOrientationUnknown; + [self updateOrientation]; result(nil); } @@ -1101,6 +1137,7 @@ - (BOOL)setupWriterForPath:(NSString *)path { if (_enableAudio && !_isAudioSetup) { [self setUpCaptureSessionForAudio]; } + _videoWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeMPEG4 error:&error]; @@ -1109,11 +1146,9 @@ - (BOOL)setupWriterForPath:(NSString *)path { [_methodChannel invokeMethod:errorMethod arguments:error.description]; return NO; } - NSDictionary *videoSettings = [NSDictionary - dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey, - [NSNumber numberWithInt:_previewSize.width], AVVideoWidthKey, - [NSNumber numberWithInt:_previewSize.height], AVVideoHeightKey, - nil]; + + NSDictionary *videoSettings = [_captureVideoOutput + recommendedVideoSettingsForAssetWriterWithOutputFileType:AVFileTypeMPEG4]; _videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings]; @@ -1124,14 +1159,7 @@ - (BOOL)setupWriterForPath:(NSString *)path { }]; NSParameterAssert(_videoWriterInput); - CGFloat rotationDegrees; - if (_lockedCaptureOrientation != UIDeviceOrientationUnknown) { - rotationDegrees = [self getRotationFromDeviceOrientation:_lockedCaptureOrientation]; - } else { - rotationDegrees = [self getRotationFromDeviceOrientation:[UIDevice currentDevice].orientation]; - } - _videoWriterInput.transform = CGAffineTransformMakeRotation(rotationDegrees * M_PI / 180); _videoWriterInput.expectsMediaDataInRealTime = YES; // Add the audio input @@ -1194,21 +1222,6 @@ - (void)setUpCaptureSessionForAudio { } } } - -- (int)getRotationFromDeviceOrientation:(UIDeviceOrientation)orientation { - switch (orientation) { - case UIDeviceOrientationPortraitUpsideDown: - return 270; - case UIDeviceOrientationLandscapeRight: - return 180; - case UIDeviceOrientationLandscapeLeft: - return 0; - case UIDeviceOrientationPortrait: - default: - return 90; - }; -} - @end @interface CameraPlugin () @@ -1257,7 +1270,13 @@ - (void)startOrientationListener { - (void)orientationChanged:(NSNotification *)note { UIDevice *device = note.object; - [self sendDeviceOrientation:device.orientation]; + UIDeviceOrientation orientation = device.orientation; + + if (_camera) { + [_camera setDeviceOrientation:orientation]; + } + + [self sendDeviceOrientation:orientation]; } - (void)sendDeviceOrientation:(UIDeviceOrientation)orientation { @@ -1318,6 +1337,7 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re FLTCam *cam = [[FLTCam alloc] initWithCameraName:cameraName resolutionPreset:resolutionPreset enableAudio:[enableAudio boolValue] + orientation:[[UIDevice currentDevice] orientation] dispatchQueue:_dispatchQueue error:&error]; diff --git a/packages/camera/camera/lib/src/camera_preview.dart b/packages/camera/camera/lib/src/camera_preview.dart index 517751b7bf64..e2f1ff931e42 100644 --- a/packages/camera/camera/lib/src/camera_preview.dart +++ b/packages/camera/camera/lib/src/camera_preview.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:camera/camera.dart'; -import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -29,11 +28,7 @@ class CameraPreview extends StatelessWidget { child: Stack( fit: StackFit.expand, children: [ - RotatedBox( - quarterTurns: _getQuarterTurns(), - child: - CameraPlatform.instance.buildPreview(controller.cameraId), - ), + _wrapInRotatedBox(child: controller.buildPreview()), child ?? Container(), ], ), @@ -41,11 +36,15 @@ class CameraPreview extends StatelessWidget { : Container(); } - DeviceOrientation _getApplicableOrientation() { - return controller.value.isRecordingVideo - ? controller.value.recordingOrientation! - : (controller.value.lockedCaptureOrientation ?? - controller.value.deviceOrientation); + Widget _wrapInRotatedBox({required Widget child}) { + if (defaultTargetPlatform != TargetPlatform.android) { + return child; + } + + return RotatedBox( + quarterTurns: _getQuarterTurns(), + child: child, + ); } bool _isLandscape() { @@ -54,13 +53,19 @@ class CameraPreview extends StatelessWidget { } int _getQuarterTurns() { - int platformOffset = defaultTargetPlatform == TargetPlatform.iOS ? 1 : 0; Map turns = { DeviceOrientation.portraitUp: 0, DeviceOrientation.landscapeLeft: 1, DeviceOrientation.portraitDown: 2, DeviceOrientation.landscapeRight: 3, }; - return turns[_getApplicableOrientation()]! + platformOffset; + return turns[_getApplicableOrientation()]!; + } + + DeviceOrientation _getApplicableOrientation() { + return controller.value.isRecordingVideo + ? controller.value.recordingOrientation! + : (controller.value.lockedCaptureOrientation ?? + controller.value.deviceOrientation); } } diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 53f9b3b40ad1..58bfa85d6b99 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.8.0 +version: 0.8.1 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: diff --git a/packages/camera/camera/test/camera_preview_test.dart b/packages/camera/camera/test/camera_preview_test.dart new file mode 100644 index 000000000000..d579341c0e58 --- /dev/null +++ b/packages/camera/camera/test/camera_preview_test.dart @@ -0,0 +1,239 @@ +// Copyright 2013 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 'dart:async'; + +import 'package:camera/camera.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quiver/core.dart'; + +class FakeController extends ValueNotifier + implements CameraController { + FakeController() : super(const CameraValue.uninitialized()); + + @override + Future dispose() async { + super.dispose(); + } + + @override + Widget buildPreview() { + return Texture(textureId: CameraController.kUninitializedCameraId); + } + + @override + int get cameraId => CameraController.kUninitializedCameraId; + + @override + void debugCheckIsDisposed() {} + + @override + CameraDescription get description => CameraDescription( + name: '', lensDirection: CameraLensDirection.back, sensorOrientation: 0); + + @override + bool get enableAudio => false; + + @override + Future getExposureOffsetStepSize() async => 1.0; + + @override + Future getMaxExposureOffset() async => 1.0; + + @override + Future getMaxZoomLevel() async => 1.0; + + @override + Future getMinExposureOffset() async => 1.0; + + @override + Future getMinZoomLevel() async => 1.0; + + @override + ImageFormatGroup? get imageFormatGroup => null; + + @override + Future initialize() async {} + + @override + Future lockCaptureOrientation([DeviceOrientation? orientation]) async {} + + @override + Future pauseVideoRecording() async {} + + @override + Future prepareForVideoRecording() async {} + + @override + ResolutionPreset get resolutionPreset => ResolutionPreset.low; + + @override + Future resumeVideoRecording() async {} + + @override + Future setExposureMode(ExposureMode mode) async {} + + @override + Future setExposureOffset(double offset) async => offset; + + @override + Future setExposurePoint(Offset? point) async {} + + @override + Future setFlashMode(FlashMode mode) async {} + + @override + Future setFocusMode(FocusMode mode) async {} + + @override + Future setFocusPoint(Offset? point) async {} + + @override + Future setZoomLevel(double zoom) async {} + + @override + Future startImageStream(onAvailable) async {} + + @override + Future startVideoRecording() async {} + + @override + Future stopImageStream() async {} + + @override + Future stopVideoRecording() async => XFile(''); + + @override + Future takePicture() async => XFile(''); + + @override + Future unlockCaptureOrientation() async {} +} + +void main() { + group('RotatedBox (Android only)', () { + testWidgets( + 'when recording rotatedBox should turn according to recording orientation', + ( + WidgetTester tester, + ) async { + debugDefaultTargetPlatformOverride = TargetPlatform.android; + + final FakeController controller = FakeController(); + controller.value = controller.value.copyWith( + isInitialized: true, + isRecordingVideo: true, + deviceOrientation: DeviceOrientation.portraitUp, + lockedCaptureOrientation: + Optional.fromNullable(DeviceOrientation.landscapeRight), + recordingOrientation: + Optional.fromNullable(DeviceOrientation.landscapeLeft), + previewSize: Size(480, 640), + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: CameraPreview(controller), + ), + ); + expect(find.byType(RotatedBox), findsOneWidget); + + RotatedBox rotatedBox = + tester.widget(find.byType(RotatedBox)); + expect(rotatedBox.quarterTurns, 1); + + debugDefaultTargetPlatformOverride = null; + }); + + testWidgets( + 'when orientation locked rotatedBox should turn according to locked orientation', + ( + WidgetTester tester, + ) async { + debugDefaultTargetPlatformOverride = TargetPlatform.android; + + final FakeController controller = FakeController(); + controller.value = controller.value.copyWith( + isInitialized: true, + deviceOrientation: DeviceOrientation.portraitUp, + lockedCaptureOrientation: + Optional.fromNullable(DeviceOrientation.landscapeRight), + recordingOrientation: + Optional.fromNullable(DeviceOrientation.landscapeLeft), + previewSize: Size(480, 640), + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: CameraPreview(controller), + ), + ); + expect(find.byType(RotatedBox), findsOneWidget); + + RotatedBox rotatedBox = + tester.widget(find.byType(RotatedBox)); + expect(rotatedBox.quarterTurns, 3); + + debugDefaultTargetPlatformOverride = null; + }); + + testWidgets( + 'when not locked and not recording rotatedBox should turn according to device orientation', + ( + WidgetTester tester, + ) async { + debugDefaultTargetPlatformOverride = TargetPlatform.android; + + final FakeController controller = FakeController(); + controller.value = controller.value.copyWith( + isInitialized: true, + deviceOrientation: DeviceOrientation.portraitUp, + lockedCaptureOrientation: null, + recordingOrientation: + Optional.fromNullable(DeviceOrientation.landscapeLeft), + previewSize: Size(480, 640), + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: CameraPreview(controller), + ), + ); + expect(find.byType(RotatedBox), findsOneWidget); + + RotatedBox rotatedBox = + tester.widget(find.byType(RotatedBox)); + expect(rotatedBox.quarterTurns, 0); + + debugDefaultTargetPlatformOverride = null; + }); + }); + + testWidgets('when not on Android there should not be a rotated box', + (WidgetTester tester) async { + debugDefaultTargetPlatformOverride = TargetPlatform.iOS; + final FakeController controller = FakeController(); + controller.value = controller.value.copyWith( + isInitialized: true, + previewSize: Size(480, 640), + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: CameraPreview(controller), + ), + ); + expect(find.byType(RotatedBox), findsNothing); + expect(find.byType(Texture), findsOneWidget); + debugDefaultTargetPlatformOverride = null; + }); +} From e9ed3cdd6b1adbb1a1bce4a5b00c10776a6e20fd Mon Sep 17 00:00:00 2001 From: PiN73 Date: Wed, 24 Mar 2021 19:17:19 +0300 Subject: [PATCH 352/924] [video_player_platform_interface] add http headers (#3702) platform_interface portion of #3671 --- .../CHANGELOG.md | 4 ++++ .../lib/messages.dart | 5 ++++- .../lib/method_channel_video_player.dart | 1 + .../lib/video_player_platform_interface.dart | 6 ++++++ .../pubspec.yaml | 2 +- .../test/method_channel_video_player_test.dart | 18 ++++++++++++++++++ 6 files changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/video_player/video_player_platform_interface/CHANGELOG.md b/packages/video_player/video_player_platform_interface/CHANGELOG.md index d0c59bd05023..24631513f800 100644 --- a/packages/video_player/video_player_platform_interface/CHANGELOG.md +++ b/packages/video_player/video_player_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.1.0 + +* Add `httpHeaders` to `DataSource` + ## 4.0.0 * **Breaking Changes**: diff --git a/packages/video_player/video_player_platform_interface/lib/messages.dart b/packages/video_player/video_player_platform_interface/lib/messages.dart index 2b7d8821a0cc..0ddbfaeaf247 100644 --- a/packages/video_player/video_player_platform_interface/lib/messages.dart +++ b/packages/video_player/video_player_platform_interface/lib/messages.dart @@ -31,6 +31,7 @@ class CreateMessage { String? uri; String? packageName; String? formatHint; + Map? httpHeaders; Object encode() { final Map pigeonMap = {}; @@ -38,6 +39,7 @@ class CreateMessage { pigeonMap['uri'] = uri; pigeonMap['packageName'] = packageName; pigeonMap['formatHint'] = formatHint; + pigeonMap['httpHeaders'] = httpHeaders; return pigeonMap; } @@ -47,7 +49,8 @@ class CreateMessage { ..asset = pigeonMap['asset'] as String? ..uri = pigeonMap['uri'] as String? ..packageName = pigeonMap['packageName'] as String? - ..formatHint = pigeonMap['formatHint'] as String?; + ..formatHint = pigeonMap['formatHint'] as String? + ..httpHeaders = pigeonMap['httpHeaders'] as Map?; } } diff --git a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart index bd9708a117be..e92e87013d68 100644 --- a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart +++ b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart @@ -37,6 +37,7 @@ class MethodChannelVideoPlayer extends VideoPlayerPlatform { case DataSourceType.network: message.uri = dataSource.uri; message.formatHint = _videoFormatStringMap[dataSource.formatHint]; + message.httpHeaders = dataSource.httpHeaders; break; case DataSourceType.file: message.uri = dataSource.uri; diff --git a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart index 1960253af193..b2bff990401e 100644 --- a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart +++ b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart @@ -151,6 +151,7 @@ class DataSource { this.formatHint, this.asset, this.package, + this.httpHeaders = const {}, }); /// The way in which the video was originally loaded. @@ -169,6 +170,11 @@ class DataSource { /// detection with whatever is set here. final VideoFormat? formatHint; + /// HTTP headers used for the request to the [uri]. + /// Only for [DataSourceType.network] videos. + /// Always empty for other video types. + Map httpHeaders; + /// The name of the asset. Only set for [DataSourceType.asset] videos. final String? asset; diff --git a/packages/video_player/video_player_platform_interface/pubspec.yaml b/packages/video_player/video_player_platform_interface/pubspec.yaml index c85f483d041f..98e1c95a8e8f 100644 --- a/packages/video_player/video_player_platform_interface/pubspec.yaml +++ b/packages/video_player/video_player_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the video_player plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player_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: 4.0.0 +version: 4.1.0 dependencies: flutter: diff --git a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart index 00ec64305a31..33a5b34b615d 100644 --- a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart +++ b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart @@ -141,8 +141,26 @@ void main() { formatHint: VideoFormat.dash, )); expect(log.log.last, 'create'); + expect(log.createMessage?.asset, null); expect(log.createMessage?.uri, 'someUri'); + expect(log.createMessage?.packageName, null); expect(log.createMessage?.formatHint, 'dash'); + expect(log.createMessage?.httpHeaders, {}); + expect(textureId, 3); + }); + + test('create with network (some headers)', () async { + final int? textureId = await player.create(DataSource( + sourceType: DataSourceType.network, + uri: 'someUri', + httpHeaders: {'Authorization': 'Bearer token'}, + )); + expect(log.log.last, 'create'); + expect(log.createMessage?.asset, null); + expect(log.createMessage?.uri, 'someUri'); + expect(log.createMessage?.packageName, null); + expect(log.createMessage?.formatHint, null); + expect(log.createMessage?.httpHeaders, {'Authorization': 'Bearer token'}); expect(textureId, 3); }); From ce1cf17352f1299ded6bf477d57a3646edccdbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Wed, 24 Mar 2021 17:45:17 +0100 Subject: [PATCH 353/924] [quick_actions] example fix (#3745) --- packages/quick_actions/quick_actions/CHANGELOG.md | 4 ++++ packages/quick_actions/quick_actions/example/lib/main.dart | 6 ++++-- packages/quick_actions/quick_actions/pubspec.yaml | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/quick_actions/quick_actions/CHANGELOG.md b/packages/quick_actions/quick_actions/CHANGELOG.md index 276ddfbf24c4..5f192825cacf 100644 --- a/packages/quick_actions/quick_actions/CHANGELOG.md +++ b/packages/quick_actions/quick_actions/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.0+1 + +* Updated example app implementation. + ## 0.5.0 * Migrate to null safety. diff --git a/packages/quick_actions/quick_actions/example/lib/main.dart b/packages/quick_actions/quick_actions/example/lib/main.dart index 3ff6528f3565..8e47d16683dd 100644 --- a/packages/quick_actions/quick_actions/example/lib/main.dart +++ b/packages/quick_actions/quick_actions/example/lib/main.dart @@ -32,7 +32,7 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - String shortcut = "no action set"; + String shortcut = 'no action set'; @override void initState() { @@ -63,7 +63,9 @@ class _MyHomePageState extends State { icon: 'ic_launcher'), ]).then((value) { setState(() { - shortcut = "actions ready"; + if (shortcut == 'no action set') { + shortcut = 'actions ready'; + } }); }); } diff --git a/packages/quick_actions/quick_actions/pubspec.yaml b/packages/quick_actions/quick_actions/pubspec.yaml index ed6555833b83..71accce09fcf 100644 --- a/packages/quick_actions/quick_actions/pubspec.yaml +++ b/packages/quick_actions/quick_actions/pubspec.yaml @@ -2,7 +2,7 @@ name: quick_actions description: Flutter plugin for creating shortcuts on home screen, also known as Quick Actions on iOS and App Shortcuts on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/quick_actions -version: 0.5.0 +version: 0.5.0+1 flutter: plugin: From 7a3dd3132eb5ae0c30420cc9cdb0d23fb30d6560 Mon Sep 17 00:00:00 2001 From: Tyler Reece Date: Wed, 24 Mar 2021 15:15:03 -0400 Subject: [PATCH 354/924] Updated README.md typo (#2606) --- packages/in_app_purchase/example/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/in_app_purchase/example/README.md b/packages/in_app_purchase/example/README.md index 6dd5b38d7003..ef32964f141d 100644 --- a/packages/in_app_purchase/example/README.md +++ b/packages/in_app_purchase/example/README.md @@ -16,7 +16,7 @@ documentation on how to do this, and we've also included a high level guide below. * [In-App Purchase (App Store)](https://developer.apple.com/in-app-purchase/) -* [Google Play Biling Overview](https://developer.android.com/google/play/billing/billing_overview) +* [Google Play Billing Overview](https://developer.android.com/google/play/billing/billing_overview) ### Android @@ -86,4 +86,4 @@ below. service (including iTunes!) with the test account will permanently invalidate it. Sign in to the test account in the example app following the steps in the [*In-App Purchase Programming - Guide*](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/ShowUI.html#//apple_ref/doc/uid/TP40008267-CH3-SW11). \ No newline at end of file + Guide*](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/ShowUI.html#//apple_ref/doc/uid/TP40008267-CH3-SW11). From 2904cbb45fa6de2584e859446643ed8c89d4e84f Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Wed, 24 Mar 2021 20:20:04 +0100 Subject: [PATCH 355/924] [flutter_plugin_tools] Also look for Java tests in plugin path (#3742) --- .../flutter/plugins/camera/DartMessenger.java | 38 ++++---- .../plugins/camera/MethodCallHandlerImpl.java | 6 +- .../plugins/camera/DartMessengerTest.java | 30 ++++++- script/tool/lib/src/java_test_command.dart | 9 +- script/tool/test/java_test_command_test.dart | 86 +++++++++++++++++++ 5 files changed, 145 insertions(+), 24 deletions(-) create mode 100644 script/tool/test/java_test_command_test.dart diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java index 164a529ffa8b..aaac1361eb3d 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java @@ -5,8 +5,8 @@ package io.flutter.plugins.camera; import android.os.Handler; -import android.os.Looper; import android.text.TextUtils; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.BinaryMessenger; @@ -17,6 +17,7 @@ import java.util.Map; class DartMessenger { + @NonNull private final Handler handler; @Nullable private MethodChannel cameraChannel; @Nullable private MethodChannel deviceChannel; @@ -41,9 +42,10 @@ enum CameraEventType { } } - DartMessenger(BinaryMessenger messenger, long cameraId) { + DartMessenger(BinaryMessenger messenger, long cameraId, @NonNull Handler handler) { cameraChannel = new MethodChannel(messenger, "flutter.io/cameraPlugin/camera" + cameraId); deviceChannel = new MethodChannel(messenger, "flutter.io/cameraPlugin/device"); + this.handler = handler; } void sendDeviceOrientationChangeEvent(PlatformChannel.DeviceOrientation orientation) { @@ -106,14 +108,14 @@ void send(CameraEventType eventType, Map args) { if (cameraChannel == null) { return; } - new Handler(Looper.getMainLooper()) - .post( - new Runnable() { - @Override - public void run() { - cameraChannel.invokeMethod(eventType.method, args); - } - }); + + handler.post( + new Runnable() { + @Override + public void run() { + cameraChannel.invokeMethod(eventType.method, args); + } + }); } void send(DeviceEventType eventType) { @@ -124,13 +126,13 @@ void send(DeviceEventType eventType, Map args) { if (deviceChannel == null) { return; } - new Handler(Looper.getMainLooper()) - .post( - new Runnable() { - @Override - public void run() { - deviceChannel.invokeMethod(eventType.method, args); - } - }); + + handler.post( + new Runnable() { + @Override + public void run() { + deviceChannel.invokeMethod(eventType.method, args); + } + }); } } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 040225ed5ff3..50bca6349217 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -6,6 +6,8 @@ import android.app.Activity; import android.hardware.camera2.CameraAccessException; +import android.os.Handler; +import android.os.Looper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import io.flutter.embedding.engine.systemchannels.PlatformChannel; @@ -353,7 +355,9 @@ private void instantiateCamera(MethodCall call, Result result) throws CameraAcce boolean enableAudio = call.argument("enableAudio"); TextureRegistry.SurfaceTextureEntry flutterSurfaceTexture = textureRegistry.createSurfaceTexture(); - DartMessenger dartMessenger = new DartMessenger(messenger, flutterSurfaceTexture.id()); + DartMessenger dartMessenger = + new DartMessenger( + messenger, flutterSurfaceTexture.id(), new Handler(Looper.getMainLooper())); camera = new Camera( activity, diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java index ed6fd56a3c34..25f5df9e9db9 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java @@ -6,7 +6,11 @@ import static junit.framework.TestCase.assertNull; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import android.os.Handler; import androidx.annotation.NonNull; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.BinaryMessenger; @@ -19,6 +23,8 @@ import java.util.List; import org.junit.Before; import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; public class DartMessengerTest { /** A {@link BinaryMessenger} implementation that does nothing but save its messages. */ @@ -43,20 +49,24 @@ List getMessages() { } } + private Handler mockHandler; private DartMessenger dartMessenger; private FakeBinaryMessenger fakeBinaryMessenger; @Before public void setUp() { + mockHandler = mock(Handler.class); fakeBinaryMessenger = new FakeBinaryMessenger(); - dartMessenger = new DartMessenger(fakeBinaryMessenger, 0); + dartMessenger = new DartMessenger(fakeBinaryMessenger, 0, mockHandler); } @Test public void sendCameraErrorEvent_includesErrorDescriptions() { - dartMessenger.sendCameraErrorEvent("error description"); + doAnswer(createPostHandlerAnswer()).when(mockHandler).post(any(Runnable.class)); + dartMessenger.sendCameraErrorEvent("error description"); List sentMessages = fakeBinaryMessenger.getMessages(); + assertEquals(1, sentMessages.size()); MethodCall call = decodeSentMessage(sentMessages.get(0)); assertEquals("error", call.method); @@ -65,6 +75,7 @@ public void sendCameraErrorEvent_includesErrorDescriptions() { @Test public void sendCameraInitializedEvent_includesPreviewSize() { + doAnswer(createPostHandlerAnswer()).when(mockHandler).post(any(Runnable.class)); dartMessenger.sendCameraInitializedEvent(0, 0, ExposureMode.auto, FocusMode.auto, true, true); List sentMessages = fakeBinaryMessenger.getMessages(); @@ -81,6 +92,7 @@ public void sendCameraInitializedEvent_includesPreviewSize() { @Test public void sendCameraClosingEvent() { + doAnswer(createPostHandlerAnswer()).when(mockHandler).post(any(Runnable.class)); dartMessenger.sendCameraClosingEvent(); List sentMessages = fakeBinaryMessenger.getMessages(); @@ -92,6 +104,7 @@ public void sendCameraClosingEvent() { @Test public void sendDeviceOrientationChangedEvent() { + doAnswer(createPostHandlerAnswer()).when(mockHandler).post(any(Runnable.class)); dartMessenger.sendDeviceOrientationChangeEvent(PlatformChannel.DeviceOrientation.PORTRAIT_UP); List sentMessages = fakeBinaryMessenger.getMessages(); @@ -101,6 +114,19 @@ public void sendDeviceOrientationChangedEvent() { assertEquals(call.argument("orientation"), "portraitUp"); } + private static Answer createPostHandlerAnswer() { + return new Answer() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + Runnable runnable = invocation.getArgument(0, Runnable.class); + if (runnable != null) { + runnable.run(); + } + return true; + } + }; + } + private MethodCall decodeSentMessage(ByteBuffer sentMessage) { sentMessage.position(0); diff --git a/script/tool/lib/src/java_test_command.dart b/script/tool/lib/src/java_test_command.dart index 45042c3c7006..4b6a561b9e6d 100644 --- a/script/tool/lib/src/java_test_command.dart +++ b/script/tool/lib/src/java_test_command.dart @@ -32,9 +32,12 @@ class JavaTestCommand extends PluginCommand { final Stream examplesWithTests = getExamples().where( (Directory d) => isFlutterPackage(d, fileSystem) && - fileSystem - .directory(p.join(d.path, 'android', 'app', 'src', 'test')) - .existsSync()); + (fileSystem + .directory(p.join(d.path, 'android', 'app', 'src', 'test')) + .existsSync() || + fileSystem + .directory(p.join(d.path, '..', 'android', 'src', 'test')) + .existsSync())); final List failingPackages = []; final List missingFlutterBuild = []; diff --git a/script/tool/test/java_test_command_test.dart b/script/tool/test/java_test_command_test.dart new file mode 100644 index 000000000000..b036d7ec0c6f --- /dev/null +++ b/script/tool/test/java_test_command_test.dart @@ -0,0 +1,86 @@ +// Copyright 2013 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:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:flutter_plugin_tools/src/java_test_command.dart'; +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; + +import 'util.dart'; + +void main() { + group('$JavaTestCommand', () { + CommandRunner runner; + final RecordingProcessRunner processRunner = RecordingProcessRunner(); + + setUp(() { + initializeFakePackages(); + final JavaTestCommand command = JavaTestCommand( + mockPackagesDir, mockFileSystem, + processRunner: processRunner); + + runner = + CommandRunner('java_test_test', 'Test for $JavaTestCommand'); + runner.addCommand(command); + }); + + tearDown(() { + cleanupPackages(); + processRunner.recordedCalls.clear(); + }); + + test('Should run Java tests in Android implementation folder', () async { + final Directory plugin = createFakePlugin( + 'plugin1', + isAndroidPlugin: true, + isFlutter: true, + withSingleExample: true, + withExtraFiles: >[ + ['example/android', 'gradlew'], + ['android/src/test', 'example_test.java'], + ], + ); + + await runner.run(['java-test']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + p.join(plugin.path, 'example/android/gradlew'), + ['testDebugUnitTest', '--info'], + p.join(plugin.path, 'example/android'), + ), + ]), + ); + }); + + test('Should run Java tests in example folder', () async { + final Directory plugin = createFakePlugin( + 'plugin1', + isAndroidPlugin: true, + isFlutter: true, + withSingleExample: true, + withExtraFiles: >[ + ['example/android', 'gradlew'], + ['example/android/app/src/test', 'example_test.java'], + ], + ); + + await runner.run(['java-test']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + p.join(plugin.path, 'example/android/gradlew'), + ['testDebugUnitTest', '--info'], + p.join(plugin.path, 'example/android'), + ), + ]), + ); + }); + }); +} From 12ea8f2770ab0d091cfa549723680fc648dfe9b3 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 24 Mar 2021 15:06:49 -0700 Subject: [PATCH 356/924] [all] remove podfile in gitignore and update all podfiles (#3747) --- .gitignore | 1 - packages/battery/battery/example/ios/Podfile | 38 +++++++++++++++++ packages/camera/camera/example/ios/Podfile | 38 +++++++++++++++++ .../connectivity/example/ios/Podfile | 38 +++++++++++++++++ .../device_info/example/ios/Podfile | 38 +++++++++++++++++ .../google_maps_flutter/example/ios/Podfile | 38 +++++++++++++++++ .../google_sign_in/example/ios/Podfile | 38 +++++++++++++++++ packages/integration_test/example/ios/Podfile | 38 +++++++++++++++++ .../ios_platform_images/example/ios/Podfile | 41 +++++++++++++++++++ packages/local_auth/example/ios/Podfile | 38 +++++++++++++++++ packages/package_info/example/ios/Podfile | 38 +++++++++++++++++ .../path_provider/example/ios/Podfile | 38 +++++++++++++++++ .../quick_actions/example/ios/Podfile | 38 +++++++++++++++++ packages/sensors/example/ios/Podfile | 38 +++++++++++++++++ packages/share/example/ios/Podfile | 38 +++++++++++++++++ .../shared_preferences/example/ios/Podfile | 38 +++++++++++++++++ .../url_launcher/example/ios/Podfile | 38 +++++++++++++++++ .../video_player/example/ios/Podfile | 38 +++++++++++++++++ .../wifi_info_flutter/example/ios/Podfile | 38 +++++++++++++++++ 19 files changed, 687 insertions(+), 1 deletion(-) create mode 100644 packages/battery/battery/example/ios/Podfile create mode 100644 packages/camera/camera/example/ios/Podfile create mode 100644 packages/connectivity/connectivity/example/ios/Podfile create mode 100644 packages/device_info/device_info/example/ios/Podfile create mode 100644 packages/google_maps_flutter/google_maps_flutter/example/ios/Podfile create mode 100644 packages/google_sign_in/google_sign_in/example/ios/Podfile create mode 100644 packages/integration_test/example/ios/Podfile create mode 100644 packages/ios_platform_images/example/ios/Podfile create mode 100644 packages/local_auth/example/ios/Podfile create mode 100644 packages/package_info/example/ios/Podfile create mode 100644 packages/path_provider/path_provider/example/ios/Podfile create mode 100644 packages/quick_actions/quick_actions/example/ios/Podfile create mode 100644 packages/sensors/example/ios/Podfile create mode 100644 packages/share/example/ios/Podfile create mode 100644 packages/shared_preferences/shared_preferences/example/ios/Podfile create mode 100644 packages/url_launcher/url_launcher/example/ios/Podfile create mode 100644 packages/video_player/video_player/example/ios/Podfile create mode 100644 packages/wifi_info_flutter/wifi_info_flutter/example/ios/Podfile diff --git a/.gitignore b/.gitignore index 823f9031d960..f4fa0b9b7795 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ flutter_export_environment.sh examples/all_plugins/pubspec.yaml -Podfile Podfile.lock Pods/ .symlinks/ diff --git a/packages/battery/battery/example/ios/Podfile b/packages/battery/battery/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/battery/battery/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/camera/camera/example/ios/Podfile b/packages/camera/camera/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/camera/camera/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/connectivity/connectivity/example/ios/Podfile b/packages/connectivity/connectivity/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/connectivity/connectivity/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/device_info/device_info/example/ios/Podfile b/packages/device_info/device_info/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/device_info/device_info/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Podfile b/packages/google_maps_flutter/google_maps_flutter/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/google_sign_in/google_sign_in/example/ios/Podfile b/packages/google_sign_in/google_sign_in/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/google_sign_in/google_sign_in/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/integration_test/example/ios/Podfile b/packages/integration_test/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/integration_test/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/ios_platform_images/example/ios/Podfile b/packages/ios_platform_images/example/ios/Podfile new file mode 100644 index 000000000000..1e8c3c90a55e --- /dev/null +++ b/packages/ios_platform_images/example/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/local_auth/example/ios/Podfile b/packages/local_auth/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/local_auth/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/package_info/example/ios/Podfile b/packages/package_info/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/package_info/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/path_provider/path_provider/example/ios/Podfile b/packages/path_provider/path_provider/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/path_provider/path_provider/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/quick_actions/quick_actions/example/ios/Podfile b/packages/quick_actions/quick_actions/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/quick_actions/quick_actions/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/sensors/example/ios/Podfile b/packages/sensors/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/sensors/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/share/example/ios/Podfile b/packages/share/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/share/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/shared_preferences/shared_preferences/example/ios/Podfile b/packages/shared_preferences/shared_preferences/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/shared_preferences/shared_preferences/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/url_launcher/url_launcher/example/ios/Podfile b/packages/url_launcher/url_launcher/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/url_launcher/url_launcher/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/video_player/video_player/example/ios/Podfile b/packages/video_player/video_player/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/video_player/video_player/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Podfile b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Podfile new file mode 100644 index 000000000000..f7d6a5e68c3a --- /dev/null +++ b/packages/wifi_info_flutter/wifi_info_flutter/example/ios/Podfile @@ -0,0 +1,38 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end From 98c79a9c7fcf0393969ee97aaf11efde1ad154b4 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Wed, 24 Mar 2021 15:56:40 -0700 Subject: [PATCH 357/924] [ci] Do not use empty exclude directories in analyze_command. (#3748) * Add CUSTOM_ANALYSIS_PLUGINS back with all the plugins that now have a custom analysis_options.yaml --- script/incremental_build.sh | 33 +++++++++++++++++++++- script/tool/lib/src/analyze_command.dart | 6 ++-- script/tool/test/analyze_command_test.dart | 15 ++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/script/incremental_build.sh b/script/incremental_build.sh index c14197c85ae7..ade89afe4ca1 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -19,8 +19,39 @@ ALL_EXCLUDED=("") # because we adopted stricter analysis rules recently and needed to exclude # already failing packages to start linting the repo as a whole. # -# TODO(mklim): Remove everything from this list. https://github.com/flutter/flutter/issues/45440 +# Finding all: `find packages -name analysis_options.yaml | sort | cut -d/ -f2` +# +# TODO(ecosystem): Remove everything from this list. https://github.com/flutter/flutter/issues/76229 CUSTOM_ANALYSIS_PLUGINS=( + android_alarm_manager + android_intent + battery + camera + connectivity + cross_file + device_info + e2e + espresso + file_selector + flutter_plugin_android_lifecycle + google_maps_flutter + google_sign_in + image_picker + in_app_purchase + integration_test + ios_platform_images + local_auth + package_info + path_provider + plugin_platform_interface + quick_actions + sensors + share + shared_preferences + url_launcher + video_player + webview_flutter + wifi_info_flutter ) # Comma-separated string of the list above diff --git a/script/tool/lib/src/analyze_command.dart b/script/tool/lib/src/analyze_command.dart index b2586c4b0fcf..9489303f5665 100644 --- a/script/tool/lib/src/analyze_command.dart +++ b/script/tool/lib/src/analyze_command.dart @@ -42,10 +42,12 @@ class AnalyzeCommand extends PluginCommand { continue; } - final bool whitelisted = argResults[_customAnalysisFlag].any( + final bool allowed = argResults[_customAnalysisFlag].any( (String directory) => + directory != null && + directory.isNotEmpty && p.isWithin(p.join(packagesDir.path, directory), file.path)); - if (whitelisted) { + if (allowed) { continue; } diff --git a/script/tool/test/analyze_command_test.dart b/script/tool/test/analyze_command_test.dart index 7b4ef81e0fc2..636d4794a484 100644 --- a/script/tool/test/analyze_command_test.dart +++ b/script/tool/test/analyze_command_test.dart @@ -93,5 +93,20 @@ void main() { pluginDir.path), ])); }); + + // See: https://github.com/flutter/flutter/issues/78994 + test('takes an empty allow list', () async { + await createFakePlugin('foo', withExtraFiles: >[ + ['analysis_options.yaml'] + ]); + + final MockProcess mockProcess = MockProcess(); + mockProcess.exitCodeCompleter.complete(0); + processRunner.processToReturn = mockProcess; + + await expectLater( + () => runner.run(['analyze', '--custom-analysis', '']), + throwsA(const TypeMatcher())); + }); }); } From e73402d873dc3fb26fe44643906dcc2157c3b49c Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 24 Mar 2021 16:19:09 -0700 Subject: [PATCH 358/924] [in_app_purchase] create sub folder (#3744) --- .../in_app_purchase/analysis_options.yaml | 1 - .../example/in_app_purchase_example.iml | 18 ----------- .../in_app_purchase_example_android.iml | 27 ---------------- .../{ => in_app_purchase}/AUTHORS | 0 .../{ => in_app_purchase}/CHANGELOG.md | 0 .../{ => in_app_purchase}/LICENSE | 0 .../{ => in_app_purchase}/README.md | 0 .../in_app_purchase/analysis_options.yaml | 1 + .../android/build.gradle | 0 .../android/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../android/settings.gradle | 0 .../android/src/main/AndroidManifest.xml | 0 .../inapppurchase/BillingClientFactory.java | 0 .../BillingClientFactoryImpl.java | 0 .../inapppurchase/InAppPurchasePlugin.java | 0 .../inapppurchase/MethodCallHandlerImpl.java | 0 .../inapppurchase/PluginPurchaseListener.java | 0 .../plugins/inapppurchase/Translator.java | 0 .../{ => in_app_purchase}/build.yaml | 0 .../{ => in_app_purchase}/example/.metadata | 0 .../{ => in_app_purchase}/example/README.md | 0 .../example/android/app/build.gradle | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../EmbeddingV1Activity.java | 0 .../EmbeddingV1ActivityTest.java | 0 .../FlutterActivityTest.java | 0 .../main/res/drawable/launch_background.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../app/src/main/res/values/styles.xml | 0 .../InAppPurchasePluginTest.java | 0 .../inapppurchase/MethodCallHandlerTest.java | 0 .../plugins/inapppurchase/TranslatorTest.java | 0 .../org.mockito.plugins.MockMaker | 0 .../example/android/build.gradle | 0 .../example/android/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../android/keystore.example.properties | 0 .../example/android/settings.gradle | 0 .../ios/Flutter/AppFrameworkInfo.plist | 0 .../example/ios/Flutter/Debug.xcconfig | 0 .../example/ios/Flutter/Release.xcconfig | 0 .../{ => in_app_purchase}/example/ios/Podfile | 0 .../ios/Runner.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../example/ios/Runner/AppDelegate.h | 0 .../example/ios/Runner/AppDelegate.m | 0 .../AppIcon.appiconset/Contents.json | 0 .../Icon-App-1024x1024@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../Icon-App-83.5x83.5@2x.png | Bin .../LaunchImage.imageset/Contents.json | 0 .../LaunchImage.imageset/LaunchImage.png | Bin .../LaunchImage.imageset/LaunchImage@2x.png | Bin .../LaunchImage.imageset/LaunchImage@3x.png | Bin .../LaunchImage.imageset/README.md | 0 .../Runner/Base.lproj/LaunchScreen.storyboard | 0 .../ios/Runner/Base.lproj/Main.storyboard | 0 .../example/ios/Runner/Info.plist | 0 .../example/ios/Runner/main.m | 0 .../in_app_purchase_pluginTests/Info.plist | 0 .../example/lib/consumable_store.dart | 0 .../example/lib/main.dart | 0 .../example/pubspec.yaml | 0 .../test_driver/test/integration_test.dart | 0 .../in_app_purchase_test.dart | 0 .../{ => in_app_purchase}/ios/Assets/.gitkeep | 0 .../ios/Classes/FIAObjectTranslator.h | 0 .../ios/Classes/FIAObjectTranslator.m | 0 .../ios/Classes/FIAPReceiptManager.h | 0 .../ios/Classes/FIAPReceiptManager.m | 0 .../ios/Classes/FIAPRequestHandler.h | 0 .../ios/Classes/FIAPRequestHandler.m | 0 .../ios/Classes/FIAPaymentQueueHandler.h | 0 .../ios/Classes/FIAPaymentQueueHandler.m | 0 .../ios/Classes/InAppPurchasePlugin.h | 0 .../ios/Classes/InAppPurchasePlugin.m | 0 .../ios/Tests/InAppPurchasePluginTest.m | 0 .../ios/Tests/PaymentQueueTest.m | 0 .../ios/Tests/ProductRequestHandlerTest.m | 0 .../{ => in_app_purchase}/ios/Tests/Stubs.h | 0 .../{ => in_app_purchase}/ios/Tests/Stubs.m | 0 .../ios/Tests/TranslatorTest.m | 0 .../ios/in_app_purchase.podspec | 0 .../lib/billing_client_wrappers.dart | 0 .../lib/in_app_purchase.dart | 0 .../lib/src/billing_client_wrappers/README.md | 0 .../billing_client_wrapper.dart | 0 .../enum_converters.dart | 0 .../enum_converters.g.dart | 0 .../purchase_wrapper.dart | 0 .../purchase_wrapper.g.dart | 0 .../sku_details_wrapper.dart | 0 .../sku_details_wrapper.g.dart | 0 .../lib/src/channel.dart | 0 .../lib/src/in_app_purchase/README.md | 0 .../in_app_purchase/app_store_connection.dart | 0 .../google_play_connection.dart | 0 .../in_app_purchase_connection.dart | 0 .../src/in_app_purchase/product_details.dart | 0 .../src/in_app_purchase/purchase_details.dart | 0 .../lib/src/store_kit_wrappers/README.md | 0 .../store_kit_wrappers/enum_converters.dart | 0 .../store_kit_wrappers/enum_converters.g.dart | 0 .../sk_payment_queue_wrapper.dart | 0 .../sk_payment_queue_wrapper.g.dart | 0 .../sk_payment_transaction_wrappers.dart | 0 .../sk_payment_transaction_wrappers.g.dart | 0 .../sk_product_wrapper.dart | 0 .../sk_product_wrapper.g.dart | 0 .../sk_receipt_manager.dart | 0 .../store_kit_wrappers/sk_request_maker.dart | 0 .../lib/store_kit_wrappers.dart | 0 .../{ => in_app_purchase}/pubspec.yaml | 0 .../billing_client_wrapper_test.dart | 0 .../purchase_wrapper_test.dart | 0 .../sku_details_wrapper_test.dart | 0 .../app_store_connection_test.dart | 0 .../google_play_connection_test.dart | 0 .../sk_methodchannel_apis_test.dart | 0 .../store_kit_wrappers/sk_product_test.dart | 0 .../sk_test_stub_objects.dart | 0 .../test/stub_in_app_purchase_platform.dart | 0 .../in_app_purchase_android.iml | 30 ------------------ 144 files changed, 1 insertion(+), 76 deletions(-) delete mode 100644 packages/in_app_purchase/analysis_options.yaml delete mode 100644 packages/in_app_purchase/example/in_app_purchase_example.iml delete mode 100644 packages/in_app_purchase/example/in_app_purchase_example_android.iml rename packages/in_app_purchase/{ => in_app_purchase}/AUTHORS (100%) rename packages/in_app_purchase/{ => in_app_purchase}/CHANGELOG.md (100%) rename packages/in_app_purchase/{ => in_app_purchase}/LICENSE (100%) rename packages/in_app_purchase/{ => in_app_purchase}/README.md (100%) create mode 100644 packages/in_app_purchase/in_app_purchase/analysis_options.yaml rename packages/in_app_purchase/{ => in_app_purchase}/android/build.gradle (100%) rename packages/in_app_purchase/{ => in_app_purchase}/android/gradle.properties (100%) rename packages/in_app_purchase/{ => in_app_purchase}/android/gradle/wrapper/gradle-wrapper.properties (100%) rename packages/in_app_purchase/{ => in_app_purchase}/android/settings.gradle (100%) rename packages/in_app_purchase/{ => in_app_purchase}/android/src/main/AndroidManifest.xml (100%) rename packages/in_app_purchase/{ => in_app_purchase}/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/build.yaml (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/.metadata (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/README.md (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/build.gradle (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/gradle/wrapper/gradle-wrapper.properties (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/AndroidManifest.xml (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/res/drawable/launch_background.xml (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/main/res/values/styles.xml (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/build.gradle (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/gradle.properties (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/gradle/wrapper/gradle-wrapper.properties (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/keystore.example.properties (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/android/settings.gradle (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Flutter/AppFrameworkInfo.plist (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Flutter/Debug.xcconfig (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Flutter/Release.xcconfig (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Podfile (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner.xcodeproj/project.pbxproj (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner.xcworkspace/contents.xcworkspacedata (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/AppDelegate.h (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/AppDelegate.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Base.lproj/Main.storyboard (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/Info.plist (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/Runner/main.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/ios/in_app_purchase_pluginTests/Info.plist (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/lib/consumable_store.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/lib/main.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/pubspec.yaml (100%) rename packages/in_app_purchase/{ => in_app_purchase}/example/test_driver/test/integration_test.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/integration_test/in_app_purchase_test.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Assets/.gitkeep (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Classes/FIAObjectTranslator.h (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Classes/FIAObjectTranslator.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Classes/FIAPReceiptManager.h (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Classes/FIAPReceiptManager.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Classes/FIAPRequestHandler.h (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Classes/FIAPRequestHandler.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Classes/FIAPaymentQueueHandler.h (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Classes/FIAPaymentQueueHandler.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Classes/InAppPurchasePlugin.h (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Classes/InAppPurchasePlugin.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Tests/InAppPurchasePluginTest.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Tests/PaymentQueueTest.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Tests/ProductRequestHandlerTest.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Tests/Stubs.h (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Tests/Stubs.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/Tests/TranslatorTest.m (100%) rename packages/in_app_purchase/{ => in_app_purchase}/ios/in_app_purchase.podspec (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/billing_client_wrappers.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/in_app_purchase.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/billing_client_wrappers/README.md (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/billing_client_wrappers/billing_client_wrapper.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/billing_client_wrappers/enum_converters.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/billing_client_wrappers/enum_converters.g.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/billing_client_wrappers/purchase_wrapper.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/billing_client_wrappers/purchase_wrapper.g.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/billing_client_wrappers/sku_details_wrapper.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/channel.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/in_app_purchase/README.md (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/in_app_purchase/app_store_connection.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/in_app_purchase/google_play_connection.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/in_app_purchase/in_app_purchase_connection.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/in_app_purchase/product_details.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/in_app_purchase/purchase_details.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/README.md (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/enum_converters.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/enum_converters.g.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/sk_product_wrapper.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/sk_receipt_manager.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/src/store_kit_wrappers/sk_request_maker.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/lib/store_kit_wrappers.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/pubspec.yaml (100%) rename packages/in_app_purchase/{ => in_app_purchase}/test/billing_client_wrappers/billing_client_wrapper_test.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/test/billing_client_wrappers/purchase_wrapper_test.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/test/billing_client_wrappers/sku_details_wrapper_test.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/test/in_app_purchase_connection/app_store_connection_test.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/test/in_app_purchase_connection/google_play_connection_test.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/test/store_kit_wrappers/sk_methodchannel_apis_test.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/test/store_kit_wrappers/sk_product_test.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/test/store_kit_wrappers/sk_test_stub_objects.dart (100%) rename packages/in_app_purchase/{ => in_app_purchase}/test/stub_in_app_purchase_platform.dart (100%) delete mode 100644 packages/in_app_purchase/in_app_purchase_android.iml diff --git a/packages/in_app_purchase/analysis_options.yaml b/packages/in_app_purchase/analysis_options.yaml deleted file mode 100644 index cda4f6e153e6..000000000000 --- a/packages/in_app_purchase/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: ../../analysis_options_legacy.yaml diff --git a/packages/in_app_purchase/example/in_app_purchase_example.iml b/packages/in_app_purchase/example/in_app_purchase_example.iml deleted file mode 100644 index e5c837191e06..000000000000 --- a/packages/in_app_purchase/example/in_app_purchase_example.iml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/packages/in_app_purchase/example/in_app_purchase_example_android.iml b/packages/in_app_purchase/example/in_app_purchase_example_android.iml deleted file mode 100644 index b050030a1b87..000000000000 --- a/packages/in_app_purchase/example/in_app_purchase_example_android.iml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/packages/in_app_purchase/AUTHORS b/packages/in_app_purchase/in_app_purchase/AUTHORS similarity index 100% rename from packages/in_app_purchase/AUTHORS rename to packages/in_app_purchase/in_app_purchase/AUTHORS diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md similarity index 100% rename from packages/in_app_purchase/CHANGELOG.md rename to packages/in_app_purchase/in_app_purchase/CHANGELOG.md diff --git a/packages/in_app_purchase/LICENSE b/packages/in_app_purchase/in_app_purchase/LICENSE similarity index 100% rename from packages/in_app_purchase/LICENSE rename to packages/in_app_purchase/in_app_purchase/LICENSE diff --git a/packages/in_app_purchase/README.md b/packages/in_app_purchase/in_app_purchase/README.md similarity index 100% rename from packages/in_app_purchase/README.md rename to packages/in_app_purchase/in_app_purchase/README.md diff --git a/packages/in_app_purchase/in_app_purchase/analysis_options.yaml b/packages/in_app_purchase/in_app_purchase/analysis_options.yaml new file mode 100644 index 000000000000..5aeb4e7c5e21 --- /dev/null +++ b/packages/in_app_purchase/in_app_purchase/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../../analysis_options_legacy.yaml diff --git a/packages/in_app_purchase/android/build.gradle b/packages/in_app_purchase/in_app_purchase/android/build.gradle similarity index 100% rename from packages/in_app_purchase/android/build.gradle rename to packages/in_app_purchase/in_app_purchase/android/build.gradle diff --git a/packages/in_app_purchase/android/gradle.properties b/packages/in_app_purchase/in_app_purchase/android/gradle.properties similarity index 100% rename from packages/in_app_purchase/android/gradle.properties rename to packages/in_app_purchase/in_app_purchase/android/gradle.properties diff --git a/packages/in_app_purchase/android/gradle/wrapper/gradle-wrapper.properties b/packages/in_app_purchase/in_app_purchase/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/in_app_purchase/android/gradle/wrapper/gradle-wrapper.properties rename to packages/in_app_purchase/in_app_purchase/android/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/in_app_purchase/android/settings.gradle b/packages/in_app_purchase/in_app_purchase/android/settings.gradle similarity index 100% rename from packages/in_app_purchase/android/settings.gradle rename to packages/in_app_purchase/in_app_purchase/android/settings.gradle diff --git a/packages/in_app_purchase/android/src/main/AndroidManifest.xml b/packages/in_app_purchase/in_app_purchase/android/src/main/AndroidManifest.xml similarity index 100% rename from packages/in_app_purchase/android/src/main/AndroidManifest.xml rename to packages/in_app_purchase/in_app_purchase/android/src/main/AndroidManifest.xml diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java similarity index 100% rename from packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java rename to packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java similarity index 100% rename from packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java rename to packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java similarity index 100% rename from packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java rename to packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java similarity index 100% rename from packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java rename to packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java similarity index 100% rename from packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java rename to packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java similarity index 100% rename from packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java rename to packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java diff --git a/packages/in_app_purchase/build.yaml b/packages/in_app_purchase/in_app_purchase/build.yaml similarity index 100% rename from packages/in_app_purchase/build.yaml rename to packages/in_app_purchase/in_app_purchase/build.yaml diff --git a/packages/in_app_purchase/example/.metadata b/packages/in_app_purchase/in_app_purchase/example/.metadata similarity index 100% rename from packages/in_app_purchase/example/.metadata rename to packages/in_app_purchase/in_app_purchase/example/.metadata diff --git a/packages/in_app_purchase/example/README.md b/packages/in_app_purchase/in_app_purchase/example/README.md similarity index 100% rename from packages/in_app_purchase/example/README.md rename to packages/in_app_purchase/in_app_purchase/example/README.md diff --git a/packages/in_app_purchase/example/android/app/build.gradle b/packages/in_app_purchase/in_app_purchase/example/android/app/build.gradle similarity index 100% rename from packages/in_app_purchase/example/android/app/build.gradle rename to packages/in_app_purchase/in_app_purchase/example/android/app/build.gradle diff --git a/packages/in_app_purchase/example/android/app/gradle/wrapper/gradle-wrapper.properties b/packages/in_app_purchase/in_app_purchase/example/android/app/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/in_app_purchase/example/android/app/gradle/wrapper/gradle-wrapper.properties rename to packages/in_app_purchase/in_app_purchase/example/android/app/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/in_app_purchase/example/android/app/src/main/AndroidManifest.xml b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/AndroidManifest.xml similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/AndroidManifest.xml rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/AndroidManifest.xml diff --git a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1Activity.java diff --git a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/EmbeddingV1ActivityTest.java diff --git a/packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/java/io/flutter/plugins/inapppurchaseexample/FlutterActivityTest.java diff --git a/packages/in_app_purchase/example/android/app/src/main/res/drawable/launch_background.xml b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/res/drawable/launch_background.xml rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/drawable/launch_background.xml diff --git a/packages/in_app_purchase/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/packages/in_app_purchase/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/packages/in_app_purchase/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/packages/in_app_purchase/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/packages/in_app_purchase/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/packages/in_app_purchase/example/android/app/src/main/res/values/styles.xml b/packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/values/styles.xml similarity index 100% rename from packages/in_app_purchase/example/android/app/src/main/res/values/styles.xml rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/main/res/values/styles.xml diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java b/packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java similarity index 100% rename from packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java b/packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java similarity index 100% rename from packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java similarity index 100% rename from packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java diff --git a/packages/in_app_purchase/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/packages/in_app_purchase/in_app_purchase/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker similarity index 100% rename from packages/in_app_purchase/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker rename to packages/in_app_purchase/in_app_purchase/example/android/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker diff --git a/packages/in_app_purchase/example/android/build.gradle b/packages/in_app_purchase/in_app_purchase/example/android/build.gradle similarity index 100% rename from packages/in_app_purchase/example/android/build.gradle rename to packages/in_app_purchase/in_app_purchase/example/android/build.gradle diff --git a/packages/in_app_purchase/example/android/gradle.properties b/packages/in_app_purchase/in_app_purchase/example/android/gradle.properties similarity index 100% rename from packages/in_app_purchase/example/android/gradle.properties rename to packages/in_app_purchase/in_app_purchase/example/android/gradle.properties diff --git a/packages/in_app_purchase/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/in_app_purchase/in_app_purchase/example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/in_app_purchase/example/android/gradle/wrapper/gradle-wrapper.properties rename to packages/in_app_purchase/in_app_purchase/example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/in_app_purchase/example/android/keystore.example.properties b/packages/in_app_purchase/in_app_purchase/example/android/keystore.example.properties similarity index 100% rename from packages/in_app_purchase/example/android/keystore.example.properties rename to packages/in_app_purchase/in_app_purchase/example/android/keystore.example.properties diff --git a/packages/in_app_purchase/example/android/settings.gradle b/packages/in_app_purchase/in_app_purchase/example/android/settings.gradle similarity index 100% rename from packages/in_app_purchase/example/android/settings.gradle rename to packages/in_app_purchase/in_app_purchase/example/android/settings.gradle diff --git a/packages/in_app_purchase/example/ios/Flutter/AppFrameworkInfo.plist b/packages/in_app_purchase/in_app_purchase/example/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from packages/in_app_purchase/example/ios/Flutter/AppFrameworkInfo.plist rename to packages/in_app_purchase/in_app_purchase/example/ios/Flutter/AppFrameworkInfo.plist diff --git a/packages/in_app_purchase/example/ios/Flutter/Debug.xcconfig b/packages/in_app_purchase/in_app_purchase/example/ios/Flutter/Debug.xcconfig similarity index 100% rename from packages/in_app_purchase/example/ios/Flutter/Debug.xcconfig rename to packages/in_app_purchase/in_app_purchase/example/ios/Flutter/Debug.xcconfig diff --git a/packages/in_app_purchase/example/ios/Flutter/Release.xcconfig b/packages/in_app_purchase/in_app_purchase/example/ios/Flutter/Release.xcconfig similarity index 100% rename from packages/in_app_purchase/example/ios/Flutter/Release.xcconfig rename to packages/in_app_purchase/in_app_purchase/example/ios/Flutter/Release.xcconfig diff --git a/packages/in_app_purchase/example/ios/Podfile b/packages/in_app_purchase/in_app_purchase/example/ios/Podfile similarity index 100% rename from packages/in_app_purchase/example/ios/Podfile rename to packages/in_app_purchase/in_app_purchase/example/ios/Podfile diff --git a/packages/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj b/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from packages/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj diff --git a/packages/in_app_purchase/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/in_app_purchase/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/packages/in_app_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from packages/in_app_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/packages/in_app_purchase/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/in_app_purchase/example/ios/Runner.xcworkspace/contents.xcworkspacedata rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/packages/in_app_purchase/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from packages/in_app_purchase/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/packages/in_app_purchase/example/ios/Runner/AppDelegate.h b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/AppDelegate.h similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/AppDelegate.h rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/AppDelegate.h diff --git a/packages/in_app_purchase/example/ios/Runner/AppDelegate.m b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/AppDelegate.m similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/AppDelegate.m rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/AppDelegate.m diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/packages/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/packages/in_app_purchase/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/packages/in_app_purchase/example/ios/Runner/Base.lproj/Main.storyboard b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Base.lproj/Main.storyboard rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Base.lproj/Main.storyboard diff --git a/packages/in_app_purchase/example/ios/Runner/Info.plist b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/Info.plist similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/Info.plist rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/Info.plist diff --git a/packages/in_app_purchase/example/ios/Runner/main.m b/packages/in_app_purchase/in_app_purchase/example/ios/Runner/main.m similarity index 100% rename from packages/in_app_purchase/example/ios/Runner/main.m rename to packages/in_app_purchase/in_app_purchase/example/ios/Runner/main.m diff --git a/packages/in_app_purchase/example/ios/in_app_purchase_pluginTests/Info.plist b/packages/in_app_purchase/in_app_purchase/example/ios/in_app_purchase_pluginTests/Info.plist similarity index 100% rename from packages/in_app_purchase/example/ios/in_app_purchase_pluginTests/Info.plist rename to packages/in_app_purchase/in_app_purchase/example/ios/in_app_purchase_pluginTests/Info.plist diff --git a/packages/in_app_purchase/example/lib/consumable_store.dart b/packages/in_app_purchase/in_app_purchase/example/lib/consumable_store.dart similarity index 100% rename from packages/in_app_purchase/example/lib/consumable_store.dart rename to packages/in_app_purchase/in_app_purchase/example/lib/consumable_store.dart diff --git a/packages/in_app_purchase/example/lib/main.dart b/packages/in_app_purchase/in_app_purchase/example/lib/main.dart similarity index 100% rename from packages/in_app_purchase/example/lib/main.dart rename to packages/in_app_purchase/in_app_purchase/example/lib/main.dart diff --git a/packages/in_app_purchase/example/pubspec.yaml b/packages/in_app_purchase/in_app_purchase/example/pubspec.yaml similarity index 100% rename from packages/in_app_purchase/example/pubspec.yaml rename to packages/in_app_purchase/in_app_purchase/example/pubspec.yaml diff --git a/packages/in_app_purchase/example/test_driver/test/integration_test.dart b/packages/in_app_purchase/in_app_purchase/example/test_driver/test/integration_test.dart similarity index 100% rename from packages/in_app_purchase/example/test_driver/test/integration_test.dart rename to packages/in_app_purchase/in_app_purchase/example/test_driver/test/integration_test.dart diff --git a/packages/in_app_purchase/integration_test/in_app_purchase_test.dart b/packages/in_app_purchase/in_app_purchase/integration_test/in_app_purchase_test.dart similarity index 100% rename from packages/in_app_purchase/integration_test/in_app_purchase_test.dart rename to packages/in_app_purchase/in_app_purchase/integration_test/in_app_purchase_test.dart diff --git a/packages/in_app_purchase/ios/Assets/.gitkeep b/packages/in_app_purchase/in_app_purchase/ios/Assets/.gitkeep similarity index 100% rename from packages/in_app_purchase/ios/Assets/.gitkeep rename to packages/in_app_purchase/in_app_purchase/ios/Assets/.gitkeep diff --git a/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.h b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAObjectTranslator.h similarity index 100% rename from packages/in_app_purchase/ios/Classes/FIAObjectTranslator.h rename to packages/in_app_purchase/in_app_purchase/ios/Classes/FIAObjectTranslator.h diff --git a/packages/in_app_purchase/ios/Classes/FIAObjectTranslator.m b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAObjectTranslator.m similarity index 100% rename from packages/in_app_purchase/ios/Classes/FIAObjectTranslator.m rename to packages/in_app_purchase/in_app_purchase/ios/Classes/FIAObjectTranslator.m diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.h b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPReceiptManager.h similarity index 100% rename from packages/in_app_purchase/ios/Classes/FIAPReceiptManager.h rename to packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPReceiptManager.h diff --git a/packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPReceiptManager.m similarity index 100% rename from packages/in_app_purchase/ios/Classes/FIAPReceiptManager.m rename to packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPReceiptManager.m diff --git a/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.h b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPRequestHandler.h similarity index 100% rename from packages/in_app_purchase/ios/Classes/FIAPRequestHandler.h rename to packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPRequestHandler.h diff --git a/packages/in_app_purchase/ios/Classes/FIAPRequestHandler.m b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPRequestHandler.m similarity index 100% rename from packages/in_app_purchase/ios/Classes/FIAPRequestHandler.m rename to packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPRequestHandler.m diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h similarity index 100% rename from packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h rename to packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m similarity index 100% rename from packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m rename to packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h b/packages/in_app_purchase/in_app_purchase/ios/Classes/InAppPurchasePlugin.h similarity index 100% rename from packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h rename to packages/in_app_purchase/in_app_purchase/ios/Classes/InAppPurchasePlugin.h diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m b/packages/in_app_purchase/in_app_purchase/ios/Classes/InAppPurchasePlugin.m similarity index 100% rename from packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m rename to packages/in_app_purchase/in_app_purchase/ios/Classes/InAppPurchasePlugin.m diff --git a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m b/packages/in_app_purchase/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m similarity index 100% rename from packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m rename to packages/in_app_purchase/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m diff --git a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m b/packages/in_app_purchase/in_app_purchase/ios/Tests/PaymentQueueTest.m similarity index 100% rename from packages/in_app_purchase/ios/Tests/PaymentQueueTest.m rename to packages/in_app_purchase/in_app_purchase/ios/Tests/PaymentQueueTest.m diff --git a/packages/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m b/packages/in_app_purchase/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m similarity index 100% rename from packages/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m rename to packages/in_app_purchase/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m diff --git a/packages/in_app_purchase/ios/Tests/Stubs.h b/packages/in_app_purchase/in_app_purchase/ios/Tests/Stubs.h similarity index 100% rename from packages/in_app_purchase/ios/Tests/Stubs.h rename to packages/in_app_purchase/in_app_purchase/ios/Tests/Stubs.h diff --git a/packages/in_app_purchase/ios/Tests/Stubs.m b/packages/in_app_purchase/in_app_purchase/ios/Tests/Stubs.m similarity index 100% rename from packages/in_app_purchase/ios/Tests/Stubs.m rename to packages/in_app_purchase/in_app_purchase/ios/Tests/Stubs.m diff --git a/packages/in_app_purchase/ios/Tests/TranslatorTest.m b/packages/in_app_purchase/in_app_purchase/ios/Tests/TranslatorTest.m similarity index 100% rename from packages/in_app_purchase/ios/Tests/TranslatorTest.m rename to packages/in_app_purchase/in_app_purchase/ios/Tests/TranslatorTest.m diff --git a/packages/in_app_purchase/ios/in_app_purchase.podspec b/packages/in_app_purchase/in_app_purchase/ios/in_app_purchase.podspec similarity index 100% rename from packages/in_app_purchase/ios/in_app_purchase.podspec rename to packages/in_app_purchase/in_app_purchase/ios/in_app_purchase.podspec diff --git a/packages/in_app_purchase/lib/billing_client_wrappers.dart b/packages/in_app_purchase/in_app_purchase/lib/billing_client_wrappers.dart similarity index 100% rename from packages/in_app_purchase/lib/billing_client_wrappers.dart rename to packages/in_app_purchase/in_app_purchase/lib/billing_client_wrappers.dart diff --git a/packages/in_app_purchase/lib/in_app_purchase.dart b/packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart similarity index 100% rename from packages/in_app_purchase/lib/in_app_purchase.dart rename to packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/README.md b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/README.md similarity index 100% rename from packages/in_app_purchase/lib/src/billing_client_wrappers/README.md rename to packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/README.md diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart similarity index 100% rename from packages/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart similarity index 100% rename from packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart similarity index 100% rename from packages/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart similarity index 100% rename from packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart similarity index 100% rename from packages/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart similarity index 100% rename from packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart diff --git a/packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart similarity index 100% rename from packages/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart diff --git a/packages/in_app_purchase/lib/src/channel.dart b/packages/in_app_purchase/in_app_purchase/lib/src/channel.dart similarity index 100% rename from packages/in_app_purchase/lib/src/channel.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/channel.dart diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/README.md b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/README.md similarity index 100% rename from packages/in_app_purchase/lib/src/in_app_purchase/README.md rename to packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/README.md diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart similarity index 100% rename from packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart similarity index 100% rename from packages/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart similarity index 100% rename from packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/product_details.dart similarity index 100% rename from packages/in_app_purchase/lib/src/in_app_purchase/product_details.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/product_details.dart diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart similarity index 100% rename from packages/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/README.md b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/README.md similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/README.md rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/README.md diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart similarity index 100% rename from packages/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart rename to packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart diff --git a/packages/in_app_purchase/lib/store_kit_wrappers.dart b/packages/in_app_purchase/in_app_purchase/lib/store_kit_wrappers.dart similarity index 100% rename from packages/in_app_purchase/lib/store_kit_wrappers.dart rename to packages/in_app_purchase/in_app_purchase/lib/store_kit_wrappers.dart diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/in_app_purchase/pubspec.yaml similarity index 100% rename from packages/in_app_purchase/pubspec.yaml rename to packages/in_app_purchase/in_app_purchase/pubspec.yaml diff --git a/packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart similarity index 100% rename from packages/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart rename to packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart diff --git a/packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart similarity index 100% rename from packages/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart rename to packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart diff --git a/packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart similarity index 100% rename from packages/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart rename to packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart similarity index 100% rename from packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart rename to packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart similarity index 100% rename from packages/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart rename to packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart b/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart similarity index 100% rename from packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart rename to packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart b/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart similarity index 100% rename from packages/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart rename to packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart b/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart similarity index 100% rename from packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart rename to packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart diff --git a/packages/in_app_purchase/test/stub_in_app_purchase_platform.dart b/packages/in_app_purchase/in_app_purchase/test/stub_in_app_purchase_platform.dart similarity index 100% rename from packages/in_app_purchase/test/stub_in_app_purchase_platform.dart rename to packages/in_app_purchase/in_app_purchase/test/stub_in_app_purchase_platform.dart diff --git a/packages/in_app_purchase/in_app_purchase_android.iml b/packages/in_app_purchase/in_app_purchase_android.iml deleted file mode 100644 index ac5d744d7acc..000000000000 --- a/packages/in_app_purchase/in_app_purchase_android.iml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - From 3f3f8342c105a856089b92120f16afcd104c5d25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl?= <32639467+danielroek@users.noreply.github.com> Date: Thu, 25 Mar 2021 10:09:03 +0100 Subject: [PATCH 359/924] [quick_actions] 3/3 Quick actions federated migration (#3736) --- AUTHORS | 1 + .../quick_actions/quick_actions/CHANGELOG.md | 4 + .../integration_test/quick_actions_test.dart | 2 +- .../quick_actions/lib/quick_actions.dart | 82 ++---------- .../quick_actions/quick_actions/pubspec.yaml | 11 +- .../test/quick_actions_test.dart | 119 +++++++----------- 6 files changed, 68 insertions(+), 151 deletions(-) diff --git a/AUTHORS b/AUTHORS index 493a0b4ef9c2..0ca697b6a756 100644 --- a/AUTHORS +++ b/AUTHORS @@ -64,3 +64,4 @@ Aleksandr Yurkovskiy Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> +Daniel Roek diff --git a/packages/quick_actions/quick_actions/CHANGELOG.md b/packages/quick_actions/quick_actions/CHANGELOG.md index 5f192825cacf..3fd0c7e28256 100644 --- a/packages/quick_actions/quick_actions/CHANGELOG.md +++ b/packages/quick_actions/quick_actions/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.0 + +* Migrate to federated architecture. + ## 0.5.0+1 * Updated example app implementation. diff --git a/packages/quick_actions/quick_actions/example/integration_test/quick_actions_test.dart b/packages/quick_actions/quick_actions/example/integration_test/quick_actions_test.dart index 4b0ec7584243..cfe3eb0db656 100644 --- a/packages/quick_actions/quick_actions/example/integration_test/quick_actions_test.dart +++ b/packages/quick_actions/quick_actions/example/integration_test/quick_actions_test.dart @@ -12,7 +12,7 @@ void main() { testWidgets('Can set shortcuts', (WidgetTester tester) async { final QuickActions quickActions = QuickActions(); - quickActions.initialize(null); + await quickActions.initialize(null); const ShortcutItem shortCutItem = ShortcutItem( type: 'action_one', diff --git a/packages/quick_actions/quick_actions/lib/quick_actions.dart b/packages/quick_actions/quick_actions/lib/quick_actions.dart index 23dd15302d57..f90a44e0443d 100644 --- a/packages/quick_actions/quick_actions/lib/quick_actions.dart +++ b/packages/quick_actions/quick_actions/lib/quick_actions.dart @@ -4,90 +4,24 @@ import 'dart:async'; -import 'package:flutter/services.dart'; -import 'package:meta/meta.dart'; +import 'package:quick_actions_platform_interface/platform_interface/quick_actions_platform.dart'; +import 'package:quick_actions_platform_interface/types/types.dart'; -const MethodChannel _kChannel = - MethodChannel('plugins.flutter.io/quick_actions'); - -/// Handler for a quick action launch event. -/// -/// The argument [type] corresponds to the [ShortcutItem]'s field. -typedef void QuickActionHandler(String type); - -/// Home screen quick-action shortcut item. -class ShortcutItem { - /// Constructs an instance with the given [type], [localizedTitle], and - /// [icon]. - /// - /// Only [icon] should be nullable. It will remain `null` if unset. - const ShortcutItem({ - required this.type, - required this.localizedTitle, - this.icon, - }); - - /// The identifier of this item; should be unique within the app. - final String type; - - /// Localized title of the item. - final String localizedTitle; - - /// Name of native resource (xcassets etc; NOT a Flutter asset) to be - /// displayed as the icon for this item. - final String? icon; -} +export 'package:quick_actions_platform_interface/types/types.dart'; /// Quick actions plugin. class QuickActions { - /// Gets an instance of the plugin with the default methodChannel. - /// - /// [initialize] should be called before using any other methods. - factory QuickActions() => _instance; - - /// This is a test-only constructor. Do not call this, it can break at any - /// time. - @visibleForTesting - QuickActions.withMethodChannel(this.channel); - - static final QuickActions _instance = - QuickActions.withMethodChannel(_kChannel); - - /// This is a test-only accessor. Do not call this, it can break at any time. - @visibleForTesting - final MethodChannel channel; - /// Initializes this plugin. /// /// Call this once before any further interaction with the the plugin. - void initialize(QuickActionHandler handler) async { - channel.setMethodCallHandler((MethodCall call) async { - assert(call.method == 'launch'); - handler(call.arguments); - }); - final String? action = - await channel.invokeMethod('getLaunchAction'); - if (action != null) { - handler(action); - } - } + Future initialize(QuickActionHandler handler) async => + QuickActionsPlatform.instance.initialize(handler); /// Sets the [ShortcutItem]s to become the app's quick actions. - Future setShortcutItems(List items) async { - final List> itemsList = - items.map(_serializeItem).toList(); - await channel.invokeMethod('setShortcutItems', itemsList); - } + Future setShortcutItems(List items) async => + QuickActionsPlatform.instance.setShortcutItems(items); /// Removes all [ShortcutItem]s registered for the app. Future clearShortcutItems() => - channel.invokeMethod('clearShortcutItems'); - - Map _serializeItem(ShortcutItem item) { - return { - 'type': item.type, - 'localizedTitle': item.localizedTitle, - 'icon': item.icon, - }; - } + QuickActionsPlatform.instance.clearShortcutItems(); } diff --git a/packages/quick_actions/quick_actions/pubspec.yaml b/packages/quick_actions/quick_actions/pubspec.yaml index 71accce09fcf..f6622525d458 100644 --- a/packages/quick_actions/quick_actions/pubspec.yaml +++ b/packages/quick_actions/quick_actions/pubspec.yaml @@ -2,7 +2,7 @@ name: quick_actions description: Flutter plugin for creating shortcuts on home screen, also known as Quick Actions on iOS and App Shortcuts on Android. homepage: https://github.com/flutter/plugins/tree/master/packages/quick_actions -version: 0.5.0+1 +version: 0.6.0 flutter: plugin: @@ -17,15 +17,18 @@ dependencies: flutter: sdk: flutter meta: ^1.3.0 + quick_actions_platform_interface: ^1.0.0 dev_dependencies: - test: ^1.16.3 flutter_test: sdk: flutter integration_test: sdk: flutter - pedantic: ^1.10.0 + mockito: ^5.0.0-nullsafety.7 + pedantic: ^1.11.0 + plugin_platform_interface: ^2.0.0 + environment: - sdk: ">=2.12.0-259.9.beta <3.0.0" + sdk: ">=2.12.0 <3.0.0" flutter: ">=1.12.13+hotfix.5" diff --git a/packages/quick_actions/quick_actions/test/quick_actions_test.dart b/packages/quick_actions/quick_actions/test/quick_actions_test.dart index ccb593f149fb..b8d7695735b6 100644 --- a/packages/quick_actions/quick_actions/test/quick_actions_test.dart +++ b/packages/quick_actions/quick_actions/test/quick_actions_test.dart @@ -2,90 +2,65 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; - -import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:quick_actions/quick_actions.dart'; +import 'package:quick_actions_platform_interface/platform_interface/quick_actions_platform.dart'; +import 'package:quick_actions_platform_interface/quick_actions_platform_interface.dart'; +import 'package:quick_actions_platform_interface/types/shortcut_item.dart'; void main() { - TestWidgetsFlutterBinding.ensureInitialized(); + group('$QuickActions', () { + setUp(() { + QuickActionsPlatform.instance = MockQuickActionsPlatform(); + }); - late QuickActions quickActions; - final List log = []; + test('initialize() PlatformInterface', () async { + QuickActions quickActions = QuickActions(); + QuickActionHandler handler = (type) {}; - setUp(() { - quickActions = QuickActions(); - quickActions.channel.setMockMethodCallHandler( - (MethodCall methodCall) async { - log.add(methodCall); - return 'non empty response'; - }, - ); - }); + await quickActions.initialize(handler); + verify(QuickActionsPlatform.instance.initialize(handler)).called(1); + }); - test('setShortcutItems with demo data', () async { - const String type = 'type'; - const String localizedTitle = 'localizedTitle'; - const String icon = 'icon'; - await quickActions.setShortcutItems( - const [ - ShortcutItem(type: type, localizedTitle: localizedTitle, icon: icon) - ], - ); - expect( - log, - [ - isMethodCall( - 'setShortcutItems', - arguments: >[ - { - 'type': type, - 'localizedTitle': localizedTitle, - 'icon': icon, - } - ], - ), - ], - ); - log.clear(); - }); + test('setShortcutItems() PlatformInterface', () { + QuickActions quickActions = QuickActions(); + QuickActionHandler handler = (type) {}; + quickActions.initialize(handler); + quickActions.setShortcutItems([]); - test('clearShortcutItems', () { - quickActions.clearShortcutItems(); - expect( - log, - [ - isMethodCall('clearShortcutItems', arguments: null), - ], - ); - log.clear(); - }); + verify(QuickActionsPlatform.instance.initialize(handler)).called(1); + verify(QuickActionsPlatform.instance.setShortcutItems([])).called(1); + }); - test('initialize', () async { - final Completer quickActionsHandler = Completer(); - quickActions.initialize((_) => quickActionsHandler.complete(true)); - expect( - log, - [ - isMethodCall('getLaunchAction', arguments: null), - ], - ); - log.clear(); + test('clearShortcutItems() PlatformInterface', () { + QuickActions quickActions = QuickActions(); + QuickActionHandler handler = (type) {}; - expect(quickActionsHandler.future, completion(isTrue)); + quickActions.initialize(handler); + quickActions.clearShortcutItems(); + + verify(QuickActionsPlatform.instance.initialize(handler)).called(1); + verify(QuickActionsPlatform.instance.clearShortcutItems()).called(1); + }); }); +} - test('Shortcut item can be constructed', () { - const String type = 'type'; - const String localizedTitle = 'title'; - const String icon = 'foo'; +class MockQuickActionsPlatform extends Mock + with MockPlatformInterfaceMixin + implements QuickActionsPlatform { + @override + Future clearShortcutItems() async => + super.noSuchMethod(Invocation.method(#clearShortcutItems, [])); - const ShortcutItem item = - ShortcutItem(type: type, localizedTitle: localizedTitle, icon: icon); + @override + Future initialize(QuickActionHandler? handler) async => + super.noSuchMethod(Invocation.method(#initialize, [handler])); - expect(item.type, type); - expect(item.localizedTitle, localizedTitle); - expect(item.icon, icon); - }); + @override + Future setShortcutItems(List? items) async => + super.noSuchMethod(Invocation.method(#setShortcutItems, [items])); } + +class MockQuickActions extends QuickActions {} From 3dd9871f8df6a060bbe8a6b6a5f1c4d03a92fa43 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 25 Mar 2021 11:23:02 +0100 Subject: [PATCH 360/924] Fixed some minor spelling mistakes in README (#3749) --- packages/in_app_purchase/in_app_purchase/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase/README.md b/packages/in_app_purchase/in_app_purchase/README.md index 321864b2a233..62adaa9b4dec 100644 --- a/packages/in_app_purchase/in_app_purchase/README.md +++ b/packages/in_app_purchase/in_app_purchase/README.md @@ -24,7 +24,7 @@ your app with each store to handle purchases using them. Both have extensive guides: * [In-App Purchase (App Store)](https://developer.apple.com/in-app-purchase/) -* [Google Play Biling Overview](https://developer.android.com/google/play/billing/billing_overview) +* [Google Play Billing Overview](https://developer.android.com/google/play/billing/billing_overview) You can check out the [example app README](https://github.com/flutter/plugins/blob/master/packages/in_app_purchase/example/README.md) for steps on how to configure in app purchases in both stores. @@ -34,7 +34,7 @@ able to start using the plugin. There's two basic options available to you to use. 1. [in_app_purchase.dart](https://github.com/flutter/plugins/tree/master/packages/in_app_purchase/lib/src/in_app_purchase), - the generic idiommatic Flutter API. This exposes the most basic IAP-related + the generic idiomatic Flutter API. This exposes the most basic IAP-related functionality. The goal is that Flutter apps should be able to use this API surface on its own for the vast majority of cases. If you use this you should be able to handle most use cases for loading and making purchases. If you would From a303d6ded0f4ddbf0819ab2cf9b42b53dc535e47 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 25 Mar 2021 13:40:14 +0100 Subject: [PATCH 361/924] Fix error message (#3750) --- packages/in_app_purchase/in_app_purchase/AUTHORS | 1 + .../in_app_purchase/in_app_purchase/CHANGELOG.md | 4 ++++ .../src/in_app_purchase/app_store_connection.dart | 2 +- .../in_app_purchase/in_app_purchase/pubspec.yaml | 2 +- .../app_store_connection_test.dart | 13 ++++++++++--- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase/AUTHORS b/packages/in_app_purchase/in_app_purchase/AUTHORS index 493a0b4ef9c2..78f9e5ad9f6b 100644 --- a/packages/in_app_purchase/in_app_purchase/AUTHORS +++ b/packages/in_app_purchase/in_app_purchase/AUTHORS @@ -64,3 +64,4 @@ Aleksandr Yurkovskiy Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> +Maurits van Beusekom diff --git a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md index 84a65f4159f3..6936edd52013 100644 --- a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.2 + +* Fix error message when trying to consume purchase on iOS. + ## 0.5.1 * [iOS] Introduce `SKPaymentQueueWrapper.presentCodeRedemptionSheet` diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index 069cf7800599..3c56f01966cb 100644 --- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -97,7 +97,7 @@ class AppStoreConnection implements InAppPurchaseConnection { @override Future consumePurchase(PurchaseDetails purchase) { - throw UnsupportedError('consume purchase is not available on Android'); + throw UnsupportedError('consume purchase is not available on iOS'); } @override diff --git a/packages/in_app_purchase/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/in_app_purchase/pubspec.yaml index 2a8f56946bf2..c7226078c722 100644 --- a/packages/in_app_purchase/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.5.1 +version: 0.5.2 dependencies: flutter: diff --git a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index dfab31906231..c112829468db 100644 --- a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -294,9 +294,16 @@ void main() { group('consume purchase', () { test('should throw when calling consume purchase on iOS', () async { expect( - () => AppStoreConnection.instance - .consumePurchase(PurchaseDetails.fromPurchase(dummyPurchase)), - throwsUnsupportedError); + () => AppStoreConnection.instance + .consumePurchase(PurchaseDetails.fromPurchase(dummyPurchase)), + throwsA( + isA().having( + (error) => error.message, + 'message', + 'consume purchase is not available on iOS', + ), + ), + ); }); }); From a17efbf861723108a034415f8267780e5fb869be Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 25 Mar 2021 15:16:36 +0100 Subject: [PATCH 362/924] Revert "Fix error message (#3750)" (#3751) This reverts commit a303d6ded0f4ddbf0819ab2cf9b42b53dc535e47. --- packages/in_app_purchase/in_app_purchase/AUTHORS | 1 - .../in_app_purchase/in_app_purchase/CHANGELOG.md | 4 ---- .../src/in_app_purchase/app_store_connection.dart | 2 +- .../in_app_purchase/in_app_purchase/pubspec.yaml | 2 +- .../app_store_connection_test.dart | 13 +++---------- 5 files changed, 5 insertions(+), 17 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase/AUTHORS b/packages/in_app_purchase/in_app_purchase/AUTHORS index 78f9e5ad9f6b..493a0b4ef9c2 100644 --- a/packages/in_app_purchase/in_app_purchase/AUTHORS +++ b/packages/in_app_purchase/in_app_purchase/AUTHORS @@ -64,4 +64,3 @@ Aleksandr Yurkovskiy Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> -Maurits van Beusekom diff --git a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md index 6936edd52013..84a65f4159f3 100644 --- a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md @@ -1,7 +1,3 @@ -## 0.5.2 - -* Fix error message when trying to consume purchase on iOS. - ## 0.5.1 * [iOS] Introduce `SKPaymentQueueWrapper.presentCodeRedemptionSheet` diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index 3c56f01966cb..069cf7800599 100644 --- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -97,7 +97,7 @@ class AppStoreConnection implements InAppPurchaseConnection { @override Future consumePurchase(PurchaseDetails purchase) { - throw UnsupportedError('consume purchase is not available on iOS'); + throw UnsupportedError('consume purchase is not available on Android'); } @override diff --git a/packages/in_app_purchase/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/in_app_purchase/pubspec.yaml index c7226078c722..2a8f56946bf2 100644 --- a/packages/in_app_purchase/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.5.2 +version: 0.5.1 dependencies: flutter: diff --git a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index c112829468db..dfab31906231 100644 --- a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -294,16 +294,9 @@ void main() { group('consume purchase', () { test('should throw when calling consume purchase on iOS', () async { expect( - () => AppStoreConnection.instance - .consumePurchase(PurchaseDetails.fromPurchase(dummyPurchase)), - throwsA( - isA().having( - (error) => error.message, - 'message', - 'consume purchase is not available on iOS', - ), - ), - ); + () => AppStoreConnection.instance + .consumePurchase(PurchaseDetails.fromPurchase(dummyPurchase)), + throwsUnsupportedError); }); }); From 708bf9c09a6c1059b8e3dbba27965e7cd5989b28 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 25 Mar 2021 15:44:18 +0100 Subject: [PATCH 363/924] Fix error message (#3752) --- packages/in_app_purchase/in_app_purchase/AUTHORS | 1 + .../in_app_purchase/in_app_purchase/CHANGELOG.md | 4 ++++ .../src/in_app_purchase/app_store_connection.dart | 2 +- .../in_app_purchase/in_app_purchase/pubspec.yaml | 2 +- .../app_store_connection_test.dart | 13 ++++++++++--- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase/AUTHORS b/packages/in_app_purchase/in_app_purchase/AUTHORS index 493a0b4ef9c2..78f9e5ad9f6b 100644 --- a/packages/in_app_purchase/in_app_purchase/AUTHORS +++ b/packages/in_app_purchase/in_app_purchase/AUTHORS @@ -64,3 +64,4 @@ Aleksandr Yurkovskiy Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> +Maurits van Beusekom diff --git a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md index 84a65f4159f3..114f11aa89b3 100644 --- a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.1+1 + +* Fix error message when trying to consume purchase on iOS. + ## 0.5.1 * [iOS] Introduce `SKPaymentQueueWrapper.presentCodeRedemptionSheet` diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index 069cf7800599..3c56f01966cb 100644 --- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -97,7 +97,7 @@ class AppStoreConnection implements InAppPurchaseConnection { @override Future consumePurchase(PurchaseDetails purchase) { - throw UnsupportedError('consume purchase is not available on Android'); + throw UnsupportedError('consume purchase is not available on iOS'); } @override diff --git a/packages/in_app_purchase/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/in_app_purchase/pubspec.yaml index 2a8f56946bf2..b42ca8806819 100644 --- a/packages/in_app_purchase/in_app_purchase/pubspec.yaml +++ b/packages/in_app_purchase/in_app_purchase/pubspec.yaml @@ -1,7 +1,7 @@ name: in_app_purchase description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play. homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase -version: 0.5.1 +version: 0.5.1+1 dependencies: flutter: diff --git a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index dfab31906231..c112829468db 100644 --- a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -294,9 +294,16 @@ void main() { group('consume purchase', () { test('should throw when calling consume purchase on iOS', () async { expect( - () => AppStoreConnection.instance - .consumePurchase(PurchaseDetails.fromPurchase(dummyPurchase)), - throwsUnsupportedError); + () => AppStoreConnection.instance + .consumePurchase(PurchaseDetails.fromPurchase(dummyPurchase)), + throwsA( + isA().having( + (error) => error.message, + 'message', + 'consume purchase is not available on iOS', + ), + ), + ); }); }); From c3dc31f665f3ccaa96898a6f719591c8642c32de Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 25 Mar 2021 17:43:51 +0100 Subject: [PATCH 364/924] Update example instructions (#3753) --- .../in_app_purchase/example/README.md | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase/example/README.md b/packages/in_app_purchase/in_app_purchase/example/README.md index ef32964f141d..0ecf42298433 100644 --- a/packages/in_app_purchase/in_app_purchase/example/README.md +++ b/packages/in_app_purchase/in_app_purchase/example/README.md @@ -72,7 +72,8 @@ below. - A consumable with product ID `consumable` - An upgrade with product ID `upgrade` - - An auto-renewing subscription with product ID `subscription` + - An auto-renewing subscription with product ID `subscription_silver` + - An non-renewing subscription with product ID `subscription_gold` 2. In XCode, `File > Open File` `example/ios/Runner.xcworkspace`. Update the Bundle ID to match the Bundle ID of the app created in step #1. @@ -82,8 +83,15 @@ below. in-app purchases with. 4. Use `flutter run` to install the app and test it. Note that you need to test - it on a real device instead of a simulator, and signing into any production - service (including iTunes!) with the test account will permanently invalidate - it. Sign in to the test account in the example app following the steps in the - [*In-App Purchase Programming - Guide*](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/ShowUI.html#//apple_ref/doc/uid/TP40008267-CH3-SW11). + it on a real device instead of a simulator. Next click on one of the products + in the example App, this enables the "SANDBOX ACCOUNT" section in the iOS + settings. You will now be asked to sign in with your sandbox test account to + complete the purchase (no worries you won't be charged). If for some reason + you aren't asked to sign-in or the wrong user is listed, go into the iOS + settings ("Settings" -> "App Store" -> "SANDBOX ACCOUNT") and update your + sandbox account from there. This procedure is explained in great detail in + the [Testing In-App Purchases with Sandbox](https://developer.apple.com/documentation/storekit/in-app_purchase/testing_in-app_purchases_with_sandbox?language=objc) article. + + +**Important:** signing into any production service (including iTunes!) with the +sandbox test account will permanently invalidate it. From eab885b84b99f72bb7b8c8b7a5edba6eaaa68808 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 25 Mar 2021 10:27:23 -0700 Subject: [PATCH 365/924] [google_maps_flutter] Fix handling of non-nullable invokeMethod return types (#3754) During the null-safety migration I accepted the auto-migrator use of as Future to handle invokeMethod returning a T?. I didn't realize that as does not actually do that kind of casting, and will fail with "type 'Future' is not a subtype of type 'Future' in type cast". There were no tests that exercised these methods in any way, so automated tests didn't catch the bug. This adds a minimal test that calls all of the non-void methods to ensure that they don't explode (and a TODO to backfill full unit tests of the entire method channel). Fixes flutter/flutter#78426 Fixes flutter/flutter#78856 --- .../CHANGELOG.md | 5 ++ .../method_channel_google_maps_flutter.dart | 22 +++--- .../pubspec.yaml | 2 +- ...thod_channel_google_maps_flutter_test.dart | 72 +++++++++++++++++++ .../google_maps_flutter_platform_test.dart | 21 ------ 5 files changed, 92 insertions(+), 30 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/method_channel/method_channel_google_maps_flutter_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index e8b12f79220d..1a620834b564 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.3 + +* Fix type issues in `isMarkerInfoWindowShown` and `getZoomLevel` introduced + in the null safety migration. + ## 2.0.2 * Mark constructors for CameraUpdate, CircleId, MapsObjectId, MarkerId, PolygonId, PolylineId and TileOverlayId as const diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index 80a71b4edd2b..49029cc3d22d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -62,8 +62,9 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { // Keep a collection of mapId to a map of TileOverlays. final Map> _tileOverlays = {}; - @override - Future init(int mapId) { + /// Returns the channel for [mapId], creating it if it doesn't already exist. + @visibleForTesting + MethodChannel ensureChannelInitialized(int mapId) { MethodChannel? channel = _channels[mapId]; if (channel == null) { channel = MethodChannel('plugins.flutter.io/google_maps_$mapId'); @@ -71,6 +72,12 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { (MethodCall call) => _handleMethodCall(call, mapId)); _channels[mapId] = channel; } + return channel; + } + + @override + Future init(int mapId) { + MethodChannel channel = ensureChannelInitialized(mapId); return channel.invokeMethod('map#waitForMap'); } @@ -414,18 +421,17 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { Future isMarkerInfoWindowShown( MarkerId markerId, { required int mapId, - }) { + }) async { assert(markerId != null); - return channel(mapId).invokeMethod('markers#isInfoWindowShown', - {'markerId': markerId.value}) as Future; + return (await channel(mapId).invokeMethod('markers#isInfoWindowShown', + {'markerId': markerId.value}))!; } @override Future getZoomLevel({ required int mapId, - }) { - return channel(mapId).invokeMethod('map#getZoomLevel') - as Future; + }) async { + return (await channel(mapId).invokeMethod('map#getZoomLevel'))!; } @override diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index 9d419351e85f..628099139021 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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: 2.0.2 +version: 2.0.3 dependencies: flutter: diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/method_channel/method_channel_google_maps_flutter_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/method_channel/method_channel_google_maps_flutter_test.dart new file mode 100644 index 000000000000..19e81c960839 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/method_channel/method_channel_google_maps_flutter_test.dart @@ -0,0 +1,72 @@ +// Copyright 2013 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:google_maps_flutter_platform_interface/src/method_channel/method_channel_google_maps_flutter.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$MethodChannelGoogleMapsFlutter', () { + late List log; + + setUp(() async { + log = []; + }); + + /// Initializes a map with the given ID and canned responses, logging all + /// calls to [log]. + void configureMockMap( + MethodChannelGoogleMapsFlutter maps, { + required int mapId, + required Future? Function(MethodCall call) handler, + }) { + maps + .ensureChannelInitialized(mapId) + .setMockMethodCallHandler((MethodCall methodCall) { + log.add(methodCall.method); + return handler(methodCall); + }); + } + + // Calls each method that uses invokeMethod with a return type other than + // void to ensure that the casting/nullability handling succeeds. + // + // TODO(stuartmorgan): Remove this once there is real test coverage of + // each method, since that would cover this issue. + test('non-void invokeMethods handle types correctly', () async { + const int mapId = 0; + final MethodChannelGoogleMapsFlutter maps = + MethodChannelGoogleMapsFlutter(); + configureMockMap(maps, mapId: mapId, + handler: (MethodCall methodCall) async { + switch (methodCall.method) { + case 'map#getLatLng': + return [1.0, 2.0]; + case 'markers#isInfoWindowShown': + return true; + case 'map#getZoomLevel': + return 2.5; + case 'map#takeSnapshot': + return null; + } + }); + + await maps.getLatLng(ScreenCoordinate(x: 0, y: 0), mapId: mapId); + await maps.isMarkerInfoWindowShown(MarkerId(''), mapId: mapId); + await maps.getZoomLevel(mapId: mapId); + await maps.takeSnapshot(mapId: mapId); + // Check that all the invokeMethod calls happened. + expect(log, [ + 'map#getLatLng', + 'markers#isInfoWindowShown', + 'map#getZoomLevel', + 'map#takeSnapshot', + ]); + }); + }); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart index 73cea10ec2d9..2c50313ab8a6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:mockito/mockito.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -36,26 +35,6 @@ void main() { GoogleMapsFlutterPlatform.instance = ExtendsGoogleMapsFlutterPlatform(); }); }); - - group('$MethodChannelGoogleMapsFlutter', () { - const MethodChannel channel = - MethodChannel('plugins.flutter.io/google_maps_flutter'); - final List log = []; - channel.setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - }); - - tearDown(() { - log.clear(); - }); - - test('foo', () async { - expect( - log, - [], - ); - }); - }); } class GoogleMapsFlutterPlatformMock extends Mock From 809d0de989d3f8fddc5f08b2593758841da4d0b6 Mon Sep 17 00:00:00 2001 From: Harpreet Sangar Date: Thu, 25 Mar 2021 18:47:47 +0000 Subject: [PATCH 366/924] Update "eponymous concept" link. (#3305) Fixes an obsolete link. --- packages/quick_actions/quick_actions/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/quick_actions/quick_actions/README.md b/packages/quick_actions/quick_actions/README.md index 4573523a5e36..46e87fa0b241 100644 --- a/packages/quick_actions/quick_actions/README.md +++ b/packages/quick_actions/quick_actions/README.md @@ -4,7 +4,7 @@ This Flutter plugin allows you to manage and interact with the application's home screen quick actions. Quick actions refer to the [eponymous -concept](https://developer.apple.com/ios/human-interface-guidelines/extensions/home-screen-actions) +concept](https://developer.apple.com/design/human-interface-guidelines/ios/system-capabilities/home-screen-actions/) on iOS and to the [App Shortcuts](https://developer.android.com/guide/topics/ui/shortcuts.html) APIs on Android (introduced in Android 7.1 / API level 25). It is safe to run this plugin From 7c87a8c52ce228305835e20413e69620da85ac71 Mon Sep 17 00:00:00 2001 From: PiN73 Date: Thu, 25 Mar 2021 22:36:56 +0300 Subject: [PATCH 367/924] [video_player] add http headers (#3671) This enables to pass HTTP headers to VideoPlayerController.network. Fixes: flutter/flutter#16466 --- .../video_player/video_player/CHANGELOG.md | 4 ++ .../flutter/plugins/videoplayer/Messages.java | 15 ++++- .../plugins/videoplayer/VideoPlayer.java | 7 ++- .../videoplayer/VideoPlayerPlugin.java | 5 ++ .../ios/Classes/FLTVideoPlayerPlugin.m | 20 +++++-- .../video_player/ios/Classes/messages.h | 3 +- .../video_player/ios/Classes/messages.m | 50 +++++++++------- .../video_player/lib/video_player.dart | 20 ++++++- .../video_player/pigeons/messages.dart | 1 + .../video_player/video_player/pubspec.yaml | 4 +- .../video_player/test/video_player_test.dart | 59 ++++++++++++++++--- 11 files changed, 144 insertions(+), 44 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 08a5e443149e..6b20fd964dec 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.0 + +* Add `httpHeaders` option to `VideoPlayerController.network` + ## 2.0.2 * Fix `VideoPlayerValue` size and aspect ratio documentation diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java index f1a909534d58..e0a4a3b8dd08 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v0.1.19), do not edit directly. +// Autogenerated from Pigeon (v0.1.21), do not edit directly. // See also: https://pub.dev/packages/pigeon package io.flutter.plugins.videoplayer; @@ -87,12 +87,23 @@ public void setFormatHint(String setterArg) { this.formatHint = setterArg; } + private HashMap httpHeaders; + + public HashMap getHttpHeaders() { + return httpHeaders; + } + + public void setHttpHeaders(HashMap setterArg) { + this.httpHeaders = setterArg; + } + HashMap toMap() { HashMap toMapResult = new HashMap<>(); toMapResult.put("asset", asset); toMapResult.put("uri", uri); toMapResult.put("packageName", packageName); toMapResult.put("formatHint", formatHint); + toMapResult.put("httpHeaders", httpHeaders); return toMapResult; } @@ -106,6 +117,8 @@ static CreateMessage fromMap(HashMap map) { fromMapResult.packageName = (String) packageName; Object formatHint = map.get("formatHint"); fromMapResult.formatHint = (String) formatHint; + Object httpHeaders = map.get("httpHeaders"); + fromMapResult.httpHeaders = (HashMap) httpHeaders; return fromMapResult; } } diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java index 840b1464b4d4..87784eebdefe 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java @@ -65,6 +65,7 @@ final class VideoPlayer { TextureRegistry.SurfaceTextureEntry textureEntry, String dataSource, String formatHint, + Map httpHeaders, VideoPlayerOptions options) { this.eventChannel = eventChannel; this.textureEntry = textureEntry; @@ -76,13 +77,17 @@ final class VideoPlayer { DataSource.Factory dataSourceFactory; if (isHTTP(uri)) { - dataSourceFactory = + DefaultHttpDataSourceFactory httpDataSourceFactory = new DefaultHttpDataSourceFactory( "ExoPlayer", null, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, true); + if (httpHeaders != null && !httpHeaders.isEmpty()) { + httpDataSourceFactory.getDefaultRequestProperties().set(httpHeaders); + } + dataSourceFactory = httpDataSourceFactory; } else { dataSourceFactory = new DefaultDataSourceFactory(context, "ExoPlayer"); } diff --git a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java index 2895db2acd6a..d77b45e03d4b 100644 --- a/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java +++ b/packages/video_player/video_player/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java @@ -23,6 +23,7 @@ import io.flutter.view.TextureRegistry; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.util.Map; import javax.net.ssl.HttpsURLConnection; /** Android platform implementation of the VideoPlayerPlugin. */ @@ -138,8 +139,11 @@ public TextureMessage create(CreateMessage arg) { handle, "asset:///" + assetLookupKey, null, + null, options); } else { + @SuppressWarnings("unchecked") + Map httpHeaders = arg.getHttpHeaders(); player = new VideoPlayer( flutterState.applicationContext, @@ -147,6 +151,7 @@ public TextureMessage create(CreateMessage arg) { handle, arg.getUri(), arg.getFormatHint(), + httpHeaders, options); } videoPlayers.put(handle.id(), player); diff --git a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m index 83144a9cb378..b359c1b6c898 100644 --- a/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m +++ b/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m @@ -46,7 +46,9 @@ @interface FLTVideoPlayer : NSObject @property(nonatomic, readonly) bool isPlaying; @property(nonatomic) bool isLooping; @property(nonatomic, readonly) bool isInitialized; -- (instancetype)initWithURL:(NSURL*)url frameUpdater:(FLTFrameUpdater*)frameUpdater; +- (instancetype)initWithURL:(NSURL*)url + frameUpdater:(FLTFrameUpdater*)frameUpdater + httpHeaders:(NSDictionary*)headers; - (void)play; - (void)pause; - (void)setIsLooping:(bool)isLooping; @@ -62,7 +64,7 @@ - (void)updatePlayingState; @implementation FLTVideoPlayer - (instancetype)initWithAsset:(NSString*)asset frameUpdater:(FLTFrameUpdater*)frameUpdater { NSString* path = [[NSBundle mainBundle] pathForResource:asset ofType:nil]; - return [self initWithURL:[NSURL fileURLWithPath:path] frameUpdater:frameUpdater]; + return [self initWithURL:[NSURL fileURLWithPath:path] frameUpdater:frameUpdater httpHeaders:nil]; } - (void)addObservers:(AVPlayerItem*)item { @@ -162,8 +164,15 @@ - (void)createVideoOutputAndDisplayLink:(FLTFrameUpdater*)frameUpdater { _displayLink.paused = YES; } -- (instancetype)initWithURL:(NSURL*)url frameUpdater:(FLTFrameUpdater*)frameUpdater { - AVPlayerItem* item = [AVPlayerItem playerItemWithURL:url]; +- (instancetype)initWithURL:(NSURL*)url + frameUpdater:(FLTFrameUpdater*)frameUpdater + httpHeaders:(NSDictionary*)headers { + NSDictionary* options = nil; + if (headers != nil && [headers count] != 0) { + options = @{@"AVURLAssetHTTPHeaderFieldsKey" : headers}; + } + AVURLAsset* urlAsset = [AVURLAsset URLAssetWithURL:url options:options]; + AVPlayerItem* item = [AVPlayerItem playerItemWithAsset:urlAsset]; return [self initWithPlayerItem:item frameUpdater:frameUpdater]; } @@ -522,7 +531,8 @@ - (FLTTextureMessage*)create:(FLTCreateMessage*)input error:(FlutterError**)erro return [self onPlayerSetup:player frameUpdater:frameUpdater]; } else if (input.uri) { player = [[FLTVideoPlayer alloc] initWithURL:[NSURL URLWithString:input.uri] - frameUpdater:frameUpdater]; + frameUpdater:frameUpdater + httpHeaders:input.httpHeaders]; return [self onPlayerSetup:player frameUpdater:frameUpdater]; } else { *error = [FlutterError errorWithCode:@"video_player" message:@"not implemented" details:nil]; diff --git a/packages/video_player/video_player/ios/Classes/messages.h b/packages/video_player/video_player/ios/Classes/messages.h index 9717f65b23c3..e21e7860ba09 100644 --- a/packages/video_player/video_player/ios/Classes/messages.h +++ b/packages/video_player/video_player/ios/Classes/messages.h @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v0.1.19), do not edit directly. +// Autogenerated from Pigeon (v0.1.21), do not edit directly. // See also: https://pub.dev/packages/pigeon #import @protocol FlutterBinaryMessenger; @@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, copy, nullable) NSString *uri; @property(nonatomic, copy, nullable) NSString *packageName; @property(nonatomic, copy, nullable) NSString *formatHint; +@property(nonatomic, strong, nullable) NSDictionary *httpHeaders; @end @interface FLTLoopingMessage : NSObject diff --git a/packages/video_player/video_player/ios/Classes/messages.m b/packages/video_player/video_player/ios/Classes/messages.m index 0993c947c2cb..14e375b33378 100644 --- a/packages/video_player/video_player/ios/Classes/messages.m +++ b/packages/video_player/video_player/ios/Classes/messages.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v0.1.19), do not edit directly. +// Autogenerated from Pigeon (v0.1.21), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "messages.h" #import @@ -11,18 +11,19 @@ #error File requires ARC to be enabled. #endif -#ifndef __clang_analyzer__ -static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) { +static NSDictionary *wrapResult(NSDictionary *result, FlutterError *error) { NSDictionary *errorDict = (NSDictionary *)[NSNull null]; if (error) { - errorDict = [NSDictionary - dictionaryWithObjectsAndKeys:(error.code ? error.code : [NSNull null]), @"code", - (error.message ? error.message : [NSNull null]), @"message", - (error.details ? error.details : [NSNull null]), @"details", - nil]; + errorDict = @{ + @"code" : (error.code ? error.code : [NSNull null]), + @"message" : (error.message ? error.message : [NSNull null]), + @"details" : (error.details ? error.details : [NSNull null]), + }; } - return [NSDictionary dictionaryWithObjectsAndKeys:(result ? result : [NSNull null]), @"result", - errorDict, @"error", nil]; + return @{ + @"result" : (result ? result : [NSNull null]), + @"error" : errorDict, + }; } @interface FLTTextureMessage () @@ -89,6 +90,10 @@ + (FLTCreateMessage *)fromMap:(NSDictionary *)dict { if ((NSNull *)result.formatHint == [NSNull null]) { result.formatHint = nil; } + result.httpHeaders = dict[@"httpHeaders"]; + if ((NSNull *)result.httpHeaders == [NSNull null]) { + result.httpHeaders = nil; + } return result; } - (NSDictionary *)toMap { @@ -98,7 +103,9 @@ - (NSDictionary *)toMap { (self.packageName ? self.packageName : [NSNull null]), @"packageName", (self.formatHint ? self.formatHint : [NSNull null]), - @"formatHint", nil]; + @"formatHint", + (self.httpHeaders ? self.httpHeaders : [NSNull null]), + @"httpHeaders", nil]; } @end @@ -221,8 +228,8 @@ void FLTVideoPlayerApiSetup(id binaryMessenger, id binaryMessenger, id binaryMessenger, id binaryMessenger, id binaryMessenger, id binaryMessenger, id binaryMessenger, id binaryMessenger, id binaryMessenger, id binaryMessenger, id binaryMessenger, id { {this.package, this.closedCaptionFile, this.videoPlayerOptions}) : dataSourceType = DataSourceType.asset, formatHint = null, + httpHeaders = const {}, super(VideoPlayerValue(duration: Duration.zero)); /// Constructs a [VideoPlayerController] playing a video from obtained from @@ -196,9 +197,15 @@ class VideoPlayerController extends ValueNotifier { /// null. /// **Android only**: The [formatHint] option allows the caller to override /// the video format detection code. - VideoPlayerController.network(this.dataSource, - {this.formatHint, this.closedCaptionFile, this.videoPlayerOptions}) - : dataSourceType = DataSourceType.network, + /// [httpHeaders] option allows to specify HTTP headers + /// for the request to the [dataSource]. + VideoPlayerController.network( + this.dataSource, { + this.formatHint, + this.closedCaptionFile, + this.videoPlayerOptions, + this.httpHeaders = const {}, + }) : dataSourceType = DataSourceType.network, package = null, super(VideoPlayerValue(duration: Duration.zero)); @@ -212,12 +219,18 @@ class VideoPlayerController extends ValueNotifier { dataSourceType = DataSourceType.file, package = null, formatHint = null, + httpHeaders = const {}, super(VideoPlayerValue(duration: Duration.zero)); /// The URI to the video file. This will be in different formats depending on /// the [DataSourceType] of the original video. final String dataSource; + /// HTTP headers used for the request to the [dataSource]. + /// Only for [VideoPlayerController.network]. + /// Always empty for other video types. + final Map httpHeaders; + /// **Android only**. Will override the platform's generic file format /// detection with whatever is set here. final VideoFormat? formatHint; @@ -276,6 +289,7 @@ class VideoPlayerController extends ValueNotifier { sourceType: DataSourceType.network, uri: dataSource, formatHint: formatHint, + httpHeaders: httpHeaders, ); break; case DataSourceType.file: diff --git a/packages/video_player/video_player/pigeons/messages.dart b/packages/video_player/video_player/pigeons/messages.dart index c0a76dd301af..e893aaa6830d 100644 --- a/packages/video_player/video_player/pigeons/messages.dart +++ b/packages/video_player/video_player/pigeons/messages.dart @@ -35,6 +35,7 @@ class CreateMessage { String uri; String packageName; String formatHint; + Map httpHeaders; } class MixWithOthersMessage { diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 17442d7ec09a..0215ead855e7 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -version: 2.0.2 +version: 2.1.0 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: @@ -17,7 +17,7 @@ flutter: dependencies: meta: ^1.3.0 - video_player_platform_interface: ^4.0.0 + video_player_platform_interface: ^4.1.0 # The design on https://flutter.dev/go/federated-plugins was to leave # this constraint as "any". We cannot do it right now as it fails pub publish diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart index 580c9ad914dd..e17dac7897a6 100644 --- a/packages/video_player/video_player/test/video_player_test.dart +++ b/packages/video_player/video_player/test/video_player_test.dart @@ -30,6 +30,9 @@ class FakeController extends ValueNotifier @override String get dataSource => ''; + @override + Map get httpHeaders => {}; + @override DataSourceType get dataSourceType => DataSourceType.file; @@ -200,22 +203,60 @@ void main() { ); await controller.initialize(); - expect(fakeVideoPlayerPlatform.dataSourceDescriptions[0].uri, - 'https://127.0.0.1'); expect( - fakeVideoPlayerPlatform.dataSourceDescriptions[0].formatHint, null); + fakeVideoPlayerPlatform.dataSourceDescriptions[0].uri, + 'https://127.0.0.1', + ); + expect( + fakeVideoPlayerPlatform.dataSourceDescriptions[0].formatHint, + null, + ); + expect( + fakeVideoPlayerPlatform.dataSourceDescriptions[0].httpHeaders, + {}, + ); }); test('network with hint', () async { final VideoPlayerController controller = VideoPlayerController.network( - 'https://127.0.0.1', - formatHint: VideoFormat.dash); + 'https://127.0.0.1', + formatHint: VideoFormat.dash, + ); await controller.initialize(); - expect(fakeVideoPlayerPlatform.dataSourceDescriptions[0].uri, - 'https://127.0.0.1'); - expect(fakeVideoPlayerPlatform.dataSourceDescriptions[0].formatHint, - 'dash'); + expect( + fakeVideoPlayerPlatform.dataSourceDescriptions[0].uri, + 'https://127.0.0.1', + ); + expect( + fakeVideoPlayerPlatform.dataSourceDescriptions[0].formatHint, + 'dash', + ); + expect( + fakeVideoPlayerPlatform.dataSourceDescriptions[0].httpHeaders, + {}, + ); + }); + + test('network with some headers', () async { + final VideoPlayerController controller = VideoPlayerController.network( + 'https://127.0.0.1', + httpHeaders: {'Authorization': 'Bearer token'}, + ); + await controller.initialize(); + + expect( + fakeVideoPlayerPlatform.dataSourceDescriptions[0].uri, + 'https://127.0.0.1', + ); + expect( + fakeVideoPlayerPlatform.dataSourceDescriptions[0].formatHint, + null, + ); + expect( + fakeVideoPlayerPlatform.dataSourceDescriptions[0].httpHeaders, + {'Authorization': 'Bearer token'}, + ); }); test('init errors', () async { From 4cd43e946d325722e88c17784170e4842d2de0e4 Mon Sep 17 00:00:00 2001 From: Alexander Aprelev Date: Thu, 25 Mar 2021 16:31:07 -0700 Subject: [PATCH 368/924] [ci] Drop redundant question marks used with dynamic. (#3756) Fixes https://github.com/flutter/flutter/issues/79089 --- .../google_sign_in_web/lib/src/generated/gapi.dart | 10 +++++----- .../in_app_purchase/in_app_purchase_connection.dart | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart index a7ee1cdd3314..1e2db0fe4609 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapi.dart @@ -19,11 +19,11 @@ import 'package:js/js.dart'; // Module gapi typedef void LoadCallback( - [dynamic? args1, - dynamic? args2, - dynamic? args3, - dynamic? args4, - dynamic? args5]); + [dynamic args1, + dynamic args2, + dynamic args3, + dynamic args4, + dynamic args5]); @anonymous @JS() diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart index a5db8e5d4206..c333478e3064 100644 --- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart +++ b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart @@ -304,5 +304,5 @@ class IAPError { final String message; /// Error details, possibly null. - final dynamic? details; + final dynamic details; } From 1ecc550155e9d0f7ce3feba28ae5ad4a375c0e17 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Thu, 25 Mar 2021 16:47:14 -0700 Subject: [PATCH 369/924] [ci] Drop extra ? for dynamic (#3757) --- .../google_sign_in_web/lib/src/generated/gapiauth2.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart index 0dec17dbd19c..d5efc71d469a 100644 --- a/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart +++ b/packages/google_sign_in/google_sign_in_web/lib/src/generated/gapiauth2.dart @@ -68,7 +68,7 @@ class GoogleAuth { /// Attaches the sign-in flow to the specified container's click handler. external dynamic attachClickHandler( - dynamic? container, + dynamic container, SigninOptions options, dynamic onsuccess(GoogleUser googleUser), dynamic onfailure(String reason)); From 5787b354bb14d40a8f83b90a2f39b7d7e3951aa4 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 26 Mar 2021 17:09:03 +0100 Subject: [PATCH 370/924] [in_app_purchase] moved android iap unit tests (#3732) --- .../in_app_purchase/android/build.gradle | 5 ++++ .../src/test/java/android/text/TextUtils.java | 11 ++++++++ .../src/test/java/android/util/Log.java | 27 +++++++++++++++++++ .../InAppPurchasePluginTest.java | 0 .../inapppurchase/MethodCallHandlerTest.java | 0 .../plugins/inapppurchase/TranslatorTest.java | 0 6 files changed, 43 insertions(+) create mode 100644 packages/in_app_purchase/in_app_purchase/android/src/test/java/android/text/TextUtils.java create mode 100644 packages/in_app_purchase/in_app_purchase/android/src/test/java/android/util/Log.java rename packages/in_app_purchase/in_app_purchase/{example/android/app => android}/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java (100%) rename packages/in_app_purchase/in_app_purchase/{example/android/app => android}/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java (100%) rename packages/in_app_purchase/in_app_purchase/{example/android/app => android}/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java (100%) diff --git a/packages/in_app_purchase/in_app_purchase/android/build.gradle b/packages/in_app_purchase/in_app_purchase/android/build.gradle index 8d5840b4daff..a36f70137129 100644 --- a/packages/in_app_purchase/in_app_purchase/android/build.gradle +++ b/packages/in_app_purchase/in_app_purchase/android/build.gradle @@ -31,12 +31,17 @@ android { lintOptions { disable 'InvalidPackage' } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { implementation 'androidx.annotation:annotation:1.0.0' implementation 'com.android.billingclient:billing:3.0.2' testImplementation 'junit:junit:4.12' + testImplementation 'org.json:json:20180813' testImplementation 'org.mockito:mockito-core:3.6.0' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' diff --git a/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/text/TextUtils.java b/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/text/TextUtils.java new file mode 100644 index 000000000000..d997ae1dcaa0 --- /dev/null +++ b/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/text/TextUtils.java @@ -0,0 +1,11 @@ +// Copyright 2013 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. + +package android.text; + +public class TextUtils { + public static boolean isEmpty(CharSequence str) { + return str == null || str.length() == 0; + } +} diff --git a/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/util/Log.java b/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/util/Log.java new file mode 100644 index 000000000000..310b9ad89cdf --- /dev/null +++ b/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/util/Log.java @@ -0,0 +1,27 @@ +// Copyright 2013 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. + +package android.util; + +public class Log { + public static int d(String tag, String msg) { + System.out.println("DEBUG: " + tag + ": " + msg); + return 0; + } + + public static int i(String tag, String msg) { + System.out.println("INFO: " + tag + ": " + msg); + return 0; + } + + public static int w(String tag, String msg) { + System.out.println("WARN: " + tag + ": " + msg); + return 0; + } + + public static int e(String tag, String msg) { + System.out.println("ERROR: " + tag + ": " + msg); + return 0; + } +} diff --git a/packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java b/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java similarity index 100% rename from packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java rename to packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java diff --git a/packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java b/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java similarity index 100% rename from packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java rename to packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java diff --git a/packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java similarity index 100% rename from packages/in_app_purchase/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java rename to packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java From e4064a31300967bd60fb4373b592229d2f91d838 Mon Sep 17 00:00:00 2001 From: ColonisationCaptain <52425971+ColonisationCaptain@users.noreply.github.com> Date: Mon, 29 Mar 2021 17:49:06 +0100 Subject: [PATCH 371/924] capitalise Platform class (#3762) --- packages/android_intent/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/android_intent/README.md b/packages/android_intent/README.md index 7d097e465926..a2f95abe2bae 100644 --- a/packages/android_intent/README.md +++ b/packages/android_intent/README.md @@ -9,7 +9,7 @@ Use it by specifying action, category, data and extra arguments for the intent. It does not support returning the result of the launched activity. Sample usage: ```dart -if (platform.isAndroid) { +if (Platform.isAndroid) { AndroidIntent intent = AndroidIntent( action: 'action_view', data: 'https://play.google.com/store/apps/details?' @@ -33,7 +33,7 @@ for it in the plugin and use an action constant to refer to it. For instance: `'action_application_details_settings'` translates to `android.settings.ACTION_APPLICATION_DETAILS_SETTINGS` ```dart -if (platform.isAndroid) { +if (Platform.isAndroid) { final AndroidIntent intent = AndroidIntent( action: 'action_application_details_settings', data: 'package:com.example.app', // replace com.example.app with your applicationId From ed290be50fb79d9389538cdfa3249223c00c2757 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 29 Mar 2021 07:27:40 -1000 Subject: [PATCH 372/924] Add tests for publish check tool command (#3760) --- .../tool/lib/src/publish_check_command.dart | 4 +- .../tool/test/publish_check_command_test.dart | 114 ++++++++++++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 script/tool/test/publish_check_command_test.dart diff --git a/script/tool/lib/src/publish_check_command.dart b/script/tool/lib/src/publish_check_command.dart index dcd28d9a89f3..fb57dfcd6dc9 100644 --- a/script/tool/lib/src/publish_check_command.dart +++ b/script/tool/lib/src/publish_check_command.dart @@ -65,10 +65,10 @@ class PublishCheckCommand extends PluginCommand { } Future hasValidPublishCheckRun(Directory package) async { - final io.Process process = await io.Process.start( + final io.Process process = await processRunner.start( 'flutter', ['pub', 'publish', '--', '--dry-run'], - workingDirectory: package.path, + workingDirectory: package, ); final StringBuffer outputBuffer = StringBuffer(); diff --git a/script/tool/test/publish_check_command_test.dart b/script/tool/test/publish_check_command_test.dart new file mode 100644 index 000000000000..dbe6e2cfe548 --- /dev/null +++ b/script/tool/test/publish_check_command_test.dart @@ -0,0 +1,114 @@ +// Copyright 2013 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 'dart:collection'; +import 'dart:io' as io; + +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:flutter_plugin_tools/src/common.dart'; +import 'package:flutter_plugin_tools/src/publish_check_command.dart'; +import 'package:test/test.dart'; + +import 'mocks.dart'; +import 'util.dart'; + +void main() { + group('$PublishCheckProcessRunner tests', () { + PublishCheckProcessRunner processRunner; + CommandRunner runner; + + setUp(() { + initializeFakePackages(); + processRunner = PublishCheckProcessRunner(); + final PublishCheckCommand publishCheckCommand = PublishCheckCommand( + mockPackagesDir, mockFileSystem, + processRunner: processRunner); + + runner = CommandRunner( + 'publish_check_command', + 'Test for publish-check command.', + ); + runner.addCommand(publishCheckCommand); + }); + + tearDown(() { + mockPackagesDir.deleteSync(recursive: true); + }); + + test('publish check all packages', () async { + final Directory plugin1Dir = await createFakePlugin('a'); + final Directory plugin2Dir = await createFakePlugin('b'); + + processRunner.processesToReturn.add( + MockProcess()..exitCodeCompleter.complete(0), + ); + processRunner.processesToReturn.add( + MockProcess()..exitCodeCompleter.complete(0), + ); + await runner.run(['publish-check']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('flutter', + ['pub', 'publish', '--', '--dry-run'], plugin1Dir.path), + ProcessCall('flutter', + ['pub', 'publish', '--', '--dry-run'], plugin2Dir.path), + ])); + }); + + test('fail on negative test', () async { + await createFakePlugin('a'); + + final MockProcess process = MockProcess(); + process.stdoutController.close(); // ignore: unawaited_futures + process.stderrController.close(); // ignore: unawaited_futures + process.exitCodeCompleter.complete(1); + + processRunner.processesToReturn.add(process); + + expect( + () => runner.run(['publish-check']), + throwsA(isA()), + ); + }); + + test('fail on bad pubspec', () async { + final Directory dir = await createFakePlugin('c'); + await dir.childFile('pubspec.yaml').writeAsString('bad-yaml'); + + final MockProcess process = MockProcess(); + processRunner.processesToReturn.add(process); + + expect(() => runner.run(['publish-check']), + throwsA(isA())); + }); + + test('pass on prerelease', () async { + await createFakePlugin('d'); + + final String preReleaseOutput = 'Package has 1 warning.' + 'Packages with an SDK constraint on a pre-release of the Dart SDK should themselves be published as a pre-release version.'; + + final MockProcess process = MockProcess(); + process.stdoutController.add(preReleaseOutput.codeUnits); + process.stdoutController.close(); // ignore: unawaited_futures + process.stderrController.close(); // ignore: unawaited_futures + + process.exitCodeCompleter.complete(1); + + processRunner.processesToReturn.add(process); + + expect(runner.run(['publish-check']), completes); + }); + }); +} + +class PublishCheckProcessRunner extends RecordingProcessRunner { + final Queue processesToReturn = Queue(); + + @override + io.Process get processToReturn => processesToReturn.removeFirst(); +} From c631fa190b5865d7263c93adfa3706c4f0a0a6e9 Mon Sep 17 00:00:00 2001 From: xster Date: Mon, 29 Mar 2021 22:03:36 -0700 Subject: [PATCH 373/924] Make sure androidx.lifecycle classes aren't R8'ed away when using flutter_plugin_android_lifecycle (#3746) --- packages/flutter_plugin_android_lifecycle/CHANGELOG.md | 4 ++++ .../android/build.gradle | 1 + .../android/proguard.txt | 9 +++++++++ packages/flutter_plugin_android_lifecycle/pubspec.yaml | 2 +- 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 packages/flutter_plugin_android_lifecycle/android/proguard.txt diff --git a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md index 08f137c09434..1c7f23b96f69 100644 --- a/packages/flutter_plugin_android_lifecycle/CHANGELOG.md +++ b/packages/flutter_plugin_android_lifecycle/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.1 +* Make sure androidx.lifecycle.DefaultLifecycleObservable doesn't get shrunk + away. + ## 2.0.0 * Bump Dart SDK for null-safety compatibility. diff --git a/packages/flutter_plugin_android_lifecycle/android/build.gradle b/packages/flutter_plugin_android_lifecycle/android/build.gradle index ac042bf144ab..9a26d574ac2e 100644 --- a/packages/flutter_plugin_android_lifecycle/android/build.gradle +++ b/packages/flutter_plugin_android_lifecycle/android/build.gradle @@ -27,6 +27,7 @@ android { defaultConfig { minSdkVersion 16 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles 'proguard.txt' } lintOptions { disable 'InvalidPackage' diff --git a/packages/flutter_plugin_android_lifecycle/android/proguard.txt b/packages/flutter_plugin_android_lifecycle/android/proguard.txt new file mode 100644 index 000000000000..d3a6df0eefd2 --- /dev/null +++ b/packages/flutter_plugin_android_lifecycle/android/proguard.txt @@ -0,0 +1,9 @@ +# The point of this package is to specify that a dependent plugin intends to +# use the AndroidX lifecycle classes. Make sure no R8 heuristics shrink classes +# brought in by the embedding's pom. +# +# This isn't strictly needed since by definition, plugins using Android +# lifecycles should implement DefaultLifecycleObserver and therefore keep it +# from being shrunk. But there seems to be an R8 bug so this needs to stay +# https://issuetracker.google.com/issues/142778206. +-keep class androidx.lifecycle.DefaultLifecycleObserver diff --git a/packages/flutter_plugin_android_lifecycle/pubspec.yaml b/packages/flutter_plugin_android_lifecycle/pubspec.yaml index fc2805ef814b..62169e4389fc 100644 --- a/packages/flutter_plugin_android_lifecycle/pubspec.yaml +++ b/packages/flutter_plugin_android_lifecycle/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_plugin_android_lifecycle description: Flutter plugin for accessing an Android Lifecycle within other plugins. -version: 2.0.0 +version: 2.0.1 homepage: https://github.com/flutter/plugins/tree/master/packages/flutter_plugin_android_lifecycle environment: From e0e9be0e499dc6a0dcbda1d7d9b19a82310d86ee Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 30 Mar 2021 13:34:20 -0700 Subject: [PATCH 374/924] Update build-all test for null-safe template (#3773) Flutter master now creates NNBD code when running 'flutter create', so the generated pubspec for build_all needs to use a compatible SDK version. This updates from 2.0.0 to 2.12.0. Also includes a test for this, which involved setting up tests for the file, and doing some refactoring to make the command testable. As a result, this fixes https://github.com/flutter/flutter/issues/61049 (although more test backfill is needed). --- script/build_all_plugins_app.sh | 8 +- .../src/create_all_plugins_app_command.dart | 53 ++++++----- .../create_all_plugins_app_command_test.dart | 91 +++++++++++++++++++ script/tool/test/util.dart | 15 ++- 4 files changed, 138 insertions(+), 29 deletions(-) create mode 100644 script/tool/test/create_all_plugins_app_command_test.dart diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index ab15a7d64249..56b05853fdcb 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -39,6 +39,12 @@ echo "Excluding the following plugins: $ALL_EXCLUDED" (cd "$REPO_DIR" && plugin_tools all-plugins-app --exclude $ALL_EXCLUDED) +# Master now creates null-safe app code by default; migrate stable so both +# branches are building in the same mode. +if [[ "${CHANNEL}" == "stable" ]]; then + (cd $REPO_DIR/all_plugins && dart migrate --apply-changes) +fi + function error() { echo "$@" 1>&2 } @@ -53,7 +59,7 @@ fi for version in "${BUILD_MODES[@]}"; do echo "Building $version..." - (cd $REPO_DIR/all_plugins && flutter build $@ --$version) + (cd $REPO_DIR/all_plugins && flutter build $@ --$version --no-sound-null-safety) if [ $? -eq 0 ]; then echo "Successfully built $version all_plugins app." diff --git a/script/tool/lib/src/create_all_plugins_app_command.dart b/script/tool/lib/src/create_all_plugins_app_command.dart index f1f11d15ca95..aaa7f7fb9667 100644 --- a/script/tool/lib/src/create_all_plugins_app_command.dart +++ b/script/tool/lib/src/create_all_plugins_app_command.dart @@ -12,11 +12,21 @@ import 'package:pubspec_parse/pubspec_parse.dart'; import 'common.dart'; -// TODO(cyanglaz): Add tests for this command. -// https://github.com/flutter/flutter/issues/61049 class CreateAllPluginsAppCommand extends PluginCommand { - CreateAllPluginsAppCommand(Directory packagesDir, FileSystem fileSystem) - : super(packagesDir, fileSystem); + CreateAllPluginsAppCommand( + Directory packagesDir, + FileSystem fileSystem, { + this.pluginsRoot, + }) : super(packagesDir, fileSystem) { + pluginsRoot ??= fileSystem.currentDirectory; + appDirectory = pluginsRoot.childDirectory('all_plugins'); + } + + /// The root directory of the plugin repository. + Directory pluginsRoot; + + /// The location of the synthesized app project. + Directory appDirectory; @override String get description => @@ -27,7 +37,7 @@ class CreateAllPluginsAppCommand extends PluginCommand { @override Future run() async { - final int exitCode = await _createPlugin(); + final int exitCode = await _createApp(); if (exitCode != 0) { throw ToolExit(exitCode); } @@ -39,7 +49,7 @@ class CreateAllPluginsAppCommand extends PluginCommand { ]); } - Future _createPlugin() async { + Future _createApp() async { final io.ProcessResult result = io.Process.runSync( 'flutter', [ @@ -47,7 +57,7 @@ class CreateAllPluginsAppCommand extends PluginCommand { '--template=app', '--project-name=all_plugins', '--android-language=java', - './all_plugins', + appDirectory.path, ], ); @@ -57,12 +67,10 @@ class CreateAllPluginsAppCommand extends PluginCommand { } Future _updateAppGradle() async { - final File gradleFile = fileSystem.file(p.join( - 'all_plugins', - 'android', - 'app', - 'build.gradle', - )); + final File gradleFile = appDirectory + .childDirectory('android') + .childDirectory('app') + .childFile('build.gradle'); if (!gradleFile.existsSync()) { throw ToolExit(64); } @@ -86,14 +94,12 @@ class CreateAllPluginsAppCommand extends PluginCommand { } Future _updateManifest() async { - final File manifestFile = fileSystem.file(p.join( - 'all_plugins', - 'android', - 'app', - 'src', - 'main', - 'AndroidManifest.xml', - )); + final File manifestFile = appDirectory + .childDirectory('android') + .childDirectory('app') + .childDirectory('src') + .childDirectory('main') + .childFile('AndroidManifest.xml'); if (!manifestFile.existsSync()) { throw ToolExit(64); } @@ -124,7 +130,7 @@ class CreateAllPluginsAppCommand extends PluginCommand { version: Version.parse('1.0.0+1'), environment: { 'sdk': VersionConstraint.compatibleWith( - Version.parse('2.0.0'), + Version.parse('2.12.0'), ), }, dependencies: { @@ -135,8 +141,7 @@ class CreateAllPluginsAppCommand extends PluginCommand { }, dependencyOverrides: pluginDeps, ); - final File pubspecFile = - fileSystem.file(p.join('all_plugins', 'pubspec.yaml')); + final File pubspecFile = appDirectory.childFile('pubspec.yaml'); pubspecFile.writeAsStringSync(_pubspecToString(pubspec)); } diff --git a/script/tool/test/create_all_plugins_app_command_test.dart b/script/tool/test/create_all_plugins_app_command_test.dart new file mode 100644 index 000000000000..58f24c9a3de1 --- /dev/null +++ b/script/tool/test/create_all_plugins_app_command_test.dart @@ -0,0 +1,91 @@ +// Copyright 2013 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:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:flutter_plugin_tools/src/create_all_plugins_app_command.dart'; +import 'package:test/test.dart'; + +import 'util.dart'; + +void main() { + group('$CreateAllPluginsAppCommand', () { + CommandRunner runner; + FileSystem fileSystem; + Directory testRoot; + Directory packagesDir; + Directory appDir; + + setUp(() { + // Since the core of this command is a call to 'flutter create', the test + // has to use the real filesystem. Put everything possible in a unique + // temporary to minimize affect on the host system. + fileSystem = LocalFileSystem(); + testRoot = fileSystem.systemTempDirectory.createTempSync(); + packagesDir = testRoot.childDirectory('packages'); + + final CreateAllPluginsAppCommand command = CreateAllPluginsAppCommand( + packagesDir, + fileSystem, + pluginsRoot: testRoot, + ); + appDir = command.appDirectory; + runner = CommandRunner( + 'create_all_test', 'Test for $CreateAllPluginsAppCommand'); + runner.addCommand(command); + }); + + tearDown(() { + testRoot.deleteSync(recursive: true); + }); + + test('pubspec includes all plugins', () async { + createFakePlugin('plugina', packagesDirectory: packagesDir); + createFakePlugin('pluginb', packagesDirectory: packagesDir); + createFakePlugin('pluginc', packagesDirectory: packagesDir); + + await runner.run(['all-plugins-app']); + final List pubspec = + appDir.childFile('pubspec.yaml').readAsLinesSync(); + + expect( + pubspec, + containsAll([ + contains(RegExp('path: .*/packages/plugina')), + contains(RegExp('path: .*/packages/pluginb')), + contains(RegExp('path: .*/packages/pluginc')), + ])); + }); + + test('pubspec has overrides for all plugins', () async { + createFakePlugin('plugina', packagesDirectory: packagesDir); + createFakePlugin('pluginb', packagesDirectory: packagesDir); + createFakePlugin('pluginc', packagesDirectory: packagesDir); + + await runner.run(['all-plugins-app']); + final List pubspec = + appDir.childFile('pubspec.yaml').readAsLinesSync(); + + expect( + pubspec, + containsAllInOrder([ + contains('dependency_overrides:'), + contains(RegExp('path: .*/packages/plugina')), + contains(RegExp('path: .*/packages/pluginb')), + contains(RegExp('path: .*/packages/pluginc')), + ])); + }); + + test('pubspec is compatible with null-safe app code', () async { + createFakePlugin('plugina', packagesDirectory: packagesDir); + + await runner.run(['all-plugins-app']); + final String pubspec = + appDir.childFile('pubspec.yaml').readAsStringSync(); + + expect(pubspec, contains(RegExp('sdk:\\s*(?:["\']>=|[^])2\\.12\\.'))); + }); + }); +} diff --git a/script/tool/test/util.dart b/script/tool/test/util.dart index 908b67b3cf75..d02b756ee9c6 100644 --- a/script/tool/test/util.dart +++ b/script/tool/test/util.dart @@ -12,6 +12,9 @@ import 'package:platform/platform.dart'; import 'package:flutter_plugin_tools/src/common.dart'; import 'package:quiver/collection.dart'; +// TODO(stuartmorgan): Eliminate this in favor of setting up a clean filesystem +// for each test, to eliminate the chance of files from one test interfering +// with another test. FileSystem mockFileSystem = MemoryFileSystem( style: LocalPlatform().isWindows ? FileSystemStyle.windows @@ -28,7 +31,8 @@ void initializeFakePackages({Directory parentDir}) { mockPackagesDir.createSync(); } -/// Creates a plugin package with the given [name] in [mockPackagesDir]. +/// Creates a plugin package with the given [name] in [packagesDirectory], +/// defaulting to [mockPackagesDir]. Directory createFakePlugin( String name, { bool withSingleExample = false, @@ -44,13 +48,16 @@ Directory createFakePlugin( bool includeChangeLog = false, bool includeVersion = false, String parentDirectoryName = '', + Directory packagesDirectory, }) { assert(!(withSingleExample && withExamples.isNotEmpty), 'cannot pass withSingleExample and withExamples simultaneously'); - final Directory pluginDirectory = (parentDirectoryName != '') - ? mockPackagesDir.childDirectory(parentDirectoryName).childDirectory(name) - : mockPackagesDir.childDirectory(name); + Directory parentDirectory = packagesDirectory ?? mockPackagesDir; + if (parentDirectoryName != '') { + parentDirectory = parentDirectory.childDirectory(parentDirectoryName); + } + final Directory pluginDirectory = parentDirectory.childDirectory(name); pluginDirectory.createSync(recursive: true); createFakePubspec( From ef641f77f40998602e3326a66b2bab9d1e9a82fd Mon Sep 17 00:00:00 2001 From: xster Date: Tue, 30 Mar 2021 13:36:18 -0700 Subject: [PATCH 375/924] Update flutter_plugin_android_lifecycle dependency versions (#3767) --- .../google_maps_flutter/google_maps_flutter/CHANGELOG.md | 5 +++++ .../google_maps_flutter/example/pubspec.yaml | 2 +- .../google_maps_flutter/google_maps_flutter/pubspec.yaml | 4 ++-- packages/image_picker/image_picker/CHANGELOG.md | 5 +++++ packages/image_picker/image_picker/example/pubspec.yaml | 2 +- packages/image_picker/image_picker/pubspec.yaml | 4 ++-- packages/local_auth/CHANGELOG.md | 5 +++++ packages/local_auth/pubspec.yaml | 4 ++-- 8 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index eb16024575bb..141a096aee94 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.2 + +* Update flutter_plugin_android_lifecycle dependency to 2.0.1 to fix an R8 issue + on some versions. + ## 2.0.1 * Update platform_plugin_interface version requirement. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml index 5d553eaa3c99..eb06e09a8757 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - flutter_plugin_android_lifecycle: ^2.0.0-nullsafety.2 + flutter_plugin_android_lifecycle: ^2.0.1 dev_dependencies: flutter_driver: diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index d30c9d030de6..5e73586e07e4 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,12 +1,12 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 2.0.1 +version: 2.0.2 dependencies: flutter: sdk: flutter - flutter_plugin_android_lifecycle: ^2.0.0 + flutter_plugin_android_lifecycle: ^2.0.1 google_maps_flutter_platform_interface: ^2.0.0 dev_dependencies: diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index fc3d5c156a17..6af3cb090ca6 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.7.4 + +* Update flutter_plugin_android_lifecycle dependency to 2.0.1 to fix an R8 issue + on some versions. + ## 0.7.3 * Endorse image_picker_for_web diff --git a/packages/image_picker/image_picker/example/pubspec.yaml b/packages/image_picker/image_picker/example/pubspec.yaml index 68b70b909162..b2e5b6399f47 100755 --- a/packages/image_picker/image_picker/example/pubspec.yaml +++ b/packages/image_picker/image_picker/example/pubspec.yaml @@ -6,7 +6,7 @@ dependencies: video_player: ^2.0.0-nullsafety.7 flutter: sdk: flutter - flutter_plugin_android_lifecycle: ^2.0.0 + flutter_plugin_android_lifecycle: ^2.0.1 image_picker: # When depending on this package from a real application you should use: # image_picker: ^x.y.z diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 0018e87ab437..73c6a6ed1824 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.7.3 +version: 0.7.4 flutter: plugin: @@ -18,7 +18,7 @@ flutter: dependencies: flutter: sdk: flutter - flutter_plugin_android_lifecycle: ^2.0.0 + flutter_plugin_android_lifecycle: ^2.0.1 image_picker_platform_interface: ^2.0.0 image_picker_for_web: ^2.0.0 diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index b4d58395295f..258144cd0daa 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.1.1 + +* Update flutter_plugin_android_lifecycle dependency to 2.0.1 to fix an R8 issue + on some versions. + ## 1.1.0 * Migrate to null safety. diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index a63027728d86..76722c00a147 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth description: Flutter plugin for Android and iOS devices to allow local authentication via fingerprint, touch ID, face ID, passcode, pin, or pattern. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 1.1.0 +version: 1.1.1 flutter: plugin: @@ -19,7 +19,7 @@ dependencies: meta: ^1.3.0 intl: ^0.17.0 platform: ^3.0.0 - flutter_plugin_android_lifecycle: ^2.0.0 + flutter_plugin_android_lifecycle: ^2.0.1 dev_dependencies: integration_test: From 860adb44e38502f2986f30718c3522a36877d0ec Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 30 Mar 2021 16:48:41 -0700 Subject: [PATCH 376/924] [google_maps_flutter] Fix TileOverlay cloning (#3771) TileOverlay was not copying its TileProvider. During the NNBD migration, map object updates were refactored to share code, and in that refactoring TileOverlay update construction was aligned with other map objects to use clones, so certain operations involving TileOverlays started dropping the TileProvider. Fixes https://github.com/flutter/flutter/issues/77500 --- .../CHANGELOG.md | 5 ++ .../lib/src/types/tile_overlay.dart | 7 ++- .../pubspec.yaml | 2 +- .../test/types/tile_overlay_test.dart | 51 +++++++++++++++---- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index 1a620834b564..b6603d66fa89 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.4 + +* Preserve the `TileProvider` when copying `TileOverlay`, fixing a + regression with tile overlays introduced in the null safety migration. + ## 2.0.3 * Fix type issues in `isMarkerInfoWindowShown` and `getZoomLevel` introduced diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart index 55dca55f9d8e..8cdd2c4699e1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/tile_overlay.dart @@ -92,6 +92,7 @@ class TileOverlay implements MapsObject { /// unless overwritten by the specified parameters. TileOverlay copyWith({ bool? fadeInParam, + TileProvider? tileProviderParam, double? transparencyParam, int? zIndexParam, bool? visibleParam, @@ -100,6 +101,7 @@ class TileOverlay implements MapsObject { return TileOverlay( tileOverlayId: tileOverlayId, fadeIn: fadeInParam ?? fadeIn, + tileProvider: tileProviderParam ?? tileProvider, transparency: transparencyParam ?? transparency, zIndex: zIndexParam ?? zIndex, visible: visibleParam ?? visible, @@ -137,6 +139,7 @@ class TileOverlay implements MapsObject { return other is TileOverlay && tileOverlayId == other.tileOverlayId && fadeIn == other.fadeIn && + tileProvider == other.tileProvider && transparency == other.transparency && zIndex == other.zIndex && visible == other.visible && @@ -144,6 +147,6 @@ class TileOverlay implements MapsObject { } @override - int get hashCode => hashValues( - tileOverlayId, fadeIn, transparency, zIndex, visible, tileSize); + int get hashCode => hashValues(tileOverlayId, fadeIn, tileProvider, + transparency, zIndex, visible, tileSize); } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index 628099139021..4bce4aa8a5a1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -3,7 +3,7 @@ description: A common platform interface for the google_maps_flutter plugin. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_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: 2.0.3 +version: 2.0.4 dependencies: flutter: diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart index a17f86d4f19a..3a4c34764ef7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/tile_overlay_test.dart @@ -7,6 +7,13 @@ import 'dart:ui' show hashValues; import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +class _TestTileProvider extends TileProvider { + @override + Future getTile(int x, int y, int? zoom) async { + return Tile(0, 0, null); + } +} + void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -58,40 +65,65 @@ void main() { }); test('equality', () async { - const TileOverlay tileOverlay1 = TileOverlay( + final TileProvider tileProvider = _TestTileProvider(); + final TileOverlay tileOverlay1 = TileOverlay( tileOverlayId: TileOverlayId('id1'), fadeIn: false, - tileProvider: null, + tileProvider: tileProvider, transparency: 0.1, zIndex: 1, visible: false, tileSize: 128); - const TileOverlay tileOverlay2 = TileOverlay( + final TileOverlay tileOverlaySameValues = TileOverlay( tileOverlayId: TileOverlayId('id1'), fadeIn: false, - tileProvider: null, + tileProvider: tileProvider, transparency: 0.1, zIndex: 1, visible: false, tileSize: 128); - const TileOverlay tileOverlay3 = TileOverlay( + final TileOverlay tileOverlayDifferentId = TileOverlay( tileOverlayId: TileOverlayId('id2'), fadeIn: false, + tileProvider: tileProvider, + transparency: 0.1, + zIndex: 1, + visible: false, + tileSize: 128); + final TileOverlay tileOverlayDifferentProvider = TileOverlay( + tileOverlayId: TileOverlayId('id1'), + fadeIn: false, tileProvider: null, transparency: 0.1, zIndex: 1, visible: false, tileSize: 128); - expect(tileOverlay1, tileOverlay2); - expect(tileOverlay1, isNot(tileOverlay3)); + expect(tileOverlay1, tileOverlaySameValues); + expect(tileOverlay1, isNot(tileOverlayDifferentId)); + expect(tileOverlay1, isNot(tileOverlayDifferentProvider)); + }); + + test('clone', () async { + final TileProvider tileProvider = _TestTileProvider(); + // Set non-default values for every parameter. + final TileOverlay tileOverlay = TileOverlay( + tileOverlayId: TileOverlayId('id1'), + fadeIn: false, + tileProvider: tileProvider, + transparency: 0.1, + zIndex: 1, + visible: false, + tileSize: 128); + expect(tileOverlay, tileOverlay.clone()); }); test('hashCode', () async { + final TileProvider tileProvider = _TestTileProvider(); const TileOverlayId id = TileOverlayId('id1'); - const TileOverlay tileOverlay = TileOverlay( + final TileOverlay tileOverlay = TileOverlay( tileOverlayId: id, fadeIn: false, - tileProvider: null, + tileProvider: tileProvider, transparency: 0.1, zIndex: 1, visible: false, @@ -101,6 +133,7 @@ void main() { hashValues( tileOverlay.tileOverlayId, tileOverlay.fadeIn, + tileOverlay.tileProvider, tileOverlay.transparency, tileOverlay.zIndex, tileOverlay.visible, From 0db60bbfc156d3c71d098a81848540c2215b5746 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 30 Mar 2021 17:38:16 -0700 Subject: [PATCH 377/924] let google_maps_flutter_web version solve for older mockito (#3769) --- .../google_maps_flutter_web/example/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml index 9f942d654caa..28955016ab40 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dev_dependencies: google_maps: ^3.4.4 http: ^0.13.0 - mockito: ^4.1.4 # Update to ^5.0.0 as soon as this migrates to null-safety + mockito: ^4.1.1+1 # Update to ^5.0.0 as soon as this migrates to null-safety flutter_driver: sdk: flutter flutter_test: From febc3e36e8acc8920bbea9658b891bdc82b53db3 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Wed, 31 Mar 2021 12:44:47 -0700 Subject: [PATCH 378/924] [path_provider] Switch to new analysis options (#3755) Removes the override to use the legacy analysis, and fixes all resulting issues. Part of flutter/flutter#76229 --- packages/path_provider/analysis_options.yaml | 1 - .../integration_test/path_provider_test.dart | 8 ++- .../path_provider/example/lib/main.dart | 20 +++---- .../example/test_driver/integration_test.dart | 3 +- .../path_provider/lib/path_provider.dart | 4 +- .../test/path_provider_test.dart | 41 +++++++++----- .../path_provider_linux/example/lib/main.dart | 8 +-- .../example/test/widget_test.dart | 12 ++--- .../example/test_driver/integration_test.dart | 3 +- .../lib/path_provider_linux.dart | 17 +++--- .../test/path_provider_linux_test.dart | 2 +- .../path_provider_macos/example/lib/main.dart | 4 +- .../example/test_driver/integration_test.dart | 3 +- .../lib/path_provider_platform_interface.dart | 4 +- .../lib/src/method_channel_path_provider.dart | 16 ++++-- .../method_channel_path_provider_test.dart | 2 +- .../example/lib/main.dart | 4 +- .../example/test_driver/integration_test.dart | 3 +- .../lib/src/folders.dart | 3 ++ .../lib/src/path_provider_windows_real.dart | 53 +++++++++---------- .../lib/src/path_provider_windows_stub.dart | 4 +- .../test/path_provider_windows_test.dart | 39 +++++++------- script/incremental_build.sh | 1 - 23 files changed, 132 insertions(+), 123 deletions(-) delete mode 100644 packages/path_provider/analysis_options.yaml diff --git a/packages/path_provider/analysis_options.yaml b/packages/path_provider/analysis_options.yaml deleted file mode 100644 index cda4f6e153e6..000000000000 --- a/packages/path_provider/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: ../../analysis_options_legacy.yaml diff --git a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart index 2613b45a8574..f1e7c0aef59b 100644 --- a/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart +++ b/packages/path_provider/path_provider/example/integration_test/path_provider_test.dart @@ -4,8 +4,6 @@ // @dart=2.9 -import 'dart:async'; - import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:path_provider/path_provider.dart'; @@ -55,7 +53,7 @@ void main() { expect(result, throwsA(isInstanceOf())); } else if (Platform.isAndroid) { final List directories = await getExternalCacheDirectories(); - for (Directory result in directories) { + for (final Directory result in directories) { _verifySampleFile(result, 'externalCache'); } } @@ -72,7 +70,7 @@ void main() { StorageDirectory.movies, ]; - for (StorageDirectory type in _allDirs) { + for (final StorageDirectory type in _allDirs) { test('getExternalStorageDirectories (type: $type)', () async { if (Platform.isIOS) { final Future> result = @@ -81,7 +79,7 @@ void main() { } else if (Platform.isAndroid) { final List directories = await getExternalStorageDirectories(type: type); - for (Directory result in directories) { + for (final Directory result in directories) { _verifySampleFile(result, '$type'); } } diff --git a/packages/path_provider/path_provider/example/lib/main.dart b/packages/path_provider/path_provider/example/lib/main.dart index 7b1d6a73a2f5..c0ac126b2a00 100644 --- a/packages/path_provider/path_provider/example/lib/main.dart +++ b/packages/path_provider/path_provider/example/lib/main.dart @@ -4,7 +4,6 @@ // ignore_for_file: public_member_api_docs -import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; @@ -22,13 +21,13 @@ class MyApp extends StatelessWidget { theme: ThemeData( primarySwatch: Colors.blue, ), - home: MyHomePage(title: 'Path Provider'), + home: const MyHomePage(title: 'Path Provider'), ); } } class MyHomePage extends StatefulWidget { - MyHomePage({Key? key, required this.title}) : super(key: key); + const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override @@ -166,8 +165,9 @@ class _MyHomePageState extends State { Padding( padding: const EdgeInsets.all(16.0), child: ElevatedButton( - child: Text( - '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Storage Directory"}'), + child: Text(Platform.isIOS + ? 'External directories are unavailable on iOS' + : 'Get External Storage Directory'), onPressed: Platform.isIOS ? null : _requestExternalStorageDirectory, ), @@ -178,8 +178,9 @@ class _MyHomePageState extends State { Padding( padding: const EdgeInsets.all(16.0), child: ElevatedButton( - child: Text( - '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Storage Directories"}'), + child: Text(Platform.isIOS + ? 'External directories are unavailable on iOS' + : 'Get External Storage Directories'), onPressed: Platform.isIOS ? null : () { @@ -197,8 +198,9 @@ class _MyHomePageState extends State { Padding( padding: const EdgeInsets.all(16.0), child: ElevatedButton( - child: Text( - '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Cache Directories"}'), + child: Text(Platform.isIOS + ? 'External directories are unavailable on iOS' + : 'Get External Cache Directories'), onPressed: Platform.isIOS ? null : _requestExternalCacheDirectories, ), diff --git a/packages/path_provider/path_provider/example/test_driver/integration_test.dart b/packages/path_provider/path_provider/example/test_driver/integration_test.dart index 18ed3cff3ee8..24a0ee720b2a 100644 --- a/packages/path_provider/path_provider/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider/example/test_driver/integration_test.dart @@ -4,7 +4,6 @@ // @dart=2.9 -import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; @@ -14,6 +13,6 @@ Future main() async { final String data = await driver.requestData(null, timeout: const Duration(minutes: 1)); await driver.close(); - final Map result = jsonDecode(data); + final Map result = jsonDecode(data) as Map; exit(result['result'] == 'true' ? 0 : 1); } diff --git a/packages/path_provider/path_provider/lib/path_provider.dart b/packages/path_provider/path_provider/lib/path_provider.dart index d63887a60267..a51aefe8e29f 100644 --- a/packages/path_provider/path_provider/lib/path_provider.dart +++ b/packages/path_provider/path_provider/lib/path_provider.dart @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; import 'dart:io' show Directory, Platform; import 'package:flutter/foundation.dart' show kIsWeb, visibleForTesting; import 'package:path_provider_linux/path_provider_linux.dart'; import 'package:path_provider_windows/path_provider_windows.dart'; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; +// ignore: implementation_imports import 'package:path_provider_platform_interface/src/method_channel_path_provider.dart'; export 'package:path_provider_platform_interface/path_provider_platform_interface.dart' @@ -36,7 +36,7 @@ class MissingPlatformDirectoryException implements Exception { @override String toString() { - String detailsAddition = details == null ? '' : ': $details'; + final String detailsAddition = details == null ? '' : ': $details'; return 'MissingPlatformDirectoryException($message)$detailsAddition'; } } diff --git a/packages/path_provider/path_provider/test/path_provider_test.dart b/packages/path_provider/path_provider/test/path_provider_test.dart index 7232a74a1253..218861606209 100644 --- a/packages/path_provider/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/path_provider/test/path_provider_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:io' show Directory; -import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:path_provider/path_provider.dart'; @@ -27,44 +26,44 @@ void main() { }); test('getTemporaryDirectory', () async { - Directory result = await getTemporaryDirectory(); + final Directory result = await getTemporaryDirectory(); expect(result.path, kTemporaryPath); }); test('getApplicationSupportDirectory', () async { - Directory result = await getApplicationSupportDirectory(); + final Directory result = await getApplicationSupportDirectory(); expect(result.path, kApplicationSupportPath); }); test('getLibraryDirectory', () async { - Directory result = await getLibraryDirectory(); + final Directory result = await getLibraryDirectory(); expect(result.path, kLibraryPath); }); test('getApplicationDocumentsDirectory', () async { - Directory result = await getApplicationDocumentsDirectory(); + final Directory result = await getApplicationDocumentsDirectory(); expect(result.path, kApplicationDocumentsPath); }); test('getExternalStorageDirectory', () async { - Directory? result = await getExternalStorageDirectory(); + final Directory? result = await getExternalStorageDirectory(); expect(result?.path, kExternalStoragePath); }); test('getExternalCacheDirectories', () async { - List? result = await getExternalCacheDirectories(); + final List? result = await getExternalCacheDirectories(); expect(result?.length, 1); expect(result?.first.path, kExternalCachePath); }); test('getExternalStorageDirectories', () async { - List? result = await getExternalStorageDirectories(); + final List? result = await getExternalStorageDirectories(); expect(result?.length, 1); expect(result?.first.path, kExternalStoragePath); }); test('getDownloadsDirectory', () async { - Directory? result = await getDownloadsDirectory(); + final Directory? result = await getDownloadsDirectory(); expect(result?.path, kDownloadsPath); }); }); @@ -95,22 +94,22 @@ void main() { }); test('getExternalStorageDirectory passes null through', () async { - Directory? result = await getExternalStorageDirectory(); + final Directory? result = await getExternalStorageDirectory(); expect(result, isNull); }); test('getExternalCacheDirectories passes null through', () async { - List? result = await getExternalCacheDirectories(); + final List? result = await getExternalCacheDirectories(); expect(result, isNull); }); test('getExternalStorageDirectories passes null through', () async { - List? result = await getExternalStorageDirectories(); + final List? result = await getExternalStorageDirectories(); expect(result, isNull); }); test('getDownloadsDirectory passses null through', () async { - Directory? result = await getDownloadsDirectory(); + final Directory? result = await getDownloadsDirectory(); expect(result, isNull); }); }); @@ -119,36 +118,44 @@ void main() { class FakePathProviderPlatform extends Fake with MockPlatformInterfaceMixin implements PathProviderPlatform { + @override Future getTemporaryPath() async { return kTemporaryPath; } + @override Future getApplicationSupportPath() async { return kApplicationSupportPath; } + @override Future getLibraryPath() async { return kLibraryPath; } + @override Future getApplicationDocumentsPath() async { return kApplicationDocumentsPath; } + @override Future getExternalStoragePath() async { return kExternalStoragePath; } + @override Future?> getExternalCachePaths() async { return [kExternalCachePath]; } + @override Future?> getExternalStoragePaths({ StorageDirectory? type, }) async { return [kExternalStoragePath]; } + @override Future getDownloadsPath() async { return kDownloadsPath; } @@ -157,36 +164,44 @@ class FakePathProviderPlatform extends Fake class AllNullFakePathProviderPlatform extends Fake with MockPlatformInterfaceMixin implements PathProviderPlatform { + @override Future getTemporaryPath() async { return null; } + @override Future getApplicationSupportPath() async { return null; } + @override Future getLibraryPath() async { return null; } + @override Future getApplicationDocumentsPath() async { return null; } + @override Future getExternalStoragePath() async { return null; } + @override Future?> getExternalCachePaths() async { return null; } + @override Future?> getExternalStoragePaths({ StorageDirectory? type, }) async { return null; } + @override Future getDownloadsPath() async { return null; } diff --git a/packages/path_provider/path_provider_linux/example/lib/main.dart b/packages/path_provider/path_provider_linux/example/lib/main.dart index 104c998bc61a..d365e6bdeab4 100644 --- a/packages/path_provider/path_provider_linux/example/lib/main.dart +++ b/packages/path_provider/path_provider_linux/example/lib/main.dart @@ -3,8 +3,6 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; -import 'dart:async'; - import 'package:flutter/services.dart'; import 'package:path_provider_linux/path_provider_linux.dart'; @@ -67,7 +65,9 @@ class _MyAppState extends State { // If the widget was removed from the tree while the asynchronous platform // message was in flight, we want to discard the reply rather than calling // setState to update our non-existent appearance. - if (!mounted) return; + if (!mounted) { + return; + } setState(() { _tempDirectory = tempDirectory; @@ -86,7 +86,7 @@ class _MyAppState extends State { ), body: Center( child: Column( - children: [ + children: [ Text('Temp Directory: $_tempDirectory\n'), Text('Documents Directory: $_documentsDirectory\n'), Text('Downloads Directory: $_downloadsDirectory\n'), diff --git a/packages/path_provider/path_provider_linux/example/test/widget_test.dart b/packages/path_provider/path_provider_linux/example/test/widget_test.dart index 4d5da3e4e330..59f839d431fa 100644 --- a/packages/path_provider/path_provider_linux/example/test/widget_test.dart +++ b/packages/path_provider/path_provider_linux/example/test/widget_test.dart @@ -9,8 +9,6 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -19,14 +17,14 @@ import 'package:pathproviderexample/main.dart'; void main() { group('Test linux path provider example', () { setUpAll(() async { - await WidgetsFlutterBinding.ensureInitialized(); + WidgetsFlutterBinding.ensureInitialized(); }); testWidgets('Finds tmp directory', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.runAsync(() async { await tester.pumpWidget(MyApp()); - await Future.delayed(Duration(milliseconds: 20)); + await Future.delayed(const Duration(milliseconds: 20)); await tester.pump(); // Verify that temporary directory is retrieved. @@ -44,7 +42,7 @@ void main() { // Build our app and trigger a frame. await tester.runAsync(() async { await tester.pumpWidget(MyApp()); - await Future.delayed(Duration(milliseconds: 20)); + await Future.delayed(const Duration(milliseconds: 20)); await tester.pump(); // Verify that documents directory is retrieved. @@ -62,7 +60,7 @@ void main() { // Build our app and trigger a frame. await tester.runAsync(() async { await tester.pumpWidget(MyApp()); - await Future.delayed(Duration(milliseconds: 20)); + await Future.delayed(const Duration(milliseconds: 20)); await tester.pump(); // Verify that downloads directory is retrieved. @@ -81,7 +79,7 @@ void main() { // Build our app and trigger a frame. await tester.runAsync(() async { await tester.pumpWidget(MyApp()); - await Future.delayed(Duration(milliseconds: 20)); + await Future.delayed(const Duration(milliseconds: 20)); await tester.pump(); // Verify that Application Support Directory is retrieved. diff --git a/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart index 18ed3cff3ee8..24a0ee720b2a 100644 --- a/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_linux/example/test_driver/integration_test.dart @@ -4,7 +4,6 @@ // @dart=2.9 -import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; @@ -14,6 +13,6 @@ Future main() async { final String data = await driver.requestData(null, timeout: const Duration(minutes: 1)); await driver.close(); - final Map result = jsonDecode(data); + final Map result = jsonDecode(data) as Map; exit(result['result'] == 'true' ? 0 : 1); } diff --git a/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart b/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart index cf8d12436429..5a81114cc92d 100644 --- a/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart +++ b/packages/path_provider/path_provider_linux/lib/path_provider_linux.dart @@ -1,12 +1,12 @@ // Copyright 2013 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 'dart:io'; -import 'dart:async'; -import 'package:xdg_directories/xdg_directories.dart' as xdg; import 'package:path/path.dart' as path; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; +import 'package:xdg_directories/xdg_directories.dart' as xdg; /// The linux implementation of [PathProviderPlatform] /// @@ -19,16 +19,17 @@ class PathProviderLinux extends PathProviderPlatform { @override Future getTemporaryPath() { - return Future.value("/tmp"); + return Future.value('/tmp'); } @override Future getApplicationSupportPath() async { - final processName = path.basenameWithoutExtension( + final String processName = path.basenameWithoutExtension( await File('/proc/self/exe').resolveSymbolicLinks()); - final directory = Directory(path.join(xdg.dataHome.path, processName)); + final Directory directory = + Directory(path.join(xdg.dataHome.path, processName)); // Creating the directory if it doesn't exist, because mobile implementations assume the directory exists - if (!await directory.exists()) { + if (!directory.existsSync()) { await directory.create(recursive: true); } return directory.path; @@ -36,11 +37,11 @@ class PathProviderLinux extends PathProviderPlatform { @override Future getApplicationDocumentsPath() { - return Future.value(xdg.getUserDirectory('DOCUMENTS')?.path); + return Future.value(xdg.getUserDirectory('DOCUMENTS')?.path); } @override Future getDownloadsPath() { - return Future.value(xdg.getUserDirectory('DOWNLOAD')?.path); + return Future.value(xdg.getUserDirectory('DOWNLOAD')?.path); } } diff --git a/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart b/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart index 81329fb7c3cb..9ab75ff477de 100644 --- a/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart +++ b/packages/path_provider/path_provider_linux/test/path_provider_linux_test.dart @@ -14,7 +14,7 @@ void main() { tearDown(() {}); test('getTemporaryPath', () async { - final plugin = PathProviderPlatform.instance; + final PathProviderPlatform plugin = PathProviderPlatform.instance; expect(await plugin.getTemporaryPath(), '/tmp'); }); } diff --git a/packages/path_provider/path_provider_macos/example/lib/main.dart b/packages/path_provider/path_provider_macos/example/lib/main.dart index 19ba86e31cf5..67a0eb32eeda 100644 --- a/packages/path_provider/path_provider_macos/example/lib/main.dart +++ b/packages/path_provider/path_provider_macos/example/lib/main.dart @@ -4,8 +4,6 @@ // ignore_for_file: public_member_api_docs -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; @@ -79,7 +77,7 @@ class _MyAppState extends State { ), body: Center( child: Column( - children: [ + children: [ Text('Temp Directory: $_tempDirectory\n'), Text('Documents Directory: $_documentsDirectory\n'), Text('Downloads Directory: $_downloadsDirectory\n'), diff --git a/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart index 18ed3cff3ee8..24a0ee720b2a 100644 --- a/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_macos/example/test_driver/integration_test.dart @@ -4,7 +4,6 @@ // @dart=2.9 -import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; @@ -14,6 +13,6 @@ Future main() async { final String data = await driver.requestData(null, timeout: const Duration(minutes: 1)); await driver.close(); - final Map result = jsonDecode(data); + final Map result = jsonDecode(data) as Map; exit(result['result'] == 'true' ? 0 : 1); } diff --git a/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart b/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart index 3eb1580711ef..99e600d05263 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/path_provider_platform_interface.dart @@ -2,13 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'src/enums.dart'; import 'src/method_channel_path_provider.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - export 'src/enums.dart'; /// The interface that implementations of path_provider must implement. diff --git a/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart b/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart index 7889e004126f..007787444adb 100644 --- a/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart +++ b/packages/path_provider/path_provider_platform_interface/lib/src/method_channel_path_provider.dart @@ -2,21 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; - -import 'enums.dart'; - import 'package:flutter/services.dart'; import 'package:meta/meta.dart'; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; import 'package:platform/platform.dart'; +import 'enums.dart'; + /// An implementation of [PathProviderPlatform] that uses method channels. class MethodChannelPathProvider extends PathProviderPlatform { /// The method channel used to interact with the native platform. @visibleForTesting MethodChannel methodChannel = - MethodChannel('plugins.flutter.io/path_provider'); + const MethodChannel('plugins.flutter.io/path_provider'); // Ideally, this property shouldn't exist, and each platform should // just implement the supported methods. Once all the platforms are @@ -30,14 +28,17 @@ class MethodChannelPathProvider extends PathProviderPlatform { _platform = platform; } + @override Future getTemporaryPath() { return methodChannel.invokeMethod('getTemporaryDirectory'); } + @override Future getApplicationSupportPath() { return methodChannel.invokeMethod('getApplicationSupportDirectory'); } + @override Future getLibraryPath() { if (!_platform.isIOS && !_platform.isMacOS) { throw UnsupportedError('Functionality only available on iOS/macOS'); @@ -45,11 +46,13 @@ class MethodChannelPathProvider extends PathProviderPlatform { return methodChannel.invokeMethod('getLibraryDirectory'); } + @override Future getApplicationDocumentsPath() { return methodChannel .invokeMethod('getApplicationDocumentsDirectory'); } + @override Future getExternalStoragePath() { if (!_platform.isAndroid) { throw UnsupportedError('Functionality only available on Android'); @@ -57,6 +60,7 @@ class MethodChannelPathProvider extends PathProviderPlatform { return methodChannel.invokeMethod('getStorageDirectory'); } + @override Future?> getExternalCachePaths() { if (!_platform.isAndroid) { throw UnsupportedError('Functionality only available on Android'); @@ -65,6 +69,7 @@ class MethodChannelPathProvider extends PathProviderPlatform { .invokeListMethod('getExternalCacheDirectories'); } + @override Future?> getExternalStoragePaths({ StorageDirectory? type, }) async { @@ -77,6 +82,7 @@ class MethodChannelPathProvider extends PathProviderPlatform { ); } + @override Future getDownloadsPath() { if (!_platform.isMacOS) { throw UnsupportedError('Functionality only available on macOS'); diff --git a/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart b/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart index 71d55861c7b1..69c9b2b01f19 100644 --- a/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart +++ b/packages/path_provider/path_provider_platform_interface/test/method_channel_path_provider_test.dart @@ -147,7 +147,7 @@ void main() { } }); - for (StorageDirectory? type in [ + for (final StorageDirectory? type in [ null, ...StorageDirectory.values ]) { diff --git a/packages/path_provider/path_provider_windows/example/lib/main.dart b/packages/path_provider/path_provider_windows/example/lib/main.dart index b4b0f999d937..509292bf7405 100644 --- a/packages/path_provider/path_provider_windows/example/lib/main.dart +++ b/packages/path_provider/path_provider_windows/example/lib/main.dart @@ -4,8 +4,6 @@ // ignore_for_file: public_member_api_docs -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:path_provider_windows/path_provider_windows.dart'; @@ -79,7 +77,7 @@ class _MyAppState extends State { ), body: Center( child: Column( - children: [ + children: [ Text('Temp Directory: $_tempDirectory\n'), Text('Documents Directory: $_documentsDirectory\n'), Text('Downloads Directory: $_downloadsDirectory\n'), diff --git a/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart b/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart index 18ed3cff3ee8..24a0ee720b2a 100644 --- a/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart +++ b/packages/path_provider/path_provider_windows/example/test_driver/integration_test.dart @@ -4,7 +4,6 @@ // @dart=2.9 -import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:flutter_driver/flutter_driver.dart'; @@ -14,6 +13,6 @@ Future main() async { final String data = await driver.requestData(null, timeout: const Duration(minutes: 1)); await driver.close(); - final Map result = jsonDecode(data); + final Map result = jsonDecode(data) as Map; exit(result['result'] == 'true' ? 0 : 1); } diff --git a/packages/path_provider/path_provider_windows/lib/src/folders.dart b/packages/path_provider/path_provider_windows/lib/src/folders.dart index e8112c1a953a..55def29df2d7 100644 --- a/packages/path_provider/path_provider_windows/lib/src/folders.dart +++ b/packages/path_provider/path_provider_windows/lib/src/folders.dart @@ -4,6 +4,9 @@ import 'package:win32/win32.dart'; +// ignore_for_file: non_constant_identifier_names + +// ignore: avoid_classes_with_only_static_members /// A class containing the GUID references for each of the documented Windows /// known folders. A property of this class may be passed to the `getPath` /// method in the [PathProvidersWindows] class to retrieve a known folder from diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart index 5fef0dba32ed..13841a058638 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_real.dart @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; -import 'dart:io'; import 'dart:ffi'; +import 'dart:io'; import 'package:ffi/ffi.dart'; import 'package:meta/meta.dart'; @@ -22,14 +21,15 @@ import 'folders.dart'; class VersionInfoQuerier { /// Returns the value for [key] in [versionInfo]s English strings section, or /// null if there is no such entry, or if versionInfo is null. - getStringValue(Pointer? versionInfo, key) { + String? getStringValue(Pointer? versionInfo, String key) { if (versionInfo == null) { return null; } - const kEnUsLanguageCode = '040904e4'; - final keyPath = TEXT('\\StringFileInfo\\$kEnUsLanguageCode\\$key'); - final length = calloc(); - final valueAddress = calloc>(); + const String kEnUsLanguageCode = '040904e4'; + final Pointer keyPath = + TEXT('\\StringFileInfo\\$kEnUsLanguageCode\\$key'); + final Pointer length = calloc(); + final Pointer> valueAddress = calloc>(); try { if (VerQueryValue(versionInfo, keyPath, valueAddress, length) == 0) { return null; @@ -54,14 +54,14 @@ class PathProviderWindows extends PathProviderPlatform { /// This is typically the same as the TMP environment variable. @override Future getTemporaryPath() async { - final buffer = calloc(MAX_PATH + 1).cast(); + final Pointer buffer = calloc(MAX_PATH + 1).cast(); String path; try { - final length = GetTempPath(MAX_PATH, buffer); + final int length = GetTempPath(MAX_PATH, buffer); if (length == 0) { - final error = GetLastError(); + final int error = GetLastError(); throw WindowsException(error); } else { path = buffer.toDartString(); @@ -69,18 +69,18 @@ class PathProviderWindows extends PathProviderPlatform { // GetTempPath adds a trailing backslash, but SHGetKnownFolderPath does // not. Strip off trailing backslash for consistency with other methods // here. - if (path.endsWith('\\')) { + if (path.endsWith(r'\')) { path = path.substring(0, path.length - 1); } } // Ensure that the directory exists, since GetTempPath doesn't. - final directory = Directory(path); + final Directory directory = Directory(path); if (!directory.existsSync()) { await directory.create(recursive: true); } - return Future.value(path); + return path; } finally { calloc.free(buffer); } @@ -88,8 +88,8 @@ class PathProviderWindows extends PathProviderPlatform { @override Future getApplicationSupportPath() async { - final appDataRoot = await getPath(WindowsKnownFolder.RoamingAppData); - final directory = Directory( + final String appDataRoot = await getPath(WindowsKnownFolder.RoamingAppData); + final Directory directory = Directory( path.join(appDataRoot, _getApplicationSpecificSubdirectory())); // Ensure that the directory exists if possible, since it will on other // platforms. If the name is longer than MAXPATH, creating will fail, so @@ -115,11 +115,11 @@ class PathProviderWindows extends PathProviderPlatform { /// folderID is a GUID that represents a specific known folder ID, drawn from /// [WindowsKnownFolder]. Future getPath(String folderID) { - final pathPtrPtr = calloc>(); + final Pointer> pathPtrPtr = calloc>(); final Pointer knownFolderID = calloc()..ref.setGUID(folderID); try { - final hr = SHGetKnownFolderPath( + final int hr = SHGetKnownFolderPath( knownFolderID, KF_FLAG_DEFAULT, NULL, @@ -132,8 +132,8 @@ class PathProviderWindows extends PathProviderPlatform { } } - final path = pathPtrPtr.value.toDartString(); - return Future.value(path); + final String path = pathPtrPtr.value.toDartString(); + return Future.value(path); } finally { calloc.free(pathPtrPtr); calloc.free(knownFolderID); @@ -160,14 +160,15 @@ class PathProviderWindows extends PathProviderPlatform { Pointer? infoBuffer; try { // Get the module name. - final moduleNameLength = GetModuleFileName(0, moduleNameBuffer, MAX_PATH); + final int moduleNameLength = + GetModuleFileName(0, moduleNameBuffer, MAX_PATH); if (moduleNameLength == 0) { - final error = GetLastError(); + final int error = GetLastError(); throw WindowsException(error); } // From that, load the VERSIONINFO resource - int infoSize = GetFileVersionInfoSize(moduleNameBuffer, unused); + final int infoSize = GetFileVersionInfoSize(moduleNameBuffer, unused); if (infoSize != 0) { infoBuffer = calloc(infoSize); if (GetFileVersionInfo(moduleNameBuffer, 0, infoSize, infoBuffer) == @@ -182,10 +183,8 @@ class PathProviderWindows extends PathProviderPlatform { versionInfoQuerier.getStringValue(infoBuffer, 'ProductName')); // If there was no product name, use the executable name. - if (productName == null) { - productName = - path.basenameWithoutExtension(moduleNameBuffer.toDartString()); - } + productName ??= + path.basenameWithoutExtension(moduleNameBuffer.toDartString()); return companyName != null ? path.join(companyName, productName) @@ -214,7 +213,7 @@ class PathProviderWindows extends PathProviderPlatform { .trimRight() // Ensure that it does not end with a '.'. .replaceAll(RegExp(r'[.]+$'), ''); - const kMaxComponentLength = 255; + const int kMaxComponentLength = 255; if (sanitized.length > kMaxComponentLength) { sanitized = sanitized.substring(0, kMaxComponentLength); } diff --git a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart index 69094af9eafa..91334d95ae24 100644 --- a/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart +++ b/packages/path_provider/path_provider_windows/lib/src/path_provider_windows_stub.dart @@ -14,9 +14,7 @@ import 'package:path_provider_platform_interface/path_provider_platform_interfac class PathProviderWindows extends PathProviderPlatform { /// Errors on attempted instantiation of the stub. It exists only to satisfy /// compile-time dependencies, and should never actually be created. - PathProviderWindows() { - assert(false); - } + PathProviderWindows() : assert(false); /// Stub; see comment on VersionInfoQuerier. VersionInfoQuerier versionInfoQuerier = VersionInfoQuerier(); diff --git a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart index 22683d721e7c..a66c9e1ffb0d 100644 --- a/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart +++ b/packages/path_provider/path_provider_windows/test/path_provider_windows_test.dart @@ -13,20 +13,21 @@ class FakeVersionInfoQuerier implements VersionInfoQuerier { final Map responses; - getStringValue(Pointer? versionInfo, key) => responses[key]; + String? getStringValue(Pointer? versionInfo, String key) => + responses[key]; } void main() { test('getTemporaryPath', () async { - final pathProvider = PathProviderWindows(); + final PathProviderWindows pathProvider = PathProviderWindows(); expect(await pathProvider.getTemporaryPath(), contains(r'C:\')); }, skip: !Platform.isWindows); test('getApplicationSupportPath with no version info', () async { - final pathProvider = PathProviderWindows(); + final PathProviderWindows pathProvider = PathProviderWindows(); pathProvider.versionInfoQuerier = FakeVersionInfoQuerier({}); - final path = await pathProvider.getApplicationSupportPath(); + final String? path = await pathProvider.getApplicationSupportPath(); expect(path, contains(r'C:\')); expect(path, contains(r'AppData')); // The last path component should be the executable name. @@ -34,12 +35,12 @@ void main() { }, skip: !Platform.isWindows); test('getApplicationSupportPath with full version info', () async { - final pathProvider = PathProviderWindows(); + final PathProviderWindows pathProvider = PathProviderWindows(); pathProvider.versionInfoQuerier = FakeVersionInfoQuerier({ 'CompanyName': 'A Company', 'ProductName': 'Amazing App', }); - final path = await pathProvider.getApplicationSupportPath(); + final String? path = await pathProvider.getApplicationSupportPath(); expect(path, isNotNull); if (path != null) { expect(path, endsWith(r'AppData\Roaming\A Company\Amazing App')); @@ -48,11 +49,11 @@ void main() { }, skip: !Platform.isWindows); test('getApplicationSupportPath with missing company', () async { - final pathProvider = PathProviderWindows(); + final PathProviderWindows pathProvider = PathProviderWindows(); pathProvider.versionInfoQuerier = FakeVersionInfoQuerier({ 'ProductName': 'Amazing App', }); - final path = await pathProvider.getApplicationSupportPath(); + final String? path = await pathProvider.getApplicationSupportPath(); expect(path, isNotNull); if (path != null) { expect(path, endsWith(r'AppData\Roaming\Amazing App')); @@ -61,12 +62,12 @@ void main() { }, skip: !Platform.isWindows); test('getApplicationSupportPath with problematic values', () async { - final pathProvider = PathProviderWindows(); + final PathProviderWindows pathProvider = PathProviderWindows(); pathProvider.versionInfoQuerier = FakeVersionInfoQuerier({ 'CompanyName': r'A Company: Name.', 'ProductName': r'A"/Terrible\|App?*Name', }); - final path = await pathProvider.getApplicationSupportPath(); + final String? path = await pathProvider.getApplicationSupportPath(); expect(path, isNotNull); if (path != null) { expect( @@ -79,12 +80,12 @@ void main() { }, skip: !Platform.isWindows); test('getApplicationSupportPath with a completely invalid company', () async { - final pathProvider = PathProviderWindows(); + final PathProviderWindows pathProvider = PathProviderWindows(); pathProvider.versionInfoQuerier = FakeVersionInfoQuerier({ 'CompanyName': r'..', 'ProductName': r'Amazing App', }); - final path = await pathProvider.getApplicationSupportPath(); + final String? path = await pathProvider.getApplicationSupportPath(); expect(path, isNotNull); if (path != null) { expect(path, endsWith(r'AppData\Roaming\Amazing App')); @@ -93,28 +94,28 @@ void main() { }, skip: !Platform.isWindows); test('getApplicationSupportPath with very long app name', () async { - final pathProvider = PathProviderWindows(); - final truncatedName = 'A' * 255; + final PathProviderWindows pathProvider = PathProviderWindows(); + final String truncatedName = 'A' * 255; pathProvider.versionInfoQuerier = FakeVersionInfoQuerier({ 'CompanyName': 'A Company', 'ProductName': truncatedName * 2, }); - final path = await pathProvider.getApplicationSupportPath(); + final String? path = await pathProvider.getApplicationSupportPath(); expect(path, endsWith('\\$truncatedName')); // The directory won't exist, since it's longer than MAXPATH, so don't check // that here. }, skip: !Platform.isWindows); test('getApplicationDocumentsPath', () async { - final pathProvider = PathProviderWindows(); - final path = await pathProvider.getApplicationDocumentsPath(); + final PathProviderWindows pathProvider = PathProviderWindows(); + final String? path = await pathProvider.getApplicationDocumentsPath(); expect(path, contains(r'C:\')); expect(path, contains(r'Documents')); }, skip: !Platform.isWindows); test('getDownloadsPath', () async { - final pathProvider = PathProviderWindows(); - final path = await pathProvider.getDownloadsPath(); + final PathProviderWindows pathProvider = PathProviderWindows(); + final String? path = await pathProvider.getDownloadsPath(); expect(path, contains(r'C:\')); expect(path, contains(r'Downloads')); }, skip: !Platform.isWindows); diff --git a/script/incremental_build.sh b/script/incremental_build.sh index ade89afe4ca1..f0c4bc4ac35e 100755 --- a/script/incremental_build.sh +++ b/script/incremental_build.sh @@ -42,7 +42,6 @@ CUSTOM_ANALYSIS_PLUGINS=( ios_platform_images local_auth package_info - path_provider plugin_platform_interface quick_actions sensors From dc22884c113362fe8385fa4fe6365c55e6900a76 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Wed, 31 Mar 2021 13:50:39 -0700 Subject: [PATCH 379/924] [google_maps_flutter_web] Migrate to null-safety. (#3726) * Updates JS-interop package to google_maps ^5.1.0 * Breaking changes: * The property `icon` of a `Marker` cannot be `null`. Defaults to `BitmapDescriptor.defaultMarker` * The property `initialCameraPosition` of a `GoogleMapController` can't be `null`. It is also marked as `required`. * The parameter `creationId` of the `buildView` method cannot be `null` (this should be handled internally for users of the plugin) * Most of the Controller methods can't be called after `remove`/`dispose`. Calling these methods now will throw an Assertion error. Before it'd be a no-op, or a null-pointer exception. --- .../google_maps_flutter_web/CHANGELOG.md | 9 + .../google_maps_flutter_web/example/README.md | 10 + .../example/build.yaml | 6 + .../google_maps_controller_test.dart | 319 +++++++++++------- .../google_maps_controller_test.mocks.dart | 202 +++++++++++ .../google_maps_plugin_test.dart | 74 ++-- .../google_maps_plugin_test.mocks.dart | 106 ++++++ .../example/integration_test/marker_test.dart | 131 +++++-- .../integration_test/markers_test.dart | 81 +++-- .../example/integration_test/shape_test.dart | 177 +++++++--- .../example/integration_test/shapes_test.dart | 70 ++-- .../example/pubspec.yaml | 21 +- .../example/regen_mocks.sh | 10 + .../example/run_test.sh | 2 + .../example/web/index.html | 1 - .../lib/google_maps_flutter_web.dart | 1 + .../lib/src/circle.dart | 23 +- .../lib/src/circles.dart | 15 +- .../lib/src/convert.dart | 192 ++++------- .../lib/src/google_maps_controller.dart | 160 ++++++--- .../lib/src/google_maps_flutter_web.dart | 76 ++--- .../lib/src/marker.dart | 54 +-- .../lib/src/markers.dart | 27 +- .../lib/src/polygon.dart | 21 +- .../lib/src/polygons.dart | 12 +- .../lib/src/polyline.dart | 22 +- .../lib/src/polylines.dart | 16 +- .../lib/src/types.dart | 4 +- .../google_maps_flutter_web/pubspec.yaml | 6 +- script/build_all_plugins_app.sh | 2 +- 30 files changed, 1245 insertions(+), 605 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/example/build.yaml create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart create mode 100755 packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 29e9287a14fb..fd56b64dbe57 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,3 +1,12 @@ +## 0.3.0 + +* Migrate package to null-safety. +* **Breaking changes:** + * The property `icon` of a `Marker` cannot be `null`. Defaults to `BitmapDescriptor.defaultMarker` + * The property `initialCameraPosition` of a `GoogleMapController` can't be `null`. It is also marked as `required`. + * The parameter `creationId` of the `buildView` method cannot be `null` (this should be handled internally for users of the plugin) + * Most of the Controller methods can't be called after `remove`/`dispose`. Calling these methods now will throw an Assertion error. Before it'd be a no-op, or a null-pointer exception. + ## 0.2.1 * Move integration tests to `example`. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/README.md b/packages/google_maps_flutter/google_maps_flutter_web/example/README.md index 0ec01e025570..582288a561a4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/README.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/README.md @@ -19,3 +19,13 @@ Make sure you have updated to the latest Flutter master. * Single: `./run_test.sh integration_test/TEST_NAME.dart` * All: `./run_test.sh` + +## Mocks + +There's new `.mocks.dart` files next to the test files that use them. + +Mock files are [generated by `package:mockito`](https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md#code-generation). The contents of these files can change with how the mocks are used within the tests, in addition to actual changes in the APIs they're mocking. + +Mock files can be updated either manually by running the following command: `flutter pub run build_runner build` (or the `regen_mocks.sh` script), or automatically on each call to the `run_test.sh` script. + +Please, add whatever changes show up in mock files to your PRs, or CI will fail. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/build.yaml b/packages/google_maps_flutter/google_maps_flutter_web/example/build.yaml new file mode 100644 index 000000000000..db3104bb04c6 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/build.yaml @@ -0,0 +1,6 @@ +targets: + $default: + sources: + - integration_test/*.dart + - lib/$lib$ + - $package$ diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart index fd4df2ee4fd8..1d33eea4c7f3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart @@ -2,43 +2,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; +import 'dart:html' as html; -import 'package:integration_test/integration_test.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps/google_maps.dart' as gmaps; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; - -class _MockCirclesController extends Mock implements CirclesController {} - -class _MockPolygonsController extends Mock implements PolygonsController {} - -class _MockPolylinesController extends Mock implements PolylinesController {} - -class _MockMarkersController extends Mock implements MarkersController {} - -class _MockGMap extends Mock implements gmaps.GMap { - final onClickController = StreamController.broadcast(); - @override - Stream get onClick => onClickController.stream; +import 'google_maps_controller_test.mocks.dart'; - final onRightclickController = StreamController.broadcast(); - @override - Stream get onRightclick => onRightclickController.stream; +// This value is used when comparing long~num, like +// LatLng values. +const _acceptableDelta = 0.0000000001; - final onBoundsChangedController = StreamController.broadcast(); - @override - Stream get onBoundsChanged => onBoundsChangedController.stream; - - final onIdleController = StreamController.broadcast(); - @override - Stream get onIdle => onIdleController.stream; -} +@GenerateMocks([], customMocks: [ + MockSpec(returnNullOnMissingStub: true), + MockSpec(returnNullOnMissingStub: true), + MockSpec(returnNullOnMissingStub: true), + MockSpec(returnNullOnMissingStub: true), +]) /// Test Google Map Controller void main() { @@ -46,8 +33,8 @@ void main() { group('GoogleMapController', () { final int mapId = 33930; - GoogleMapController controller; - StreamController stream; + late GoogleMapController controller; + late StreamController stream; // Creates a controller with the default mapId and stream controller, and any `options` needed. GoogleMapController _createController({ @@ -57,17 +44,18 @@ void main() { Set polygons = const {}, Set polylines = const {}, Set circles = const {}, - Map options, + Map options = const {}, }) { return GoogleMapController( - mapId: mapId, - streamController: stream, - initialCameraPosition: initialCameraPosition, - markers: markers, - polygons: polygons, - polylines: polylines, - circles: circles, - mapOptions: options ?? {}); + mapId: mapId, + streamController: stream, + initialCameraPosition: initialCameraPosition, + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + mapOptions: options, + ); } setUp(() { @@ -81,7 +69,9 @@ void main() { testWidgets('constructor creates widget', (WidgetTester tester) async { expect(controller.widget, isNotNull); - expect(controller.widget.viewType, endsWith('$mapId')); + expect(controller.widget, isA()); + expect((controller.widget as HtmlElementView).viewType, + endsWith('$mapId')); }); testWidgets('widget is cached when reused', (WidgetTester tester) async { @@ -90,27 +80,130 @@ void main() { expect(identical(first, again), isTrue); }); - testWidgets('dispose closes the stream and removes the widget', - (WidgetTester tester) async { - controller.dispose(); - expect(stream.isClosed, isTrue); - expect(controller.widget, isNull); + group('dispose', () { + testWidgets('closes the stream and removes the widget', + (WidgetTester tester) async { + controller.dispose(); + + expect(stream.isClosed, isTrue); + expect(controller.widget, isNull); + }); + + testWidgets('cannot call getVisibleRegion after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() async { + await controller.getVisibleRegion(); + }, throwsAssertionError); + }); + + testWidgets('cannot call getScreenCoordinate after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() async { + await controller.getScreenCoordinate( + LatLng(43.3072465, -5.6918241), + ); + }, throwsAssertionError); + }); + + testWidgets('cannot call getLatLng after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() async { + await controller.getLatLng( + ScreenCoordinate(x: 640, y: 480), + ); + }, throwsAssertionError); + }); + + testWidgets('cannot call moveCamera after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() async { + await controller.moveCamera(CameraUpdate.zoomIn()); + }, throwsAssertionError); + }); + + testWidgets('cannot call getZoomLevel after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() async { + await controller.getZoomLevel(); + }, throwsAssertionError); + }); + + testWidgets('cannot updateCircles after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() { + controller.updateCircles(CircleUpdates.from({}, {})); + }, throwsAssertionError); + }); + + testWidgets('cannot updatePolygons after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() { + controller.updatePolygons(PolygonUpdates.from({}, {})); + }, throwsAssertionError); + }); + + testWidgets('cannot updatePolylines after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() { + controller.updatePolylines(PolylineUpdates.from({}, {})); + }, throwsAssertionError); + }); + + testWidgets('cannot updateMarkers after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() { + controller.updateMarkers(MarkerUpdates.from({}, {})); + }, throwsAssertionError); + + expect(() { + controller.showInfoWindow(MarkerId('any')); + }, throwsAssertionError); + + expect(() { + controller.hideInfoWindow(MarkerId('any')); + }, throwsAssertionError); + }); + + testWidgets('isInfoWindowShown defaults to false', + (WidgetTester tester) async { + controller.dispose(); + + expect(controller.isInfoWindowShown(MarkerId('any')), false); + }); }); }); group('init', () { - _MockCirclesController circles; - _MockMarkersController markers; - _MockPolygonsController polygons; - _MockPolylinesController polylines; - _MockGMap map; + late MockCirclesController circles; + late MockMarkersController markers; + late MockPolygonsController polygons; + late MockPolylinesController polylines; + late gmaps.GMap map; setUp(() { - circles = _MockCirclesController(); - markers = _MockMarkersController(); - polygons = _MockPolygonsController(); - polylines = _MockPolylinesController(); - map = _MockGMap(); + circles = MockCirclesController(); + markers = MockMarkersController(); + polygons = MockPolygonsController(); + polylines = MockPolylinesController(); + map = gmaps.GMap(html.DivElement()); }); testWidgets('listens to map events', (WidgetTester tester) async { @@ -123,17 +216,25 @@ void main() { polylines: polylines, ); - expect(map.onClickController.hasListener, isFalse); - expect(map.onRightclickController.hasListener, isFalse); - expect(map.onBoundsChangedController.hasListener, isFalse); - expect(map.onIdleController.hasListener, isFalse); - controller.init(); - expect(map.onClickController.hasListener, isTrue); - expect(map.onRightclickController.hasListener, isTrue); - expect(map.onBoundsChangedController.hasListener, isTrue); - expect(map.onIdleController.hasListener, isTrue); + // Trigger events on the map, and verify they've been broadcast to the stream + final capturedEvents = stream.stream.take(5); + + gmaps.Event.trigger( + map, 'click', [gmaps.MapMouseEvent()..latLng = gmaps.LatLng(0, 0)]); + gmaps.Event.trigger(map, 'rightclick', + [gmaps.MapMouseEvent()..latLng = gmaps.LatLng(0, 0)]); + gmaps.Event.trigger(map, 'bounds_changed', []); // Causes 2 events + gmaps.Event.trigger(map, 'idle', []); + + final events = await capturedEvents.toList(); + + expect(events[0], isA()); + expect(events[1], isA()); + expect(events[2], isA()); + expect(events[3], isA()); + expect(events[4], isA()); }); testWidgets('binds geometry controllers to map\'s', @@ -227,7 +328,7 @@ void main() { testWidgets('empty infoWindow does not create InfoWindow instance.', (WidgetTester tester) async { controller = _createController(markers: { - Marker(markerId: MarkerId('marker-1'), infoWindow: null), + Marker(markerId: MarkerId('marker-1')), }); controller.debugSetOverrides( @@ -239,11 +340,11 @@ void main() { final capturedMarkers = verify(markers.addMarkers(captureAny)).captured[0] as Set; - expect(capturedMarkers.first.infoWindow, isNull); + expect(capturedMarkers.first.infoWindow, InfoWindow.noText); }); group('Initialization options', () { - gmaps.MapOptions capturedOptions; + gmaps.MapOptions? capturedOptions; setUp(() { capturedOptions = null; }); @@ -260,9 +361,9 @@ void main() { controller.init(); expect(capturedOptions, isNotNull); - expect(capturedOptions.mapTypeId, gmaps.MapTypeId.SATELLITE); - expect(capturedOptions.zoomControl, true); - expect(capturedOptions.gestureHandling, 'auto', + expect(capturedOptions!.mapTypeId, gmaps.MapTypeId.SATELLITE); + expect(capturedOptions!.zoomControl, true); + expect(capturedOptions!.gestureHandling, 'auto', reason: 'by default the map handles zoom/pan gestures internally'); }); @@ -280,7 +381,7 @@ void main() { controller.init(); expect(capturedOptions, isNotNull); - expect(capturedOptions.gestureHandling, 'none', + expect(capturedOptions!.gestureHandling, 'none', reason: 'disabling scroll gestures disables all gesture handling'); }); @@ -298,29 +399,11 @@ void main() { controller.init(); expect(capturedOptions, isNotNull); - expect(capturedOptions.gestureHandling, 'none', + expect(capturedOptions!.gestureHandling, 'none', reason: 'disabling scroll gestures disables all gesture handling'); }); - testWidgets('does not set initial position if absent', - (WidgetTester tester) async { - controller = _createController( - initialCameraPosition: null, - ); - - controller.debugSetOverrides(createMap: (_, options) { - capturedOptions = options; - return map; - }); - - controller.init(); - - expect(capturedOptions, isNotNull); - expect(capturedOptions.zoom, isNull); - expect(capturedOptions.center, isNull); - }); - testWidgets('sets initial position when passed', (WidgetTester tester) async { controller = _createController( @@ -340,8 +423,8 @@ void main() { controller.init(); expect(capturedOptions, isNotNull); - expect(capturedOptions.zoom, 12); - expect(capturedOptions.center, isNotNull); + expect(capturedOptions!.zoom, 12); + expect(capturedOptions!.center, isNotNull); }); }); @@ -366,10 +449,15 @@ void main() { // These are the methods that are delegated to the gmaps.GMap object, that we can mock... group('Map control methods', () { - _MockGMap map; + late gmaps.GMap map; setUp(() { - map = _MockGMap(); + map = gmaps.GMap( + html.DivElement(), + gmaps.MapOptions() + ..zoom = 10 + ..center = gmaps.LatLng(0, 0), + ); controller = _createController(); controller.debugSetOverrides(createMap: (_, __) => map); controller.init(); @@ -380,9 +468,8 @@ void main() { controller.updateRawOptions({ 'mapType': 2, }); - final options = verify(map.options = captureAny).captured[0]; - expect(options.mapTypeId, gmaps.MapTypeId.SATELLITE); + expect(map.mapTypeId, gmaps.MapTypeId.SATELLITE); }); testWidgets('can turn on/off traffic', (WidgetTester tester) async { @@ -404,17 +491,19 @@ void main() { group('viewport getters', () { testWidgets('getVisibleRegion', (WidgetTester tester) async { - await controller.getVisibleRegion(); + final gmCenter = map.center!; + final center = + LatLng(gmCenter.lat.toDouble(), gmCenter.lng.toDouble()); + + final bounds = await controller.getVisibleRegion(); - verify(map.bounds); + expect(bounds.contains(center), isTrue, + reason: + 'The computed visible region must contain the center of the created map.'); }); testWidgets('getZoomLevel', (WidgetTester tester) async { - when(map.zoom).thenReturn(10); - - await controller.getZoomLevel(); - - verify(map.zoom); + expect(await controller.getZoomLevel(), map.zoom); }); }); @@ -423,10 +512,11 @@ void main() { await (controller .moveCamera(CameraUpdate.newLatLngZoom(LatLng(19, 26), 12))); - verify(map.zoom = 12); - final captured = verify(map.panTo(captureAny)).captured[0]; - expect(captured.lat, 19); - expect(captured.lng, 26); + final gmCenter = map.center!; + + expect(map.zoom, 12); + expect(gmCenter.lat, closeTo(19, _acceptableDelta)); + expect(gmCenter.lng, closeTo(26, _acceptableDelta)); }); }); @@ -445,7 +535,7 @@ void main() { }); testWidgets('updateCircles', (WidgetTester tester) async { - final mock = _MockCirclesController(); + final mock = MockCirclesController(); controller.debugSetOverrides(circles: mock); final previous = { @@ -472,7 +562,7 @@ void main() { }); testWidgets('updateMarkers', (WidgetTester tester) async { - final mock = _MockMarkersController(); + final mock = MockMarkersController(); controller.debugSetOverrides(markers: mock); final previous = { @@ -499,7 +589,7 @@ void main() { }); testWidgets('updatePolygons', (WidgetTester tester) async { - final mock = _MockPolygonsController(); + final mock = MockPolygonsController(); controller.debugSetOverrides(polygons: mock); final previous = { @@ -526,7 +616,7 @@ void main() { }); testWidgets('updatePolylines', (WidgetTester tester) async { - final mock = _MockPolylinesController(); + final mock = MockPolylinesController(); controller.debugSetOverrides(polylines: mock); final previous = { @@ -553,9 +643,10 @@ void main() { }); testWidgets('infoWindow visibility', (WidgetTester tester) async { - final mock = _MockMarkersController(); - controller.debugSetOverrides(markers: mock); + final mock = MockMarkersController(); final markerId = MarkerId('marker-with-infowindow'); + when(mock.isInfoWindowShown(markerId)).thenReturn(true); + controller.debugSetOverrides(markers: mock); controller.showInfoWindow(markerId); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart new file mode 100644 index 000000000000..47933285b208 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart @@ -0,0 +1,202 @@ +// Copyright 2013 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. + +// Mocks generated by Mockito 5.0.2 from annotations +// in google_maps_flutter_web_integration_tests/integration_test/google_maps_controller_test.dart. +// Do not manually edit this file. + +import 'package:google_maps/src/generated/google_maps_core.js.g.dart' as _i2; +import 'package:google_maps_flutter_platform_interface/src/types/circle.dart' + as _i4; +import 'package:google_maps_flutter_platform_interface/src/types/marker.dart' + as _i7; +import 'package:google_maps_flutter_platform_interface/src/types/polygon.dart' + as _i5; +import 'package:google_maps_flutter_platform_interface/src/types/polyline.dart' + as _i6; +import 'package:google_maps_flutter_web/google_maps_flutter_web.dart' as _i3; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: comment_references +// ignore_for_file: unnecessary_parenthesis + +class _FakeGMap extends _i1.Fake implements _i2.GMap {} + +/// A class which mocks [CirclesController]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockCirclesController extends _i1.Mock implements _i3.CirclesController { + @override + Map<_i4.CircleId, _i3.CircleController> get circles => + (super.noSuchMethod(Invocation.getter(#circles), + returnValue: <_i4.CircleId, _i3.CircleController>{}) + as Map<_i4.CircleId, _i3.CircleController>); + @override + _i2.GMap get googleMap => (super.noSuchMethod(Invocation.getter(#googleMap), + returnValue: _FakeGMap()) as _i2.GMap); + @override + set googleMap(_i2.GMap? _googleMap) => + super.noSuchMethod(Invocation.setter(#googleMap, _googleMap), + returnValueForMissingStub: null); + @override + int get mapId => + (super.noSuchMethod(Invocation.getter(#mapId), returnValue: 0) as int); + @override + set mapId(int? _mapId) => + super.noSuchMethod(Invocation.setter(#mapId, _mapId), + returnValueForMissingStub: null); + @override + void addCircles(Set<_i4.Circle>? circlesToAdd) => + super.noSuchMethod(Invocation.method(#addCircles, [circlesToAdd]), + returnValueForMissingStub: null); + @override + void changeCircles(Set<_i4.Circle>? circlesToChange) => + super.noSuchMethod(Invocation.method(#changeCircles, [circlesToChange]), + returnValueForMissingStub: null); + @override + void removeCircles(Set<_i4.CircleId>? circleIdsToRemove) => + super.noSuchMethod(Invocation.method(#removeCircles, [circleIdsToRemove]), + returnValueForMissingStub: null); + @override + void bindToMap(int? mapId, _i2.GMap? googleMap) => + super.noSuchMethod(Invocation.method(#bindToMap, [mapId, googleMap]), + returnValueForMissingStub: null); +} + +/// A class which mocks [PolygonsController]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockPolygonsController extends _i1.Mock + implements _i3.PolygonsController { + @override + Map<_i5.PolygonId, _i3.PolygonController> get polygons => + (super.noSuchMethod(Invocation.getter(#polygons), + returnValue: <_i5.PolygonId, _i3.PolygonController>{}) + as Map<_i5.PolygonId, _i3.PolygonController>); + @override + _i2.GMap get googleMap => (super.noSuchMethod(Invocation.getter(#googleMap), + returnValue: _FakeGMap()) as _i2.GMap); + @override + set googleMap(_i2.GMap? _googleMap) => + super.noSuchMethod(Invocation.setter(#googleMap, _googleMap), + returnValueForMissingStub: null); + @override + int get mapId => + (super.noSuchMethod(Invocation.getter(#mapId), returnValue: 0) as int); + @override + set mapId(int? _mapId) => + super.noSuchMethod(Invocation.setter(#mapId, _mapId), + returnValueForMissingStub: null); + @override + void addPolygons(Set<_i5.Polygon>? polygonsToAdd) => + super.noSuchMethod(Invocation.method(#addPolygons, [polygonsToAdd]), + returnValueForMissingStub: null); + @override + void changePolygons(Set<_i5.Polygon>? polygonsToChange) => + super.noSuchMethod(Invocation.method(#changePolygons, [polygonsToChange]), + returnValueForMissingStub: null); + @override + void removePolygons(Set<_i5.PolygonId>? polygonIdsToRemove) => super + .noSuchMethod(Invocation.method(#removePolygons, [polygonIdsToRemove]), + returnValueForMissingStub: null); + @override + void bindToMap(int? mapId, _i2.GMap? googleMap) => + super.noSuchMethod(Invocation.method(#bindToMap, [mapId, googleMap]), + returnValueForMissingStub: null); +} + +/// A class which mocks [PolylinesController]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockPolylinesController extends _i1.Mock + implements _i3.PolylinesController { + @override + Map<_i6.PolylineId, _i3.PolylineController> get lines => + (super.noSuchMethod(Invocation.getter(#lines), + returnValue: <_i6.PolylineId, _i3.PolylineController>{}) + as Map<_i6.PolylineId, _i3.PolylineController>); + @override + _i2.GMap get googleMap => (super.noSuchMethod(Invocation.getter(#googleMap), + returnValue: _FakeGMap()) as _i2.GMap); + @override + set googleMap(_i2.GMap? _googleMap) => + super.noSuchMethod(Invocation.setter(#googleMap, _googleMap), + returnValueForMissingStub: null); + @override + int get mapId => + (super.noSuchMethod(Invocation.getter(#mapId), returnValue: 0) as int); + @override + set mapId(int? _mapId) => + super.noSuchMethod(Invocation.setter(#mapId, _mapId), + returnValueForMissingStub: null); + @override + void addPolylines(Set<_i6.Polyline>? polylinesToAdd) => + super.noSuchMethod(Invocation.method(#addPolylines, [polylinesToAdd]), + returnValueForMissingStub: null); + @override + void changePolylines(Set<_i6.Polyline>? polylinesToChange) => super + .noSuchMethod(Invocation.method(#changePolylines, [polylinesToChange]), + returnValueForMissingStub: null); + @override + void removePolylines(Set<_i6.PolylineId>? polylineIdsToRemove) => super + .noSuchMethod(Invocation.method(#removePolylines, [polylineIdsToRemove]), + returnValueForMissingStub: null); + @override + void bindToMap(int? mapId, _i2.GMap? googleMap) => + super.noSuchMethod(Invocation.method(#bindToMap, [mapId, googleMap]), + returnValueForMissingStub: null); +} + +/// A class which mocks [MarkersController]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMarkersController extends _i1.Mock implements _i3.MarkersController { + @override + Map<_i7.MarkerId, _i3.MarkerController> get markers => + (super.noSuchMethod(Invocation.getter(#markers), + returnValue: <_i7.MarkerId, _i3.MarkerController>{}) + as Map<_i7.MarkerId, _i3.MarkerController>); + @override + _i2.GMap get googleMap => (super.noSuchMethod(Invocation.getter(#googleMap), + returnValue: _FakeGMap()) as _i2.GMap); + @override + set googleMap(_i2.GMap? _googleMap) => + super.noSuchMethod(Invocation.setter(#googleMap, _googleMap), + returnValueForMissingStub: null); + @override + int get mapId => + (super.noSuchMethod(Invocation.getter(#mapId), returnValue: 0) as int); + @override + set mapId(int? _mapId) => + super.noSuchMethod(Invocation.setter(#mapId, _mapId), + returnValueForMissingStub: null); + @override + void addMarkers(Set<_i7.Marker>? markersToAdd) => + super.noSuchMethod(Invocation.method(#addMarkers, [markersToAdd]), + returnValueForMissingStub: null); + @override + void changeMarkers(Set<_i7.Marker>? markersToChange) => + super.noSuchMethod(Invocation.method(#changeMarkers, [markersToChange]), + returnValueForMissingStub: null); + @override + void removeMarkers(Set<_i7.MarkerId>? markerIdsToRemove) => + super.noSuchMethod(Invocation.method(#removeMarkers, [markerIdsToRemove]), + returnValueForMissingStub: null); + @override + void showMarkerInfoWindow(_i7.MarkerId? markerId) => + super.noSuchMethod(Invocation.method(#showMarkerInfoWindow, [markerId]), + returnValueForMissingStub: null); + @override + void hideMarkerInfoWindow(_i7.MarkerId? markerId) => + super.noSuchMethod(Invocation.method(#hideMarkerInfoWindow, [markerId]), + returnValueForMissingStub: null); + @override + bool isInfoWindowShown(_i7.MarkerId? markerId) => + (super.noSuchMethod(Invocation.method(#isInfoWindowShown, [markerId]), + returnValue: false) as bool); + @override + void bindToMap(int? mapId, _i2.GMap? googleMap) => + super.noSuchMethod(Invocation.method(#bindToMap, [mapId, googleMap]), + returnValueForMissingStub: null); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart index dee37618c940..2de431a5445e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart @@ -2,36 +2,40 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; +import 'dart:js_util' show getProperty; import 'package:integration_test/integration_test.dart'; import 'package:flutter/widgets.dart'; import 'package:google_maps/google_maps.dart' as gmaps; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; -class _MockGoogleMapController extends Mock implements GoogleMapController {} +import 'google_maps_plugin_test.mocks.dart'; + +@GenerateMocks([], customMocks: [ + MockSpec(returnNullOnMissingStub: true), +]) /// Test GoogleMapsPlugin void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('GoogleMapsPlugin', () { - _MockGoogleMapController controller; - GoogleMapsPlugin plugin; - int reportedMapId; + late MockGoogleMapController controller; + late GoogleMapsPlugin plugin; + int? reportedMapId; void onPlatformViewCreated(int id) { reportedMapId = id; } setUp(() { - controller = _MockGoogleMapController(); + controller = MockGoogleMapController(); plugin = GoogleMapsPlugin(); reportedMapId = null; }); @@ -72,34 +76,21 @@ void main() { final testMapId = 33930; final initialCameraPosition = CameraPosition(target: LatLng(0, 0)); - testWidgets('throws without _webOnlyMapCreationId', - (WidgetTester tester) async { - expect( - () => plugin.buildView( - null, - onPlatformViewCreated, - initialCameraPosition: initialCameraPosition, - ), - throwsAssertionError, - reason: - '_webOnlyMapCreationId is mandatory to prevent unnecessary reloads in web.', - ); - }); - testWidgets( 'returns an HtmlElementView and caches the controller for later', (WidgetTester tester) async { final Map cache = {}; plugin.debugSetMapById(cache); - final HtmlElementView widget = plugin.buildView( + final Widget widget = plugin.buildView( testMapId, onPlatformViewCreated, initialCameraPosition: initialCameraPosition, ); + expect(widget, isA()); expect( - widget.viewType, + (widget as HtmlElementView).viewType, contains('$testMapId'), reason: 'view type should contain the mapId passed when creating the map.', @@ -160,11 +151,10 @@ void main() { expect(styles.length, 1); // Let's peek inside the styles... var style = styles[0] as gmaps.MapTypeStyle; - expect(style.featureType, gmaps.MapTypeStyleFeatureType.POI_PARK); - expect( - style.elementType, gmaps.MapTypeStyleElementType.LABELS_TEXT_FILL); - expect(style.stylers.length, 1); - expect(style.stylers[0].color, '#6b9a76'); + expect(style.featureType, 'poi.park'); + expect(style.elementType, 'labels.text.fill'); + expect(style.stylers?.length, 1); + expect(getProperty(style.stylers![0]!, 'color'), '#6b9a76'); }); }); @@ -247,31 +237,50 @@ void main() { verify(controller.moveCamera(expectedUpdates)); }); + // Viewport testWidgets('getVisibleRegion', (WidgetTester tester) async { + when(controller.getVisibleRegion()) + .thenAnswer((_) async => LatLngBounds( + northeast: LatLng(47.2359634, -68.0192019), + southwest: LatLng(34.5019594, -120.4974629), + )); await plugin.getVisibleRegion(mapId: mapId); verify(controller.getVisibleRegion()); }); + testWidgets('getZoomLevel', (WidgetTester tester) async { + when(controller.getZoomLevel()).thenAnswer((_) async => 10); await plugin.getZoomLevel(mapId: mapId); verify(controller.getZoomLevel()); }); + testWidgets('getScreenCoordinate', (WidgetTester tester) async { + when(controller.getScreenCoordinate(any)).thenAnswer( + (_) async => ScreenCoordinate(x: 320, y: 240) // fake return + ); + final latLng = LatLng(43.3613, -5.8499); await plugin.getScreenCoordinate(latLng, mapId: mapId); verify(controller.getScreenCoordinate(latLng)); }); + testWidgets('getLatLng', (WidgetTester tester) async { + when(controller.getLatLng(any)) + .thenAnswer((_) async => LatLng(43.3613, -5.8499) // fake return + ); + final coordinates = ScreenCoordinate(x: 19, y: 26); await plugin.getLatLng(coordinates, mapId: mapId); verify(controller.getLatLng(coordinates)); }); + // InfoWindows testWidgets('showMarkerInfoWindow', (WidgetTester tester) async { final markerId = MarkerId('testing-123'); @@ -280,6 +289,7 @@ void main() { verify(controller.showInfoWindow(markerId)); }); + testWidgets('hideMarkerInfoWindow', (WidgetTester tester) async { final markerId = MarkerId('testing-123'); @@ -287,7 +297,10 @@ void main() { verify(controller.hideInfoWindow(markerId)); }); + testWidgets('isMarkerInfoWindowShown', (WidgetTester tester) async { + when(controller.isInfoWindowShown(any)).thenReturn(true); + final markerId = MarkerId('testing-123'); await plugin.isMarkerInfoWindowShown(markerId, mapId: mapId); @@ -299,7 +312,7 @@ void main() { // Verify all event streams are filtered correctly from the main one... group('Event Streams', () { int mapId = 0; - StreamController streamController; + late StreamController streamController; setUp(() { streamController = StreamController.broadcast(); when(controller.events) @@ -308,7 +321,8 @@ void main() { }); // Dispatches a few events in the global streamController, and expects *only* the passed event to be there. - void _testStreamFiltering(Stream stream, MapEvent event) async { + Future _testStreamFiltering( + Stream stream, MapEvent event) async { Timer.run(() { streamController.add(_OtherMapEvent(mapId)); streamController.add(event); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart new file mode 100644 index 000000000000..43150f63ef93 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart @@ -0,0 +1,106 @@ +// Copyright 2013 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. + +// Mocks generated by Mockito 5.0.2 from annotations +// in google_maps_flutter_web_integration_tests/integration_test/google_maps_plugin_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i5; + +import 'package:google_maps_flutter_platform_interface/src/events/map_event.dart' + as _i6; +import 'package:google_maps_flutter_platform_interface/src/types/camera.dart' + as _i7; +import 'package:google_maps_flutter_platform_interface/src/types/circle_updates.dart' + as _i8; +import 'package:google_maps_flutter_platform_interface/src/types/location.dart' + as _i2; +import 'package:google_maps_flutter_platform_interface/src/types/marker.dart' + as _i12; +import 'package:google_maps_flutter_platform_interface/src/types/marker_updates.dart' + as _i11; +import 'package:google_maps_flutter_platform_interface/src/types/polygon_updates.dart' + as _i9; +import 'package:google_maps_flutter_platform_interface/src/types/polyline_updates.dart' + as _i10; +import 'package:google_maps_flutter_platform_interface/src/types/screen_coordinate.dart' + as _i3; +import 'package:google_maps_flutter_web/google_maps_flutter_web.dart' as _i4; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: comment_references +// ignore_for_file: unnecessary_parenthesis + +class _FakeLatLngBounds extends _i1.Fake implements _i2.LatLngBounds {} + +class _FakeScreenCoordinate extends _i1.Fake implements _i3.ScreenCoordinate {} + +class _FakeLatLng extends _i1.Fake implements _i2.LatLng {} + +/// A class which mocks [GoogleMapController]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockGoogleMapController extends _i1.Mock + implements _i4.GoogleMapController { + @override + _i5.Stream<_i6.MapEvent> get events => + (super.noSuchMethod(Invocation.getter(#events), + returnValue: Stream<_i6.MapEvent>.empty()) + as _i5.Stream<_i6.MapEvent>); + @override + void updateRawOptions(Map? optionsUpdate) => + super.noSuchMethod(Invocation.method(#updateRawOptions, [optionsUpdate]), + returnValueForMissingStub: null); + @override + _i5.Future<_i2.LatLngBounds> getVisibleRegion() => + (super.noSuchMethod(Invocation.method(#getVisibleRegion, []), + returnValue: Future.value(_FakeLatLngBounds())) + as _i5.Future<_i2.LatLngBounds>); + @override + _i5.Future<_i3.ScreenCoordinate> getScreenCoordinate(_i2.LatLng? latLng) => + (super.noSuchMethod(Invocation.method(#getScreenCoordinate, [latLng]), + returnValue: Future.value(_FakeScreenCoordinate())) + as _i5.Future<_i3.ScreenCoordinate>); + @override + _i5.Future<_i2.LatLng> getLatLng(_i3.ScreenCoordinate? screenCoordinate) => + (super.noSuchMethod(Invocation.method(#getLatLng, [screenCoordinate]), + returnValue: Future.value(_FakeLatLng())) as _i5.Future<_i2.LatLng>); + @override + _i5.Future moveCamera(_i7.CameraUpdate? cameraUpdate) => + (super.noSuchMethod(Invocation.method(#moveCamera, [cameraUpdate]), + returnValue: Future.value(null), + returnValueForMissingStub: Future.value()) as _i5.Future); + @override + _i5.Future getZoomLevel() => + (super.noSuchMethod(Invocation.method(#getZoomLevel, []), + returnValue: Future.value(0.0)) as _i5.Future); + @override + void updateCircles(_i8.CircleUpdates? updates) => + super.noSuchMethod(Invocation.method(#updateCircles, [updates]), + returnValueForMissingStub: null); + @override + void updatePolygons(_i9.PolygonUpdates? updates) => + super.noSuchMethod(Invocation.method(#updatePolygons, [updates]), + returnValueForMissingStub: null); + @override + void updatePolylines(_i10.PolylineUpdates? updates) => + super.noSuchMethod(Invocation.method(#updatePolylines, [updates]), + returnValueForMissingStub: null); + @override + void updateMarkers(_i11.MarkerUpdates? updates) => + super.noSuchMethod(Invocation.method(#updateMarkers, [updates]), + returnValueForMissingStub: null); + @override + void showInfoWindow(_i12.MarkerId? markerId) => + super.noSuchMethod(Invocation.method(#showInfoWindow, [markerId]), + returnValueForMissingStub: null); + @override + void hideInfoWindow(_i12.MarkerId? markerId) => + super.noSuchMethod(Invocation.method(#hideInfoWindow, [markerId]), + returnValueForMissingStub: null); + @override + bool isInfoWindowShown(_i12.MarkerId? markerId) => + (super.noSuchMethod(Invocation.method(#isInfoWindowShown, [markerId]), + returnValue: false) as bool); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart index 1a85f3bb28e1..2bfa27b73a77 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart @@ -2,100 +2,157 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; +import 'dart:html' as html; import 'package:integration_test/integration_test.dart'; import 'package:google_maps/google_maps.dart' as gmaps; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; - -class _MockMarker extends Mock implements gmaps.Marker { - final onClickController = StreamController(); - final onDragEndController = StreamController(); - - @override - Stream get onClick => onClickController.stream; - - @override - Stream get onDragend => onDragEndController.stream; -} - -class _MockMouseEvent extends Mock implements gmaps.MouseEvent {} - -class _MockInfoWindow extends Mock implements gmaps.InfoWindow {} /// Test Markers void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - bool called = false; + // Since onTap/DragEnd events happen asynchronously, we need to store when the event + // is fired. We use a completer so the test can wait for the future to be completed. + late Completer _methodCalledCompleter; + + /// This is the future value of the [_methodCalledCompleter]. Reinitialized + /// in the [setUp] method, and completed (as `true`) by [onTap] and [onDragEnd] + /// when those methods are called from the MarkerController. + late Future methodCalled; + void onTap() { - called = true; + _methodCalledCompleter.complete(true); } void onDragEnd(gmaps.LatLng _) { - called = true; + _methodCalledCompleter.complete(true); } setUp(() { - called = false; + _methodCalledCompleter = Completer(); + methodCalled = _methodCalledCompleter.future; }); group('MarkerController', () { - _MockMarker marker; + late gmaps.Marker marker; setUp(() { - marker = _MockMarker(); + marker = gmaps.Marker(); }); testWidgets('onTap gets called', (WidgetTester tester) async { MarkerController(marker: marker, onTap: onTap); - // Simulate a click - await marker.onClickController.add(null); - expect(called, isTrue); + + // Trigger a click event... + gmaps.Event.trigger(marker, 'click', [gmaps.MapMouseEvent()]); + + // The event handling is now truly async. Wait for it... + expect(await methodCalled, isTrue); }); testWidgets('onDragEnd gets called', (WidgetTester tester) async { - when(marker.draggable).thenReturn(true); MarkerController(marker: marker, onDragEnd: onDragEnd); - // Simulate a drag end - await marker.onDragEndController.add(_MockMouseEvent()); - expect(called, isTrue); + + // Trigger a drag end event... + gmaps.Event.trigger(marker, 'dragend', + [gmaps.MapMouseEvent()..latLng = gmaps.LatLng(0, 0)]); + + expect(await methodCalled, isTrue); }); testWidgets('update', (WidgetTester tester) async { final controller = MarkerController(marker: marker); - final options = gmaps.MarkerOptions()..draggable = false; + final options = gmaps.MarkerOptions()..draggable = true; + + expect(marker.draggable, isNull); + controller.update(options); - verify(marker.options = options); + + expect(marker.draggable, isTrue); }); testWidgets('infoWindow null, showInfoWindow.', (WidgetTester tester) async { final controller = MarkerController(marker: marker); + controller.showInfoWindow(); + expect(controller.infoWindowShown, isFalse); }); testWidgets('showInfoWindow', (WidgetTester tester) async { - final infoWindow = _MockInfoWindow(); + final infoWindow = gmaps.InfoWindow(); + final map = gmaps.GMap(html.DivElement()); + marker.set('map', map); final controller = MarkerController(marker: marker, infoWindow: infoWindow); + controller.showInfoWindow(); - verify(infoWindow.open(any, any)).called(1); + + expect(infoWindow.get('map'), map); expect(controller.infoWindowShown, isTrue); }); testWidgets('hideInfoWindow', (WidgetTester tester) async { - final infoWindow = _MockInfoWindow(); + final infoWindow = gmaps.InfoWindow(); + final map = gmaps.GMap(html.DivElement()); + marker.set('map', map); final controller = MarkerController(marker: marker, infoWindow: infoWindow); + controller.hideInfoWindow(); - verify(infoWindow.close()).called(1); + + expect(infoWindow.get('map'), isNull); expect(controller.infoWindowShown, isFalse); }); + + group('remove', () { + late MarkerController controller; + + setUp(() { + final infoWindow = gmaps.InfoWindow(); + final map = gmaps.GMap(html.DivElement()); + marker.set('map', map); + controller = MarkerController(marker: marker, infoWindow: infoWindow); + }); + + testWidgets('drops gmaps instance', (WidgetTester tester) async { + controller.remove(); + + expect(controller.marker, isNull); + }); + + testWidgets('cannot call update after remove', + (WidgetTester tester) async { + final options = gmaps.MarkerOptions()..draggable = true; + + controller.remove(); + + expect(() { + controller.update(options); + }, throwsAssertionError); + }); + + testWidgets('cannot call showInfoWindow after remove', + (WidgetTester tester) async { + controller.remove(); + + expect(() { + controller.showInfoWindow(); + }, throwsAssertionError); + }); + + testWidgets('cannot call hideInfoWindow after remove', + (WidgetTester tester) async { + controller.remove(); + + expect(() { + controller.hideInfoWindow(); + }, throwsAssertionError); + }); + }); }); } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart index e9e458c85685..6f2bf610f77d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart @@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; import 'dart:convert'; -import 'dart:html'; +import 'dart:html' as html; +import 'dart:js_util' show getProperty; -import 'package:http/http.dart' as http; -import 'package:integration_test/integration_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps/google_maps.dart' as gmaps; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart' as http; +import 'package:integration_test/integration_test.dart'; import 'resources/icon_image_base64.dart'; @@ -20,12 +20,15 @@ void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('MarkersController', () { - StreamController stream; - MarkersController controller; + late StreamController events; + late MarkersController controller; + late gmaps.GMap map; setUp(() { - stream = StreamController(); - controller = MarkersController(stream: stream); + events = StreamController(); + controller = MarkersController(stream: events); + map = gmaps.GMap(html.DivElement()); + controller.bindToMap(123, map); }); testWidgets('addMarkers', (WidgetTester tester) async { @@ -48,7 +51,7 @@ void main() { }; controller.addMarkers(markers); - expect(controller.markers[MarkerId('1')].marker.draggable, isFalse); + expect(controller.markers[MarkerId('1')]?.marker?.draggable, isFalse); // Update the marker with radius 10 final updatedMarkers = { @@ -57,7 +60,7 @@ void main() { controller.changeMarkers(updatedMarkers); expect(controller.markers.length, 1); - expect(controller.markers[MarkerId('1')].marker.draggable, isTrue); + expect(controller.markers[MarkerId('1')]?.marker?.draggable, isTrue); }); testWidgets('removeMarkers', (WidgetTester tester) async { @@ -95,15 +98,15 @@ void main() { controller.addMarkers(markers); - expect(controller.markers[MarkerId('1')].infoWindowShown, isFalse); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isFalse); controller.showMarkerInfoWindow(MarkerId('1')); - expect(controller.markers[MarkerId('1')].infoWindowShown, isTrue); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isTrue); controller.hideMarkerInfoWindow(MarkerId('1')); - expect(controller.markers[MarkerId('1')].infoWindowShown, isFalse); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isFalse); }); // https://github.com/flutter/flutter/issues/67380 @@ -121,33 +124,21 @@ void main() { }; controller.addMarkers(markers); - expect(controller.markers[MarkerId('1')].infoWindowShown, isFalse); - expect(controller.markers[MarkerId('2')].infoWindowShown, isFalse); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isFalse); + expect(controller.markers[MarkerId('2')]?.infoWindowShown, isFalse); controller.showMarkerInfoWindow(MarkerId('1')); - expect(controller.markers[MarkerId('1')].infoWindowShown, isTrue); - expect(controller.markers[MarkerId('2')].infoWindowShown, isFalse); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isTrue); + expect(controller.markers[MarkerId('2')]?.infoWindowShown, isFalse); controller.showMarkerInfoWindow(MarkerId('2')); - expect(controller.markers[MarkerId('1')].infoWindowShown, isFalse); - expect(controller.markers[MarkerId('2')].infoWindowShown, isTrue); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isFalse); + expect(controller.markers[MarkerId('2')]?.infoWindowShown, isTrue); }); - // https://github.com/flutter/flutter/issues/64938 - testWidgets('markers with icon:null work', (WidgetTester tester) async { - final markers = { - Marker(markerId: MarkerId('1'), icon: null), - }; - - controller.addMarkers(markers); - - expect(controller.markers.length, 1); - expect(controller.markers[MarkerId('1')].marker.icon, isNull); - }); - - // + // https://github.com/flutter/flutter/issues/66622 testWidgets('markers with custom bitmap icon work', (WidgetTester tester) async { final bytes = Base64Decoder().convert(iconImageBase64); @@ -159,11 +150,15 @@ void main() { controller.addMarkers(markers); expect(controller.markers.length, 1); - expect(controller.markers[MarkerId('1')].marker.icon, isNotNull); - expect(controller.markers[MarkerId('1')].marker.icon.url, - startsWith('blob:')); + expect(controller.markers[MarkerId('1')]?.marker?.icon, isNotNull); + + final blobUrl = getProperty( + controller.markers[MarkerId('1')]!.marker!.icon!, + 'url', + ); + + expect(blobUrl, startsWith('blob:')); - final blobUrl = controller.markers[MarkerId('1')].marker.icon.url; final response = await http.get(Uri.parse(blobUrl)); expect(response.bodyBytes, bytes, @@ -187,8 +182,8 @@ void main() { controller.addMarkers(markers); expect(controller.markers.length, 1); - final content = - controller.markers[MarkerId('1')].infoWindow.content as HtmlElement; + final content = controller.markers[MarkerId('1')]?.infoWindow?.content + as html.HtmlElement; expect(content.innerHtml, contains('title for test')); expect( content.innerHtml, @@ -211,12 +206,12 @@ void main() { controller.addMarkers(markers); expect(controller.markers.length, 1); - final content = - controller.markers[MarkerId('1')].infoWindow.content as HtmlElement; + final content = controller.markers[MarkerId('1')]?.infoWindow?.content + as html.HtmlElement; content.click(); - final event = await stream.stream.first; + final event = await events.stream.first; expect(event, isA()); expect((event as InfoWindowTapEvent).value, equals(MarkerId('1'))); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart index 0c351971af7c..547aaec6dc0a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart @@ -2,114 +2,195 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; import 'package:integration_test/integration_test.dart'; import 'package:google_maps/google_maps.dart' as gmaps; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; - -class _MockCircle extends Mock implements gmaps.Circle { - final onClickController = StreamController(); - @override - Stream get onClick => onClickController.stream; -} - -class _MockPolygon extends Mock implements gmaps.Polygon { - final onClickController = StreamController(); - @override - Stream get onClick => onClickController.stream; -} - -class _MockPolyline extends Mock implements gmaps.Polyline { - final onClickController = StreamController(); - @override - Stream get onClick => onClickController.stream; -} /// Test Shapes (Circle, Polygon, Polyline) void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - bool called = false; + // Since onTap events happen asynchronously, we need to store when the event + // is fired. We use a completer so the test can wait for the future to be completed. + late Completer _methodCalledCompleter; + + /// This is the future value of the [_methodCalledCompleter]. Reinitialized + /// in the [setUp] method, and completed (as `true`) by [onTap], when it gets + /// called by the corresponding Shape Controller. + late Future methodCalled; + void onTap() { - called = true; + _methodCalledCompleter.complete(true); } setUp(() { - called = false; + _methodCalledCompleter = Completer(); + methodCalled = _methodCalledCompleter.future; }); group('CircleController', () { - _MockCircle circle; + late gmaps.Circle circle; setUp(() { - circle = _MockCircle(); + circle = gmaps.Circle(); }); testWidgets('onTap gets called', (WidgetTester tester) async { CircleController(circle: circle, consumeTapEvents: true, onTap: onTap); - expect(circle.onClickController.hasListener, isTrue); - // Simulate a click - await circle.onClickController.add(null); - expect(called, isTrue); + + // Trigger a click event... + gmaps.Event.trigger(circle, 'click', [gmaps.MapMouseEvent()]); + + // The event handling is now truly async. Wait for it... + expect(await methodCalled, isTrue); }); testWidgets('update', (WidgetTester tester) async { final controller = CircleController(circle: circle); - final options = gmaps.CircleOptions()..draggable = false; + final options = gmaps.CircleOptions()..draggable = true; + + expect(circle.draggable, isNull); + controller.update(options); - verify(circle.options = options); + + expect(circle.draggable, isTrue); + }); + + group('remove', () { + late CircleController controller; + + setUp(() { + controller = CircleController(circle: circle); + }); + + testWidgets('drops gmaps instance', (WidgetTester tester) async { + controller.remove(); + + expect(controller.circle, isNull); + }); + + testWidgets('cannot call update after remove', + (WidgetTester tester) async { + final options = gmaps.CircleOptions()..draggable = true; + + controller.remove(); + + expect(() { + controller.update(options); + }, throwsAssertionError); + }); }); }); group('PolygonController', () { - _MockPolygon polygon; + late gmaps.Polygon polygon; setUp(() { - polygon = _MockPolygon(); + polygon = gmaps.Polygon(); }); testWidgets('onTap gets called', (WidgetTester tester) async { PolygonController(polygon: polygon, consumeTapEvents: true, onTap: onTap); - expect(polygon.onClickController.hasListener, isTrue); - // Simulate a click - await polygon.onClickController.add(null); - expect(called, isTrue); + + // Trigger a click event... + gmaps.Event.trigger(polygon, 'click', [gmaps.MapMouseEvent()]); + + // The event handling is now truly async. Wait for it... + expect(await methodCalled, isTrue); }); testWidgets('update', (WidgetTester tester) async { final controller = PolygonController(polygon: polygon); - final options = gmaps.PolygonOptions()..draggable = false; + final options = gmaps.PolygonOptions()..draggable = true; + + expect(polygon.draggable, isNull); + controller.update(options); - verify(polygon.options = options); + + expect(polygon.draggable, isTrue); + }); + + group('remove', () { + late PolygonController controller; + + setUp(() { + controller = PolygonController(polygon: polygon); + }); + + testWidgets('drops gmaps instance', (WidgetTester tester) async { + controller.remove(); + + expect(controller.polygon, isNull); + }); + + testWidgets('cannot call update after remove', + (WidgetTester tester) async { + final options = gmaps.PolygonOptions()..draggable = true; + + controller.remove(); + + expect(() { + controller.update(options); + }, throwsAssertionError); + }); }); }); group('PolylineController', () { - _MockPolyline polyline; + late gmaps.Polyline polyline; setUp(() { - polyline = _MockPolyline(); + polyline = gmaps.Polyline(); }); testWidgets('onTap gets called', (WidgetTester tester) async { PolylineController( polyline: polyline, consumeTapEvents: true, onTap: onTap); - expect(polyline.onClickController.hasListener, isTrue); - // Simulate a click - await polyline.onClickController.add(null); - expect(called, isTrue); + + // Trigger a click event... + gmaps.Event.trigger(polyline, 'click', [gmaps.MapMouseEvent()]); + + // The event handling is now truly async. Wait for it... + expect(await methodCalled, isTrue); }); testWidgets('update', (WidgetTester tester) async { final controller = PolylineController(polyline: polyline); - final options = gmaps.PolylineOptions()..draggable = false; + final options = gmaps.PolylineOptions()..draggable = true; + + expect(polyline.draggable, isNull); + controller.update(options); - verify(polyline.options = options); + + expect(polyline.draggable, isTrue); + }); + + group('remove', () { + late PolylineController controller; + + setUp(() { + controller = PolylineController(polyline: polyline); + }); + + testWidgets('drops gmaps instance', (WidgetTester tester) async { + controller.remove(); + + expect(controller.line, isNull); + }); + + testWidgets('cannot call update after remove', + (WidgetTester tester) async { + final options = gmaps.PolylineOptions()..draggable = true; + + controller.remove(); + + expect(() { + controller.update(options); + }, throwsAssertionError); + }); }); }); } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart index 9bb3599311d2..80b4e0823bb5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; import 'dart:ui'; +import 'dart:html' as html; import 'package:integration_test/integration_test.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; @@ -23,13 +22,20 @@ const _acceptableDelta = 0.01; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + late gmaps.GMap map; + + setUp(() { + map = gmaps.GMap(html.DivElement()); + }); + group('CirclesController', () { - StreamController stream; - CirclesController controller; + late StreamController events; + late CirclesController controller; setUp(() { - stream = StreamController(); - controller = CirclesController(stream: stream); + events = StreamController(); + controller = CirclesController(stream: events); + controller.bindToMap(123, map); }); testWidgets('addCircles', (WidgetTester tester) async { @@ -52,7 +58,7 @@ void main() { }; controller.addCircles(circles); - expect(controller.circles[CircleId('1')].circle.visible, isTrue); + expect(controller.circles[CircleId('1')]?.circle?.visible, isTrue); final updatedCircles = { Circle(circleId: CircleId('1'), visible: false), @@ -60,7 +66,7 @@ void main() { controller.changeCircles(updatedCircles); expect(controller.circles.length, 1); - expect(controller.circles[CircleId('1')].circle.visible, isFalse); + expect(controller.circles[CircleId('1')]?.circle?.visible, isFalse); }); testWidgets('removeCircles', (WidgetTester tester) async { @@ -99,7 +105,7 @@ void main() { controller.addCircles(circles); - final circle = controller.circles.values.first.circle; + final circle = controller.circles.values.first.circle!; expect(circle.get('fillColor'), '#fabada'); expect(circle.get('fillOpacity'), closeTo(0.5, _acceptableDelta)); @@ -109,12 +115,13 @@ void main() { }); group('PolygonsController', () { - StreamController stream; - PolygonsController controller; + late StreamController events; + late PolygonsController controller; setUp(() { - stream = StreamController(); - controller = PolygonsController(stream: stream); + events = StreamController(); + controller = PolygonsController(stream: events); + controller.bindToMap(123, map); }); testWidgets('addPolygons', (WidgetTester tester) async { @@ -137,7 +144,7 @@ void main() { }; controller.addPolygons(polygons); - expect(controller.polygons[PolygonId('1')].polygon.visible, isTrue); + expect(controller.polygons[PolygonId('1')]?.polygon?.visible, isTrue); // Update the polygon final updatedPolygons = { @@ -146,7 +153,7 @@ void main() { controller.changePolygons(updatedPolygons); expect(controller.polygons.length, 1); - expect(controller.polygons[PolygonId('1')].polygon.visible, isFalse); + expect(controller.polygons[PolygonId('1')]?.polygon?.visible, isFalse); }); testWidgets('removePolygons', (WidgetTester tester) async { @@ -185,7 +192,7 @@ void main() { controller.addPolygons(polygons); - final polygon = controller.polygons.values.first.polygon; + final polygon = controller.polygons.values.first.polygon!; expect(polygon.get('fillColor'), '#fabada'); expect(polygon.get('fillOpacity'), closeTo(0.5, _acceptableDelta)); @@ -243,7 +250,7 @@ void main() { final polygon = controller.polygons.values.first.polygon; final pointInHole = gmaps.LatLng(28.632, -68.401); - expect(geometry.poly.containsLocation(pointInHole, polygon), false); + expect(geometry.Poly.containsLocation(pointInHole, polygon), false); }); testWidgets('Hole Path gets reversed to display correctly', @@ -268,25 +275,22 @@ void main() { controller.addPolygons(polygons); - expect( - controller.polygons.values.first.polygon.paths.getAt(1).getAt(0).lat, - 28.745); - expect( - controller.polygons.values.first.polygon.paths.getAt(1).getAt(1).lat, - 29.57); - expect( - controller.polygons.values.first.polygon.paths.getAt(1).getAt(2).lat, - 27.339); + final paths = controller.polygons.values.first.polygon!.paths!; + + expect(paths.getAt(1)?.getAt(0)?.lat, 28.745); + expect(paths.getAt(1)?.getAt(1)?.lat, 29.57); + expect(paths.getAt(1)?.getAt(2)?.lat, 27.339); }); }); group('PolylinesController', () { - StreamController stream; - PolylinesController controller; + late StreamController events; + late PolylinesController controller; setUp(() { - stream = StreamController(); - controller = PolylinesController(stream: stream); + events = StreamController(); + controller = PolylinesController(stream: events); + controller.bindToMap(123, map); }); testWidgets('addPolylines', (WidgetTester tester) async { @@ -309,7 +313,7 @@ void main() { }; controller.addPolylines(polylines); - expect(controller.lines[PolylineId('1')].line.visible, isTrue); + expect(controller.lines[PolylineId('1')]?.line?.visible, isTrue); final updatedPolylines = { Polyline(polylineId: PolylineId('1'), visible: false), @@ -317,7 +321,7 @@ void main() { controller.changePolylines(updatedPolylines); expect(controller.lines.length, 1); - expect(controller.lines[PolylineId('1')].line.visible, isFalse); + expect(controller.lines[PolylineId('1')]?.line?.visible, isFalse); }); testWidgets('removePolylines', (WidgetTester tester) async { @@ -355,7 +359,7 @@ void main() { controller.addPolylines(lines); - final line = controller.lines.values.first.line; + final line = controller.lines.values.first.line!; expect(line.get('strokeColor'), '#fabada'); expect(line.get('strokeOpacity'), closeTo(0.5, _acceptableDelta)); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml index 28955016ab40..311f05a69dc4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml @@ -1,9 +1,15 @@ name: google_maps_flutter_web_integration_tests publish_to: none +# Tests require flutter beta or greater to run. environment: - sdk: ">=2.2.2 <3.0.0" # Bump this to 2.12 when migrating to nnbd. - flutter: ">=1.27.0-0" # For integration_test from sdk + sdk: ">=2.12.0 <3.0.0" + flutter: ">=2.0.0" + # Actually, Flutter 2.0.0 shipped with a slightly older version of integration_test that + # did *not* support null safety. This flutter constraint should be changed to >=2.1.0 when + # that version (or greater) is shipped to the `stable` channel. + # This causes integration tests to *not* work in `stable`, for now. Please, run integration tests + # in `beta` or newer (flutter/plugins runs these tests in `master`). dependencies: google_maps_flutter_web: @@ -12,12 +18,19 @@ dependencies: sdk: flutter dev_dependencies: - google_maps: ^3.4.4 + build_runner: ^1.11.0 + google_maps: ^5.1.0 http: ^0.13.0 - mockito: ^4.1.1+1 # Update to ^5.0.0 as soon as this migrates to null-safety + mockito: ^5.0.0 flutter_driver: sdk: flutter flutter_test: sdk: flutter integration_test: sdk: flutter + +# Remove these once environment flutter is set to ">=2.1.0". +# Used to reconcile mockito ^5.0.0 with flutter 2.0.x (current stable). +dependency_overrides: + crypto: ^3.0.0 + convert: ^3.0.0 diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh new file mode 100755 index 000000000000..78bcdc0f9e28 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh @@ -0,0 +1,10 @@ +#!/usr/bin/bash +# Copyright 2013 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. + +flutter pub get + +echo "(Re)generating mocks." + +flutter pub run build_runner build --delete-conflicting-outputs diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh index aa52974f310e..fcac5f600acb 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh @@ -6,6 +6,8 @@ if pgrep -lf chromedriver > /dev/null; then echo "chromedriver is running." + ./regen_mocks.sh + if [ $# -eq 0 ]; then echo "No target specified, running all tests..." find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html b/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html index f324d1c7538f..3121d189b913 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html @@ -12,4 +12,3 @@ - diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart index 0aa563ccb889..6dc2dab572a6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart @@ -6,6 +6,7 @@ library google_maps_flutter_web; import 'dart:async'; import 'dart:html'; +import 'dart:js_util'; import 'src/shims/dart_ui.dart' as ui; // Conditionally imports dart:ui in web import 'dart:convert'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart index 84bae1b98e2e..65057d8c869e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart @@ -6,15 +6,15 @@ part of google_maps_flutter_web; /// The `CircleController` class wraps a [gmaps.Circle] and its `onTap` behavior. class CircleController { - gmaps.Circle _circle; + gmaps.Circle? _circle; final bool _consumeTapEvents; /// Creates a `CircleController`, which wraps a [gmaps.Circle] object and its `onTap` behavior. CircleController({ - @required gmaps.Circle circle, + required gmaps.Circle circle, bool consumeTapEvents = false, - ui.VoidCallback onTap, + ui.VoidCallback? onTap, }) : _circle = circle, _consumeTapEvents = consumeTapEvents { if (onTap != null) { @@ -26,21 +26,26 @@ class CircleController { /// Returns the wrapped [gmaps.Circle]. Only used for testing. @visibleForTesting - gmaps.Circle get circle => _circle; + gmaps.Circle? get circle => _circle; /// Returns `true` if this Controller will use its own `onTap` handler to consume events. bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Circle] object. + /// + /// This cannot be called after [remove]. void update(gmaps.CircleOptions options) { - _circle.options = options; + assert(_circle != null, 'Cannot `update` Circle after calling `remove`.'); + _circle!.options = options; } /// Disposes of the currently wrapped [gmaps.Circle]. void remove() { - _circle.visible = false; - _circle.radius = 0; - _circle.map = null; - _circle = null; + if (_circle != null) { + _circle!.visible = false; + _circle!.radius = 0; + _circle!.map = null; + _circle = null; + } } } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart index 659d8ac823a6..2a19d87adfec 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart @@ -14,8 +14,8 @@ class CirclesController extends GeometryController { /// Initialize the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. CirclesController({ - @required StreamController stream, - }) : _streamController = stream, + required StreamController stream, + }) : _streamController = stream, _circleIdToController = Map(); /// Returns the cache of [CircleController]s. Test only. @@ -26,7 +26,7 @@ class CirclesController extends GeometryController { /// /// Wraps each [Circle] into its corresponding [CircleController]. void addCircles(Set circlesToAdd) { - circlesToAdd?.forEach((circle) { + circlesToAdd.forEach((circle) { _addCircle(circle); }); } @@ -50,20 +50,21 @@ class CirclesController extends GeometryController { /// Updates a set of [Circle] objects with new options. void changeCircles(Set circlesToChange) { - circlesToChange?.forEach((circleToChange) { + circlesToChange.forEach((circleToChange) { _changeCircle(circleToChange); }); } void _changeCircle(Circle circle) { - final circleController = _circleIdToController[circle?.circleId]; + final circleController = _circleIdToController[circle.circleId]; circleController?.update(_circleOptionsFromCircle(circle)); } /// Removes a set of [CircleId]s from the cache. void removeCircles(Set circleIdsToRemove) { - circleIdsToRemove?.forEach((circleId) { - final CircleController circleController = _circleIdToController[circleId]; + circleIdsToRemove.forEach((circleId) { + final CircleController? circleController = + _circleIdToController[circleId]; circleController?.remove(); _circleIdToController.remove(circleId); }); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index c875bf782474..2e71c795ff0e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -4,11 +4,10 @@ part of google_maps_flutter_web; -final _nullLatLng = LatLng(0, 0); -final _nullLatLngBounds = LatLngBounds( - northeast: _nullLatLng, - southwest: _nullLatLng, -); +// Default values for when the gmaps objects return null/undefined values. +final _nullGmapsLatLng = gmaps.LatLng(0, 0); +final _nullGmapsLatLngBounds = + gmaps.LatLngBounds(_nullGmapsLatLng, _nullGmapsLatLng); // Defaults taken from the Google Maps Platform SDK documentation. final _defaultCssColor = '#000000'; @@ -115,80 +114,6 @@ bool _isTrafficLayerEnabled(Map rawOptions) { return rawOptions['trafficEnabled'] ?? false; } -// Coverts the incoming JSON object into a List of MapTypeStyler objects. -List _parseStylers(List stylerJsons) { - return stylerJsons?.map((styler) { - return gmaps.MapTypeStyler() - ..color = styler['color'] - ..gamma = styler['gamma'] - ..hue = styler['hue'] - ..invertLightness = styler['invertLightness'] - ..lightness = styler['lightness'] - ..saturation = styler['saturation'] - ..visibility = styler['visibility'] - ..weight = styler['weight']; - })?.toList(); -} - -// Converts a String to its corresponding MapTypeStyleElementType enum value. -final _elementTypeToEnum = { - 'all': gmaps.MapTypeStyleElementType.ALL, - 'geometry': gmaps.MapTypeStyleElementType.GEOMETRY, - 'geometry.fill': gmaps.MapTypeStyleElementType.GEOMETRY_FILL, - 'geometry.stroke': gmaps.MapTypeStyleElementType.GEOMETRY_STROKE, - 'labels': gmaps.MapTypeStyleElementType.LABELS, - 'labels.icon': gmaps.MapTypeStyleElementType.LABELS_ICON, - 'labels.text': gmaps.MapTypeStyleElementType.LABELS_TEXT, - 'labels.text.fill': gmaps.MapTypeStyleElementType.LABELS_TEXT_FILL, - 'labels.text.stroke': gmaps.MapTypeStyleElementType.LABELS_TEXT_STROKE, -}; - -// Converts a String to its corresponding MapTypeStyleFeatureType enum value. -final _featureTypeToEnum = { - 'administrative': gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE, - 'administrative.country': - gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE_COUNTRY, - 'administrative.land_parcel': - gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE_LAND_PARCEL, - 'administrative.locality': - gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE_LOCALITY, - 'administrative.neighborhood': - gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE_NEIGHBORHOOD, - 'administrative.province': - gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE_PROVINCE, - 'all': gmaps.MapTypeStyleFeatureType.ALL, - 'landscape': gmaps.MapTypeStyleFeatureType.LANDSCAPE, - 'landscape.man_made': gmaps.MapTypeStyleFeatureType.LANDSCAPE_MAN_MADE, - 'landscape.natural': gmaps.MapTypeStyleFeatureType.LANDSCAPE_NATURAL, - 'landscape.natural.landcover': - gmaps.MapTypeStyleFeatureType.LANDSCAPE_NATURAL_LANDCOVER, - 'landscape.natural.terrain': - gmaps.MapTypeStyleFeatureType.LANDSCAPE_NATURAL_TERRAIN, - 'poi': gmaps.MapTypeStyleFeatureType.POI, - 'poi.attraction': gmaps.MapTypeStyleFeatureType.POI_ATTRACTION, - 'poi.business': gmaps.MapTypeStyleFeatureType.POI_BUSINESS, - 'poi.government': gmaps.MapTypeStyleFeatureType.POI_GOVERNMENT, - 'poi.medical': gmaps.MapTypeStyleFeatureType.POI_MEDICAL, - 'poi.park': gmaps.MapTypeStyleFeatureType.POI_PARK, - 'poi.place_of_worship': gmaps.MapTypeStyleFeatureType.POI_PLACE_OF_WORSHIP, - 'poi.school': gmaps.MapTypeStyleFeatureType.POI_SCHOOL, - 'poi.sports_complex': gmaps.MapTypeStyleFeatureType.POI_SPORTS_COMPLEX, - 'road': gmaps.MapTypeStyleFeatureType.ROAD, - 'road.arterial': gmaps.MapTypeStyleFeatureType.ROAD_ARTERIAL, - 'road.highway': gmaps.MapTypeStyleFeatureType.ROAD_HIGHWAY, - 'road.highway.controlled_access': - gmaps.MapTypeStyleFeatureType.ROAD_HIGHWAY_CONTROLLED_ACCESS, - 'road.local': gmaps.MapTypeStyleFeatureType.ROAD_LOCAL, - 'transit': gmaps.MapTypeStyleFeatureType.TRANSIT, - 'transit.line': gmaps.MapTypeStyleFeatureType.TRANSIT_LINE, - 'transit.station': gmaps.MapTypeStyleFeatureType.TRANSIT_STATION, - 'transit.station.airport': - gmaps.MapTypeStyleFeatureType.TRANSIT_STATION_AIRPORT, - 'transit.station.bus': gmaps.MapTypeStyleFeatureType.TRANSIT_STATION_BUS, - 'transit.station.rail': gmaps.MapTypeStyleFeatureType.TRANSIT_STATION_RAIL, - 'water': gmaps.MapTypeStyleFeatureType.WATER, -}; - // The keys we'd expect to see in a serialized MapTypeStyle JSON object. final _mapStyleKeys = { 'elementType', @@ -202,37 +127,36 @@ bool _isJsonMapStyle(Map value) { } // Converts an incoming JSON-encoded Style info, into the correct gmaps array. -List _mapStyles(String mapStyleJson) { +List _mapStyles(String? mapStyleJson) { List styles = []; if (mapStyleJson != null) { - styles = json.decode(mapStyleJson, reviver: (key, value) { - if (value is Map && _isJsonMapStyle(value)) { - return gmaps.MapTypeStyle() - ..elementType = _elementTypeToEnum[value['elementType']] - ..featureType = _featureTypeToEnum[value['featureType']] - ..stylers = _parseStylers(value['stylers']); - } - return value; - }).cast(); + styles = json + .decode(mapStyleJson, reviver: (key, value) { + if (value is Map && _isJsonMapStyle(value)) { + return gmaps.MapTypeStyle() + ..elementType = value['elementType'] + ..featureType = value['featureType'] + ..stylers = + (value['stylers'] as List).map((e) => jsify(e)).toList(); + } + return value; + }) + .cast() + .toList(); + // .toList calls are required so the JS API understands the underlying data structure. } return styles; } gmaps.LatLng _latLngToGmLatLng(LatLng latLng) { - if (latLng == null) return null; return gmaps.LatLng(latLng.latitude, latLng.longitude); } LatLng _gmLatLngToLatLng(gmaps.LatLng latLng) { - if (latLng == null) return _nullLatLng; - return LatLng(latLng.lat, latLng.lng); + return LatLng(latLng.lat.toDouble(), latLng.lng.toDouble()); } LatLngBounds _gmLatLngBoundsTolatLngBounds(gmaps.LatLngBounds latLngBounds) { - if (latLngBounds == null) { - return _nullLatLngBounds; - } - return LatLngBounds( southwest: _gmLatLngToLatLng(latLngBounds.southWest), northeast: _gmLatLngToLatLng(latLngBounds.northEast), @@ -241,10 +165,10 @@ LatLngBounds _gmLatLngBoundsTolatLngBounds(gmaps.LatLngBounds latLngBounds) { CameraPosition _gmViewportToCameraPosition(gmaps.GMap map) { return CameraPosition( - target: _gmLatLngToLatLng(map.center), - bearing: map.heading ?? 0, - tilt: map.tilt ?? 0, - zoom: map.zoom?.toDouble() ?? 10, + target: _gmLatLngToLatLng(map.center ?? _nullGmapsLatLng), + bearing: map.heading?.toDouble() ?? 0, + tilt: map.tilt?.toDouble() ?? 0, + zoom: map.zoom?.toDouble() ?? 0, ); } @@ -252,9 +176,13 @@ CameraPosition _gmViewportToCameraPosition(gmaps.GMap map) { // TODO: Move to their appropriate objects, maybe make these copy constructors: // Marker.fromMarker(anotherMarker, moreOptions); -gmaps.InfoWindowOptions _infoWindowOptionsFromMarker(Marker marker) { - if ((marker.infoWindow?.title?.isEmpty ?? true) && - (marker.infoWindow?.snippet?.isEmpty ?? true)) { +gmaps.InfoWindowOptions? _infoWindowOptionsFromMarker(Marker marker) { + final markerTitle = marker.infoWindow.title ?? ''; + final markerSnippet = marker.infoWindow.snippet ?? ''; + + // If both the title and snippet of an infowindow are empty, we don't really + // want an infowindow... + if ((markerTitle.isEmpty) && (markerSnippet.isEmpty)) { return null; } @@ -262,17 +190,18 @@ gmaps.InfoWindowOptions _infoWindowOptionsFromMarker(Marker marker) { // to click events... final HtmlElement container = DivElement() ..id = 'gmaps-marker-${marker.markerId.value}-infowindow'; - if (marker.infoWindow.title?.isNotEmpty ?? false) { + + if (markerTitle.isNotEmpty) { final HtmlElement title = HeadingElement.h3() ..className = 'infowindow-title' - ..innerText = marker.infoWindow.title; + ..innerText = markerTitle; container.children.add(title); } - if (marker.infoWindow.snippet?.isNotEmpty ?? false) { + if (markerSnippet.isNotEmpty) { final HtmlElement snippet = DivElement() ..className = 'infowindow-snippet' ..setInnerHtml( - sanitizeHtml(marker.infoWindow.snippet), + sanitizeHtml(markerSnippet), treeSanitizer: NodeTreeSanitizer.trusted, ); container.children.add(snippet); @@ -290,10 +219,10 @@ gmaps.InfoWindowOptions _infoWindowOptionsFromMarker(Marker marker) { // Preserves the position from the [currentMarker], if set. gmaps.MarkerOptions _markerOptionsFromMarker( Marker marker, - gmaps.Marker currentMarker, + gmaps.Marker? currentMarker, ) { - final iconConfig = marker.icon?.toJson() as List; - gmaps.Icon icon; + final iconConfig = marker.icon.toJson() as List; + gmaps.Icon? icon; if (iconConfig != null) { if (iconConfig[0] == 'fromAssetImage') { @@ -324,7 +253,7 @@ gmaps.MarkerOptions _markerOptionsFromMarker( marker.position.latitude, marker.position.longitude, ) - ..title = sanitizeHtml(marker.infoWindow?.title ?? "") + ..title = sanitizeHtml(marker.infoWindow.title ?? "") ..zIndex = marker.zIndex ..visible = marker.visible ..opacity = marker.alpha @@ -356,7 +285,7 @@ gmaps.PolygonOptions _polygonOptionsFromPolygon( final polygonDirection = _isPolygonClockwise(path); List> paths = [path]; int holeIndex = 0; - polygon.holes?.forEach((hole) { + polygon.holes.forEach((hole) { List holePath = hole.map((point) => _latLngToGmLatLng(point)).toList(); if (_isPolygonClockwise(holePath) == polygonDirection) { @@ -387,6 +316,13 @@ gmaps.PolygonOptions _polygonOptionsFromPolygon( /// based on: https://stackoverflow.com/a/1165943 /// /// returns [true] if clockwise [false] if counterclockwise +/// +/// This method expects that the incoming [path] is a `List` of well-formed, +/// non-null [gmaps.LatLng] objects. +/// +/// Currently, this method is only called from [_polygonOptionsFromPolygon], and +/// the `path` is a transformed version of [Polygon.points] or each of the +/// [Polygon.holes], guaranteeing that `lat` and `lng` can be accessed with `!`. bool _isPolygonClockwise(List path) { var direction = 0.0; for (var i = 0; i < path.length; i++) { @@ -447,7 +383,7 @@ void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { map.panBy(json[1], json[2]); break; case 'zoomBy': - gmaps.LatLng focusLatLng; + gmaps.LatLng? focusLatLng; double zoomDelta = json[1] ?? 0; // Web only supports integer changes... int newZoomDelta = zoomDelta < 0 ? zoomDelta.floor() : zoomDelta.ceil(); @@ -460,16 +396,16 @@ void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { // print('Error computing new focus LatLng. JS Error: ' + e.toString()); } } - map.zoom = map.zoom + newZoomDelta; + map.zoom = (map.zoom ?? 0) + newZoomDelta; if (focusLatLng != null) { map.panTo(focusLatLng); } break; case 'zoomIn': - map.zoom++; + map.zoom = (map.zoom ?? 0) + 1; break; case 'zoomOut': - map.zoom--; + map.zoom = (map.zoom ?? 0) - 1; break; case 'zoomTo': map.zoom = json[1]; @@ -481,17 +417,27 @@ void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { // original JS by: Byron Singh (https://stackoverflow.com/a/30541162) gmaps.LatLng _pixelToLatLng(gmaps.GMap map, int x, int y) { - final ne = map.bounds.northEast; - final sw = map.bounds.southWest; + final bounds = map.bounds; final projection = map.projection; + final zoom = map.zoom; + + assert( + bounds != null, 'Map Bounds required to compute LatLng of screen x/y.'); + assert(projection != null, + 'Map Projection required to compute LatLng of screen x/y'); + assert(zoom != null, + 'Current map zoom level required to compute LatLng of screen x/y'); + + final ne = bounds!.northEast; + final sw = bounds.southWest; - final topRight = projection.fromLatLngToPoint(ne); - final bottomLeft = projection.fromLatLngToPoint(sw); + final topRight = projection!.fromLatLngToPoint!(ne)!; + final bottomLeft = projection.fromLatLngToPoint!(sw)!; - final scale = 1 << map.zoom; // 2 ^ zoom + final scale = 1 << (zoom!.toInt()); // 2 ^ zoom final point = - gmaps.Point((x / scale) + bottomLeft.x, (y / scale) + topRight.y); + gmaps.Point((x / scale) + bottomLeft.x!, (y / scale) + topRight.y!); - return projection.fromPointToLatLng(point); + return projection.fromPointToLatLng!(point)!; } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart index cc8d79a6226d..25284909d596 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart @@ -27,11 +27,11 @@ class GoogleMapController { String _getViewType(int mapId) => 'plugins.flutter.io/google_maps_$mapId'; // The Flutter widget that contains the rendered Map. - HtmlElementView _widget; - HtmlElement _div; + HtmlElementView? _widget; + late HtmlElement _div; /// The Flutter widget that will contain the rendered Map. Used for caching. - HtmlElementView get widget { + Widget? get widget { if (_widget == null && !_streamController.isClosed) { _widget = HtmlElementView( viewType: _getViewType(_mapId), @@ -41,14 +41,14 @@ class GoogleMapController { } // The currently-enabled traffic layer. - gmaps.TrafficLayer _trafficLayer; + gmaps.TrafficLayer? _trafficLayer; /// A getter for the current traffic layer. Only for tests. @visibleForTesting - gmaps.TrafficLayer get trafficLayer => _trafficLayer; + gmaps.TrafficLayer? get trafficLayer => _trafficLayer; // The underlying GMap instance. This is the interface with the JS SDK. - gmaps.GMap _googleMap; + gmaps.GMap? _googleMap; // The StreamController used by this controller and the geometry ones. final StreamController _streamController; @@ -57,10 +57,10 @@ class GoogleMapController { Stream get events => _streamController.stream; // Geometry controllers, for different features of the map. - CirclesController _circlesController; - PolygonsController _polygonsController; - PolylinesController _polylinesController; - MarkersController _markersController; + CirclesController? _circlesController; + PolygonsController? _polygonsController; + PolylinesController? _polylinesController; + MarkersController? _markersController; // Keeps track if _attachGeometryControllers has been called or not. bool _controllersBoundToMap = false; @@ -69,9 +69,9 @@ class GoogleMapController { /// Initializes the GMap, and the sub-controllers related to it. Wires events. GoogleMapController({ - @required int mapId, - @required StreamController streamController, - @required CameraPosition initialCameraPosition, + required int mapId, + required StreamController streamController, + required CameraPosition initialCameraPosition, Set markers = const {}, Set polygons = const {}, Set polylines = const {}, @@ -107,11 +107,11 @@ class GoogleMapController { /// Overrides certain properties to install mocks defined during testing. @visibleForTesting void debugSetOverrides({ - DebugCreateMapFunction createMap, - MarkersController markers, - CirclesController circles, - PolygonsController polygons, - PolylinesController polylines, + DebugCreateMapFunction? createMap, + MarkersController? markers, + CirclesController? circles, + PolygonsController? polygons, + PolylinesController? polylines, }) { _overrideCreateMap = createMap; _markersController = markers ?? _markersController; @@ -120,11 +120,11 @@ class GoogleMapController { _polylinesController = polylines ?? _polylinesController; } - DebugCreateMapFunction _overrideCreateMap; + DebugCreateMapFunction? _overrideCreateMap; gmaps.GMap _createMap(HtmlElement div, gmaps.MapOptions options) { if (_overrideCreateMap != null) { - return _overrideCreateMap(div, options); + return _overrideCreateMap!(div, options); } return gmaps.GMap(div, options); } @@ -142,10 +142,11 @@ class GoogleMapController { options = _applyInitialPosition(_initialCameraPosition, options); // Create the map... - _googleMap = _createMap(_div, options); + final map = _createMap(_div, options); + _googleMap = map; - _attachMapEvents(_googleMap); - _attachGeometryControllers(_googleMap); + _attachMapEvents(map); + _attachGeometryControllers(map); _renderInitialGeometry( markers: _markers, @@ -154,19 +155,21 @@ class GoogleMapController { polylines: _polylines, ); - _setTrafficLayer(_googleMap, _isTrafficLayerEnabled(_rawMapOptions)); + _setTrafficLayer(map, _isTrafficLayerEnabled(_rawMapOptions)); } // Funnels map gmap events into the plugin's stream controller. void _attachMapEvents(gmaps.GMap map) { map.onClick.listen((event) { + assert(event.latLng != null); _streamController.add( - MapTapEvent(_mapId, _gmLatLngToLatLng(event.latLng)), + MapTapEvent(_mapId, _gmLatLngToLatLng(event.latLng!)), ); }); map.onRightclick.listen((event) { + assert(event.latLng != null); _streamController.add( - MapLongPressEvent(_mapId, _gmLatLngToLatLng(event.latLng)), + MapLongPressEvent(_mapId, _gmLatLngToLatLng(event.latLng!)), ); }); map.onBoundsChanged.listen((event) { @@ -188,28 +191,47 @@ class GoogleMapController { void _attachGeometryControllers(gmaps.GMap map) { // Now we can add the initial geometry. // And bind the (ready) map instance to the other geometry controllers. - _circlesController.bindToMap(_mapId, map); - _polygonsController.bindToMap(_mapId, map); - _polylinesController.bindToMap(_mapId, map); - _markersController.bindToMap(_mapId, map); + // + // These controllers are either created in the constructor of this class, or + // overriden (for testing) by the [debugSetOverrides] method. They can't be + // null. + assert(_circlesController != null, + 'Cannot attach a map to a null CirclesController instance.'); + assert(_polygonsController != null, + 'Cannot attach a map to a null PolygonsController instance.'); + assert(_polylinesController != null, + 'Cannot attach a map to a null PolylinesController instance.'); + assert(_markersController != null, + 'Cannot attach a map to a null MarkersController instance.'); + + _circlesController!.bindToMap(_mapId, map); + _polygonsController!.bindToMap(_mapId, map); + _polylinesController!.bindToMap(_mapId, map); + _markersController!.bindToMap(_mapId, map); + _controllersBoundToMap = true; } // Renders the initial sets of geometry. void _renderInitialGeometry({ - Set markers, - Set circles, - Set polygons, - Set polylines, + Set markers = const {}, + Set circles = const {}, + Set polygons = const {}, + Set polylines = const {}, }) { assert( _controllersBoundToMap, 'Geometry controllers must be bound to a map before any geometry can ' + 'be added to them. Ensure _attachGeometryControllers is called first.'); - _markersController.addMarkers(markers); - _circlesController.addCircles(circles); - _polygonsController.addPolygons(polygons); - _polylinesController.addPolylines(polylines); + + // The above assert will only succeed if the controllers have been bound to a map + // in the [_attachGeometryControllers] method, which ensures that all these + // controllers below are *not* null. + + _markersController!.addMarkers(markers); + _circlesController!.addCircles(circles); + _polygonsController!.addPolygons(polygons); + _polylinesController!.addPolylines(polylines); } // Merges new options coming from the plugin into the _rawMapOptions map. @@ -227,10 +249,12 @@ class GoogleMapController { /// /// This method converts the map into the proper [gmaps.MapOptions] void updateRawOptions(Map optionsUpdate) { + assert(_googleMap != null, 'Cannot update options on a null map.'); + final newOptions = _mergeRawOptions(optionsUpdate); _setOptions(_rawOptionsToGmapsOptions(newOptions)); - _setTrafficLayer(_googleMap, _isTrafficLayerEnabled(newOptions)); + _setTrafficLayer(_googleMap!, _isTrafficLayerEnabled(newOptions)); } // Sets new [gmaps.MapOptions] on the wrapped map. @@ -241,11 +265,10 @@ class GoogleMapController { // Attaches/detaches a Traffic Layer on the passed `map` if `attach` is true/false. void _setTrafficLayer(gmaps.GMap map, bool attach) { if (attach && _trafficLayer == null) { - _trafficLayer = gmaps.TrafficLayer(); - _trafficLayer.set('map', map); + _trafficLayer = gmaps.TrafficLayer()..set('map', map); } if (!attach && _trafficLayer != null) { - _trafficLayer.set('map', null); + _trafficLayer!.set('map', null); _trafficLayer = null; } } @@ -255,35 +278,61 @@ class GoogleMapController { /// Returns the [LatLngBounds] of the current viewport. Future getVisibleRegion() async { - return _gmLatLngBoundsTolatLngBounds(await _googleMap.bounds); + assert(_googleMap != null, 'Cannot get the visible region of a null map.'); + + return _gmLatLngBoundsTolatLngBounds( + await _googleMap!.bounds ?? _nullGmapsLatLngBounds, + ); } /// Returns the [ScreenCoordinate] for a given viewport [LatLng]. Future getScreenCoordinate(LatLng latLng) async { + assert(_googleMap != null, + 'Cannot get the screen coordinates with a null map.'); + assert(_googleMap!.projection != null, + 'Cannot compute screen coordinate with a null map or projection.'); + final point = - _googleMap.projection.fromLatLngToPoint(_latLngToGmLatLng(latLng)); - return ScreenCoordinate(x: point.x, y: point.y); + _googleMap!.projection!.fromLatLngToPoint!(_latLngToGmLatLng(latLng))!; + + assert(point.x != null && point.y != null, + 'The x and y of a ScreenCoordinate cannot be null.'); + + return ScreenCoordinate(x: point.x!.toInt(), y: point.y!.toInt()); } /// Returns the [LatLng] for a `screenCoordinate` (in pixels) of the viewport. Future getLatLng(ScreenCoordinate screenCoordinate) async { + assert(_googleMap != null, + 'Cannot get the lat, lng of a screen coordinate with a null map.'); + final gmaps.LatLng latLng = - _pixelToLatLng(_googleMap, screenCoordinate.x, screenCoordinate.y); + _pixelToLatLng(_googleMap!, screenCoordinate.x, screenCoordinate.y); return _gmLatLngToLatLng(latLng); } /// Applies a `cameraUpdate` to the current viewport. Future moveCamera(CameraUpdate cameraUpdate) async { - return _applyCameraUpdate(_googleMap, cameraUpdate); + assert(_googleMap != null, 'Cannot update the camera of a null map.'); + + return _applyCameraUpdate(_googleMap!, cameraUpdate); } /// Returns the zoom level of the current viewport. - Future getZoomLevel() async => _googleMap.zoom.toDouble(); + Future getZoomLevel() async { + assert(_googleMap != null, 'Cannot get zoom level of a null map.'); + assert(_googleMap!.zoom != null, + 'Zoom level should not be null. Is the map correctly initialized?'); + + return _googleMap!.zoom!.toDouble(); + } // Geometry manipulation /// Applies [CircleUpdates] to the currently managed circles. void updateCircles(CircleUpdates updates) { + assert( + _circlesController != null, 'Cannot update circles after dispose().'); _circlesController?.addCircles(updates.circlesToAdd); _circlesController?.changeCircles(updates.circlesToChange); _circlesController?.removeCircles(updates.circleIdsToRemove); @@ -291,6 +340,8 @@ class GoogleMapController { /// Applies [PolygonUpdates] to the currently managed polygons. void updatePolygons(PolygonUpdates updates) { + assert( + _polygonsController != null, 'Cannot update polygons after dispose().'); _polygonsController?.addPolygons(updates.polygonsToAdd); _polygonsController?.changePolygons(updates.polygonsToChange); _polygonsController?.removePolygons(updates.polygonIdsToRemove); @@ -298,6 +349,8 @@ class GoogleMapController { /// Applies [PolylineUpdates] to the currently managed lines. void updatePolylines(PolylineUpdates updates) { + assert(_polylinesController != null, + 'Cannot update polylines after dispose().'); _polylinesController?.addPolylines(updates.polylinesToAdd); _polylinesController?.changePolylines(updates.polylinesToChange); _polylinesController?.removePolylines(updates.polylineIdsToRemove); @@ -305,6 +358,8 @@ class GoogleMapController { /// Applies [MarkerUpdates] to the currently managed markers. void updateMarkers(MarkerUpdates updates) { + assert( + _markersController != null, 'Cannot update markers after dispose().'); _markersController?.addMarkers(updates.markersToAdd); _markersController?.changeMarkers(updates.markersToChange); _markersController?.removeMarkers(updates.markerIdsToRemove); @@ -312,22 +367,29 @@ class GoogleMapController { /// Shows the [InfoWindow] of the marker identified by its [MarkerId]. void showInfoWindow(MarkerId markerId) { + assert(_markersController != null, + 'Cannot show infowindow of marker [${markerId.value}] after dispose().'); _markersController?.showMarkerInfoWindow(markerId); } /// Hides the [InfoWindow] of the marker identified by its [MarkerId]. void hideInfoWindow(MarkerId markerId) { + assert(_markersController != null, + 'Cannot hide infowindow of marker [${markerId.value}] after dispose().'); _markersController?.hideMarkerInfoWindow(markerId); } /// Returns true if the [InfoWindow] of the marker identified by [MarkerId] is shown. bool isInfoWindowShown(MarkerId markerId) { - return _markersController?.isInfoWindowShown(markerId); + return _markersController?.isInfoWindowShown(markerId) ?? false; } // Cleanup /// Disposes of this controller and its resources. + /// + /// You won't be able to call many of the methods on this controller after + /// calling `dispose`! void dispose() { _widget = null; _googleMap = null; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart index 5e95a538c07a..692917fef4da 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart @@ -45,7 +45,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future updateMapOptions( Map optionsUpdate, { - @required int mapId, + required int mapId, }) async { _map(mapId).updateRawOptions(optionsUpdate); } @@ -54,7 +54,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future updateMarkers( MarkerUpdates markerUpdates, { - @required int mapId, + required int mapId, }) async { _map(mapId).updateMarkers(markerUpdates); } @@ -63,7 +63,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future updatePolygons( PolygonUpdates polygonUpdates, { - @required int mapId, + required int mapId, }) async { _map(mapId).updatePolygons(polygonUpdates); } @@ -72,7 +72,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future updatePolylines( PolylineUpdates polylineUpdates, { - @required int mapId, + required int mapId, }) async { _map(mapId).updatePolylines(polylineUpdates); } @@ -81,15 +81,15 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future updateCircles( CircleUpdates circleUpdates, { - @required int mapId, + required int mapId, }) async { _map(mapId).updateCircles(circleUpdates); } @override Future updateTileOverlays({ - @required Set newTileOverlays, - @required int mapId, + required Set newTileOverlays, + required int mapId, }) async { return; // Noop for now! } @@ -97,7 +97,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future clearTileCache( TileOverlayId tileOverlayId, { - @required int mapId, + required int mapId, }) async { return; // Noop for now! } @@ -106,7 +106,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future animateCamera( CameraUpdate cameraUpdate, { - @required int mapId, + required int mapId, }) async { return moveCamera(cameraUpdate, mapId: mapId); } @@ -115,7 +115,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future moveCamera( CameraUpdate cameraUpdate, { - @required int mapId, + required int mapId, }) async { return _map(mapId).moveCamera(cameraUpdate); } @@ -128,8 +128,8 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { /// pass full styles. @override Future setMapStyle( - String mapStyle, { - @required int mapId, + String? mapStyle, { + required int mapId, }) async { _map(mapId).updateRawOptions({ 'styles': _mapStyles(mapStyle), @@ -139,7 +139,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { /// Returns the bounds of the current viewport. @override Future getVisibleRegion({ - @required int mapId, + required int mapId, }) { return _map(mapId).getVisibleRegion(); } @@ -148,7 +148,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future getScreenCoordinate( LatLng latLng, { - @required int mapId, + required int mapId, }) { return _map(mapId).getScreenCoordinate(latLng); } @@ -157,7 +157,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future getLatLng( ScreenCoordinate screenCoordinate, { - @required int mapId, + required int mapId, }) { return _map(mapId).getLatLng(screenCoordinate); } @@ -170,7 +170,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future showMarkerInfoWindow( MarkerId markerId, { - @required int mapId, + required int mapId, }) async { _map(mapId).showInfoWindow(markerId); } @@ -183,7 +183,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future hideMarkerInfoWindow( MarkerId markerId, { - @required int mapId, + required int mapId, }) async { _map(mapId).hideInfoWindow(markerId); } @@ -196,7 +196,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future isMarkerInfoWindowShown( MarkerId markerId, { - @required int mapId, + required int mapId, }) async { return _map(mapId).isInfoWindowShown(markerId); } @@ -204,7 +204,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { /// Returns the zoom level of the `mapId`. @override Future getZoomLevel({ - @required int mapId, + required int mapId, }) { return _map(mapId).getZoomLevel(); } @@ -213,64 +213,64 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { // into the plugin @override - Stream onCameraMoveStarted({@required int mapId}) { + Stream onCameraMoveStarted({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onCameraMove({@required int mapId}) { + Stream onCameraMove({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onCameraIdle({@required int mapId}) { + Stream onCameraIdle({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onMarkerTap({@required int mapId}) { + Stream onMarkerTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onInfoWindowTap({@required int mapId}) { + Stream onInfoWindowTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onMarkerDragEnd({@required int mapId}) { + Stream onMarkerDragEnd({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onPolylineTap({@required int mapId}) { + Stream onPolylineTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onPolygonTap({@required int mapId}) { + Stream onPolygonTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onCircleTap({@required int mapId}) { + Stream onCircleTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onTap({@required int mapId}) { + Stream onTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onLongPress({@required int mapId}) { + Stream onLongPress({required int mapId}) { return _events(mapId).whereType(); } /// Disposes of the current map. It can't be used afterwards! @override - void dispose({@required int mapId}) { - _map(mapId)?.dispose(); + void dispose({required int mapId}) { + _map(mapId).dispose(); _mapById.remove(mapId); } @@ -278,19 +278,16 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { Widget buildView( int creationId, PlatformViewCreatedCallback onPlatformViewCreated, { - @required CameraPosition initialCameraPosition, + required CameraPosition initialCameraPosition, Set markers = const {}, Set polygons = const {}, Set polylines = const {}, Set circles = const {}, Set tileOverlays = const {}, - Set> gestureRecognizers = + Set>? gestureRecognizers = const >{}, Map mapOptions = const {}, }) { - assert(creationId != null, - 'buildView needs a `_webOnlyMapCreationId` in its creationParams to prevent widget reloads in web.'); - // Bail fast if we've already rendered this map ID... if (_mapById[creationId]?.widget != null) { return _mapById[creationId].widget; @@ -314,6 +311,9 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { onPlatformViewCreated.call(creationId); - return mapController.widget; + assert(mapController.widget != null, + 'The widget of a GoogleMapController cannot be null before calling dispose on it.'); + + return mapController.widget!; } } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart index 62238fc2d86b..5b0169b565e5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart @@ -6,33 +6,35 @@ part of google_maps_flutter_web; /// The `MarkerController` class wraps a [gmaps.Marker], how it handles events, and its associated (optional) [gmaps.InfoWindow] widget. class MarkerController { - gmaps.Marker _marker; + gmaps.Marker? _marker; final bool _consumeTapEvents; - final gmaps.InfoWindow _infoWindow; + final gmaps.InfoWindow? _infoWindow; bool _infoWindowShown = false; /// Creates a `MarkerController`, which wraps a [gmaps.Marker] object, its `onTap`/`onDrag` behavior, and its associated [gmaps.InfoWindow]. MarkerController({ - @required gmaps.Marker marker, - gmaps.InfoWindow infoWindow, + required gmaps.Marker marker, + gmaps.InfoWindow? infoWindow, bool consumeTapEvents = false, - LatLngCallback onDragEnd, - ui.VoidCallback onTap, + LatLngCallback? onDragEnd, + ui.VoidCallback? onTap, }) : _marker = marker, _infoWindow = infoWindow, _consumeTapEvents = consumeTapEvents { if (onTap != null) { - _marker.onClick.listen((event) { + marker.onClick.listen((event) { onTap.call(); }); } if (onDragEnd != null) { - _marker.onDragend.listen((event) { - _marker.position = event.latLng; - onDragEnd.call(event.latLng); + marker.onDragend.listen((event) { + if (marker != null) { + marker.position = event.latLng; + } + onDragEnd.call(event.latLng ?? _nullGmapsLatLng); }); } } @@ -44,42 +46,54 @@ class MarkerController { bool get infoWindowShown => _infoWindowShown; /// Returns the [gmaps.Marker] associated to this controller. - gmaps.Marker get marker => _marker; + gmaps.Marker? get marker => _marker; /// Returns the [gmaps.InfoWindow] associated to the marker. @visibleForTesting - gmaps.InfoWindow get infoWindow => _infoWindow; + gmaps.InfoWindow? get infoWindow => _infoWindow; /// Updates the options of the wrapped [gmaps.Marker] object. + /// + /// This cannot be called after [remove]. void update( gmaps.MarkerOptions options, { - String newInfoWindowContent, + HtmlElement? newInfoWindowContent, }) { - _marker.options = options; + assert(_marker != null, 'Cannot `update` Marker after calling `remove`.'); + _marker!.options = options; if (_infoWindow != null && newInfoWindowContent != null) { - _infoWindow.content = newInfoWindowContent; + _infoWindow!.content = newInfoWindowContent; } } /// Disposes of the currently wrapped [gmaps.Marker]. void remove() { - _marker.visible = false; - _marker.map = null; - _marker = null; + if (_marker != null) { + _infoWindowShown = false; + _marker!.visible = false; + _marker!.map = null; + _marker = null; + } } /// Hide the associated [gmaps.InfoWindow]. + /// + /// This cannot be called after [remove]. void hideInfoWindow() { + assert(_marker != null, 'Cannot `hideInfoWindow` on a `remove`d Marker.'); if (_infoWindow != null) { - _infoWindow.close(); + _infoWindow!.close(); _infoWindowShown = false; } } /// Show the associated [gmaps.InfoWindow]. + /// + /// This cannot be called after [remove]. void showInfoWindow() { + assert(_marker != null, 'Cannot `showInfoWindow` on a `remove`d Marker.'); if (_infoWindow != null) { - _infoWindow.open(_marker.map, _marker); + _infoWindow!.open(_marker!.map, _marker); _infoWindowShown = true; } } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart index bc9827a20270..704577b6e3fb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart @@ -14,8 +14,8 @@ class MarkersController extends GeometryController { /// Initialize the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. MarkersController({ - @required StreamController stream, - }) : _streamController = stream, + required StreamController stream, + }) : _streamController = stream, _markerIdToController = Map(); /// Returns the cache of [MarkerController]s. Test only. @@ -26,7 +26,7 @@ class MarkersController extends GeometryController { /// /// Wraps each [Marker] into its corresponding [MarkerController]. void addMarkers(Set markersToAdd) { - markersToAdd?.forEach(_addMarker); + markersToAdd.forEach(_addMarker); } void _addMarker(Marker marker) { @@ -35,14 +35,15 @@ class MarkersController extends GeometryController { } final infoWindowOptions = _infoWindowOptionsFromMarker(marker); - gmaps.InfoWindow gmInfoWindow; + gmaps.InfoWindow? gmInfoWindow; if (infoWindowOptions != null) { gmInfoWindow = gmaps.InfoWindow(infoWindowOptions); // Google Maps' JS SDK does not have a click event on the InfoWindow, so // we make one... if (infoWindowOptions.content is HtmlElement) { - infoWindowOptions.content.onClick.listen((_) { + final content = infoWindowOptions.content as HtmlElement; + content.onClick.listen((_) { _onInfoWindowTap(marker.markerId); }); } @@ -70,11 +71,11 @@ class MarkersController extends GeometryController { /// Updates a set of [Marker] objects with new options. void changeMarkers(Set markersToChange) { - markersToChange?.forEach(_changeMarker); + markersToChange.forEach(_changeMarker); } void _changeMarker(Marker marker) { - MarkerController markerController = _markerIdToController[marker?.markerId]; + MarkerController? markerController = _markerIdToController[marker.markerId]; if (markerController != null) { final markerOptions = _markerOptionsFromMarker( marker, @@ -83,18 +84,18 @@ class MarkersController extends GeometryController { final infoWindow = _infoWindowOptionsFromMarker(marker); markerController.update( markerOptions, - newInfoWindowContent: infoWindow?.content, + newInfoWindowContent: infoWindow?.content as HtmlElement?, ); } } /// Removes a set of [MarkerId]s from the cache. void removeMarkers(Set markerIdsToRemove) { - markerIdsToRemove?.forEach(_removeMarker); + markerIdsToRemove.forEach(_removeMarker); } void _removeMarker(MarkerId markerId) { - final MarkerController markerController = _markerIdToController[markerId]; + final MarkerController? markerController = _markerIdToController[markerId]; markerController?.remove(); _markerIdToController.remove(markerId); } @@ -106,7 +107,7 @@ class MarkersController extends GeometryController { /// See also [hideMarkerInfoWindow] and [isInfoWindowShown]. void showMarkerInfoWindow(MarkerId markerId) { _hideAllMarkerInfoWindow(); - MarkerController markerController = _markerIdToController[markerId]; + MarkerController? markerController = _markerIdToController[markerId]; markerController?.showInfoWindow(); } @@ -114,7 +115,7 @@ class MarkersController extends GeometryController { /// /// See also [showMarkerInfoWindow] and [isInfoWindowShown]. void hideMarkerInfoWindow(MarkerId markerId) { - MarkerController markerController = _markerIdToController[markerId]; + MarkerController? markerController = _markerIdToController[markerId]; markerController?.hideInfoWindow(); } @@ -122,7 +123,7 @@ class MarkersController extends GeometryController { /// /// See also [showMarkerInfoWindow] and [hideMarkerInfoWindow]. bool isInfoWindowShown(MarkerId markerId) { - MarkerController markerController = _markerIdToController[markerId]; + MarkerController? markerController = _markerIdToController[markerId]; return markerController?.infoWindowShown ?? false; } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart index 4ce1f022e586..9921d2ff3876 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart @@ -6,15 +6,15 @@ part of google_maps_flutter_web; /// The `PolygonController` class wraps a [gmaps.Polygon] and its `onTap` behavior. class PolygonController { - gmaps.Polygon _polygon; + gmaps.Polygon? _polygon; final bool _consumeTapEvents; /// Creates a `PolygonController` that wraps a [gmaps.Polygon] object and its `onTap` behavior. PolygonController({ - @required gmaps.Polygon polygon, + required gmaps.Polygon polygon, bool consumeTapEvents = false, - ui.VoidCallback onTap, + ui.VoidCallback? onTap, }) : _polygon = polygon, _consumeTapEvents = consumeTapEvents { if (onTap != null) { @@ -26,20 +26,25 @@ class PolygonController { /// Returns the wrapped [gmaps.Polygon]. Only used for testing. @visibleForTesting - gmaps.Polygon get polygon => _polygon; + gmaps.Polygon? get polygon => _polygon; /// Returns `true` if this Controller will use its own `onTap` handler to consume events. bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Polygon] object. + /// + /// This cannot be called after [remove]. void update(gmaps.PolygonOptions options) { - _polygon.options = options; + assert(_polygon != null, 'Cannot `update` Polygon after calling `remove`.'); + _polygon!.options = options; } /// Disposes of the currently wrapped [gmaps.Polygon]. void remove() { - _polygon.visible = false; - _polygon.map = null; - _polygon = null; + if (_polygon != null) { + _polygon!.visible = false; + _polygon!.map = null; + _polygon = null; + } } } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart index 4671e6d77a87..ef51bd6043df 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart @@ -14,8 +14,8 @@ class PolygonsController extends GeometryController { /// Initializes the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. PolygonsController({ - @required StreamController stream, - }) : _streamController = stream, + required StreamController stream, + }) : _streamController = stream, _polygonIdToController = Map(); /// Returns the cache of [PolygonController]s. Test only. @@ -60,15 +60,15 @@ class PolygonsController extends GeometryController { } void _changePolygon(Polygon polygon) { - PolygonController polygonController = - _polygonIdToController[polygon?.polygonId]; + PolygonController? polygonController = + _polygonIdToController[polygon.polygonId]; polygonController?.update(_polygonOptionsFromPolygon(googleMap, polygon)); } /// Removes a set of [PolygonId]s from the cache. void removePolygons(Set polygonIdsToRemove) { - polygonIdsToRemove?.forEach((polygonId) { - final PolygonController polygonController = + polygonIdsToRemove.forEach((polygonId) { + final PolygonController? polygonController = _polygonIdToController[polygonId]; polygonController?.remove(); _polygonIdToController.remove(polygonId); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart index bf1dbb222555..eb4b6d88b503 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart @@ -6,15 +6,15 @@ part of google_maps_flutter_web; /// The `PolygonController` class wraps a [gmaps.Polyline] and its `onTap` behavior. class PolylineController { - gmaps.Polyline _polyline; + gmaps.Polyline? _polyline; final bool _consumeTapEvents; /// Creates a `PolylineController` that wraps a [gmaps.Polyline] object and its `onTap` behavior. PolylineController({ - @required gmaps.Polyline polyline, + required gmaps.Polyline polyline, bool consumeTapEvents = false, - ui.VoidCallback onTap, + ui.VoidCallback? onTap, }) : _polyline = polyline, _consumeTapEvents = consumeTapEvents { if (onTap != null) { @@ -26,20 +26,26 @@ class PolylineController { /// Returns the wrapped [gmaps.Polyline]. Only used for testing. @visibleForTesting - gmaps.Polyline get line => _polyline; + gmaps.Polyline? get line => _polyline; /// Returns `true` if this Controller will use its own `onTap` handler to consume events. bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Polyline] object. + /// + /// This cannot be called after [remove]. void update(gmaps.PolylineOptions options) { - _polyline.options = options; + assert( + _polyline != null, 'Cannot `update` Polyline after calling `remove`.'); + _polyline!.options = options; } /// Disposes of the currently wrapped [gmaps.Polyline]. void remove() { - _polyline.visible = false; - _polyline.map = null; - _polyline = null; + if (_polyline != null) { + _polyline!.visible = false; + _polyline!.map = null; + _polyline = null; + } } } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart index e91b82fd1947..184c0d954744 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart @@ -14,8 +14,8 @@ class PolylinesController extends GeometryController { /// Initializes the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. PolylinesController({ - @required StreamController stream, - }) : _streamController = stream, + required StreamController stream, + }) : _streamController = stream, _polylineIdToController = Map(); /// Returns the cache of [PolylineContrller]s. Test only. @@ -26,7 +26,7 @@ class PolylinesController extends GeometryController { /// /// Wraps each line into its corresponding [PolylineController]. void addPolylines(Set polylinesToAdd) { - polylinesToAdd?.forEach((polyline) { + polylinesToAdd.forEach((polyline) { _addPolyline(polyline); }); } @@ -50,22 +50,22 @@ class PolylinesController extends GeometryController { /// Updates a set of [Polyline] objects with new options. void changePolylines(Set polylinesToChange) { - polylinesToChange?.forEach((polylineToChange) { + polylinesToChange.forEach((polylineToChange) { _changePolyline(polylineToChange); }); } void _changePolyline(Polyline polyline) { - PolylineController polylineController = - _polylineIdToController[polyline?.polylineId]; + PolylineController? polylineController = + _polylineIdToController[polyline.polylineId]; polylineController ?.update(_polylineOptionsFromPolyline(googleMap, polyline)); } /// Removes a set of [PolylineId]s from the cache. void removePolylines(Set polylineIdsToRemove) { - polylineIdsToRemove?.forEach((polylineId) { - final PolylineController polylineController = + polylineIdsToRemove.forEach((polylineId) { + final PolylineController? polylineController = _polylineIdToController[polylineId]; polylineController?.remove(); _polylineIdToController.remove(polylineId); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart index 10b5199a894e..ff980eb4c34b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart @@ -17,10 +17,10 @@ typedef LatLngCallback = void Function(gmaps.LatLng latLng); /// instance and our internal `mapId` value. abstract class GeometryController { /// The GMap instance that this controller operates on. - gmaps.GMap googleMap; + late gmaps.GMap googleMap; /// The map ID for events. - int mapId; + late int mapId; /// Binds a `mapId` and the [gmaps.GMap] instance to this controller. void bindToMap(int mapId, gmaps.GMap googleMap) { diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index 22df1b24afe0..5312a56cd14a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.2.1 +version: 0.3.0 flutter: plugin: @@ -17,7 +17,7 @@ dependencies: sdk: flutter meta: ^1.3.0 google_maps_flutter_platform_interface: ^2.0.1 - google_maps: ^3.4.5 + google_maps: ^5.1.0 stream_transform: ^2.0.0 sanitize_html: ^2.0.0 @@ -27,5 +27,5 @@ dev_dependencies: pedantic: ^1.10.0 environment: - sdk: ">=2.3.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" flutter: ">=1.20.0" diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 56b05853fdcb..06566f059a54 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -59,7 +59,7 @@ fi for version in "${BUILD_MODES[@]}"; do echo "Building $version..." - (cd $REPO_DIR/all_plugins && flutter build $@ --$version --no-sound-null-safety) + (cd $REPO_DIR/all_plugins && flutter build $@ --$version) if [ $? -eq 0 ]; then echo "Successfully built $version all_plugins app." From 310fcc77f2fbca9c6f7293c728ba5fc075992995 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 1 Apr 2021 10:50:39 -0700 Subject: [PATCH 380/924] [google_maps_flutter] Fix NNBD migration mistake in example (#3768) --- .../google_maps_flutter/google_maps_flutter/CHANGELOG.md | 8 ++++++-- .../google_maps_flutter/example/lib/tile_overlay.dart | 6 +++--- .../google_maps_flutter/google_maps_flutter/pubspec.yaml | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index 141a096aee94..865d8f3e61ef 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,11 +1,15 @@ +## 2.0.3-dev + +* Fix incorrect typecast in TileOverlay example. + ## 2.0.2 -* Update flutter_plugin_android_lifecycle dependency to 2.0.1 to fix an R8 issue +* Update flutter\_plugin\_android\_lifecycle dependency to 2.0.1 to fix an R8 issue on some versions. ## 2.0.1 -* Update platform_plugin_interface version requirement. +* Update platform\_plugin\_interface version requirement. ## 2.0.0 diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart index a367511cb72f..1d6dd69c186b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/tile_overlay.dart @@ -67,8 +67,8 @@ class TileOverlayBodyState extends State { @override Widget build(BuildContext context) { - Set overlays = { - if (_tileOverlay != null) _tileOverlay, + Set overlays = { + if (_tileOverlay != null) _tileOverlay!, }; return Column( mainAxisSize: MainAxisSize.min, @@ -84,7 +84,7 @@ class TileOverlayBodyState extends State { target: LatLng(59.935460, 30.325177), zoom: 7.0, ), - tileOverlays: overlays as Set, + tileOverlays: overlays, onMapCreated: _onMapCreated, ), ), diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 5e73586e07e4..6cbd1fa1d781 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 2.0.2 +version: 2.0.3-dev dependencies: flutter: From 55b86008376a518b44da86618bd591709cff2ebd Mon Sep 17 00:00:00 2001 From: Ari Weiland Date: Thu, 1 Apr 2021 15:22:48 -0400 Subject: [PATCH 381/924] [webview_flutter] Fix scroll bar position for Android non-hybrid WebViews (#3765) --- packages/webview_flutter/CHANGELOG.md | 5 +++++ packages/webview_flutter/lib/src/webview_android.dart | 5 +---- packages/webview_flutter/pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index 6d2b4bb26815..b8e5e0bba5e0 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.3 + +* Fixes bug where scroll bars on the Android non-hybrid WebView are rendered on +the wrong side of the screen. + ## 2.0.2 * Fixes bug where text fields are hidden behind the keyboard diff --git a/packages/webview_flutter/lib/src/webview_android.dart b/packages/webview_flutter/lib/src/webview_android.dart index 8850c7977e9c..ca1440d69929 100644 --- a/packages/webview_flutter/lib/src/webview_android.dart +++ b/packages/webview_flutter/lib/src/webview_android.dart @@ -47,10 +47,7 @@ class AndroidWebView implements WebViewPlatform { id, webViewPlatformCallbacksHandler)); }, gestureRecognizers: gestureRecognizers, - // WebView content is not affected by the Android view's layout direction, - // we explicitly set it here so that the widget doesn't require an ambient - // directionality. - layoutDirection: TextDirection.rtl, + layoutDirection: Directionality.maybeOf(context) ?? TextDirection.rtl, creationParams: MethodChannelWebViewPlatform.creationParamsToMap(creationParams), creationParamsCodec: const StandardMessageCodec(), diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index 6ee9e119bd3a..a89ded4e9014 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter -version: 2.0.2 +version: 2.0.3 environment: sdk: ">=2.12.0-259.9.beta <3.0.0" From 8531d561469a9a6bc832a7f947856d74a7b3f03b Mon Sep 17 00:00:00 2001 From: Shail Patel Date: Thu, 1 Apr 2021 15:59:02 -0400 Subject: [PATCH 382/924] [video_player]Update README.me (#3713) --- packages/video_player/video_player/CHANGELOG.md | 4 ++++ packages/video_player/video_player/README.md | 2 +- packages/video_player/video_player/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 6b20fd964dec..d1482d628d6d 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.1 + +* Update example code in README to reflect API changes. + ## 2.1.0 * Add `httpHeaders` option to `VideoPlayerController.network` diff --git a/packages/video_player/video_player/README.md b/packages/video_player/video_player/README.md index 7e36008cbbc3..f1c959a945ba 100644 --- a/packages/video_player/video_player/README.md +++ b/packages/video_player/video_player/README.md @@ -92,7 +92,7 @@ class _VideoAppState extends State { title: 'Video Demo', home: Scaffold( body: Center( - child: _controller.value.initialized + child: _controller.value.isInitialized ? AspectRatio( aspectRatio: _controller.value.aspectRatio, child: VideoPlayer(_controller), diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index 0215ead855e7..77b562347dea 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -1,7 +1,7 @@ name: video_player description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. -version: 2.1.0 +version: 2.1.1 homepage: https://github.com/flutter/plugins/tree/master/packages/video_player/video_player flutter: From 76a417ca8456aba9d8781bb8bc6bc5b0cb219525 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 2 Apr 2021 12:53:05 -0700 Subject: [PATCH 383/924] [local_auth] Update Jetpack dependencies (#3786) The plugin was still using several beta version of Jetpack libraries from 2 years ago. Updates to the latest stable version of each. Fixes https://github.com/flutter/flutter/issues/52742 --- packages/local_auth/CHANGELOG.md | 4 ++++ packages/local_auth/android/build.gradle | 6 +++--- packages/local_auth/pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index 258144cd0daa..7e86672799e8 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.2 + +* Update Jetpack dependencies to latest stable versions. + ## 1.1.1 * Update flutter_plugin_android_lifecycle dependency to 2.0.1 to fix an R8 issue diff --git a/packages/local_auth/android/build.gradle b/packages/local_auth/android/build.gradle index ae8e6f2828a2..714ac63d5ca6 100644 --- a/packages/local_auth/android/build.gradle +++ b/packages/local_auth/android/build.gradle @@ -34,9 +34,9 @@ android { } dependencies { - api "androidx.core:core:1.1.0-beta01" - api "androidx.biometric:biometric:1.0.0-beta01" - api "androidx.fragment:fragment:1.1.0-alpha06" + api "androidx.core:core:1.3.2" + api "androidx.biometric:biometric:1.1.0" + api "androidx.fragment:fragment:1.3.2" androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:rules:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 76722c00a147..e9d406d891c5 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth description: Flutter plugin for Android and iOS devices to allow local authentication via fingerprint, touch ID, face ID, passcode, pin, or pattern. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 1.1.1 +version: 1.1.2 flutter: plugin: From 4322497bfbb13b8bff23e4d77854fa62ad2b18e7 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 5 Apr 2021 04:46:23 -0700 Subject: [PATCH 384/924] [google_maps_flutter] remove unnecessary test (#3787) --- .../test/android_google_map_test.dart | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart deleted file mode 100644 index 8ee845469e25..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter/test/android_google_map_test.dart +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2013 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. - -@TestOn('android') -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; - -import 'fake_maps_controllers.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - final FakePlatformViewsController fakePlatformViewsController = - FakePlatformViewsController(); - - setUpAll(() { - SystemChannels.platform_views.setMockMethodCallHandler( - fakePlatformViewsController.fakePlatformViewsMethodHandler); - }); - - setUp(() { - fakePlatformViewsController.reset(); - }); - - testWidgets('Can update liteModeEnabled', (WidgetTester tester) async { - await tester.pumpWidget( - const Directionality( - textDirection: TextDirection.ltr, - child: GoogleMap( - initialCameraPosition: CameraPosition(target: LatLng(10.0, 15.0)), - liteModeEnabled: false, - ), - ), - ); - - final FakePlatformGoogleMap platformGoogleMap = - fakePlatformViewsController.lastCreatedView!; - - expect(platformGoogleMap.liteModeEnabled, false); - - await tester.pumpWidget( - const Directionality( - textDirection: TextDirection.ltr, - child: GoogleMap( - initialCameraPosition: CameraPosition(target: LatLng(10.0, 15.0)), - liteModeEnabled: true, - ), - ), - ); - - expect(platformGoogleMap.liteModeEnabled, true); - }); -} From bd2dbb151ecf0e5b381bb6be954ed3accf01a0ae Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 5 Apr 2021 13:54:05 -0700 Subject: [PATCH 385/924] [tool] refactor publish plugin command (#3779) --- .../tool/lib/src/publish_plugin_command.dart | 92 +++++++++++-------- .../test/publish_plugin_command_test.dart | 8 +- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/script/tool/lib/src/publish_plugin_command.dart b/script/tool/lib/src/publish_plugin_command.dart index eb59091db34a..d00400294ab3 100644 --- a/script/tool/lib/src/publish_plugin_command.dart +++ b/script/tool/lib/src/publish_plugin_command.dart @@ -85,15 +85,24 @@ class PublishPluginCommand extends PluginCommand { final Print _print; final Stdin _stdin; // The directory of the actual package that we are publishing. - Directory _packageDir; StreamSubscription _stdinSubscription; @override Future run() async { checkSharding(); + final String package = argResults[_packageOption]; + if (package == null) { + _print( + 'Must specify a package to publish. See `plugin_tools help publish-plugin`.'); + throw ToolExit(1); + } + _print('Checking local repo...'); - _packageDir = _checkPackageDir(); - await _checkGitStatus(); + if (!await GitDir.isGitDir(packagesDir.path)) { + _print('$packagesDir is not a valid Git repository.'); + throw ToolExit(1); + } + final bool shouldPushTag = argResults[_pushTagsOption]; final String remote = argResults[_remoteOption]; String remoteUrl; @@ -102,23 +111,39 @@ class PublishPluginCommand extends PluginCommand { } _print('Local repo is ready!'); - await _publish(); - _print('Package published!'); - if (!argResults[_tagReleaseOption]) { - return await _finishSuccesfully(); + final Directory packageDir = _getPackageDir(package); + await _publishPlugin(packageDir: packageDir); + if (argResults[_tagReleaseOption] as bool) { + await _tagRelease( + packageDir: packageDir, + remote: remote, + remoteUrl: remoteUrl, + shouldPushTag: shouldPushTag); } + await _finishSuccesfully(); + } - _print('Tagging release...'); - final String tag = _getTag(); + Future _publishPlugin({@required Directory packageDir}) async { + await _checkGitStatus(packageDir); + await _publish(packageDir); + _print('Package published!'); + } + + Future _tagRelease( + {@required Directory packageDir, + @required String remote, + @required String remoteUrl, + @required bool shouldPushTag}) async { + final String tag = _getTag(packageDir); + _print('Tagging release $tag...'); await processRunner.runAndExitOnError('git', ['tag', tag], - workingDir: _packageDir); + workingDir: packageDir); if (!shouldPushTag) { - return await _finishSuccesfully(); + return; } _print('Pushing tag to $remote...'); await _pushTagToRemote(remote: remote, tag: tag, remoteUrl: remoteUrl); - await _finishSuccesfully(); } Future _finishSuccesfully() async { @@ -126,36 +151,28 @@ class PublishPluginCommand extends PluginCommand { _print('Done!'); } - Directory _checkPackageDir() { - final String package = argResults[_packageOption]; - if (package == null) { - _print( - 'Must specify a package to publish. See `plugin_tools help publish-plugin`.'); - throw ToolExit(1); - } - final Directory _packageDir = packagesDir.childDirectory(package); - if (!_packageDir.existsSync()) { - _print('${_packageDir.absolute.path} does not exist.'); + // Returns the packageDirectory based on the package name. + // Throws ToolExit if the `package` doesn't exist. + Directory _getPackageDir(String package) { + final Directory packageDir = packagesDir.childDirectory(package); + if (!packageDir.existsSync()) { + _print('${packageDir.absolute.path} does not exist.'); throw ToolExit(1); } - return _packageDir; + return packageDir; } - Future _checkGitStatus() async { - if (!await GitDir.isGitDir(packagesDir.path)) { - _print('$packagesDir is not a valid Git repository.'); - throw ToolExit(1); - } - + Future _checkGitStatus(Directory packageDir) async { final ProcessResult statusResult = await processRunner.runAndExitOnError( 'git', [ 'status', '--porcelain', '--ignored', - _packageDir.absolute.path + packageDir.absolute.path ], - workingDir: _packageDir); + workingDir: packageDir); + final String statusOutput = statusResult.stdout; if (statusOutput.isNotEmpty) { _print( @@ -169,17 +186,17 @@ class PublishPluginCommand extends PluginCommand { Future _verifyRemote(String remote) async { final ProcessResult remoteInfo = await processRunner.runAndExitOnError( 'git', ['remote', 'get-url', remote], - workingDir: _packageDir); + workingDir: packagesDir); return remoteInfo.stdout; } - Future _publish() async { + Future _publish(Directory packageDir) async { final List publishFlags = argResults[_pubFlagsOption]; _print( - 'Running `pub publish ${publishFlags.join(' ')}` in ${_packageDir.absolute.path}...\n'); + 'Running `pub publish ${publishFlags.join(' ')}` in ${packageDir.absolute.path}...\n'); final Process publish = await processRunner.start( 'flutter', ['pub', 'publish'] + publishFlags, - workingDirectory: _packageDir); + workingDirectory: packageDir); publish.stdout .transform(utf8.decoder) .listen((String data) => _print(data)); @@ -196,9 +213,9 @@ class PublishPluginCommand extends PluginCommand { } } - String _getTag() { + String _getTag(Directory packageDir) { final File pubspecFile = - fileSystem.file(p.join(_packageDir.path, 'pubspec.yaml')); + fileSystem.file(p.join(packageDir.path, 'pubspec.yaml')); final YamlMap pubspecYaml = loadYaml(pubspecFile.readAsStringSync()); final String name = pubspecYaml['name']; final String version = pubspecYaml['version']; @@ -220,7 +237,6 @@ class PublishPluginCommand extends PluginCommand { _print('Tag push canceled.'); throw ToolExit(1); } - await processRunner.runAndExitOnError('git', ['push', remote, tag], workingDir: packagesDir); } diff --git a/script/tool/test/publish_plugin_command_test.dart b/script/tool/test/publish_plugin_command_test.dart index 9a0f1d6b6e63..cfa40b9dc0a5 100644 --- a/script/tool/test/publish_plugin_command_test.dart +++ b/script/tool/test/publish_plugin_command_test.dart @@ -50,7 +50,7 @@ void main() { mockStdin = MockStdin(); commandRunner = CommandRunner('tester', '') ..addCommand(PublishPluginCommand( - mockPackagesDir, const LocalFileSystem(), + mockPackagesDir, mockPackagesDir.fileSystem, processRunner: processRunner, print: (Object message) => printedMessages.add(message.toString()), stdinput: mockStdin)); @@ -65,7 +65,6 @@ void main() { test('requires a package flag', () async { await expectLater(() => commandRunner.run(['publish-plugin']), throwsA(const TypeMatcher())); - expect( printedMessages.last, contains("Must specify a package to publish.")); }); @@ -73,7 +72,7 @@ void main() { test('requires an existing flag', () async { await expectLater( () => commandRunner - .run(['publish-plugin', '--package', 'iamerror']), + .run(['publish-plugin', '--package', 'iamerror', '--no-push-tags']), throwsA(const TypeMatcher())); expect(printedMessages.last, contains('iamerror does not exist')); @@ -84,7 +83,7 @@ void main() { await expectLater( () => commandRunner - .run(['publish-plugin', '--package', testPluginName]), + .run(['publish-plugin', '--package', testPluginName, '--no-push-tags']), throwsA(const TypeMatcher())); expect( @@ -98,7 +97,6 @@ void main() { () => commandRunner .run(['publish-plugin', '--package', testPluginName]), throwsA(const TypeMatcher())); - expect(processRunner.results.last.stderr, contains("No such remote")); }); From 00ec3cdccb3c39b86c033b0ab5748564001ab5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Kihlstr=C3=B6m?= Date: Mon, 5 Apr 2021 23:54:21 +0200 Subject: [PATCH 386/924] [google_maps_flutter] Reword README (#3784) --- packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md | 4 ++++ packages/google_maps_flutter/google_maps_flutter/README.md | 2 +- packages/google_maps_flutter/google_maps_flutter/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index 865d8f3e61ef..4ac4f2ad7749 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.4-dev + +* Fix english wording in instructions. + ## 2.0.3-dev * Fix incorrect typecast in TileOverlay example. diff --git a/packages/google_maps_flutter/google_maps_flutter/README.md b/packages/google_maps_flutter/google_maps_flutter/README.md index 6bb11a8da793..767ef8c1a561 100644 --- a/packages/google_maps_flutter/google_maps_flutter/README.md +++ b/packages/google_maps_flutter/google_maps_flutter/README.md @@ -21,7 +21,7 @@ To use this plugin, add `google_maps_flutter` as a [dependency in your pubspec.y * To enable Google Maps for iOS, select "Maps SDK for iOS" in the "Additional APIs" section, then select "ENABLE". * Make sure the APIs you enabled are under the "Enabled APIs" section. -* You can also find detailed steps to get start with Google Maps Platform [here](https://developers.google.com/maps/gmp-get-started). +For more details, see [Getting started with Google Maps Platform](https://developers.google.com/maps/gmp-get-started). ### Android diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 6cbd1fa1d781..f2484e84c180 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter -version: 2.0.3-dev +version: 2.0.4-dev dependencies: flutter: From 08f8f21e749256b02ee821a9a436b3827469ac39 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 5 Apr 2021 16:03:45 -0700 Subject: [PATCH 387/924] [local_auth] Fix callback thread handling (#3778) Ensure that all auth replies, which are sent on an internal framework queue per documentation, are dispatched back to the main thread for handling, as all resulting operations (method channel callbacks, display of UI) are things that must be done on the main thread In order to test this, sets up local_auth with XCTest-based tests, and adds the ability to inject a mock LAContext. (This does not do full unit test backfill, to limit the scope of the PR.) Fixes flutter/flutter#47465 --- packages/local_auth/CHANGELOG.md | 4 + packages/local_auth/example/ios/Podfile | 6 + .../ios/Runner.xcodeproj/project.pbxproj | 194 +++++++++++++++--- .../contents.xcworkspacedata | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../local_auth/example/ios/XCTests/Info.plist | 22 ++ .../ios/Classes/FLTLocalAuthPlugin.m | 112 +++++----- .../ios/Tests/FLTLocalAuthPluginTests.m | 189 +++++++++++++++++ packages/local_auth/pubspec.yaml | 2 +- 10 files changed, 472 insertions(+), 77 deletions(-) create mode 100644 packages/local_auth/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/local_auth/example/ios/XCTests/Info.plist create mode 100644 packages/local_auth/ios/Tests/FLTLocalAuthPluginTests.m diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index 7e86672799e8..429e217cc167 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.3 + +* Fix crashes due to threading issues in iOS implementation. + ## 1.1.2 * Update Jetpack dependencies to latest stable versions. diff --git a/packages/local_auth/example/ios/Podfile b/packages/local_auth/example/ios/Podfile index f7d6a5e68c3a..65497359e0a6 100644 --- a/packages/local_auth/example/ios/Podfile +++ b/packages/local_auth/example/ios/Podfile @@ -29,6 +29,12 @@ flutter_ios_podfile_setup target 'Runner' do flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + + target 'XCTests' do + inherit! :search_paths + + pod 'OCMock', '3.5' + end end post_install do |installer| diff --git a/packages/local_auth/example/ios/Runner.xcodeproj/project.pbxproj b/packages/local_auth/example/ios/Runner.xcodeproj/project.pbxproj index 8960fe4d8af3..708c643bdf28 100644 --- a/packages/local_auth/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/local_auth/example/ios/Runner.xcodeproj/project.pbxproj @@ -9,18 +9,26 @@ /* Begin PBXBuildFile section */ 0CCCD07A2CE24E13C9C1EEA4 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D274A3F79473B1549B2BBD5 /* libPods-Runner.a */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3398D2E426164AD8005A052F /* FLTLocalAuthPluginTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3398D2E326164AD8005A052F /* FLTLocalAuthPluginTests.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + D6C28B8B9E1BDEC22D03304F /* libPods-XCTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EB178B442E18480B8054307 /* libPods-XCTests.a */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 3398D2D226163948005A052F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -28,8 +36,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -39,15 +45,20 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3398D2CD26163948005A052F /* XCTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XCTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3398D2D126163948005A052F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 3398D2DC261649CD005A052F /* liblocal_auth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = liblocal_auth.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 3398D2DF26164A03005A052F /* liblocal_auth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = liblocal_auth.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 3398D2E326164AD8005A052F /* FLTLocalAuthPluginTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FLTLocalAuthPluginTests.m; path = ../../../ios/Tests/FLTLocalAuthPluginTests.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 4EB178B442E18480B8054307 /* libPods-XCTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-XCTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 658CDD04B21E4EA92F8EF229 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 81D8AFFB31AECDACBC5B11F8 /* Pods-XCTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XCTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-XCTests/Pods-XCTests.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -56,15 +67,22 @@ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9D274A3F79473B1549B2BBD5 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; EB36DF6C3F25E00DF4175422 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + F6BEBFD3433B1712765D62F7 /* Pods-XCTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XCTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-XCTests/Pods-XCTests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 3398D2CA26163948005A052F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D6C28B8B9E1BDEC22D03304F /* libPods-XCTests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 0CCCD07A2CE24E13C9C1EEA4 /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -72,12 +90,19 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 3398D2CE26163948005A052F /* XCTests */ = { + isa = PBXGroup; + children = ( + 3398D2E326164AD8005A052F /* FLTLocalAuthPluginTests.m */, + 3398D2D126163948005A052F /* Info.plist */, + ); + path = XCTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -90,6 +115,7 @@ children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, + 3398D2CE26163948005A052F /* XCTests */, 97C146EF1CF9000F007C117D /* Products */, F8CC53B854B121315C7319D2 /* Pods */, E2D5FA899A019BD3E0DB0917 /* Frameworks */, @@ -100,6 +126,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 3398D2CD26163948005A052F /* XCTests.xctest */, ); name = Products; sourceTree = ""; @@ -131,7 +158,10 @@ E2D5FA899A019BD3E0DB0917 /* Frameworks */ = { isa = PBXGroup; children = ( + 3398D2DF26164A03005A052F /* liblocal_auth.a */, + 3398D2DC261649CD005A052F /* liblocal_auth.a */, 9D274A3F79473B1549B2BBD5 /* libPods-Runner.a */, + 4EB178B442E18480B8054307 /* libPods-XCTests.a */, ); name = Frameworks; sourceTree = ""; @@ -141,6 +171,8 @@ children = ( EB36DF6C3F25E00DF4175422 /* Pods-Runner.debug.xcconfig */, 658CDD04B21E4EA92F8EF229 /* Pods-Runner.release.xcconfig */, + 81D8AFFB31AECDACBC5B11F8 /* Pods-XCTests.debug.xcconfig */, + F6BEBFD3433B1712765D62F7 /* Pods-XCTests.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -148,6 +180,25 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 3398D2CC26163948005A052F /* XCTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3398D2D426163948005A052F /* Build configuration list for PBXNativeTarget "XCTests" */; + buildPhases = ( + B5AF6C7A6759E6F38749E537 /* [CP] Check Pods Manifest.lock */, + 3398D2C926163948005A052F /* Sources */, + 3398D2CA26163948005A052F /* Frameworks */, + 3398D2CB26163948005A052F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 3398D2D326163948005A052F /* PBXTargetDependency */, + ); + name = XCTests; + productName = XCTests; + productReference = 3398D2CD26163948005A052F /* XCTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -159,7 +210,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 16CF73924D0A9C13B2100A83 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -179,6 +229,11 @@ LastUpgradeCheck = 1100; ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { + 3398D2CC26163948005A052F = { + CreatedOnToolsVersion = 12.4; + ProvisioningStyle = Automatic; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; }; @@ -198,11 +253,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 3398D2CC26163948005A052F /* XCTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 3398D2CB26163948005A052F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -217,61 +280,68 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 16CF73924D0A9C13B2100A83 /* [CP] Embed Pods Frameworks */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "[CP] Embed Pods Frameworks"; + name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Thin Binary"; + name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - 9740EEB61CF901F6004384FC /* Run Script */ = { + 98D96A2D1A74AF66E3DD2DBC /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); - name = "Run Script"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; - 98D96A2D1A74AF66E3DD2DBC /* [CP] Check Pods Manifest.lock */ = { + B5AF6C7A6759E6F38749E537 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-XCTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -281,6 +351,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 3398D2C926163948005A052F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3398D2E426164AD8005A052F /* FLTLocalAuthPluginTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -293,6 +371,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 3398D2D326163948005A052F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 3398D2D226163948005A052F /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -313,9 +399,55 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 3398D2D526163948005A052F /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 81D8AFFB31AECDACBC5B11F8 /* Pods-XCTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = XCTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.google.XCTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; + }; + name = Debug; + }; + 3398D2D626163948005A052F /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F6BEBFD3433B1712765D62F7 /* Pods-XCTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = XCTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.google.XCTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; + }; + name = Release; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -372,7 +504,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -466,6 +597,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 3398D2D426163948005A052F /* Build configuration list for PBXNativeTarget "XCTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3398D2D526163948005A052F /* Debug */, + 3398D2D626163948005A052F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/packages/local_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/local_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16ed0f..919434a6254f 100644 --- a/packages/local_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/packages/local_auth/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/packages/local_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/local_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 3bb3697ef41c..5b12c3ad032e 100644 --- a/packages/local_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/local_auth/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -37,6 +37,16 @@ + + + + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/local_auth/example/ios/XCTests/Info.plist b/packages/local_auth/example/ios/XCTests/Info.plist new file mode 100644 index 000000000000..64d65ca49577 --- /dev/null +++ b/packages/local_auth/example/ios/XCTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m index 40a14b9f4b47..a00c7eed2703 100644 --- a/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m +++ b/packages/local_auth/ios/Classes/FLTLocalAuthPlugin.m @@ -6,11 +6,17 @@ #import "FLTLocalAuthPlugin.h" @interface FLTLocalAuthPlugin () -@property(copy, nullable) NSDictionary *lastCallArgs; -@property(nullable) FlutterResult lastResult; +@property(nonatomic, copy, nullable) NSDictionary *lastCallArgs; +@property(nonatomic, nullable) FlutterResult lastResult; +// For unit tests to inject dummy LAContext instances that will be used when a new context would +// normally be created. Each call to createAuthContext will remove the current first element from +// the array. +- (void)setAuthContextOverrides:(NSArray *)authContexts; @end -@implementation FLTLocalAuthPlugin +@implementation FLTLocalAuthPlugin { + NSMutableArray *_authContextOverrides; +} + (void)registerWithRegistrar:(NSObject *)registrar { FlutterMethodChannel *channel = @@ -40,6 +46,19 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result #pragma mark Private Methods +- (void)setAuthContextOverrides:(NSArray *)authContexts { + _authContextOverrides = [authContexts mutableCopy]; +} + +- (LAContext *)createAuthContext { + if ([_authContextOverrides count] > 0) { + LAContext *context = [_authContextOverrides firstObject]; + [_authContextOverrides removeObjectAtIndex:0]; + return context; + } + return [[LAContext alloc] init]; +} + - (void)alertMessage:(NSString *)message firstButton:(NSString *)firstButton flutterResult:(FlutterResult)result @@ -75,7 +94,7 @@ - (void)alertMessage:(NSString *)message } - (void)getAvailableBiometrics:(FlutterResult)result { - LAContext *context = [[LAContext alloc] init]; + LAContext *context = self.createAuthContext; NSError *authError = nil; NSMutableArray *biometrics = [[NSMutableArray alloc] init]; if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics @@ -96,9 +115,10 @@ - (void)getAvailableBiometrics:(FlutterResult)result { } result(biometrics); } + - (void)authenticateWithBiometrics:(NSDictionary *)arguments withFlutterResult:(FlutterResult)result { - LAContext *context = [[LAContext alloc] init]; + LAContext *context = self.createAuthContext; NSError *authError = nil; self.lastCallArgs = nil; self.lastResult = nil; @@ -109,27 +129,12 @@ - (void)authenticateWithBiometrics:(NSDictionary *)arguments [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:arguments[@"localizedReason"] reply:^(BOOL success, NSError *error) { - if (success) { - result(@YES); - } else { - switch (error.code) { - case LAErrorPasscodeNotSet: - case LAErrorTouchIDNotAvailable: - case LAErrorTouchIDNotEnrolled: - case LAErrorTouchIDLockout: - [self handleErrors:error - flutterArguments:arguments - withFlutterResult:result]; - return; - case LAErrorSystemCancel: - if ([arguments[@"stickyAuth"] boolValue]) { - self.lastCallArgs = arguments; - self.lastResult = result; - return; - } - } - result(@NO); - } + dispatch_async(dispatch_get_main_queue(), ^{ + [self handleAuthReplyWithSuccess:success + error:error + flutterArguments:arguments + flutterResult:result]; + }); }]; } else { [self handleErrors:authError flutterArguments:arguments withFlutterResult:result]; @@ -137,7 +142,7 @@ - (void)authenticateWithBiometrics:(NSDictionary *)arguments } - (void)authenticate:(NSDictionary *)arguments withFlutterResult:(FlutterResult)result { - LAContext *context = [[LAContext alloc] init]; + LAContext *context = self.createAuthContext; NSError *authError = nil; _lastCallArgs = nil; _lastResult = nil; @@ -148,27 +153,12 @@ - (void)authenticate:(NSDictionary *)arguments withFlutterResult:(FlutterResult) [context evaluatePolicy:kLAPolicyDeviceOwnerAuthentication localizedReason:arguments[@"localizedReason"] reply:^(BOOL success, NSError *error) { - if (success) { - result(@YES); - } else { - switch (error.code) { - case LAErrorPasscodeNotSet: - case LAErrorTouchIDNotAvailable: - case LAErrorTouchIDNotEnrolled: - case LAErrorTouchIDLockout: - [self handleErrors:error - flutterArguments:arguments - withFlutterResult:result]; - return; - case LAErrorSystemCancel: - if ([arguments[@"stickyAuth"] boolValue]) { - self->_lastCallArgs = arguments; - self->_lastResult = result; - return; - } - } - result(@NO); - } + dispatch_async(dispatch_get_main_queue(), ^{ + [self handleAuthReplyWithSuccess:success + error:error + flutterArguments:arguments + flutterResult:result]; + }); }]; } else { [self handleErrors:authError flutterArguments:arguments withFlutterResult:result]; @@ -178,6 +168,32 @@ - (void)authenticate:(NSDictionary *)arguments withFlutterResult:(FlutterResult) } } +- (void)handleAuthReplyWithSuccess:(BOOL)success + error:(NSError *)error + flutterArguments:(NSDictionary *)arguments + flutterResult:(FlutterResult)result { + NSAssert([NSThread isMainThread], @"Response handling must be done on the main thread."); + if (success) { + result(@YES); + } else { + switch (error.code) { + case LAErrorPasscodeNotSet: + case LAErrorTouchIDNotAvailable: + case LAErrorTouchIDNotEnrolled: + case LAErrorTouchIDLockout: + [self handleErrors:error flutterArguments:arguments withFlutterResult:result]; + return; + case LAErrorSystemCancel: + if ([arguments[@"stickyAuth"] boolValue]) { + self->_lastCallArgs = arguments; + self->_lastResult = result; + return; + } + } + result(@NO); + } +} + - (void)handleErrors:(NSError *)authError flutterArguments:(NSDictionary *)arguments withFlutterResult:(FlutterResult)result { diff --git a/packages/local_auth/ios/Tests/FLTLocalAuthPluginTests.m b/packages/local_auth/ios/Tests/FLTLocalAuthPluginTests.m new file mode 100644 index 000000000000..97e78e2f624b --- /dev/null +++ b/packages/local_auth/ios/Tests/FLTLocalAuthPluginTests.m @@ -0,0 +1,189 @@ +// Copyright 2013 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 LocalAuthentication; +@import XCTest; + +#import + +#if __has_include() +#import +#else +@import local_auth; +#endif + +// Private API needed for tests. +@interface FLTLocalAuthPlugin (Test) +- (void)setAuthContextOverrides:(NSArray*)authContexts; +@end + +// Set a long timeout to avoid flake due to slow CI. +static const NSTimeInterval kTimeout = 30.0; + +@interface FLTLocalAuthPluginTests : XCTestCase +@end + +@implementation FLTLocalAuthPluginTests + +- (void)setUp { + self.continueAfterFailure = NO; +} + +- (void)testSuccessfullAuthWithBiometrics { + FLTLocalAuthPlugin* plugin = [[FLTLocalAuthPlugin alloc] init]; + id mockAuthContext = OCMClassMock([LAContext class]); + plugin.authContextOverrides = @[ mockAuthContext ]; + + const LAPolicy policy = LAPolicyDeviceOwnerAuthenticationWithBiometrics; + NSString* reason = @"a reason"; + OCMStub([mockAuthContext canEvaluatePolicy:policy error:[OCMArg setTo:nil]]).andReturn(YES); + + // evaluatePolicy:localizedReason:reply: calls back on an internal queue, which is not + // guaranteed to be on the main thread. Ensure that's handled correctly by calling back on + // a background thread. + void (^backgroundThreadReplyCaller)(NSInvocation*) = ^(NSInvocation* invocation) { + void (^reply)(BOOL, NSError*); + [invocation getArgument:&reply atIndex:4]; + dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{ + reply(YES, nil); + }); + }; + OCMStub([mockAuthContext evaluatePolicy:policy localizedReason:reason reply:[OCMArg any]]) + .andDo(backgroundThreadReplyCaller); + + FlutterMethodCall* call = [FlutterMethodCall methodCallWithMethodName:@"authenticate" + arguments:@{ + @"biometricOnly" : @(YES), + @"localizedReason" : reason, + }]; + + XCTestExpectation* expectation = [self expectationWithDescription:@"Result is called"]; + [plugin handleMethodCall:call + result:^(id _Nullable result) { + XCTAssertTrue([NSThread isMainThread]); + XCTAssertTrue([result isKindOfClass:[NSNumber class]]); + XCTAssertTrue([result boolValue]); + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kTimeout handler:nil]; +} + +- (void)testSuccessfullAuthWithoutBiometrics { + FLTLocalAuthPlugin* plugin = [[FLTLocalAuthPlugin alloc] init]; + id mockAuthContext = OCMClassMock([LAContext class]); + plugin.authContextOverrides = @[ mockAuthContext ]; + + const LAPolicy policy = LAPolicyDeviceOwnerAuthentication; + NSString* reason = @"a reason"; + OCMStub([mockAuthContext canEvaluatePolicy:policy error:[OCMArg setTo:nil]]).andReturn(YES); + + // evaluatePolicy:localizedReason:reply: calls back on an internal queue, which is not + // guaranteed to be on the main thread. Ensure that's handled correctly by calling back on + // a background thread. + void (^backgroundThreadReplyCaller)(NSInvocation*) = ^(NSInvocation* invocation) { + void (^reply)(BOOL, NSError*); + [invocation getArgument:&reply atIndex:4]; + dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{ + reply(YES, nil); + }); + }; + OCMStub([mockAuthContext evaluatePolicy:policy localizedReason:reason reply:[OCMArg any]]) + .andDo(backgroundThreadReplyCaller); + + FlutterMethodCall* call = [FlutterMethodCall methodCallWithMethodName:@"authenticate" + arguments:@{ + @"biometricOnly" : @(NO), + @"localizedReason" : reason, + }]; + + XCTestExpectation* expectation = [self expectationWithDescription:@"Result is called"]; + [plugin handleMethodCall:call + result:^(id _Nullable result) { + XCTAssertTrue([NSThread isMainThread]); + XCTAssertTrue([result isKindOfClass:[NSNumber class]]); + XCTAssertTrue([result boolValue]); + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kTimeout handler:nil]; +} + +- (void)testFailedAuthWithBiometrics { + FLTLocalAuthPlugin* plugin = [[FLTLocalAuthPlugin alloc] init]; + id mockAuthContext = OCMClassMock([LAContext class]); + plugin.authContextOverrides = @[ mockAuthContext ]; + + const LAPolicy policy = LAPolicyDeviceOwnerAuthenticationWithBiometrics; + NSString* reason = @"a reason"; + OCMStub([mockAuthContext canEvaluatePolicy:policy error:[OCMArg setTo:nil]]).andReturn(YES); + + // evaluatePolicy:localizedReason:reply: calls back on an internal queue, which is not + // guaranteed to be on the main thread. Ensure that's handled correctly by calling back on + // a background thread. + void (^backgroundThreadReplyCaller)(NSInvocation*) = ^(NSInvocation* invocation) { + void (^reply)(BOOL, NSError*); + [invocation getArgument:&reply atIndex:4]; + dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{ + reply(NO, [NSError errorWithDomain:@"error" code:99 userInfo:nil]); + }); + }; + OCMStub([mockAuthContext evaluatePolicy:policy localizedReason:reason reply:[OCMArg any]]) + .andDo(backgroundThreadReplyCaller); + + FlutterMethodCall* call = [FlutterMethodCall methodCallWithMethodName:@"authenticate" + arguments:@{ + @"biometricOnly" : @(YES), + @"localizedReason" : reason, + }]; + + XCTestExpectation* expectation = [self expectationWithDescription:@"Result is called"]; + [plugin handleMethodCall:call + result:^(id _Nullable result) { + XCTAssertTrue([NSThread isMainThread]); + XCTAssertTrue([result isKindOfClass:[NSNumber class]]); + XCTAssertFalse([result boolValue]); + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kTimeout handler:nil]; +} + +- (void)testFailedAuthWithoutBiometrics { + FLTLocalAuthPlugin* plugin = [[FLTLocalAuthPlugin alloc] init]; + id mockAuthContext = OCMClassMock([LAContext class]); + plugin.authContextOverrides = @[ mockAuthContext ]; + + const LAPolicy policy = LAPolicyDeviceOwnerAuthentication; + NSString* reason = @"a reason"; + OCMStub([mockAuthContext canEvaluatePolicy:policy error:[OCMArg setTo:nil]]).andReturn(YES); + + // evaluatePolicy:localizedReason:reply: calls back on an internal queue, which is not + // guaranteed to be on the main thread. Ensure that's handled correctly by calling back on + // a background thread. + void (^backgroundThreadReplyCaller)(NSInvocation*) = ^(NSInvocation* invocation) { + void (^reply)(BOOL, NSError*); + [invocation getArgument:&reply atIndex:4]; + dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{ + reply(NO, [NSError errorWithDomain:@"error" code:99 userInfo:nil]); + }); + }; + OCMStub([mockAuthContext evaluatePolicy:policy localizedReason:reason reply:[OCMArg any]]) + .andDo(backgroundThreadReplyCaller); + + FlutterMethodCall* call = [FlutterMethodCall methodCallWithMethodName:@"authenticate" + arguments:@{ + @"biometricOnly" : @(NO), + @"localizedReason" : reason, + }]; + + XCTestExpectation* expectation = [self expectationWithDescription:@"Result is called"]; + [plugin handleMethodCall:call + result:^(id _Nullable result) { + XCTAssertTrue([NSThread isMainThread]); + XCTAssertTrue([result isKindOfClass:[NSNumber class]]); + XCTAssertFalse([result boolValue]); + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kTimeout handler:nil]; +} + +@end diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index e9d406d891c5..5e2dbb4e6183 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth description: Flutter plugin for Android and iOS devices to allow local authentication via fingerprint, touch ID, face ID, passcode, pin, or pattern. homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 1.1.2 +version: 1.1.3 flutter: plugin: From 4bd178b9fd893140c1e982f07f96cd1485a1c89e Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 5 Apr 2021 17:34:03 -0700 Subject: [PATCH 388/924] [in_app_purchase] improve readme (#3731) --- .../in_app_purchase/CHANGELOG.md | 6 +- .../in_app_purchase/in_app_purchase/README.md | 254 +++++++++++------- .../in_app_purchase/doc/iap_android.gif | Bin 0 -> 427150 bytes .../in_app_purchase/doc/iap_ios.gif | Bin 0 -> 827439 bytes .../in_app_purchase/example/README.md | 3 +- .../in_app_purchase/pubspec.yaml | 2 +- 6 files changed, 166 insertions(+), 99 deletions(-) create mode 100644 packages/in_app_purchase/in_app_purchase/doc/iap_android.gif create mode 100644 packages/in_app_purchase/in_app_purchase/doc/iap_ios.gif diff --git a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md index 114f11aa89b3..beb4356dc398 100644 --- a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md @@ -1,10 +1,14 @@ +## 0.5.1+2 + +* Update README to provide a better instruction of the plugin. + ## 0.5.1+1 * Fix error message when trying to consume purchase on iOS. ## 0.5.1 -* [iOS] Introduce `SKPaymentQueueWrapper.presentCodeRedemptionSheet` +* [iOS] Introduce `SKPaymentQueueWrapper.presentCodeRedemptionSheet` ## 0.5.0 diff --git a/packages/in_app_purchase/in_app_purchase/README.md b/packages/in_app_purchase/in_app_purchase/README.md index 62adaa9b4dec..a51187e792ab 100644 --- a/packages/in_app_purchase/in_app_purchase/README.md +++ b/packages/in_app_purchase/in_app_purchase/README.md @@ -1,56 +1,74 @@ -# In App Purchase +A storefront-independent API for purchases in Flutter apps. -A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases -through the App Store (on iOS) and Google Play (on Android). + + +This plugin supports in-app purchases (_IAP_) through an _underlying store_, +which can be the App Store (on iOS) or Google Play (on Android). + +> This plugin is in beta. Use it with caution and +> [file any potential issues you see](https://github.com/flutter/flutter/issues/new/choose). + +

+ An animated image of the iOS in-app purchase UI +      + An animated image of the Android in-app purchase UI +

## Features -Add this to your Flutter app to: +Use this plugin in your Flutter app to: -1. Show in app products that are available for sale from the underlying shop. - Includes consumables, permanent upgrades, and subscriptions. -2. Load in app products currently owned by the user according to the underlying - shop. -3. Send your user to the underlying store to purchase your products. +* Show in-app products that are available for sale from the underlying store. + Products can include consumables, permanent upgrades, and subscriptions. +* Load in-app products that the user owns. +* Send the user to the underlying store to purchase products. +* Present a UI for redeeming subscription offer codes. (iOS 14 only) -## Getting Started +## Getting started -This plugin is in beta. Please use with caution and file any potential issues -you see on our [issue tracker](https://github.com/flutter/flutter/issues/new/choose). +This plugin relies on the App Store and Google Play for making in-app purchases. +It exposes a unified surface, but you still need to understand and configure +your app with each store. Both stores have extensive guides: -This plugin relies on the App Store and Google Play for making in app purchases. -It exposes a unified surface, but you'll still need to understand and configure -your app with each store to handle purchases using them. Both have extensive -guides: +* [App Store documentation](https://developer.apple.com/in-app-purchase/) +* [Google Play documentation](https://developer.android.com/google/play/billing/billing_overview) -* [In-App Purchase (App Store)](https://developer.apple.com/in-app-purchase/) -* [Google Play Billing Overview](https://developer.android.com/google/play/billing/billing_overview) +For a list of steps for configuring in-app purchases in both stores, see the +[example app README](https://github.com/flutter/plugins/blob/master/packages/in_app_purchase/in_app_purchase/example/README.md). -You can check out the [example app README](https://github.com/flutter/plugins/blob/master/packages/in_app_purchase/example/README.md) for steps on how -to configure in app purchases in both stores. +Once you've configured your in-app purchases in their respective stores, you +can start using the plugin. Two basic options are available: -Once you've configured your in app purchases in their respective stores, you're -able to start using the plugin. There's two basic options available to you to -use. +1. A generic, idiomatic Flutter API: [in_app_purchase](https://pub.dev/documentation/in_app_purchase/latest/in_app_purchase/in_app_purchase-library.html). + This API supports most use cases for loading and making purchases. -1. [in_app_purchase.dart](https://github.com/flutter/plugins/tree/master/packages/in_app_purchase/lib/src/in_app_purchase), - the generic idiomatic Flutter API. This exposes the most basic IAP-related - functionality. The goal is that Flutter apps should be able to use this API - surface on its own for the vast majority of cases. If you use this you should - be able to handle most use cases for loading and making purchases. If you would - like a more platform dependent approach, we also provide the second option as - below. +2. Platform-specific Dart APIs: [store_kit_wrappers](https://pub.dev/documentation/in_app_purchase/latest/store_kit_wrappers/store_kit_wrappers-library.html) + and [billing_client_wrappers](https://pub.dev/documentation/in_app_purchase/latest/billing_client_wrappers/billing_client_wrappers-library.html). + These APIs expose platform-specific behavior and allow for more fine-tuned + control when needed. However, if you use one of these APIs, your + purchase-handling logic is significantly different for the different + storefronts. -2. Dart APIs exposing the underlying platform APIs as directly as possible: - [store_kit_wrappers.dart](https://github.com/flutter/plugins/blob/master/packages/in_app_purchase/lib/src/store_kit_wrappers) and - [billing_client_wrappers.dart](https://github.com/flutter/plugins/blob/master/packages/in_app_purchase/lib/src/billing_client_wrappers). These - API surfaces should expose all the platform-specific behavior and allow for - more fine-tuned control when needed. However if you use this you'll need to - code your purchase handling logic significantly differently depending on - which platform you're on. +## Usage + +This section has examples of code for the following tasks: + +* [Initializing the plugin](#initializing-the-plugin) +* [Listening to purchase updates](#listening-to-purchase-updates) +* [Connecting to the underlying store](#connecting-to-the-underlying-store) +* [Loading products for sale](#loading-products-for-sale) +* [Loading previous purchases](#loading-previous-purchases) +* [Making a purchase](#making-a-purchase) +* [Completing a purchase](#completing-a-purchase) +* [Upgrading or downgrading an existing in-app subscription](#upgrading-or-downgrading-an-existing-in-app-subscription) +* [Presenting a code redemption sheet (iOS 14)](#presenting-a-code-redemption-sheet-ios-14) ### Initializing the plugin +The following initialization code is required for Google Play: + ```dart void main() { // Inform the plugin that this app supports pending purchases on Android. @@ -59,24 +77,32 @@ void main() { // // On iOS this is a no-op. InAppPurchaseConnection.enablePendingPurchases(); - runApp(MyApp()); } ``` +### Listening to purchase updates + +In your app's `initState` method, subscribe to any incoming purchases. These +can propagate from either underlying store. +You should always start listening to purchase update as early as possible to be able +to catch all purchase updates, including the ones from the previous app session. +To listen to the update: + ```dart -// Subscribe to any incoming purchases at app initialization. These can -// propagate from either storefront so it's important to listen as soon as -// possible to avoid losing events. class _MyAppState extends State { StreamSubscription> _subscription; @override void initState() { - final Stream purchaseUpdates = + final Stream purchaseUpdated = InAppPurchaseConnection.instance.purchaseUpdatedStream; - _subscription = purchaseUpdates.listen((purchases) { - _handlePurchaseUpdates(purchases); + _subscription = purchaseUpdated.listen((purchaseDetailsList) { + _listenToPurchaseUpdated(purchaseDetailsList); + }, onDone: () { + _subscription.cancel(); + }, onError: (error) { + // handle error here. }); super.initState(); } @@ -88,7 +114,35 @@ class _MyAppState extends State { } ``` -### Connecting to the Storefront +Here is an example of how to handle purchase updates: + +```dart +void _listenToPurchaseUpdated(List purchaseDetailsList) { + purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async { + if (purchaseDetails.status == PurchaseStatus.pending) { + _showPendingUI(); + } else { + if (purchaseDetails.status == PurchaseStatus.error) { + _handleError(purchaseDetails.error!); + } else if (purchaseDetails.status == PurchaseStatus.purchased) { + bool valid = await _verifyPurchase(purchaseDetails); + if (valid) { + _deliverProduct(purchaseDetails); + } else { + _handleInvalidPurchase(purchaseDetails); + return; + } + } + if (purchaseDetails.pendingCompletePurchase) { + await InAppPurchaseConnection.instance + .completePurchase(purchaseDetails); + } + } + }); +} +``` + +### Connecting to the underlying store ```dart final bool available = await InAppPurchaseConnection.instance.isAvailable(); @@ -100,30 +154,41 @@ if (!available) { ### Loading products for sale ```dart -// Set literals require Dart 2.2. Alternatively, use `Set _kIds = ['product1', 'product2'].toSet()`. -const Set _kIds = {'product1', 'product2'}; -final ProductDetailsResponse response = await InAppPurchaseConnection.instance.queryProductDetails(_kIds); +// Set literals require Dart 2.2. Alternatively, use +// `Set _kIds = ['product1', 'product2'].toSet()`. +const Set _kIds = {'product1', 'product2'}; +final ProductDetailsResponse response = + await InAppPurchaseConnection.instance.queryProductDetails(_kIds); if (response.notFoundIDs.isNotEmpty) { - // Handle the error. + // Handle the error. } List products = response.productDetails; ``` ### Loading previous purchases +In the following example, implement `_verifyPurchase` so that it verifies the +purchase following the best practices for each underlying store: + +* [Verifying App Store purchases](https://developer.apple.com/documentation/storekit/in-app_purchase/validating_receipts_with_the_app_store) +* [Verifying Google Play purchases](https://developer.android.com/google/play/billing/security#verify) + + ```dart -final QueryPurchaseDetailsResponse response = await InAppPurchaseConnection.instance.queryPastPurchases(); +final QueryPurchaseDetailsResponse response = + await InAppPurchaseConnection.instance.queryPastPurchases(); if (response.error != null) { - // Handle the error. + // Handle the error. } for (PurchaseDetails purchase in response.pastPurchases) { - _verifyPurchase(purchase); // Verify the purchase following the best practices for each storefront. - _deliverPurchase(purchase); // Deliver the purchase to the user in your app. - if (Platform.isIOS) { - // Mark that you've delivered the purchase. Only the App Store requires - // this final confirmation. - InAppPurchaseConnection.instance.completePurchase(purchase); - } + // Verify the purchase following best practices for each underlying store. + _verifyPurchase(purchase); + // Deliver the purchase to the user in your app. + _deliverPurchase(purchase); + if (purchase.pendingCompletePurchase) { + // Mark that you've delivered the purchase. This is mandatory. + InAppPurchaseConnection.instance.completePurchase(purchase); + } } ``` @@ -133,27 +198,9 @@ once they're marked as consumed and fails to return them here. For restoring these across devices you'll need to persist them on your own server and query that as well. -### Listening to purchase updates - -You should always start listening to purchase update as early as possible to be able -to catch all purchase updates, including the ones from the previous app session. -To listen to the update: - -```dart - Stream purchaseUpdated = - InAppPurchaseConnection.instance.purchaseUpdatedStream; - _subscription = purchaseUpdated.listen((purchaseDetailsList) { - _listenToPurchaseUpdated(purchaseDetailsList); - }, onDone: () { - _subscription.cancel(); - }, onError: (error) { - // handle error here. - }); -``` - ### Making a purchase -Both storefronts handle consumable and non-consumable products differently. If +Both underlying stores handle consumable and non-consumable products differently. If you're using `InAppPurchaseConnection`, you need to make a distinction here and call the right purchase method for each type. @@ -161,35 +208,39 @@ call the right purchase method for each type. final ProductDetails productDetails = ... // Saved earlier from queryPastPurchases(). final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails); if (_isConsumable(productDetails)) { - InAppPurchaseConnection.instance.buyConsumable(purchaseParam: purchaseParam); + InAppPurchaseConnection.instance.buyConsumable(purchaseParam: purchaseParam); } else { - InAppPurchaseConnection.instance.buyNonConsumable(purchaseParam: purchaseParam); + InAppPurchaseConnection.instance.buyNonConsumable(purchaseParam: purchaseParam); } -// From here the purchase flow will be handled by the underlying storefront. +// From here the purchase flow will be handled by the underlying store. // Updates will be delivered to the `InAppPurchaseConnection.instance.purchaseUpdatedStream`. ``` -### Complete a purchase +### Completing a purchase The `InAppPurchaseConnection.purchaseUpdatedStream` will send purchase updates after you initiate the purchase flow using `InAppPurchaseConnection.buyConsumable` or `InAppPurchaseConnection.buyNonConsumable`. -After delivering the content to the user, you need to call `InAppPurchaseConnection.completePurchase` to tell the `GooglePlay` -and `AppStore` that the purchase has been finished. +After delivering the content to the user, call +`InAppPurchaseConnection.completePurchase` to tell the App Store and +Google Play that the purchase has been finished. -WARNING! Failure to call `InAppPurchaseConnection.completePurchase` and get a successful response within 3 days of the purchase will result a refund. +> **Warning:** Failure to call `InAppPurchaseConnection.completePurchase` and +> get a successful response within 3 days of the purchase will result a refund. -### Upgrading or Downgrading an existing InApp Subscription +### Upgrading or downgrading an existing in-app subscription -In order to upgrade/downgrade an existing InApp subscription on `PlayStore`, -you need to provide an instance of `ChangeSubscriptionParam` with the old -`PurchaseDetails` that the user needs to migrate from, and an optional `ProrationMode` -with the `PurchaseParam` object while calling `InAppPurchaseConnection.buyNonConsumable`. -`AppStore` does not require this since they provides a subscription grouping mechanism. -Each subscription you offer must be assigned to a subscription group. -So the developers can group related subscriptions together to prevents users from -accidentally purchasing multiple subscriptions. -Please refer to the 'Creating a Subscription Group' sections of [Apple's subscription guide](https://developer.apple.com/app-store/subscriptions/) +To upgrade/downgrade an existing in-app subscription in Google Play, +you need to provide an instance of `ChangeSubscriptionParam` with the old +`PurchaseDetails` that the user needs to migrate from, and an optional +`ProrationMode` with the `PurchaseParam` object while calling +`InAppPurchaseConnection.buyNonConsumable`. +The App Store does not require this because it provides a subscription +grouping mechanism. Each subscription you offer must be assigned to a +subscription group. Grouping related subscriptions together can help prevent +users from accidentally purchasing multiple subscriptions. Refer to the +[Creating a Subscription Group](https://developer.apple.com/app-store/subscriptions/#groups) section of +[Apple's subscription guide](https://developer.apple.com/app-store/subscriptions/). ```dart final PurchaseDetails oldPurchaseDetails = ...; @@ -202,7 +253,17 @@ InAppPurchaseConnection.instance .buyNonConsumable(purchaseParam: purchaseParam); ``` -## Development +### Presenting a code redemption sheet (iOS 14) + +The following code brings up a sheet that enables the user to redeem offer +codes that you've set up in App Store Connect. For more information on +redeeming offer codes, see [Implementing Offer Codes in Your App](https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/implementing_offer_codes_in_your_app). + +```dart +InAppPurchaseConnection.instance.presentCodeRedemptionSheet(); +``` + +## Contributing to this plugin This plugin uses [json_serializable](https://pub.dev/packages/json_serializable) for the @@ -211,3 +272,6 @@ editing any of the serialized data structs, rebuild the serializers by running `flutter packages pub run build_runner build --delete-conflicting-outputs`. `flutter packages pub run build_runner watch --delete-conflicting-outputs` will watch the filesystem for changes. + +If you would like to contribute to the plugin, check out our +[contribution guide](https://github.com/flutter/plugins/blob/master/CONTRIBUTING.md). diff --git a/packages/in_app_purchase/in_app_purchase/doc/iap_android.gif b/packages/in_app_purchase/in_app_purchase/doc/iap_android.gif new file mode 100644 index 0000000000000000000000000000000000000000..86348e4f629420294ac49a6b67c14515325b657a GIT binary patch literal 427150 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%0AhgL5b7zl_E!uL=esAUXlOmm-5VG4g82AP}^C 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

W3WSDh8L@!Jao|KkjPL!B zBmJrQJtn8IN69m01BWn|x^a8xs7!3bg}rUxrQ6gtAJbutln!_Z@*Zl7!j-AJOS#8v zn&DgU2rAd}qcZH(F5cP>xE{{^Q%yh|9=Ib8M5s4dg?oc!y z-ud0LOXlXg*By~UV~}N}E~mdkFL%hFzgHO{z5?Ok9kj;+;@EICLd^4cL=5`$h%$^x zfDQZems!BC?nW$^BCetzN?9PD${beuVSQZl#vRN(B5+%N>6Y69hNDGyvSG5Wc%#nU%ydmao%H~Arqw;`++>T`mlZtFUnvGxchz{C<_ zqPBU&jdjd#tj^5I&d!aZo_Wl^{|t>#F%coR^pR3GqD{7*c_6^o8xN38r z%G@55eKRbFdiEwWvP1K!pZJ_4>WaVGm8F%+o~laRS&ER+^CZ{jyKYzREPNjRpwi%t z^WLA&r6lJ~W{F0g^W^Y(%UPz`jd}mFdE48`;m9gh*)wM~>OI|*-4C8{5KnJe#@fAk zR$_jwy{yMWni6PR9rPWph4g61Jgwu}V|(Llb!J2(=SEha>v#}Ep}Y?G8oQMYAq*bd zkQ`MZvxQgme?mNp`;OE;yfK8giE51Sl;R0}rlfo7O4c5H(#`^sJh%E&EL~e=! z=hWoEW`X;F90wc^4k5xQ z0R2Vfw9<>8Lhx&>+l3Ya_MB_!Wd1M?@@gU?jl;)1a#8C_Mx*K_2APMH_z$@t3l0eF zWg%D7PVeQb9S;#Gidk%6BVy44IXtW(B!Ef)GeUVgaUhciL+TRpw~}G|zxdF}Au1bl z1vK(P${I=gN&5$J&Rk{PQV#i2Cig~D+Dtn{6}Jpsjh)ClQ(fjVr`r`L?V&9!@Sy#} zPJ?Q#_Ub#WpIW{xoG^-0Rl7A?R;I@xxBI1KxV+Q*>E@pHtmIqiTcr>L-SpK9F-fTgbwWUj*-`qqQVh~`^Y>0|4gR)+M@2%JR-6+jzI^gio3 zoG7f%j99+<@s_xZQS{F>5?y5sA+uNK*IJC{`&lyDX;bMtd=Kau#X9b|B65p~k0y-q zV+KSE45^=2=RolL(&{v@yz60AmO{aM)L`9Izg&CieF z@)h?VX2==R(0w$qb0~S^Flg=9tviSlhF5<=73RZlAJX$Cces~4TV4?0AheC@uI<(sxd5?ob7w-<= z%0P<8#Ina^u<}JfG+(XUi3@e3`^GkRDk1Hfp-h0`l;@p*AAi<^w2oaf)zm{%A@O*e9Y}k+_tDlmDM!l_=R5hN zKvhjX_f6IH7ITanzUJlE8x0!`EuWY3=%vCDy@S}6itRpmbt}oVumw)Kr>vHuck_-zCE%(2PRy&#vi;n^U*inJ4SItp}P%Oe<$9 zeVIOb=aZvH#N$tm4Yo6xk)F{@sdwCCK0Jtg67g=~ix&kFG2%rP*tOCGGyK_bhFngv(Rb{#|?KG7b@4o?LW}I6a$Gbmp{w_%>z! zYYqugarpwpD5Oc!3{F?Sp*XNw8jb+Gd!q&b*%5xk)VUilZ zSqk2^M==|(=<+voGsg^D|L71fe%WxI*uH7PvIjPsjyH8WMNLJ?sfH zQ@c8yN!}f&cV__Cf1F{3=%QxbC%!96$6IxoNw`hqz-UgGhtD&NQ*P2xE*f1zb~Bs$ zy%R1*M@hF>C%Y40-iV%}iQ=lbNEpU%r z^5dWj)#WOE0ekK$N$r?;QTGu_QUObtkC5(Gark!Bc4;7M_?vJ$Auv%D^|Im#FAKJ8 z(4H}@%V0_&_#G%`U7nhArNlx;MJ;G0-Sz4__8Z&>1|XHrc&9d)PjHAgBo!&-$@Cr@ z8-Sl{?1NL$;*pk8VygL9jiWi;D5y3a`FO!5}?8v*GxSRIFBvNbflV#)afDW8oN5Pnf-}QVV{i9!^9=mDzEXVgK9XpX4<36wK+&1iY z>{P*b_eInuCAD-gd0ULavcL27#|y_IJHLCZCOCIIS2})rRDHH#mzbw#S#ZqEch9wc z=Nli&j-OeH@mhc3eDnLvThIQ(TYmD9xDe$~s*wBKJ`$+j@Z2%F>^d2-pVWQZBQ#z! z)>|-u)U)|TXyWet^3A1#JzJGeB-x})@>h`h`clWmprMdmwWNNGC+?uzH@bwz9AB}l zG|J3+aP~9LS3shz0ZfR|SaXZsMk`g^GsO4F3t}^mkrQIe_$k4^4(-p{8MaUqT0yKEsj zd6!KXyBGe9U#uX|z#OTNQS8%xBcCKgD8@8m7c+{>@mEs0!Oc@$4;%qqGqq4SU4{zg zBm$boLay_rBnFrSoh%$4$lp@dqB*0x{PYXkd&*+>nZ|TKFwyByG6~Nr3 zeGDD@p*FOUhLCYD){bVGVJUJ6_#8QjthpXd4Q~N`889jk->V7rPBKJyi+?+U)Ri-~ z-mfenZ@Af5!{7r$m!pg35JY8nUMg%e3p}P$`9(Ug_pJR5M)>Cqh(>Fa174oZZ z`X*(p-K{iU%zm1?HB4Su$OsuV}g(dPy^-C-aD@{`{pq9j3c#QZ)AL*tc$q7c?`LF%$bxAhp-b%-YO6wunAp zY8cyti#6NBFg?I9!&dj|gqc~-OWI7EC0{i?q?l_f*f%3(ZvRov!Jv;0GIuJKw+iXA zk2NQmnY-loIa!;#nMt}&7h^~IVypT>?ruN$!F(EQ;o4Rb#e{=MkWG5&o{ARtGR~{# zfBR;M{b=w(figeF~neh3@dRTXa6Z{@ap|rF@rsCli)NA5FSX`%G^)62rn?UjEwEu zc$;n+7TaJ9ScWb42PpPG$$+22P<&Gor5351TdBT{79cj<|JnfKqWPxl{ipE7GUWZ01`5T{B)LUURfuI6)xuqyBu&ZX86>I1!$4#eQ~7HdW1!?1_h2p zPg$@&juds6-C6~`qtX@i2K#(%#;vm)WrSA7@(1!q2ce_B-exn_Hl6D>8*`Z3XS~gy zUF`QTu$|YjSeU*zA7cB+*LKm}b~fKuC&qSZ-TJ}E?IlNkQ>Nw{=&e`pL8gyI3-u0t zv_AC7{m|!-LtkPKt)(3Lnt$k9&7rT;8Lsc8qN@0RE+5)hKLiL7K(Yj|CIMndfZ7mX z9%Fa{uA>30$|Ud?5RkP5flh+pC_!k3fLb94{~(}$jBO~GiE7%38QNiN?8H6nB#zo` zI%6l9YA01-CtYi|xzkQ&)J}HBPHx3+%MUxOkiERDy@ICwueBI9_DUZ1%17(agrt+{4l0sN?=Kj+Uv82MQdm zY8?-DI$Do9+RQlGt~lxn-HCpuW+&@puj%Aq=;UbQ3qu2In2g6+`~EIsB`2Q=crWY(;kzD3!Gy*onuFx&-6`3 z*G``K;Y<-CQDvw6gq-~}NpwGAocUC|5-ITv>GaX5s83+sDcXis<)o(Nq|N|X8-Ox@ zkXVM!x{?o>;m%rm(DHP!27#`{g=h`Xj27v;EGM)mPz+nfoJo&fq3>R#YmC8sf6!R6 zkIpzjLYQE0+|*f3Qijcx##+24i*#xQ0wXYXk&?C81~>xUF$ZdmfM`vDNo**_l7Tq_ zbCY~%&S97l==SUfM67FDle2CmOrD$I#pFpv;E+n^5Hien!7XFuu?7bcxdM@BfN4k3 zT^3WoTpE~L2`11LlH-E`x~>Z4VJ^&-4L-=G?Ps+g13zlhoQX^YhhXD1xO^e#1eLMJ zCTPCB+yvJsk4~Y4$x(3U(aCi4)Y@U5ECX~{tWiuCAqX}DOmass_06VW>YUgzIH|v!51m(;!24(je2;H z48;MAy#u6mC%O|rzqdnzu3pL5E9tT$G+vzmQARlL59R%9A%?SujouvI_wz6wKZ+0>@q~ogtp=e{tf4Us%>- zdc6OsT`xmy1EPpN5uVQig#MD{0sOtqiw?WCHI!^j1B*yoM{(qP5(T!Z@j3s?II!smU#Ympc@z;&~_H#q7N?y4-4_{6W zW$B(!aBSD!cBq1oYm}Mi@bpf)>45^Bp@u8gRnVSj*}a(|j@R_$k>6qCj)ay{$B31$ zx+G1dsRXAUdmAkYjkDj0J;Yifh7%~3?Gc+*)E(cQ(j*=Ai3i1Zd#2`GwYa58_t51}lT?;Cah~{*iC%qaYheW8_t0F!DOse%rGf7@y`HEM z+jmygZKo3 zDCMnj?pZD&+OQI6U|#`T5Irv>CPT+_Ldk*gI{TlTlJwM@vA-G8EvQ{sqnM&xzPcZw zQP^3OWHlG=yI-@|SPw~OXYM{6-E)SRYCiTU=V|Qru71{zyEQq3%6DrNrBp0xKnT^a z)}2<$H_-?&(W1<3If2C^xt`HOs#hbTDy?{a^+zSMcx<&NU1Sm9=1< zOtw3`>&rt%PkQ#&w4M{WC8AujE}7VXpO(rjlYak1T!rM}5oNww-I24UzE6|2UZrOY zMoMf~nhmTh*SC&0FnnEAvi;kJ;^UfzvhtK|=YP;r&mODYA-JQg13W-Eq93MKC03kl zrWtS66?7;y@2gtleG$nCt3YCapmu2vn4w+|RoLcyUDG%5TD)V_oA%`9$IES_`ol6F zFS^w<6C}I7Ox@7@VU{e?3k5^R2Ynf_(hc$2z*$)?|5&h0RCoKf8{Mk7V4&xM}{6$|LIVM{muf)j21{nFQZy$-fq7?yESl5#gW@&G<|)qm-8 z=Q&+XuW6gUU6%+Zsl~c^4}vy!MNDlOJd-t-LY$m%3;EFc=^(CWM)IjG!OVy4{n`9de8$~gr5yOtd?R=F_EQPsbldunkWAmN&&npOo6SDV-v0W+=lYGi z^BJiZS7XlJOnKLPL(AjK>-Qe!d&4gu&uV<(_SV+lV{mtqy>g$0bkw`pfZLnr?ke0d zDAhc7Jl3M^;3K2g_f0*tUT0rE)bYdL_|T7~FK&_>!FC@muepBN`~K4%E3qEWrxMQl za(>L=AYYA*&*F{wcb3wG1)nTPx1y0q)#!&GF7tJ6(w&$0wL=I>2mJ($BYR8Y>7n}t z&r2{PTc68HSi5(#o~4Bw96WNb$Lrxn*nrmZj?h@k#zR=ez{JQY0``qwsw|j_-qr!} zlPhJ*PIvY7nC*aLdcAQfQ+;H!6Dc0h&1zD|0on0cyqU&AQ)e;V@ z<~jV04&kMYNBcXP$%pPSUtes6T{NSufoGLw5D+@%tT6Xhgq z(fOEJ=MLZUT&i<_Q+lxeQ|EV;eNANst8iu6!#7m)tPffd5EY7>zR?Xn}t-VzewrM#ZE?EX|Ydznd?(eLLemkymQ!h>TvYF8Ghdh5G z*50r5lzFiGTlhYd1mWUFN$|+BG`{2W5o%)mW#r{S=dPe#_1@|sAh#xqblL;I_L2&_ z3g<&(pPOQi9leC)#jA>JoW#{9%c>oA8Gh_{wmG#$w~&8B&G2T`=a^FQ0b%j?8ZY|8 z+d7YGoQzvCeEp1AH>j9*vSPmu4g2)^oKSt#t%I}g^S*Q}+SEr+4$ppW|I+zTQHa`XLYz0z9D6VUU?o8N43R55q*#=Xfd^iM6Ckh>SyA?HR6 zGxV%%zBiwG)QvA59IED3FZ5(~ugsfJ3asmyA-beb%l~Rhfc0VH<)VJQ!gq3&>Cff9 zuie6<-k(3N;k)^H&VYHu)ik$|!*XJ#!sB?TLZ!%p>i%3wCU<96Ne$d=v1r(1wjsMS zc0u)guC&LC_c`}#;5*Lk*%)<9)6N{t_t$>hHe^@#zMxFQ&+yB`k<*`d=9G>28xNnp z9oGE*@{*wc_Bg2_mxxBT$X#DK`suM#sK)Y1jm71y`#}-m>^mKc_M2Sq)e?2<1`S?0#kAkgMnz;FzIynez@-Oaa!r-lD@(Rwu2aJi zyBc$Cj@nnZPfq>RDY{zwI_SIpqwyEooX#H$J_0_Eir?&Nn;d-;asB(uYFbOjlNG;H zB{8#Ww_9#}8GU<}{&4pB=N2y9c9k}Keb&(^lG`J6{KS*JPXxSnU%sz-l(%H=34h$$ zjl*3hBK8~16sGlY_nkcvw{`lS;>H&pS^Mol`mM2OCfl?+pl;dSEAK%xX-{ip;fEYZ z%wxlV(}T~?oQ&6YdlW{AS1PnQX2w<6#0l+_Bg-?BcYl9)yMK>@)m3H&%`vZ_ zwfs~x-SX`1fOkx@Wvb{nw|7H{d=+u?C0Hzz60b3IGtq@X6-i_B5-#kL%?QOyk%xXP zJ70cB+1vR#Y+F=Xc{G#4ABjHYP3GsUBFX^1901|5Nx+$aOo~LrgbMKdL6Lw!8C-xw z;XeWhY=`q@q51kK{0iA&ITXGI+}UiFfI}oA8z)c~%HP1IB#t5b#t>A1ZyrwL0DRRr z1cMU&4Sup_^5nBI6qAFRCr9czAI(YRPvo3T^sG zKnRGa0Y&KqktV27ilJ%f2}MKi8hR59B%zm35sx{ij3YoBIUr#~_S;}3Y@fuH@ILZxs}0vaH&oPr7PbmHCS zr$CViB!L#{fQ31-#T61#$Al12Z~_rpO@pgt14A>gY9csmEWsHAt>lM>kHKn?_tP== zGTj3hA@JOp_-%4 zC!w4sZk^i@n%k6<+tQr-ayGa9AeVJKuS+wpM>DrCG;bg$Z>TwMWH#^BLEhN${Bh0v zx5x8)Li1;G^5>fK=Lhp&#OHXddQuNHAAQC@S_yr$Hk;)Ultb6Z+JrK^4<7B5XKrgg z-V3Gt2z~qu?|0Dr_@4psuYo^DMVQIKV-b;pk81I6^)q?g3OZG0=4GCt+wHP`coB zScYA*w>vYuWWi7Fe6eODq?X2(d!d@=iy@lDCoTbXG}!eo={5a8ED7>{-!Gd5T!*D= z!HO=oct*4R9h%pX08J-E)X{)=YgigbayByh#X>+V78*@}I4}bfQDJwo!9l-DFB-z@ zkfBIX;QV#oa#pGBC7}9{21sVp?|kuf_)_G^0dHWHx{k#*kf7~xkZ5A!3nDaNArTq^ zO+Z8K+#uOB_+tbldjY5>LHV*F`!gLIGZ50Fw!+*#a7n!DM7Cn>>k0!}~>Df|_B$1wc9z z#)pA7@i+v%b zYp$l5S8$UT{Ol18PAB}&&HCGKq|2%UWORt4h`;}h2J76~48yzUhccAsGEQ0-h0A$H zYDh}eL2+nas(dWh<{mT+cdn%!J`4t*UF(}2M;s_KM8GtoDhXRK*QN8 zC6Nhx{4k)BS-B$upuWNy_#w3ml@AEjbx63!0xbLM;GKkSAMgH>`$KQNhn{Hj=_h$1 z;zNgV(QUt?Md6Sr7Ep@}l3ycd@Iy<8Pzn-K`!y=>Av~4^ba+C87e=ecI=d6P3-6D9 zM)ptr={r`{4N@50LUZF*I>+=q>WIKKS>TA=omv!N=r;Hy7Mj5CwIx>-`byumre{-ZR>7i@};u)mXLg(_$NM%@zoM0);Qpww%GGPhbrd1 zCT(-i$v)A`X^cD3bfIF(A3pl@D{OcB^k=j4xq}cMCh&h#un3AH)3Vv~Bhg zvMJmhZVGMovu%XbqL zsGp|lc1sg_jOg*}E&kKvPmKAP#OaWTX7nz5=wN*ZEFChD4;Pgc;fJr~oW1 zfiTWMef%d8`eQC~^*q3BFnI7gAe)(*Ky+dtgRW^UWTOXBmE1@8Vyg-8@B#qL2S0L? z_lHI*^i^tB#Je?xp{LsYWq)|d1*44IRQdw!1#RAQdg00H>0#bQA83GcsaQ7;OB z8se~I#IT(kEsG-+x*5YnJvDe5uq+<<m{-a4bwn z0e-C|HJiUuIcouRLJArwxh*{&&3fNVB*Q|;H3i(-j{-7z*sI&P=8eU0^q~1uK(eje z^j(T&=QR^?@wnmb==r2WpB9U6=dJ(_Uv`5ocOE&}zo6I| zXxFJE_tk)>ndSu@y_s%jFEKex!KzixBB%~o?3 z-2V*wHcc=25OAp#LKYqVG_#J&U;QG;>Z(6(e+_q8^ zcaP5Pm_b5*+IA#v%+R!c7$42*e&pYx;U7(G#Nb(yu}{eGj>FceBlmyco;7E?!3nfj zaRcsnG+^-St*_VH`tucv+P(2lhZT)O{8RU0BfP^25Z!@5Ci+b@5okceqgP?=VSTl% zfh<(e77kjC0vu4!Eq_;B`?Z{o4T`R5fm=UzQiD2h^wrXU%OL|j8Li4_y z&W7=avsixMm=sYxM|r6s`VjpQD(vjdV%(c0y`pghh&wz}wybb66l96_o@_Xa~!*YxV$ z<+;g9>#XNhRxOwv=OH>`y{hC%tU^&enO{PzZt9y&li)O~MW{?+{-yW(bnoAjTMj+8 zt2IJ$i3kaX&}fmx@f^o0oS?GX6dCXDs++6icy92(-|=m^WmcWgoNRTPi;3CIN?*mp z;djk}tGAo8e{Q}zCh~LBC#PxnQ}>zQ4ORC;hZif=C2iN)3RT6;M``HLV9sj4b+=|ZkRhSl2G1(C~k z62}k*4w~sHcb^1UblQEHe?qqh7k+x*=I86eEA1auDSShCac{^hu(%ze zloT^Uk6CA#>=82o@7Sdb{Qd>MhE|5v5ZDU0ixxa~?Y6G-Aojch_`Ii`z~`wT;m^B; z(q1WgQ+5k_x-L+AnGzQp--lk460;MaigPZ{DSXD+Lwx1*(95)Tvp>{BDxa;8#DHCd zJ$}bA>8Wj+)1dspSht|WL~2Kd=}3z9EBV0`eo?LO-jYVnQR5|-vAR9!GxGTLz6?0T zgf@j9UT&}BcwD<6cyK0pv%^wM=Ecu0#d}|qsNKoUTPa4BSH}~-e{=8q4gb44*_|tg z(EG>r{`+U$qc^{g{uL7N{&7J&HBeA$L-glI%~h34AAF3yHm8KR-S%EO`mX8wn#X@_ zVPAh|Dur*hPT&9axlQE3pZUh~hxd0|Ij=_Sy|ca@{PR=RRfYZ4#?ya){5O5)&!3+^ zPyhb+_ZI1+$_EZ!(FTrF*r-Yaq8@^(b%(pD@vXEfuYD z^DrnhPHRTeA+}6v!sbna&Vn<4b_hkpLonWwI4F>au~&qyiQx`udV1_3uMeg;nG>yE85Hudp6EJ#F?#JaU!U8G?=aL^Aarr_Sj=I$F zCOvb8#+hpz21gSoUN2qBES3HyFQRolK{8;sq!J%s#zc#!b$ME)k5V10kFfXIEY53f zqLem@KWbb1o&8G~WMn!{RPcmXTGhonv_&T{raa}O50VZIJh?10U6p0-ep?hw$eu1F zeJ(pCQBoylzi={qCgEC7ktZw+C&O5O0T^)JejuzMKSiiidH%x*JM`|XNiE*E|KVEiv6rV4lY2G~ojlW}L>e%@811OLjm^n2bnJ2&l*_}8H;-yi** zcS9fI$0AZtgTS@8OdgvzQLej1C*QkcuG);JspTTeeBE{L=}+XY1U$X`*8>}C^Y+QP zz;craPm6miTe?G@q#m*%EgR|20!M66kG+s<_F)kO;4@OD0L zJ5jBcpOgRB+x_DvcPEisx!{y6bu+#l`k?)PfoJf_93_6Ox!(77REdQuSDqh&je3T3jXIbmU)!JTnWB6;NsEmfgh; z>L3*bwc>ka5x(_C;!EdCa9n5Hm4N}FPkiIi22v0PtbW1)k<8QYLJ9V`XYL_uL%&^X|>Cgp}S_?bUdZ!BTe>+vZV=y(@J zjznDnku~4E)Mav^fGi6d#gGX`VJSVfB}Nhyxq@O{8hj=Ltk0yN3eNrkWeL}T7eAqK zaZdz|sg5&b9e1i0iF%Q(0^HkvEzob!s0uPHIix~JMhgz}Y@~pkN2uI&6tltdgSY9m z-GZLk;PYX;%H>=)BzO-045u47inRMQOP&62<%yTSVhkXO0;r6&`=stZ&i7A(L{v3*L!Kx>*cwW<3dc zabnR_^MRm*fLU+K@y6XIo-zL9H>hO1xI|iFlhklFthwQ;j0WLzvV(IzS?i>;cUf#J zdaYZX)Y^6XzP|geoQJ%ETb2G1Lp|^L0_QnMoy)P4}Os`$T)i{)7XIX*T8y#GQ;jv z;(UI#MKZmZe~ZxfP+Zybb6mp=C=knSjD%#*5AHN8!^~pYD(x0-D1d`Ika_*dZd{Ts zmnR2zsohYi_t4X-rt*39ETI$}hFcOhIEw&im9f!N3bks)Fc6v7 z;Qi?Cyi{|h5fRPxLf1%V#7JtxV6l+gWHB6ojSVgsX8qv`+=q9`8yD}URAqAGu-pxW z5F^0wDOc<@t{l~bpiu=E_uXnsLj!a6su1Sse(2V@8@hap0(D79k#?2Nt zm&b0+0!D)cpiOO~dS~NG=U21Z7zSFs2WmK~OIZ#W<5nG8a2S0jeUmfLDA60b!x}zX zGV4`}r#ONE*-kWUc#q-zn`>v@(+nbXL zX8f0-51da#d$XC>xVy>;K^v56#s7tQS)MV{smq)>s`~B3p_;w9x{tX=gt=z2`K5ew zt!i`aHuKA)=2zaEU;SpT21Z$B^oPs;FXr_=>5lFH7xTLH*8(G4bu9{~P*x8R(BF&`#ok@w9rSQ%Mx!{vVXCCz8 z><6ORgelFEEKjr!`ioEcJBym(l*fP`CtDX%@ujLWncv8C`t(DvO?o~)xy?Gship-B zL&H4+DoMLoVw&Y@ARNK^4>F8vUYiUvZcpd~*F%*qG* z?r>h5lP7?^HSFG5lCRL-A3jdzwA{D7KRTz% z&oQF~DsAGDWg{|xa=Cz06&-bzMe!PAaY|EV2I4uHU|9@UcME=r#5JYxF~?_Gnguc2 z!dt~fw~umy%Ba`Nz}^7FA?`gPWQuR!4H^lSuMJ z5GMy2@)?ZZCx2N6>+OTor8&T&@BXQNocs|j&;Q}El-)Z8E-Ps+Ggi!R7wQji<7~v8 z93ML)6zFyVL<2`g^OI$oKtfGqc0VVofRoMWWB|~~Db7nxJ*qQQG@7CSaDdU|w7&%Y znAwnTpr2CU*?fC%Y057jvW>fgBBW8F42%XKhn8d0RmoJ&1rUI36__D&YEVvcfRvCV z1tu4OBXa_vOZy}=a!C$Lx>^u*kwosP;5^#C#2;ks%>>PueEd@nx)~RJg|PT5nbSek zVdmuG_t9x}G{}ZML}v|z!jKgPIMMsID#Z6}TxNND8D}-CfT47lkh}G4Zm50Cq}%`a z!Rbw)nhv}V8g;fJPRp}mRR7@%>K()Wa%v;(`u|3EU$&d>o$a|iZ~kgVoi(FGm@fO~ z!heoRD_Kcbo&TX=mz%%1vRo(r=vT$KKad! zVQKH4vR)W8m!i1l#@+1cFvtsW(`-)JX`SLUf*EPynf7`3! zw%7B`J3W?U9n|s_0EF7-tnb@U*pJo%$X8}Klk%6l?Uy_D-e1(b&tu{LzNH^lMcGN7Ok?zc~t|XEp4kdz}X+^T1$tj&qSkUK=vUZ zJsd?9cjZb?n*x?g6>X1NIHJ-NeG)}hk!8bOvUAuI`4Et;%-qNapJ?8%A8%S?vRAI` zuUuK@-03((Q^QF25sfCI`{Z>6y>#FVjsaEAPmvGo0+$oiU9I zH%3)qrs}xgeb4x>@9+D)y=cV{kbRkFOW^yulOUxKP`$pVfIfwdL(c|)Z6&4D7eLn8 zV4DzOnYt{k8F^z2)sjh37@+1hwMn&bDKmvpDDr-(N1@`Ejw`+kYIcu)kj<@TYm>K+ z2X89PMDM^?4-K2R9;+@ZxG$TPadov(EVrT+%D!Jx2ccPHc@#*Q)v5%53^>RN1yr*S zU+!;uMDcwQSe=pU-?6;8C43d6Dg9390a-qHO@*S~0^0AM4#?@1iCOqF)B7H{JWU8LhF#N&m*Fxv-m4?^@$JU9DzE z51bbM`JPUl^L_R0W5isJ$vjbQ-uqRM;xst3cO|plwY4%$-SzG z405^2bq+(mI1sJG!G+c!sx*NN(O-24oINqYDlAUFAu_p1wynQ=IfQFXoDsY zdl5NQ!;r(d$sP6kVI7=k8kgOppB=X;dSlDPtaY2$oL7IBD$fr(w~x2spr8oRY6H=h?&RIyoXQxsdi}11 z0n4L*p$fqDufX6Ks^=P~E&8f5hKwOn6x=}<<0#5cfB0IHKSq)lH>1_oqU||06$ip= zuYl?!e{{4{`S0wrpRBP9Vze+I`vUOuQfho^kwP|C$kQcxcP`a9iY_hK2DzN+L)mt+ zhW*Fc=gO&6K-C|Jc4ThoaFBHh!t60*>7t#qJL~B`L3zCX+L%qogV2x3p@+pa!MWCC z{h8>_s}x0dF8kZmf@+FVQ?xG8+J*yUJF_tu{1@ZSCC{WjzJ)gkaZv)umKchXbc|jT z^&*A~)kMkf0NJpj--tx6+zH53Jn(yc4}<*p-128rp#6u&*$xPRYH2@Pk?C%9#>V(< znL%-%QMZz-qOt)gy>Pz)nbUQ(eMbYIA6amnh$zwfw zMM+^?$!ndM>#>3gp1acH#fJ3jUtdVUPhdc^Jy93?jutE0{8<}cUNvUO^GjSf`y1tb zTFG`C65+0vh^=)R=94<1wl?45Lye&V(_hC~(cH(*&F!vdD}x3P_dO;`jdInKe%Bob zmH&5J>EUoXShgG3k{uus=^J`Ho)7_-!SGFf{P z5c}DwaXw#p1rjIb_i|fb#BG0(`$S}>Z=Y!Rkm*URzb_ObmU1y&Us87N`mls;(>O+y z)A8YyRJpFB{#ly0sJ?OuM^T}ZZKhzK>?DVyk(7Bt8Z4fDZ)%s{{7Q2QL8APSV|MI` zz4sH8@{2o8BJ5;}IiMW$WgX>09r zjsyva0?}qQzvf3fU=et5rT$)fvr7;H*&gYu=jrPFMxW(Xu2&`Enpv+`e0#s5PdEaz zK@_`r#4$#sr8uouBHsDP`boKTH>IJv9EjMk0(okv$U&)p8gE`yGG$fN97sQ5u)Usc zRis9q686x2dcQ98{F#!AckjM|7w79Mf4ewtIngXOg}-(Ap+{cwifYZB;l6qgKabIe zlOC0AYVUknP4;GehcBzY5A3kVy${_mQP&|JRQG+10$piZpdO2CT8#H^Q2&(tI6~cw zRIIGIOt+2HT*>ijKUn6|`PWQvC3I@8XQbXdSbv(85+?Sf^~ym)!TDv4Z=s-5@|(>Y z?OOk}ffB91b-q&!x9>XfQDb{hu0#9#sMa0Z|5FToK?H?oeiL zVzHXXkkJ1wh8E9}IrcO`M8S35!ms#$)%}a(#*e9F%BX}bY5cE=?H+SI@xBw~3`sAC zPjy1J6HkqE{VFUstj8*G0#h$@(gpa<#X=)TC<^cfQ#Z{*%X&oh+zXDRhB zyp+3^O2kN5sby4-wr@I*+$73a|AV(9w8_D-uK1dgnl=pTDAkkoFYJBGLI0hcY=c#w zi6v=#9W$w-`>T6Tx6zwRhk7T)l-J(&Jx~dL^>6W+$-1uzOsw3TZy_+;8?)h zG*6b7 zLN2j(Sh|LAa7X`y>aLi1z6_g&=cnO?12!be&zX?)nsP570=od2?4%{@d(i5pc_lYR zYs<%OFsCF-j~Wm6LSxtH$1>fSoJQyK=Z_F{DeVnUAKehED9>Wb3?(@~(Pfv}=f8dP z$u910i-*aJoNBi4@sTs9g;6#PyuR%8UdZ&D}?zT=`fp0c- zRv0NYR;Abe*P%>z7G!aCP*$rqToS6=B?l8fcY<%o`wH>?i{`pzDt*nj^tjsyvnA|R z?lWb~SIuWVY-&E3fRWx26J#PC;sqIwj=X|X8ZY?;4GTsd4Y_ssy*S^;^EYuAgxBF0 z#NyVg6XN(|(rVk=SO_Qg^}D5PuzjsOr}E{pVJqkhz6p^-Nh2ZV z+a+beCGpXK5mUn9^_@$I-=p7^n9lNvube=wes6Ap{xz!JOAJ(*u$LQG8N|Fa(YV0` zxSFQ>SdQBh+0tp6-SNLI8s7D?=3l(sXg-;Xe&qZ}^#kJL^?g6me>Dxt8-P=CUy*HI zn3c;N1^)Nh#}vlAvROWjYfKHKT2#Joq30Iz70fTYgc3 zFZ!~;^q{9pXMhPmSz&yE>qZb-Bm!%T4B+vv4ZJ2Kh@#4miwxBKxGwsuih6XsfDhWF zleWDTdxfW{=}=!y=RP|vuA^NfK$q4s9pIPQ1-? zMzmkL??U=^lB@9~M$Vl2S=N7LXFD~L=PZ(2X5hNu z4lSn6Nj$N0z&5ih?f<34GpshF;7_r%4!gzk$~dBz=qzW~Ib_wcLuV$H$h#Q~+sy4S znnp?#gPVuVny#mpY%MFrt`9p3e$VbRK6fFje8ly__ncQr=Po{#8TB;#{%}fYMd>6y z!E$FOcY)`rM!&%;BJ5c92l=O$rUzdIwS1?q-G8dRYVexd>)RiE>=dY_=8csHJM6?v^NlN<0+3H>|+M=xMo)3$)6}Kqs<|#j8 zmX=`DbV0b1MpZhWHlF>#uT-_9Ouk)!FK^|7fCpAb)Y~D((%m0{>h(}$(qJhFo#M_B zs)C(nyw!kXP4x)X+I|k!I$k7djp34aeFMYAE%H~-N8A7OoQzvhDXgVzSj|eLWLywJ zG+;pT&PU=ddPfP?V06S-NHb--Ydj6^AcUa_~NuSg{BTNr#1_{Z(nyRu=yHUg{HKDXjKra|9qS&n z>ma&VcfL4E@Zhq0Px3i9s(;LAl~(9gm$hAexHO6A)Rps_&`i{wcYIk#?3G6>8og|g z6bK3IwM$G}-d-sZPG#!J`E@2+GL{4?*W^&AedDb%yAUZjsoTd*q0JYjCb#a(o7|Xl z4Q_ZR?1NZuT|7Cg_S^5nmVSl2&9BXfC$>+RufDJ|Qx*wg+T~|VG`cLqwy5fMx#;R2 z@y~z#$F3+X_|o3gr*v~WIedQfi3h-!#qRpZ!?|J=Q}RDJRQf5cr7|y8XY%jmm6uI?AK7=v(?_U|lVH@~kbEWtKwypqDLjrRn zJn$?V0x_zV-@_aM$s&P+$0F;tfOtCWR5on01ahI@(3%E*<^qqWIn#+?IKnZDNCL9& zrmCCC$3fUV0`4Se0u`DR1WsT91g0mG21z7=vypHnlFVec;WnDxa)p$Tpd=RH&ORDp zNNpgvm;rM{y2O(pgF)nkEV58N__P!}g#claJmWclY8n{6;z3#fJc)1~2BZNAnGuGh z7eIb8ZnsFeUN~pT*50;QsKX%%Qbz~y$cV}<2f~7%`dX+^eOUWNI49(RBMScJJR}hd ztszFGEWolzkhnlL+V-|)!m5R!m0a$ryYVL`?Hm@2t|Oq0gvd-bbtT2TD~Sm$3EgtV zpK`(b3>YHy?zIFb4ep1_{xD@OB>n3%ZRUWhVUmP|i8{T+j)1Tp-4vdzuvLti%2Tr^ zjiDbxunYSs_pR9qDR>u`suY~MU*`9#DfQfR>OW~ej^ngb>NKu$Uq~nokwt?Y+~b+0 z)lB&j)zgIVX~))sKg5`b<(Qn9O=C0eQ^(n$GEEekc2Gt-ci?+8Cq217UEaV?`XF6g zB;x|!R}r7Vbr_hTad7KWbH?9*)NEYFHJOk;=@gxV^bd^8z^9qU&6ziI>{EUQf7SPA zOkzKUq!?HlS50F-oHOo4ro>OjFOKnkDu8@K@!dx8-61kOni=lp4DaJvp0k#w2Ig}0 zcd7&LjqE2OrObvz?#m0`KQfTqNW6V>Fb;%zBL1c`!RklP?9DLp#V$ThC6OSD=CNFcAS1KlKyU8rR$@B%@!KDO}MFVFM2uWB%2{y(60lkeTCyoJz=WO6X zP}f5iuc2#fH6o-9pXYUuy)m2JQ4a4o04L|W;@&JatvNeU|qdH0$d@_SW&7or7F!;-h!YNpkfb zFPPwR+QWDPgw6pN>;v6d;8YGElLW>Qf!2Wsq5F5#9U(Awu?3bu=YU`hLPQO7Xqt@F za!A*Dv5{e3c6pAFaK@n6asH#0&JDlfVB%=fQ@rQ>afsql5;H!xFYPD#SaZ; zS$WRcX(Jd+T4B<0zEmWiQ}ff~m%Kiba#C5Ay`gz$*h50zCQXQ%g&y{14fmJL&1Ah1 zEzfBTHZWxD9Pp;{^DPp=pT~HYXit}zymrDBi~MCQgU7k}Ok5}(aHDUC`dSZ$@litz zV0oWVUZ1eM5wbZYVtkHUybr%*d*$Q|3|3r;cMP`4VO=VFdWkQYl+#!KG*66gjUTc( z%X=oQYA?s~%Nn-Kx|07!B_DU?GZM_eVYeT`8^^4Y9$HUM8{XA``&&Yb2FjAQo>iZHSUqMnxtaxTu40uJcQ!xo zDu*X~lzl9VY5$y1OXRLZCT6iSCE2hOy+9!V8MK7W?g5>LE3j&Q=wKkgmh5V7@RB%4 z9m%kK3+UD;EvEsMneY=q@Jf!l%mVY&OgrZmzzy&lmMvkdKTkg>>@?t;!am+$*z(xe z*Px(u8qiC^HPh(95dON)Cu32A+Z~<`p#? z0oSD)is9u{?FO+Ds0} zvNcZw3rJ(;N@vxJKdiR1>4))ORS`^8S~R0~0V_0eEEnwFeA)(M|CSuT z`Z%4#hcg^nc@CO}@=iy?uP^|;dZ3yJlnfaD@_MQB`=xtJK^+E~SdhziKso7^WA>%l zu9de?tM*gk3mHsHyHK=(aAo&y=Wu3Pm$OfOu5r>Nw(eo{#izda6Ux&)826eP8h;ob z}5WsiY2T=hnqU5hDKY#DE(?+p(uzm%E7iH6ot z5;U|ImSg-XlMabZ+0yMD{DqYYv~pAEn6I~}hj{}_bpuKA=5g}_sY#Aj2{oVJ+GbRlDQn)|QVU~xrt}Jh z^NZa1Hq$TDXgWr9+3vG_*qkKSn=C=aJ8)ztN_(_6CC$XO$>9B@Dj{Zp+%E``bp!71 zB&#GM*n7%Ovh0cboY!?m6rT2?1`E}kYY65~Y~e|JDsBTgci)wRk|gb{SmBz)irc7% z-R5Y9{Q@W93Rda24I%7vWt+qV&&sFDSoTWU*&PfKr zA&~=eP)|ufLQB?xJgLmA{^4S|u{sU_J{9>UlskDqp1c7O=7@j zVw{zl&3GB4s=1g4$JrT#Np3hiogb3BoJ5<;dh4Dp_XF5S>_2H-Idstkj~`kQOGCz5 zo3%~-qzn-91{_%IR0j}}Km9x5dG61tg%)CoT}`!(DL89}`v!4&e`XVRtAroofP@4F z4FxAQc8GM3XEQ;NxsHq0iTq}lMa?3i<^}n4V=+nNA0ANT0RC$C)(Z2^$cbLb?6t3V?fdtJ&_+;x^I+7OHe$V zu_ERAIQ=q8L$l|PdjNeMHOR(tlKH#KaHD0|CAxhHN9Ptd`!57i-UFzaz`L_Dn15Xd zo8w+j1DpVa*aG`>8SX%XfnUPLlWV!pE!Lr%)?z<~oLCGSw$l?cizk-;@`A?}v^0=v z|I39Zv4GgI@eu@6X~0~^Hb0(a8jQ_1sO*ra2M)bn^aRDbUTSV2MMjPEJ^5|7-)zSX zVcq^^6xQmrKM4G{@oXfJpiVCdrol6@^X2^B@$409A>m@XnG_%Vk{m8|p-BP^Q45D^ z1wrlkEV+`Fw1?Z%7JwmMcveX52eqY6wNghcbm#Z|z!sW@!fMjO1IS?#K|kR|fDv2^ zGV-sYZl1B!8T0YK-~SV&v5lMuj{u+AoV3GR8vaJ(_u4mnSSil7r11A|5D^Zn!I*GB zG7>1L{}4>7C2iW?YcYSpe5kFJq-K!OK(hY0Vsw1Hvq~2?T%2Gd)7Q;)HxUh$bn&k` z+cN}V^e$M+h=ZXYO ze_kV-ziQHb?)Rsi|L^akL4WZ<&cjWvJ6lHsw}4v%u#T{^Q`))B0`y(9NI^(hOGd6xs3iEBEOdg3Mq3;F@Dnm2dC#Moq&?4&!G%G}@m=%=I?H5F1&w zW3chfxgpWHx9%2|Sm^J)y0@!I6+WTm`EYe`$O*b_J%qm`fi62aG}%cmv3uW=QTaCC zsvJQtk{T2~V^d?JTyas(wA_%}Ru6`cHH;v0c2oYReff%flj_TEF@hKW+zQ!%VgAOJ~cS zo|q+W%BKemnm)H=7X{wTGz!_&NjK^83mjm)*Wo&m&axkE9&;@E~rRURMe%{DZTsS*Cz9x ztqL_a>QqKFzPe6jEu8RrAx<;y#+Ogig+k&~?50@=*PV_)48?X8wR(AfAf!4Rfe^^@E%3d4n z#fMzn!#QVI2H{=q8T^BY$EX%{eI8O(0+ z4E$*y^66x-gra}u&kz2$mR~ULWG>wNDDVOt^7;-%B5>i&mTuEcyxqF5!!bB@e>8r= zylF{S`KG9doMDe(+s(DazPvYa2<#a1CMIY0XE=fWrd4W~& zqk6uZ2P^qeJ#YGL6CyPYg{ns+lNCI@WV2!dy$(hBt;I?&Rob=G40~A<(zxI_q1s=HBS7j)}{J#DM5$hIp&AH&FuBS zkrOSF$%Qr#ie1{FK691w?&aEoEl2P!@R0`h-Y$77C@9$q;c+=#o~JUOAul_-#CR1L z&PB8B!sz|FDA;+OXWQEJNxQ)~2~0C=Q3t_o8rD+Mw#z#a4ge^si%8Y=jzV~r>7GsC z7Vbzp2e;-YQ))=i!4e6PSO9dc=GsfU+MH{oa1U#5r zQav1y8G?dISS9Nm2@Kh8Bs)~0m$lmUj8}`-7_p~g1oLH+`~P4|BJf*4e2ddB5q!a#lcb- zFFLy94;EvM!Bpmt@MmJX71~iymHAagT!?NEixwx3eV)*NCi$#ifB;IPNVrbJOloWa z&HbwDyaT~VhQ%LaTfoO#J_9wr?pG`@-lgVnBw1T=R=8q89bcsA z=7Pao(p}+7W};|}Ly^92TtZRGTd{bmB{fy1 z{bSq#L?+;dI`Qq+! zs4?w1H*T@E<8S4CIuxgw#A;MM$8|=&buJ-&)f`uzeSH%lF5N9Z0x=RBGE}R3WLd3> zv7OUA_^xu}3&j~9&PSY4t9{JDjdp;m%z8?RG}~9ZIc&$jj%ldvh%g%|y>2^MtLDAL z^l=X#wqw^km<;^*dWLl^i!8qPydY2^2!yb!TtkTe){c{p)506SoO=1?+C9rAIh$v? z4J{bLfA{q!CI@6iRDs1!x1$>$HF+C^Hk0q3pGrG}U$d^A)X*Up!ZwnhfSZ^4(W{MJRGlTnZ)0^dFpJB?yeB6r2Ckp3x$k=M zDSp(;)j#+BA6Je3gP}VG{`uejP_KM$J{r98U1Vzutn@YXb-@?p^(?kiY&r0x{Ur=IPZ$>Ml=-Mz4XNPeW;aA!?%cgx{Zar#mt5h+qMm@ zpNqV)qDKy4_X#m-0a3j7)<9>sh%vqo3gLIlu8B^Opzbe^j5!fNr+$rrF9jd@c;@w< zh^GMc&Rg5LjFrF>JSTmWitXN%?{$d+>>>v&2oWMpm0}gZ4N#oNtV47Vgw8ktk^}Gm zL_l^&0X^~SBGm)e5#DKc)7>JbeEuJ@-aH!0_ksV`+%sdW4HY6nh>R`!KK5bkOU6DF zA!^FLHs+pTEZJi$X>1WHA;y-ml|4iVWeb%`Y0)R;H{bJ|=Q-y&zjNl#nSZXi@9Vm+ z`+C1#Z><=CL_UhfrE-Dq0WkTWrLYUpY1d#cZT(usLlvNAabmTysh^jengX!-*#JtpaB_7{_RslzOia<~y&6cH`3#70zx z_VEu92TwziI41`xc*?yJR(iPz8vnQ$r0_TvRx)9l`QEz0OVkAU1U}J-^k*|*$aFEp; zsU-Im%?n!EJQ*aFmBJq)paG$qdyIr9cA9po>DhO&+;kWwRE$afUyP3pRFWm4CIJ}z ze=$BCBGHK2tGsK3V3G`nV7OWchS0;|*{7$fd7%-^I|dIS8nc{rcv(YVJY^p2{#n_5 zY)4fu`V4B4VPby=r3{|O0_uUF2?jVsv*LHuVzv;VcLCys1ocb+=}X2k+-i^e;a-!J zStppWGjRSR5F*rRfb2Z)M2Y=lY*4Sw65OFdvL>}P@EAj{+0=Rlh7r=k3YshO{*n)J?~LuZRo zo|?y*R^JeF%!Zm?ulrdcAq)jxbz*YO*@9d&ByB!%Ft;3TRf+Qa5(56otk-@UXnz zGUO1ZdH4G;ZKH`cFrpA`W%d$wbQ)Ocg<4OF${|cfi7@LSo{0WZ_4y$*5-{8cl($JZ z21S4Wl+rfIr4j0ZKu2xp)j2=w^;GkkhbUFEEWDK51wy*1fQSvR_m&lIvF;<@M{4U_eAhTMu^l=o;Y_fh} zugX3IhXBm%`LOelCsiN{Np{xK!9@cajWDxpsP4h|#ZHTrQ%`7Q^7_U=tOzK#H#CyZ zpoKg^p`j|`yw#s z`jW!N)1tWIpqoBeW@>4O>C@aM-D()~55xF1=%?89h6X-@gChP~0^PHU z5zovNT7>*ToG5sH7c|(_(xyA0<3PD_J**R;Oprv|gZ)b+O~Nz;0xA$>LJ}^Z*~q2{ zAZ!n!SUp|QnN>4G!SubNhqq~F2e`@OzXr?cDWgrnp!WPmzo;R!?037m5Y<6 zvXzgGr1B66+6O8lLB&8(44!277b3$1R421hlV#^oI#%1jQnaItGU%MGVMVBv>xZgt zlav`%N_3daF6oG*xQaM3_>+4G#foER&ZR+zc!H7imtm!j(__y1yFBUlJgq+OX2_7x zz>(D^DbBTRzk|S^!+J6d&<{8A$n37U)}kL0JbwkS!fSe=L2PZZCWCA?G;hKNXr_5M zeE{!#BK=%F-!rQw_`~hc{Ld_2-!r*>#?T4y_nLPZyKp^^CnS_?7Dz^8$pjm+2BGZr z5#Txu%yOyJMBYJHZdSGoQMS=6nlaPAIF#%;PCM0NF=iGxGg#-;#?kur;LZqd za*O#V(nbiNv8{#4233eqO)W6j)YcZpaQWV5Ir`e}PP@}bM-l&L!GF{p|Ewf!Jp1!^ zq;B28$Yml|54`qLGsVOnNS-PZvC_Nft{P{B+p}~VhY0*IGyZ6a@*e*TV3_*4%LkIne#U;=0c8N*s*0!Ye@FU^IP6$s1Ay(D-a>9;TB zI1Dfxx?so#nr%Z=X;60zs7oc+eDd<Zks7xEafIg;;?fjl^r!K{GsPdP7EqM#kF$9cKMZs72C0XO4$DMP=`~Hv>$-e$5cq zAeiIw&MO6~Mx;%f8ne0IInyB8M2P|MLV(RK;E2A7YPN|6{9d0rNBDQ_aOD`adUWZZTp(llg5zyy4~&=?F8SqPc)#jm=GDyb!T07fa&e}Myw4D=pY1cy4XT#O_4vr+ zE-o$jh`7P-0^Qe&Bb~p4Pz*qA=#}e#B(1JDDVb|dGG9sx_>?iMH^>7O8D?9jz&kS( zHM%?SsNHU?d2&W;O<-_MY%r@Ic%o{{c@xN5G({etKl1?lM73EX`n3iFNNsk&ahu_G zz|vbDYSedru=XsGYbBpG(wuc$Y$SV&g4G+5=zWr(78FB=CT0%urIjK=`ZO63Bch`^ z18NcpRUwk)5zuodsx}r#p7v05;Hh^f85Tkx3>r(7i6-jA=|jx!_K)AB!D!(2!;T-? zZ*`T`tg<`gF_eK`DC`+Y4um@Tkv);(QE`Fj#*13vnkonYhk<#BgCSnxtZQ$UgY~ty z*BU~_y8#U*L>a@Sg6K5e1x+j7Xjnsa&Ro(D$7ouRe|(*kt^inxXcV0_FG8({gv~Hu zqi?!?Ak3_mRd@k6CPKY%AeIrKH^*abuj5XAB@loY_ zSR%z>_Xo5I$|empq(Y5wP*gAsEiS@>KlF*@tU!Br99X3cx)5QkMO8mq_-HKPHaV%Q zH6^t)%EB1c>B(M1n9)3>d>2r%Cp$99ehh$wp}-BPIOclEbr@Uh^Mp2oh12km>e zCJN+78z7*?EooHtQ|r((Keip#oFck=!(|=rE{;W*JAx&QiAExm?Zzx@`i??0-FQ$x zLS}E4g6bmSzH9;oYGKC%NG5CYTJ3#+NQx$OcK5ciVYvB?T*1 z;gTUPC2@#Gm0o8*wd{7oOp?TQK3S-MnM;vB{jh>6AEd|kOfnq-fum@Q3XE`yXDyYI zhQBd*^1(q8T$HxNXD(Dd1VKo-;wunBDKx%k5;V_Ts`P!7<0WA{-q=#O(UWv2i3-r8 z@CRwGwrvJnBbN_}q=`F@h(!$?!Ab_x9$N^c;inLiDZ7>yf;6TiM$Rtr$f(36TF$7% z!{~AdXnF^Ay!x|y2&=ajCKNIT<&X;9 znSo1n9B%yG3B^4+_K8s*^xyksfuA(5xD%~~pKY{d-2D55|IKqTx#GBSgmeG?yXwM5A zZ)&6{hI4WF$o8L{P)?@$it~om_KSXNOffi+K!UOZ68w*q&v{Dl@sd-; zh(S5W>uSgbNr7gD!B6eSpyXFcZoBAX%E`($we5FXO+kM3GO{8foNlUj?D?NhSxI4~ z7X#NW7ixZ}&iZe$^5W)v5r6S@1w)6C>fj24&4YK@hF?XmbDQf>O(_vx``9xs(-cLr zG%9glEJUbjcspboUl|XczSm@l`JNPM-)rL1*fd;pAbqF$Xu$rFk9O zRGPXy2k)^kUWI^4#LWUp{+mLwN5|;!Q{-MQ+992yutA4o5Fa>W=SkukbDVBaV=iCx z5y)ut;CPD!&n!(yI(CcVJju_E69iB(XI<>}^wmRIiE> zQ4KCeJ2o7V=xr(Yex1$fe*6s2t!PlNDVy_%zXUg43$zLQ z$Sxy$3|Y-)BFOvInmt#FD^?49)XEBy;w8BoiYcg{1d5~78mD)~pu(xuO02UnAIoHS z5(lfZ5Kpzjb_1w~_~Z*!75vQ%=poq0iLk^Q^P7hbCRjd!+fR`M81{h3rRxaIQX9Uj z^iUP6uj;sr&z&nLxR1TI*HT821aKJ8|L7{kYDSeS0AnV}Z)C6Cu*RFnY`kt>!S(v- zD(B@;%8lUEnt03;~>BpxL z)PG_iCI>tael1`L2*dH~A?ns<*P@5|jG{x0x}1% z+f23OF7lBhY!bhrFn|s6|A$UA|1ap|h@J5`Cvlf3k7XGW#$UcCEGblrW^ zVjQJFulmI03y-{d(s-~18<=~#>gI#2E!Oh}_yf)j)55%S9Z{dwmOTou7`31I3ztDe z%lq~wvkQ1<(7vudPZPl=>wV4lZ?TWzG3l?q=r^QsV$mg{@cZ`5dzOWp&Jl!>xkit3 z|F9*5PYbPK>u*H=ocS_v+AhNSN-(xYx&O6>dgpGX_e}kl%xRH3ifb=!2)_N??WGa5 z{PyObL*CQBnwsw13(4UJ2c5;*60e+7e84GE&i2Ma~$kiN}| zsFcj8+AA)1*x%Bo>BGqPd$~!A^Y~H5vZW<0o&K6Y*0Va>T%#_ZKX57?-?XtX50i`896o8p%iws&s)~&|Z1M z!5i={Y1T3QL91lzD@hj*2gGruDrMsliGG?SPkghHu4~#zZE{2Sgn{5^nboWEN~EM` z#i8Xl6Le)W7d5Dh{QeVzNOe67w^$<7rUw|x8PK@3lbU8s3>!5`oD$G!6d=}np5 zjp3|v)Hi#d*O6ky>61-^%EW=yf{@f35szOKr0(qX(4XwDI6fM2_jqi1n5t%qf2uJx zR+UXM6S^a1@p-C6*e2xu%DoKHc^RdVPfuhd#+vR0fFecdL4sZ%W=?$KAC?VZJAb^p_jByg~pWx`6bu`>U00 zsPlV+e*GBvGr(6-&&#hToLqdfDY%#co_Lu*$;Bz zQ%K!d0;1W+Xrd|y^nXEGc3N4vI$#WiKLRs!m;Wr?6UCKJoVo1iy;d>zC@^AN>5n7* z`yoHP8!4Kdzy|uj;@BU+cpezLXW!{7wlJK?;SB@BR)2CbjD^*A)6_RSZaGUf1roDk z&&QXo2d6wh!LO#yR+fEM(=w5X-KAbjEji*AJ;*ZUr#%Hr4%SlizqzPT!#-9XsTAm6 zim(lFKee_)loc!&eU>ZIMMtJb>l)l~NX7mUmrZiTH1SmloVgD>SK`POQrje56Igxj z%9KX%;JJc%B;TR61+${pI-&0Tn#|dl0eziolJ^mla&@J3kL$hd?3w3dy;4YUPdyxU z!uOXzdY>73+=n{z&)lw&-IfXFvw4Llq!YVRdpl^BOJ@9(Q>Y@{qTWes*>brz8PW^Y-3fD*eYe zDKb`%PTEK-OB4dBHT?T7Tt%E@`Yig~Ir+yNb{l!+1;dw(4&81grSVmS&%7(V7x7rI zTs?bWsd7HBm&2w?ve@7MzRYJg{;Chna`Vym4R6yqt_4@{mDZXW9Q8=gF00_%4X@TZ zuQDoN@G!iy)Ni{BfxfuLn^}T`87VlWTQ#;g*B~w2YF^{+)H$|H&OlwSs7%`&QZJS_ zi+>F2=CFD3W-|W-W#j(wVGB*+oaDqJX@z#b$tz-(w;wj_pkV)vxI=3@azar-k2t)Z z{`<*T+weLD#%Qkwys97{_q^onVv=a75a`M|W;lz$J~{WWu+Q|1klC=4WALkNk~M0M7M6MH=Y=~=`w$vd zzxHk6%n_Tr+{c9De^}Skf3&}deWO|iCZNJ{BC%yk-`VZoBz#J+CHgcnX()n70=WLMAZ3z`rzLG-)!^M9}hxB zuXz0uo@;*OS7_JpIz|7{cM_|hc-}*7RRqf zKIzf_93&XG^hPYIZC3x&HIv2p0mZ1M93FT;ddcfCTaETd<6lB5MV7y`Ms>j^b|T*% z;htsmi}F7tD9awKB3!llPyX8lO+435ykI<2nfOXEEL{_s(;Cth`*tf!Z=Lt>FnZWw z;%lBq*P7h5_7PFuWRs;;WD3S~A}VvQ?2G3X`d9m8#J{j|LH%uvVaIgd#P@35?)UaL zJ7(g=t|BX-mKhOyw>(AV*;;)Xyzn`NY=`Qb0{CfK5?-#AN zx-0B<`+bF8yD>*~-aNP(^-Sd7C+f|vjk7-cLpSg6Wgh+~DfXCZDMjMbdZG7X^eJM> zXZZuo4!Z90cF)XS?3;#9+`Qm*%C!uAK35DNFwK@MztsC7lRa@e;o*L1N%>~4;a>@% zBudytgRQ~HzY>l3xR*U*I|W-EXU3Fym2o$>gN7i7Qmt%ob+W{k4m+@YeFE`CRg%k( z+4Wyo;+|>r>1`at=nv2Jlt;=5zHieh;w)oU_8;VP$c{s0Y=+`;dfy~ad>$O zJdn00s&z-Pp!8nx@98*c42;m_`8BBQEZ6B+A!~Icmgx-Of=#$ z1`ODxu4+nY4Qp2C|yQ^ItDZmve>xEAJU)!YhYo$MBcWwFJV73SM&$J@%qry_5c zyT+m|!qc;34S(g=wNcW3A?VLGz#CC(D)&hcn5RcQ)Tg z#>bR>(2jc7UiNt*^*O6k;AG@`?YrOH?otE`e{#fqWpxS^MSe<6yx|sJel{Lz#TtkL z;B~Bx9KG__-OHLu0&R(&EP1+BL`4)kZZe|oESz^cjJ@VA@u))sAO}0DuY+*GLnX}I+&zewW$X})gFY*#(9`uHeBOyC|ybx9<&dalp}Q@$>xFZ z1H?@qdWui`{W&;S47+PK?7ni=eeqN`JXer%DkL?XMP=k;c$Zp&%cGsm+S<=XPm{Cev&uN{Hd#bOO|qA0a(D)-Ue?MACBnZ_VF?6SHi6v- znTRKlw4-6y2w_?1!SIP=P~}_G zIvM_pjLf)%t3@rO#iIPwoJ8Fg#B2JTcD&{Du>32uI`%sO9Q3$9O+msPC(gy)>A3sz z7i<~X*`)iwPJxzA9-oyQ81m1|sewYBi9-8h{(>SkN=#v*$r0^Yn&4Wz=n zknm7EIWjQ0MY#HUEf-}d<=aAK@MQO7W4ByGw|r^0LPOeWNzJ<=gzqG~^q+=Qbcz*@ z!-Jq+S(lbdg9osI_t|d703;7__)Ao-S=goa-G??#Kp6W9)#%eT2B^yT1eWM zV>kam-Q0q;*b{Y5R?TRUK5$jvLf?u(kQ8O%;?})i7dt*$a-2mmT^qXNcDg57(|K`% z`g_o%6kG`;XNrebAG(u#xqC=7xaWM_Wds~I31*G;5LfP|XFp$9UDv>84qnqhbzE^3-;9yN?alh_w5qJYOss3!LOpW$?_UcdsIO@8ek2abrcA z?SM{8+8o_ss~yk&g490z%9Hr66t+A$=GyRrz5`otgsqo$dr#(Mq)?6qhZoH?gvG>Z zq?BeU55{M}gU}PM$WEg8L=a)5daQdcp2@u&mKm7qKOBp`d_8+9k(EH_h^_31fBZ5M zF?%7Fepm?4JekYcHmzPi+R;$3q{l=*n3z8`&EAO+iAh|CC;#`0Y8_3EYRtnCVBZVl z($hlNFO$z}5%G<+j@?9;zcC;F%$N(!YJ`&g*pij+7yQiVRyZ|tm~cLZlai(W0Ta#+*?>xCjSAI!65zYF0(0{j^k}9`5=A zzE7{N{(YXL*B|{C(fPc#YcBl=wqGO|t}e_XtKf}VnNKgj>~Ib3NSR9|s0S!>WQfj^ z6=qqaj~{v%pu+nv4Exb%J8C)-e!VOeWnSpwfqfb|vrwizUzcC1sV+#C;6Rwu5ITn( zJ;tT?e36T(HaV{13$Ey;OlqS{5!|9SmZbkC&_21pAhe^VeE7ku(XoZl@mH_92F1O~ z|E0vYw|ht9i2G3P*DN($exG&n&T^F@!GZ)*_yGr`Us1 z8dpBxx^}q;@fHc66^ASQTT>KUpJlG88LZC|)-@ED&zFvm6hO|lo$;KBB(>J7x; z#(T#_;Xe3e-$|H*=%+;c{#4my2lr3jbTVw7{U7#SiY+ms7rj_ z&n0A%Z>M~Iz;)x)LqE0$zC!S2 z;m?5#L#IsbmXDysdYal-ZK62;{q5~IAqkCK{ z)2XABkFwwRt~TGP2~*?zZg;;)p|0ZL*@T>IYRk%F)Sa%rgZOt(pImsp=b|-}{V>Y- zkm{QCgQvTlF7lK8b^aIYmH@*SK0Wl}&MjgMwKWZVn?ljQ^)Bd9p{zlSdOIxk?T=Gp zt7@g1mqiPXmxVd{6jV-3-z`jhGd>*|yFdCXe&_POC>JqfB+>F$eCpvu!`6PmwVPbg zHz_{bmtFG^B83Zr8JdEm^bhx5E0Cvu<~oXo1`^(=h2(C{&pdt`*EN^7TOX#>ULK&I zsl)NnGzAv8J7bjqgD%FapQZksi%&&Qtuo>|F!L!5c`3@DDsD!m9okmBlRIe949T>a zhhMpA$^B7U4o*&}1@EwKd&I`we!0LMcGIIRMLmKN6nlcxPLo z%RNO^xd>mK9t(L??40)QKCS*V498*4%Gode|sPO zVc*d+BLqdhvj<3{-PnF7*gpOS^6^?Cbv6{8ZS?_2qowZN@m$+upG2nY*nhO_VG&0??I*RKbRC{)Geg`U=UAkKUE*66i;>E) zWLbX&(9144x7T^CS{qTf6eekxYFab7IFNb5FsXDku?5H(hvf!-Ri)2_ zOX(A@k(E5kUCI~Jl?HataH|!JOLBV+5TQISZT4qoyvGlI@G9{KL6K;kW-}Lc$95AQ zl_m^~foc-}>52L;TQmJwXTmz>t+Bv3rPy2D_(J>F(v8G!dSL;4?0=L>Hk(l>)g&g9w236(1 znpJE$p8D3W9dI=_E5YNyOi0e>fM9;=weG~zLwLMVX(r@-W*W}!)~;^Te`6-a)_?XZ zb&EMi?%fhvkd#+#+&!96^AMeOuH@?7`&w`EM$_J3E&mezc{Q^iC4cweTdnLTr6vqL zHKh4gv-}t<-nzFa>~p4az$d-REc4HBWm;PE-N=R$e+05E*|@;&*8FSyMyZ?uDD#Sr z@D0vefm9(Tfie$!A<>=m%JHE+pLzHIcjj*TnREPysYyfCstGFNlHY0!Kk%??1UXoF z3?LO=C`-u;R*g$&trblm14xJko6k+8$yb(Y{)S{7tE z(CBw;16oyh|?MMNcKqYrd&!@&7+?jFD(8Yqm!Dp(0@;AfgjTCZ#GQM zA8br&8|Rze{BUeRSgJKqZ01V8s;_lRps4ykYGk12Mqzjk%qztHhEnXnl)#js`YA}5 z71!dFK$}{UX@y_8aWVGKoNA>*FrU(g^_mQKIqM`No_vg{H`~|R^4Beu|Cw$Jbc?5& z#7oHLFw2EW{7oj&60AL!U02Kgc@)anBXDH}*M{#irE?>1aW0@+)J5})WOzLFZM&vd zVEqq%@cK*^xMljiVyvC33_35@+C-!z$0QxPJ8R#zN_V=8<7%i<0me+ zND_KVKzI&gxf2k8*noWwYSOsrnWKroh4kA>OGo&1B??-mcVTKPt8(c-UWqJck>RP{xVJ$uunMI)}@{Y%4^c={N!QR(<9ve#E{E6KX5(abvy$KFAE>?i(N26 zQZc?F*S96%y)EyME#GW1W2{dMyI6ClAIhfIoQkFnXK(N|@V{|UB+n&pOmJKHPDEHr z^5sqLTVD$~Y6V%cNHVR{4||+XIF;01X?Bh;FSfY!Yy`u=z}U&6gv>Elx@Cd5%vT`H zTk@;nvPxEa9S6^LMbD;Wi+YP)P9}0rGXIg*t54;BBh)H?INRIJ;ppYBWbdEU4t7!% zn7uC$QRC+I!lg&&ic|iNnjo*KeQW2r_RSv;6PB;w58dZ`Wqvl^@(Q_h+GAn3Kv?QZ zXpIYGZy^HmqovwZ41dpYad9)Ut^4n%Yk(8ax=d92c*5228jt07Vpl?k^bhlz& zB>W4bzwF{MIU74=;T>Le*6Tg?vd(nYoA6o-uMbW&v9k|&f7JMReYCzAI}HAdXiU-H zF*zMKVfXpFQq|ub8_o7to&Rn;e(v=-tT1NjqxasEJkg^ewEj~=|6olYA-k6zX+2}N z`__9}|Knv>y{WB#(L*=?@?4AtM!!6a9(4WpEp#qU;5(BY7jGmOy&EU8OH9$p7Ud5^ zmb=j)u~@hf=&_ye7NYc0jy6jM?1Y^@pT`X47BkQNlw{xoDN4v> zA1cIU2qN~qSNyw?1h*cmk%kq$KPSs}90Q`5b#iO~B${kMC&?pwmA0AcI3SP?s8j*o z2&n!LgbjU!mGo}#&^vq{rgt)<|L(e>?k?40g5<4E0AIs2s_6B#26$EbdoL`(SS)gjs%UE&`Sgg8Ue+j;nw?rCy@ed1w`xNvg*u~??sC^j38TPNU(|-U&*^||?DVjqNEP--i9&&hf zo}?)Yi(3F$WW@>{W=)`IGC>zK**O|;t5t9#^!x$`V>2viSlxp^F!fzX(g55=*5Crp z;J^un-Z65lr5K$|jNhwqtoYuj7ZW&k~VotnFyt{FN-`Ii6A zz#emtmiL=f^!KX-0(uRAV=ZH#*`gZT`7dvj(tv%E*WDWjbe!ty4>M`~W5w*!PCnkX z>47PYv&^XPN|x_R?g!FzyI)?k#+h2vxUE^?>#g;!7(MHr1H(3Jol_{C!2zwBJd67u z^+!tw3$X^HCN|KWvGPU3ikDsU->p5>^q16ZMm%-qtZm+MchoK#9xgO!Ic~#GE%mH5 z*y!z({#K4Zi0j|Vuzg=@`(DrbX@2*+aAqg8>!Vc1#|_(EPt51zc3%%{_P*=0dk$S? zU>Eu)l(Z&(sZD$>wfp9*`(LSDUq1HllHI=@yTb!JHXi#UqV^CT`|5hV)v-|x*@;#) zeYlq$+~0QT_(XM>Z9}Ck_qaXJyKzRtczK@PmvH9dPLBreMOD}^*WlQmr^6i+YtD$t zUJqNnXnSVmG{kPIxg98NFIgYWIo6#w>h$Q(l-h~T+q$}%3LWn<>{kbX-z|3kGRBlb?Q$>n zDr$9)Tr@F6pkH#KF_T>s5K8OsUToIyK5$-KpD|`(7&8thVGde6MR7&5Zp$PB%lYgz zp-3S++q0s_ie`<_f?lWwvP_K$#bQ9KNlJYm#BH0T!s-aY1J=rbArp#YDd};P#ZFM4 z2ty%VjJ;g$dg%6Cnm%cx8~)(I(<^gN`$wKGCTrIMpGvwt|3WZqP@`JlSQELB4~jzc zC^y2a>6Et)WF>pR8Ua8X1z9R$bsXr-B9{iBhssQ{ffjgyLB8(fa050mxQ>=5%Ot+Ej2R4p5-6_!p<`i)0tf2#N{S!~?E4ic2=dqZX>fgqpEIt#P() z42UTMG((e7jWD-Hvc@EULz2~qFfTlaMMGWL$ST=`S+I`fuIaV!)9=2MV)VPUiBM*k z2Q1tw_70#f^rC#!)hHUcGY|SN0LtRSe6ld0nU$TsfWpmt*h6uFuxs5=eFlKt23e;| z*0l?c7?_tmkR`f!gU4;5zAH}J0V>+2O*E)EKG8a8Qyl_yd;(-XK6t_5gdKDDJYipk4k2Zh$kx%?mzBMo>sMaxm@b}uX5aT zaP~>)LQLp_&Mx>g4%oZ0d@N#6QFfSu9aUkvetW{0a(+wc2P>p}FwE{h`rX*u+W%mV z6D{5^{5yoy^-~TYircz+laSjFMxKIjO(I!`0BY?*bj|Fa53~jf5Y7r!I(VL{*UFxXtnStb9I^5TJoO#?h9R7ZfYL5R z!j|Tx;)mWPoxTA2A3=}X%xgvqp~ZD%%ulK_0VPaNM<}T987%P>P~4ojF-#i&G5)Ln z&9QOY!-xkDgaalDq~Efd5~lY6FMmK?*6K_6kX5bF%sD^}%>t@8Q4ClC2k2;zaL+a_ z70+Z5rZU?kd0E(b4Cp*5`7-@9wVLvMgvCfv)W2WS&=OX|k$aCQ7%GFNuP~4Qj(;@M zIp$*PNpYJtSG9_!MAs9*=WU_%O46-Sab;?&(7zCXR?z_Ia;i9q5X5gSSi`5g- z)Wk1-y#p5cdl}a1V+f$ag&74LCDKh$Gg?AHD^oL&T(JY1+Z)PY)=cTJ!_4DPgB6p_ z=TjZ2^|=Q;R|_a=*?>EqzRCE)LaN~)&Syt6(Crpz*I#w1aN*xUuLC& zr8>XvOEM5IOP7V^HuC7)V=312uRFXGfRCwOSVy{a#6EjJb4Fj0vDF#@0^W?e29K?o zQH5tGRJG&^9_!~zYMlwjjj1z|cY#4_B_@b-m)qomi`wrw{eV)Fgyb`^- z8FCW63sA@3bUw#4*W>EGvDF6{y&_>GX_b{uGdjMwRZ8 zX7iu_wf*$|q221(+LPrGn^3@zP4BCEx8jO#H0p!GK3q8)hGE$TYP(g?pd;qK$u{7Q z27`AYS6QVdvL8pcA$j|E74VRAO0;&!mPs}sgM%GvGda>zw-q)$o3Ut-n$Mog5DV1X z?f`txPw>wyjjeZ+j3%9*b z{#m&pCDvgzK{BX?Vj2tx!X3~&l_O0Qgpq{~qQng|4&HmmBSwa^ z3y(EPpXp6v-D<<%s(?n`(^+n}#}CHDzq67Xi1HR2AnlJ`dLN3mFD<hK7F%c#fH_n&C>fNjQgC}Cn|RFpf{9Yc(;>NM2;{xjxmTw=*s@XrI*yM7-o1ie+@p6r8 zyrLs(FqWq|2o?H1jN=$e`AXkV`?oDl6gKr~N|KqZwIq(FTy+)RVNK+-K5h4E|?gt+lJ{LTR#1cSwb|*C?n2?(Y;y>ZMgq85Vv47itN- z{#^8-+8X9uR{k1B+MR5KkVz4u4vP}lZe*j|Ies6DG}4Ej5@anzWY(DUl275){ICME zRo7EaA0M(SzMbkb7jetKF(_QmfWT#NS~o0&>X{YKPzA)P=VF&y z_(o5rLu-@eAJB5(G7MScTc=a)X@p zA}!466!HJV)m^_e`Th^wUo(0VW0Vf0yBnn)p(35q2q+)ACTjzM}iY+4|jd&ScgGgjrHQ+)1OJt`RXxPu8UTksqj_Kx=Gv(52L;Tnq&ouT;O{Ry8 zV{To^zBR4;eb}T^xmAD0o%fc7xz!fes9?BJPJpl{%4`PZrDA94)#)(>wbBOv*C`l= zkht(G2_v0i?0>KZ6MT0Kaz%hSK`EXBeYV=Iw11}ZB;6Qh$#QIro!9@mYZCV=(rKTE zn%fPRP}XN11^vJai^pOFa9=J4D^0U-heoI;s$`~o-DEkBft(%vKwyp^f52Jrj!+%! zW2QzIRHie;tNT1zcujJ+j)qJ@KIK>a>3yUG2B~<|I+%|(n5Xi@^|=^N_GwyrlY|L7 zyBON|I0EMBfKLcVn+h!1!ge3@C3uqO1zOh?->-t$Z;bGqF1m9{m--}joIpHd*H@uc z0_4{Ih(AJ3rKpeKB(BMTjk_r%1sicLz9kbuFwHyzFnMqK8$o!GxyQ)I;67mA5`54$ zcqQknDHC9$Z#=T>6@t8YIZS2TM8Lgy==7)cWR(LScEzu5 zvf~xi7BFSBWo-8@{h_%8s*0*84`g8R0aV>KX{@a^ogrLg`kKKOV*?s zBZ3iT^56ZQ#NqllU2M&aKcm?x{0QFcGA;$PI=GcX2)FwPN#5HBX3`*TQh$h2xG|-q zy0?Mwz(Aw`Vq|kV9+}TDmFzEs8)7$ngE7npvps`M-Q#IzE`{)Av*FK~Akt)@!v6#r zPq=p3li&n#dKp}gZ_CW%1U@Oq0I|B}ZSs)4i3**F^m7YVh%EBp=>46V=ez$KO z)n88yj7e;;=^ZH06!;;?k!F(bK{U5FMdb9bt+LCk6~dcthO}eO1$VfQEb4)vxAj>q z(2|_@=p5n|El^5`HP5VU5o#qOMbjI9DtKYQN_mQ8Wd`R+5zcQ^I&1G93cRJEsuYc6fi*2(bzr3+K30gt|!anVer^cs_}=e)D2j=ARqEE$Mx&a6b= zK*ZfJDg3z=px(7Ok)+l7NO3>dzH8}qSX*g$<9=vV z*YeswE&9NT;-{PP`m+QlEl8D2keTTcgM5kgX~Ou9UHbH@&L`HM6NOLK#lnM)!>LaP zg^YF6KZ;gpN4HmA!wQ{u}P{CjcEz;W#h=bt}^g z)xbXGoC1r_%!&^=^(OErWQCt{#Hx;+lQrsJ&RgF2a<^<%g5cq_O0#~Go7;xofrKe9 zrc#X4v&=_avcfO6y!l-S0&Ka4g&N&5=G2@2!nmSH(dHZAP}C<%FxJQ~ckxJX%#hM6 z@uibxkT?gnnK=g^`yjUxh)n7=>+v^!=&`rSmft*tqeen)R`8|G47@xXm+reG&F@=g zsxVkqHX>iauQoJTDIuAxmGG@Pl7f;7x(U~7F6X{`2p1VYAoW>Q9C;$@ZVGI)iXaaAtaUEAp3R}&3?i2^}mqGiT6vA7(vleoXJojC~Yje~1}&?0yd zdcSBhE-2PA(slK83GS>+{~kY|GO(9Q1j<{i9~IbOl0Ujl(oHNcDC04h|PC}B?U;#f{06}+T(Up3vid;uS$ z0@O)zX)NUQ{ceo>4n&pV%*uc$S|92LjxGX0npKK#^oa-i|MYh|;|)9!0iFKY$1n20 zTETxW28bE~A&o8y$+!y5`k1v6U1w9Ti1g$6N(C_~{xQZ%4gD`MuI|6>kRq@Z;*7qi zg`|WdY6pa(_y43ZZ*H<@W@~fQ*Yu) ztH<|dWAhB)#RS|d*~}NwK(S}IGrf`*j^%kDjiq-J~l);zO5!6zsyj4A3q`OI_KWG zE0r`|lQf-W{=LT3X!WVlDt96!L2Y9qbfss%#&pHAg99Q=2U-z{;+?pWi!?uEP-CrB zzoy8Yz~y+8ez9YqpDRQGg|?!YA!Yi}A|~$sI7yUuhc~Uk{N8UykV%PI_l{&zOwet& zL4PQK&8BZ33IfUWYhrPJA3&hP6M&QlnAgYz;DQsk=@X|=GM*Qidl)bLFh(gn6j~VK zcOVH7fx9xV;_V>(bQ8JeVWfwt&_Tb@G4QKMKc5juc@M{r?c+NHD#JnC4sY`1*7&l^ zzD(gI7mzMG4ocggDiz$`!Orbch?ETwm}eql0OF776Wlfdpv;8)2_6RkPO7n%#2g&J z98CVs(i^DI+*dwr655THS|Anm;!!rR%CH(GI#8(B7yv=>(}2Pwco4-_z{3Q90g5hQ zMaE44y+F|fqq_e0Ww8F|3MLB2KqQ0dX7R4Sff5D5O0iE+!-3jfrH6p@{~QDSMHO$*S|@=*b=1W3-8nWg;xisSqHCL5GQqs zBF)Cs2e{W+@&UKq2B4?9YNcC6oof@x+@Tf`M~tPo(00~U@Rwrzrf?5XdbLz`vEuzo zbwzhV?VEp!>#(MEE~O1**t*`zT1A6W88BU=Y3rQQwnfwSC8f6(VJMH3+wb;UcR^dW zDesd^ly;JvcCwUq3&M8rz;_{Gx5R6_Fb_UHSK1qH+M7_?p9uRe=Xz77bZp(H=yy$@ z{)NSU4O=`{bI=qPiByhOyJiIVKUN9(|Fg<`RbEU)SsxzGEoU>x}^BfJ`W}iu_3IQZ4*GjX> zohn$|BS$&6K9CGJXTYCXH&=J%aY*CKd^z<%_kr7@@@)!>PXlKvJnNnIoh!$v_(9#A znmHQeThU7Tt?DXsm>4qmx817u$LtK;-1TQ4Z;=Q7j3y`w2!;`{~?Zj?65ozb~y z4|Q?Wn6Ajrc1m=M+MaLr8%s)LyJ=VaX!^#LN4d&#J+S}SSoEWWo=(3sxqt4Jn`6{F zP>S`#OFf-GJ}x}H{^siHr?pX?zS$GO>S4a7&IFd%QuMVb%lCEb^;(=>v46MYm*rRpNFskoo7Q;LV+TNzWME@v~9*JyrO2Aw;PGC$>ickr<)v`ay`$DHDc+g-#^ zB1ik~2zig>zZ1!mijG;wBjSeMI=bV3OFH}H=vLqV82#J3$hRf9x)^rlnU6Pd$dLtE zxsEqS76Mb|o%cnFA|d5-cf1nBJKvY3#N}63g`YBcNqdz2&N;Z?zMY;dvH08v886c$ zflRG#O2rV;eSLJS1oXFB=Kl9*C)HLVgb9JSh$iS84_6X?Ml->HM>HvPEh3|AJ+UK;a**`5K?ga2eb(X+RBStZ8}| zg-0JcTqBefzAcDwn4VQ35uJL5v4XWYoUO+f;}e-;G8+nl!PTbQ}tX*<57xi3h2`J`Fe$I`GS!!Fxr#ldmt)7&?+db2+t4ZgdJ zxp}l}mGR3a?^VFdoqy4ngWoBH-~F5U&~Me3@^M=5MS`Zty9bx`U^mO$B_gy@|cPMvqey>;UX0-<~=BFF~9CV5&Y`nRsrb{!lb_V(Vm57ZzB1Ik2+&Ik6y3-?uHH9 zM)AWj&J*sE< z^dz2Uu=xIvSC$&^Ij1ph>GA|s(+$rVr*rlplG`-L&pZ5LvZe25yG6M_wd};|s7xMh zm!|)4TsPhGs8vSyAMzxR7WvI^Y}hS45qtL;zuxTvsvoUgN7#{ZR#L*>s0Q)7;djrA zoSE~8Zn1iog}3V#dqtN%v1D)goW5wYCS9C2>J8+(G*1*b>YknKGMCQvy}n%)>GH__ zRxWQ}EmU6T%9X$fJpVI{$8SC2e{K=C!mBh^*nb6S{z{FC`0o4u!$`31eotM2s-J~s z96s|w5>z;-H`zA8iL=~yt5WA1zz|JB-B0^cPr$(#_gxEZC`1i zQ*!dKeusb?AWlPFsFuN_D*@Cz!3M+!Bcr%kw>-y3k&ZC?!Y8a9TuqiwA*aNl&M)xQ zVP*Dzd_^;(`}iU!o^bDT2*nCJg5z(XC11TG z=X_%pFX*#wrpPGkS3ap$zaabU+KfZzrLw;vd0d&oUo5mAtHPwu2hDxFa$Y#I^ryzt zKdd1hEd8t&{>aDIs}yhiSK-$6={?QnEd)hngLz!CqukE8fxbZQ-!XR#G!ALt{~c>` zp{Xh7oMPRTADvh9)%+S=eW9qLmu#&$1zqR=Dr@QSE*&Hn@S=LwSnjlTelO(>zpGgj zA6-b{GC4&j>qFhP+;T3GasPSpsoKx8xjlI4#8Dzscgc{wfKjd0^dNLU%@ekgw)8#v z!ISls)14c}ZFZIFoI!7fM;$Xv7SJe7*{A2~uE3+dkIqDYb-twMRPOduzIc7-u69~k zw8eDFxrD{+`}~d(KX*>5j{Uivv^xIVQp>d7eJeh5dgt{-+>W{bj7#a8w|(bwzD+_0 z6^&ILO-uTeCONSEYf>q2jWRpo#xF^zMwAN_^=g zzqcqXKAnYHvAi-nXPg*&BfDcSB09Jl7&uf4Du7_-U)QVm`sqY;w7!44M>E~vuPv!0n_Q@D^ zc|A)?m*)2d zdovW6I^*BZXYGmmcf#XWXP*D+;(pFth&kSTv-WH7{ol{|50BrTx%<2K+PUvF%71sb z|2vw!n{<$QFJWhL?Wap`&&lBoBI)bBljC=n|2rDAP?$mW__(Sio`}Vi71DcMO)t1&55mp{O_^nY(;+ z-04Fc8ihwK;KW_KwHYw#K|1RWG!i=5Wqat zQ(&ftIP*iSF)hg|hNz3e=~M59Y+>CgP=_Gc<6lW%?vv=hl0pDU%vogH_n|Zpe6L39 z?S1IsJTso0z)F{1U5{s{LPOVKOs5#$4Bfp3`^*A2TY%Nt#s6a=#QVaWdsE&zldX4R zoDbr>C{W*%^%!3U`P)2{xI+pV!Rjw0F%en#2$4;OX)R&CO#j7zd18}08B7|G;S82<^DKd7uugRPb`8@`!UEChT~DCl2QVx;IT4*ac9`yY z0PBoM4>ro^1f<+2W3}kgt?jAda2!*3#xMv;&02MER`+#S92IsAo$TzL!DM(oWm!qy zq#Mo9->4)%0Nk?-7K2HmnZR7vq3#D6f#{U0WiV(V^g4kB^N8J-0ewk_UTbES(^*RC zneXQ_Ll~Uvv`h{HM|dCu4U{;pNQ1K{(V6-iHSGWDfy5BbD_dU7K_0c z;^=Pia4Z=|E8hA=oQ-{OKj?p~Qk(WaR;je}VEsh5R9dEVJGK-ZRJzkqDo88c`(4Tt zM95)%_`L(Wai^&H{==-4#FZBh|1CZQ96baHl|l5%U~Xk_x5RrX@kfhgTt{UHp>iI* zaz3|mWL!C_sGP^`p~y=->rpw2Pz74ALfoxFBCbNTsN&2*qTEu&C2GEs&?B~;Qnk7Y z4Yx<4agTJ|9_n>II#_&k?q#WwP~}cx>Q6!3x8Io{Or<~&;okkqKcj@NDar7|xYC#+ zo1=;w+IzueX((2BB;r113+l{(Vr^kq+myN>SeOdw+x=Wj z2lT@TtSA-QiDqe`QcP2G+$p)kOEt8*#O_#F6HV9)0n06b>e`zXYgquh4ukE&-jM6p-0HSnO0bmNL`sfUY_`8;_SN;r>_G&Fqr$s7_ezd3 zYVjJb2Zfm~MfZ-Njwgc2t#=BXT<%^OO`nHToaoY8*IU%tXu;HEKRKc~85UXB+Nw?S ztE)6~As$FKzo8OCmmW*$SDINr@K}D9`}>*qShlZz+hTBQpnPReahrK(+YRf|fIn@k zyG&O3;HG=KT1o<- znYA@ams@Yw^DfRF_U`|LyZe^2YKw}~cUWQ$n(UXWhh%GpER%eeT0=gh_}UhImLt~x zDGg`iTn2Eiov=TDBm8_@|M@%l=W8E1+T0!l)i*4KH_6-Unp_G(-IlQqJEKLjiZrTeE7dO3B_^&l&W-m??jtG+UzYcQZw(&g7M zaDM!Gv2|KBCR;X`>aGIYvLdw<^<9Z=mi)-#i_T*!z8_xJkL}InTO@fTlrlLZ!e$`Z zW5EBUdnBV_AZ?F>Cu6v~5JqOJ4pd>@W2QRAP}6l9XgRPuMMdt|yzAhM7}V33BRM*0 zuo(34|GeZuPY8mGrKD>Wq1&N9mcqfgx?andk>s@8Z5EVdsb4+yr#mKOd^*1FM{sY- zF?0jVa&8a0j2NRZ$3GyrmYJ}>1nMO+`kz842N^~|4=<~Xg&kxw&@plCcS!lSB)OGb#?r>GueJ&qNy9Y)Bx@5=JYa} z!jyE;#|O@F3FSY8^VT0hPcaJ12cpsIn45q<5)k@GVl>9WF{FSTfot>NlHx>X}Ac_*i9DuXMwUn#gK^ug;;qeaUI+PcN^+#l{G(k; zfg#BkJ|Cl#RotjW6V>&@%zO6Wy$lCZ8b*8?2J{;ic)MqIoT;7|k|$>L1}S|k9T-<2|a!1HO1!;p~wXM+>9DW23)?!K8GzbW&H ze){<)zJ62bQisavt^3QH8dvcWNn0C@Tc`E53{F2h_iyW;=(foxZ0bh>UlaXnaD1uG z=+=ujzhbxKc4(fI`!4Cw&sL9zS6a(rv3>LC?G<7{+_`rVAv;!lIPl&^T27 z^`z#q8RVn?&Rde$((4nk*^)%bqTb!eh((PMJ*OVm!n;Z#yr>bd2OZrSFEu5nlSaqD7<`9G}#d#$JmW@juF zGoEQSv1Qbe8f94$;JJP3Fyn*J!EqDgRchV+f4Ia0=4S1I`%Vr(wz`!iuWI?OZ(OH8 zIoZ@@DJercTOPRGY zB#~rZQc`DaFV6KR#yhygw=ZTGx+YEA<;Uodwq%mq1SoEXKc2HJVtCWC-c#&X-^0| zB=x>uyHaVHue2YV_rI1`pvouDx9{h7Z@Z$yy?X6VU{c+;B76qTRd1jz zd_V3p>+o)m-n^_-+7qLiTQylAk3C{OFSpDSLCwT*8>gA-79r(o)-KVf%VR-W?%Pyc zUe{QGj(Z#Z^|PT#q_+Ff_b*>ztq0vzU!g9kZPL$*S^D(duNwF~WfR*%jW+Yw($ z;T5j$>lf!hLM<731Dj%53dT)V%Hzjs4;uVvE-88Qd&M2W$JXl zuZ9sNli!phJ+olJhg7w%rF?rR^N~+xRpYFtyA^x;#O%6^3%`BkxRkImX=LGRk#bZ1ka>LK_Oqqe z}#;rioKVEw%f7peI1hdC0Kp>66> zU7_?h1^Qvk)q$?C?$59F!=L~9+4Wf?EKDn?pI!SnVvyH4;pVXLo#UG$XYYGNX8E&q zx{j;QCqzx?|2mFhmyOy$=-WNf3tsmPZ!cYI@43AaKEL{PHGcB% zoi_xQtI-|JVpjv4@>H*my>@(W7W?ki+ET{ba*;nV-Ayk_mG;|H>f=8zg3c#AqudS- zQO$Roz5d!h1#VpsmbB|g3p*WmM9$-g6hD6}n2Yo8k6QHt!OIV%a%3b$Bg6xbK-mX; z5>lZSSeV&502lx>xK(W+kyZx!_3NY$fVU-zNo>F`x|r~pP|)vAE%YOkS#ah%1|Yw3 z0mx4nvgo~mZskV*(Ry+ATS|(_-Uio&s1otb2#rpLId}R_Khi>#Y+F*nR~ut4ANVBA zeNdeJ#eunsiAe^f*Hi%g1*V>LCDU(kKxp-FST*lUW>lr0=(3E3K{t@cd)x2K-@^+= zFgprC!e8u71jbB?Cp*@`|E%C51|#(~JG;_fl3&--I?(R_WtFm)21L8Oa)U~lH!4h4 zX_sH`A0Y4g+w%WdrGcbuXyFC-(w2fICaX*=v~q*lQwMA$c$a%I9z|+}p)p`}+;8ik ze>v2dN-2faGLrhqPUQX3hALt7O_=Vi-Te`X8u@3g7jJPrWv8xeqjU;i__}N&A{kI2 z$wJI|84#i|hA8}D(FUXQH1C~AfF7sbm})DIzb@jMI`8PXsmW}4xVO2f;v!6I2guS) zHIa|FS*b^CVNawD2u~b9wPgStI4ntc$=l*Qt&cmLVJ^^V^w7EGTbcgbZIpvgikDeA z(vJqdvW%F{*(~Q0O9b03BcREFEu4{9fIZW z(+}q|#%k^PLVQsWg`6vC=OO+4BO_3e7$8tM2-nt8^;tT_eOe2p&DH=IeNbFFskNYk7fQd43o8o71M8DbBKo5S*UR>V6@1=mqbsz?jNpt{4a-^({<;uEa^xQ?Hpkh1c0dzU z7U0hAIa|S9B0&&7UQbqQF=kMxrZP`|zc-%m;6vh zLz@d@a4h6a9G`V4L7$h|?|S{T^n3Yb^=~mYPNv^2TEYhE&c+3MXt&HE0;IA97e6`; zwB#>$S9y+=T=x(Ey3l{=_R|NeqXE~{mL{ujYd#8|2)X9|KUS&W_ct^m#eL=f!zw=p zws(leh6aU1F08)(*~%Rf9=9d*re&o)G_*K8@jlPvsWt7B-jD7FR#v$=FU_j@z?ZCv zAHUCazx!bty3a_voHxfC8dxP7W=Yiln&-bAAOK0ad|pK;6Mt2@O3cT?V);8oC7@aa z6qihVxxtZAsw+GZF?>%xzMxHWlPfr;bos+Hw=;G~!CQvi1)hOibahI73P^TK0U|P* zcO}|-ldb&wxZAMia?c}Dv<}5MCA9`F5|l!d9=4>0AD9Xp+x}vn(_xQ3Fctl|Hu!tO zfIZIERQA)ln}SO}2VlVjr37TZ;4Q{MJv2GveJYuIy__4484zAKN>xXTvr_?JsavO< z+%Y@*5%(mO+L?nC_Wl-yQNaT55G;z#8=vS@Q{?f$>7FW10`^>cgx$m}YY>lV48_x&4U0wgB)cvq9 ziuPLsee;g?_jlQ$R8t{7T>5G=QTd?76k{mTOj3*?d>UY;1kS0tJok_x4Msur4$gbJ zFjqWD+6=rq1;P|T8yzM;w|(ub>8^!;e20pe1G*B)+xw0A%~TX??lN6Q4$(3g*t zM>x$kHBmQnS8TzkD;AoEpt7?qb3ruTLW|D0C+_Jq_FeE5gUT(Yl-QO{{U~WTZEjZr zUR~Dj@&o^guhn6kUk=G~01$@9Kw4-xGv}cWC-~A}q6)B|G5z({MDsGrIXdAj4Wb1g zT45l}I*}59U@CL(#2f`qPyj>n2#&p6ssMsU8HowRrZ5OgGPlF^HZ{{1@ZTV%gD%vp zzV-t2kGn?CH^RkAMZ0ml8LF3Qest*|jR>#`fT->bGK>RD>41$ekRTi44NIc>0p5}s zDe?xb8iCKdkXo%FE6k!1ov6Yvm0Ex4P6unjG3r+c7IbjA2Ei1N6}eIywO!?L!|XV{ z@9^p9p?mA|WlR6*M+$TZ9Rk)Q6DE40jUVym-Uv?@rom9qFuLb}=}|hsn;zh;yg{l9 zAa@;zMob6OwQ0~aZLnEpIz+1-LI@pfQvwEe2g)l2)py)o| z%6k7Jydu16*p$GeO8N_Utd)^%6y+S8a7Z1P-@!}8WvkPXxie=)&A>|(g0F7vE(2;5 zBtDNmo9j_PX=Q|Ly}Fu)@QfH#%QLh1X0EjWRrEIX**3d-R#Kz0OM-t0>nqj%4O|S? z)bOpgt*q6uk|EY!`#G21Ole>vrd52s~A7T?!p1D>4IJQTDoIu)2Zm z^Li_oXpI`^+25zqooB&!?Chk?XQ~>i6b&oY4bK|c$f){CokxQW>+~^8n#yKvn$cBn zOlq|;eSb{PhR5}7#e=mL?s-gilfHoG0Yfi^WK|KFoQn5sk6!$=#o$=M8asqp0717B zAuL2ufXiqAz${gBLdSHgP)W=oC~vdta7@FX?0n~pej#z#BQ8sYPOyt0lo=5CZNSdd zabn&pvjx0`PL;y~J_JE9MHAow_e>cRitu^Ub-W@StnEUyQn6~BnYi>@+Lu)6 z0NLyfnajH@Kb2kk))U;*sX?DSL~$AbzzHSu3f`a-DgQ}(Uwl0~SVhIrjek^yYONN; zcWi&l+vS~{ z*lMvth2+@fc1OZZ9y;(8m@koFcYx311vA~13Kgz}CZv$TW}SpT1fo8jU@;j1Ym zB%9JZ_l&?(3~08(MFp&fD*8p4y}N^+`4v2o!seOGE9=0g;}riauuj@my?QR6=Bi(X z@~zM=vtWs?aeU-yaPV-7zPN^QKe#MDs|XsF1$j&x}_7oXW@BWJF-|4bj}-cX&rK@v*VT5zm+#DzS1mV^h*uv@gOg_ zg*2(*L&5P9VIdpAX*xHB zbpMFXb!3{SZcYE3tLk;PP)$=sB}*DuZKkjdsF=Nu4gm|zLj5H#Y?)Wy*U-J)Qf~Nk z!=A0izF$@YG^r3o%P4m6?s|6OY`+?CL*j3c1T5H7HgopW&CGqOL@LNHhMLx;GmiK zbSZ-xVWB7P@Ia&9ex}&8p+gjyv7{KVJE|Ah*RSCMF((tvjPmpu%+MS@9zrk!5bV5( z4h)b&Z-1&S#2F4g1Ax2>@SzL4DXNTyT_U`rZOdaIZnof`0I)6!>^Wj3>}hcxK-7$Y zGBLlp49un(8u|*vT1jwZ4m8A)6sbggIKhfps|bQl+Y=1E393d!?J{Vr9oRXDBNeYkH>@ z1Fy(XbEXk7bfR@xu!jz0A`Br_UOF#_rg0Do^It~G`3%^9eW?!xSt}VbPEX`H$qG=Py3|!ZpFJNOqNe?%00FTz9Qs<~Bv-Htx_8GiYZ=ko0%Z)2%C{iU8~#|LL<|3I$ko=*0fCyT2Q zUe7eH{uiXY3X|Hv2vOu2c++V^@^r_E769DS^}`?`Wc880)pf8EmDhj*rg~}^=6v*H zTe-$eTk3$h48N7k_Gm#~Kk%#WHJ9Q^1*>6BJshaY>w05(A8cUzBk*R7w}!4Rl}W8X zpo;6{BNR1vKnwoH4SdUn2gdf-vc}+(6JVnKFOVwQP)UVwo{?{+!{gCYtKSRKjj?(| zb!%sPTVKza&`tP3%Q*iJMEwEMS}-xPg?MwKMESn0>ky@^EI_Bg3l`iqbi7oW2eUS) zfCeZ23(mHdPKa;NC?hyvNiPP}lrW!tdqKt{dx=Y6br-^D6vQwHqA+OmjUB8+2bt)+ zXHL&>vL#+tf;#WKZ7O|#vh)IE27oNKF}sjp=LLcXndm@gR=}VZm~$ZjutyohWZ{2_ zRVQY-5T3Y02R~_w>ga};0l;ZmLFOY+H*%C1ACX77-@zLkR+11RM|ZdYuD4?j{75`b zCTT2?rod$N79sQLs2BNX%-kY@;{|pF3wfOc_E&OLidAE0)CDIY#T2W3rgdbe+O?nC)Z^Wy z2)S~fn)1jWW!^QPn{zd@lB%v&z?OU|{zmIN z(+toS+ZEJkeDkr|+Gj&kP1{0)vNs8Cs$bq&=$E${x)S0>$T z3x4xl@bbUo-&$7zJzt&%uvcn%w)B1`yf}x}3_Ut5tX#D|6WEHokmTPpbwS``^p_!Q z_^s?Sf^0v(zzALG|&u%ku3}x4T|H`@?3? z{A_+r=KX(RqBbf6oXc`+*?*-t4*I#=6(V{Uv!uWDy#EoeI&zryr?PJaX&pQ)R&TIB zB5`5qq^18_Y$38z)n4dKuVc|1six6scMs*4Hx!kV8CZmL4SudyHxYJfb(m`T!s^D@ zQjy3$mFuUNSArLXT2>!2H-7eBWk~E+8Ae*yCnh0q<3)_0N5``>i3vWxgs;+W`XM9t zYSIOYvn5#wNn^luK`t)C@1yZ1IYWXmBUdEy-I~(m#wERaoCGp&+=L->V@jdCHf2*o zqNyt7WBjfZv0-Fu-V<}7K!<5KTGM&=g3!~T4J)C7SN`lufg(Jkr>P7WMz(pRWk`|k z07}OYWyFU?;}E{WQmXG-Q0O#oMh?YBkgnpdZyKg_4IL_EB_2?6dhEcHNs2?c=sdg#8MPgfjkt32?}tEMYCI( z{RY5Ph=G8ql=X4OiZ8it=0J6tfxIDTuu>ZW?!M#0-$ounOFf0E%k-Z}s#=z!M9Nv1 zJCyvXLB6+!5ioOlMOyQYiHO9hWV1XxPcz+A)?)+ayyDO8O&dIYgl2bkF)2qMSxG=5}Q~2 z4n$l75WSZ5WDOEc01{_#zBuqFh`oO}UDALT-^PNC%Q@N%` z$?h_@Bky2|XPSB|JPbe_lx2{DcR5VmD1hL@)F^#un32vTN9qm%Aew!D;U|zYglvZF zUx$|aG&Qgj*3Wz~(l{3l42wB1Em*Q&{p#HwYJ1(io%TIhefxXo!H{MnLCg^F6P3l^pCjFLb!na?0PXupnJak(bo+WRv}#ep(p0oTXMEs^c#=aKoK* zT#Z^~u<-s9^=jZb^`e=EcbYYVotOVbQnwVg6(>7hBpI}nY?bJ$Y5$&x{ilwuYVgyK z7o5a$3FaM@_$fLsj;2_A&3etVt7op~9<8M@xPBazXxw<&Qr}c0A`qz+(PtYb6J1YF zcpDcPH}ileNAlK&_v{cksL9PNV_hrRa$9fC=Jl;|=SF0Qu9AJ^S@t;3SJmnbAdmwV zz{`IHd!7$~F!(lb284jidG~QHuH6<|J2CUOVG(w@iu&kK%XdHOk0QG(mC~|h2XNN7 zfan~7p<8x3CBAi*^JQYffd_4zP2S(skAZ+|QHKNS zihFXSVw^29mP((nEY=JCN@saY<4x^Jm)f9FWdO{KKU_fA^nMJM_$R+Dd zK(pE2<}D$+I|BC?Oy!2%ekjX`vpKvXJWPr2Eux+VL52CG%bWF}LKfV+-x{TW zGK_$;><~7Uo0%F4AZTcF-x=?loGOPv01j~uCDI*had++8gS+XFCjf1u3^+&Y(15}S zD?G&Q&p>R_74#sWU8@(*qM)lf{^_U%;Z- zJSg0WHLVhUPsE1xdB)!Wbh+gim>)gJ$^H$>`S00!vEf6GtK;__Gm1T}zU`yAm0a0D zJ_t6S0fbv`5HGE~b&bHq+7SqpD^f9qL4!($`dSzeJ^ zcm^rnd`l3fRm4!;M0^kv=W^??tQZ*IIQ@F@{~_xv!v^|#=h`{v+RnMp{rP@) zU7>GDUFpqS_@g!mhz+K2cGetd#~~BH-3BA9N=TN0w`apv5GpcUm6rnjak^gnnXC1( zsF^fFoQ7M1zFLC9?G4&l(6zFd4a#F?$S^zL(ufplAdz{=9|j08|~UR)$wW)d3EtwjT_pk z(UNc6s@3JRHLd3)n#&msS_70rZd%L;60J>2(;96^0u8CUR-n6XNR1A%MmN!2Cva1R z9w;o$quDyv?+t}kasPMaYVUoAvG+bBCy5C(fle!dZkOjiR9*Da{XS&Ngof9Ip4XJZ z!%WD-bl=^?3dG#|>5stVe;+qsMc?v`U80=t8za^4)7L%_N}!|VrE}Ia%d9n_^Dr&q zeW0T*1Ms--3c6oa`vA7ZmoUJFNQkxYuC1i>$Z#JwriBV7Wx=u*%o9OlibyuC={$giLf<9yi;EjNY6F|yv zS}i!OH-W^#E1Vr3=!*z9^8&L1B2&GB#<}^WKS;VRs>@aj!weZ3G@cA|gS2=+$p~^% z5)cmo!b2btfyeU^0IURn1%jLv03zNnSP|r$4GB8#PyPV~@6`uG?EWvp1_Dt2zh=Pd z|IZA_23vX8T-BKRI-f0V^hNbZ7N=(Fy-5Eh?X+H)@2Y%zEwORIiCt;_(EVL*uhsDC zSV#SRq*U>GXJN4Cd$*aY0HdONKAm;O@dl;iL3Lflg8JD)Leqlg^$+vnO7nA@mO6NR z%6Rg$KUkHrzm<%=vVeW=_WtpYs%Sc0P$o7!_(DFSNU}ZYJD;qB><%R_1}H8sk)g z4$QZ{223#Stq+=Tq|qpJoKJYrlX&>J`4R(V@4QiUjClpynZkb)vh-z^Sy6o5-s^EI zczOCmxz{I4jC9!X&TT`GO88tZy^L+w?AWb8m8XN9l&G6TlYTD44TFM8*{yem^yZIJ ztGwjryZ)}|=jDCP3hH0X5%j1eQeQqK1raaTbqnIJW$?64L=tQm7Iz9QMKNxK7rEzW zNU)-A?G>yi!#+qG8{qLf^Uka(qu4Z_Vfo3#Uclf(mfpi@M_uSodD?VI$k>Wy4WJ5Q z!gQ-~^C4h4Yzk(mGd5%NX$_r|Ycn`h@YFW^$vtDMvyClW%>ysqLhoVlwzf|f(*u2t z!j0_`np5qa(%aLRoieh7(VcPxgqfRPt;wuGXyV>bick}+BAsv|g<>94c6-h++}`J=Cr!s(xS>U>I$fv&Hojj~vH#1D zz9yeyrm<0De1aaB-IUHm>QW79oB&i&aCS9?G|Xr5~l5(LO1I)PvOT?UKRrz1N9bn>zC^i+p7{K;jZTM z{Z~k4YGGR~)U!ALLPTi0Ak|Gr?c5G6`B^ellz>${p{D5m~S^nzdj>YL@&Rheg#~vC;woRUr!f1zFfWs-s2IcvY7BUa!%JjCUwRBp3e$@|3km%l@%Ml99rJ@YdJ~m z-{s~b4%N$ri1>e3Td%(V`*SjKqk1;s*xzt=n8<8J_)PJjbB!uj9t2!K`v z@a`x9%q||eu~Pn<3a9$p))YxvQvo0bj8I0Mpg37Me(2c1srJ94Y5Xeyw|4vf>SK{& zMwL{S@^6{*v2pvT^;^P>gJ*?pn7b2ew{N2LhM?oO<7r7ZC?dSy-rH|O!b;Ze7VEtg zG7C<;LUG;;C09LXI*m4)<-F~Ndn;CSnhu}cps&UaLzcypSxKvJ6?(r@d^nY9iFT!X zE1)BmdXg36&c!AtuPc5gp1%9z8`GOn9adF|*jPdpL;qxwm^)XFU%DH|^MynO3dv}v z%M#{^9n1qyvZs-~-2dHa9G3Omp`jg%zS^8_kjEQ)1(ElIS^g)#v9 zR@Gd8N{&zRNpRThpDo?*Y#-jI_9B!?^_fB(@#@rgXLg1#34??#5;}x4ia}=_EaN>u zx#*@zzd8vq4_puZBC^XOvIkaJtEBF^^rG(#N|f!aq?F)oH0~o1`)KYJv8QkRv@29m z_OC8lIcXGDqA)wWWkKy2`If1-g7Ubrk~%QRoBqpWqV(lDrTZdM|LeF)LaR=Fzmg`$ zsGT2diuF*$8ljC{~3~QS!2x)2XEMHP%)j6eJAs1#<@$GLPx1^36 z1+sh*PdxfPP;+fm&oW$L{^llCs?^gG#IxpWAh!#p2>@uZI`=Hk33XL$xTDOwD@?n? zNpA0H?Q^|gR(lpWmo0Ya&KlpX!L$7Q*;kJ;K~%Sj;m=RKD``Bp#8OJX*qTKUduL8$ z4Zk{tPsKUpRmF0T_BTUv-nfy9Gw8qXPcxHiR+^|fBlU5V^`y@%Tiv3i6mU_7J;=Mz zt|56D=_Gmes=ECA1g+Wfb&5IX&Adv`hzR0U|Fb4s6zsOtJ^5KAs4H4mCc} z;EIwgHp1c$-*ViDJ$021&apIFqk-OeU6lKR_I^5?Eu>&b{oi-)m;26CN)qo?${rye zwYV@bJQ?L@4?x|$)}R$DyczqO=aI$W@Qrn4Y0y&jjQ0D)7G<^R$dle5iTd7~l0O;H zshibYEB@Y^(Wm`Ed?#UVl?V52ucmPyJL}{=?CrnA&s5O7Y|u6K-Tkoe9-;HH$^3&a z*_TIsZK{u37?cm}-e1jk4!?XB`r*LwkKF>{_;H)p=Y7}bSBt~*r*SL+YtmkYOG$BE z9mUVKd~}PKr(3(aQjT_1ckt-=V_CL0eNJR)e^!wuukuFNv^a|KpJ?;X_#*VTqu#E3 zK@G|EeLo5StIfRq&L>%eQT~n)Q~UrB!w=s57$lWdxL^Sb=6d1qE!F&b=2tYN@C@S0>3*8vc2KauPeM5 zqL@|=7cFFtnKZ@bunWm?=9~Pt|GmfDzFznGbLRcEQ7u}5Q>|B>n*ZXOX;<;%Q^mWt zy#s_{fY83DSC#e0#1re^9$K;|#Px8*H5xyk_;E|@^WT$4Z?5_KBl3#wK9l%>WC|=! z6qC1PKyZ>h^?)osjk6cG{g%rXQek(+Z*wTE-dSrO8D#ca+Xm0;>M`qS{wl#(_pym? zO!>UyZH!86h4IfCN<|ObKvPryNixAL<3<@s;|1g)XB^b>eny@lmq#?e$Nfh^)-qdU zzH27m!Yo~_!<`DyT(8iI3))&qY7Lzhi!%^6=V&+6NPD>T*Bbi?X=~6NI5A1T<*@>8 z3mj*Pv0a25Cz!`NBjCS+$h{&$k|RR(f^-)2tgQn`Bh)Pmyq{VJXI2@ji(`CD92*K)wWaC0|Lb9>W*VG7Mo=dd7Llerg3N zvO6g)iz#fQ31+`i+Zoe3aj8C=fhTodO{3u{-r-kuXhz0#DY(v7`RMj4aBb{|`9yLL0e1?w|Zlb%dmX3#GLCkh0+j~H0jC!`Lizh_JZKtkXB z%H;EkIav&u!6%Pgy0V;mu5Ni2jb?RSW~nk@zstqvHmLr7nX!MFbn8_}DC1+Al+2gp z*))P!k(wvB_S{puvM`J;nB6RP{m{Y7YzetkodWGA0vQ5UVS>Lsg?2J$y^|ha=1AIl z4vjirc)2m&G-87qGPree3iLA3u&xgUp$ft$6A;g=7U2k$_cs5pqv&CtW;VSo1TFHy?dttdtMTP>! zMYe@)wq7Cy#nrcpdY2x%Jt-pmE_!QQJTivO(l24e;l5ysKKT?b3YPYc6}I>kP=A&f=kk6TT6vqf`xHwRG_QMm9HgCr{Zd=5GurX`5;6 z8c{Nmd8V2(36*c|6+@z`ETZc9?W&$o)bck~ndlWy{!$74&pf~zf;EkdgWuOmC3CtV z82LLxG;kJQNE5NkiLn*n9=NSObA6Y7h}#ngQOq|<+r(wiRL5LZ?OSVI=+^ww+*`(? zdk8{eqd!TM(e09DJT?pjkRvV4zwnUxjU)Jp-F8G|>Q?!k{E7%>yZeewCaFyp`z`OU zEaR^#`a!q6CNV$56u#cm_gsXiZN*g8Sd-x`94GZ-*P^P2jJ~GUlu%%k1S@KmseMgr zFZNqLpMXEp+MQE8GmffV-&2iS^#0-2^4%bKm60tgLui_)MTHcu7`POG5l=BEpp$swQE76Vb(Q}#mizPsg(%tG`)bPHt|x_ z#x1L4DwwFq7!>_5e@+^uIrp#tZQifh98jx-NU%DdqK`$GuQfq-=OC}pY>;x|YX|bSayKQ&hDade**&u(&sQLh-;$bS{5iN2Nle^iSjc)Y~ zGOVK8Oq{BgjFt+Xgdiq*l_k0W@ z2vgt+e%#+}qFlz<_s{5OFc{QI_jm2EXIn(>EU;(T8>C`dLH`*nzU{B8hgJ>svrrMN zRtl$fL$Pa>t-{Z0?FcgI^-?Rgoq~Bkc>Ck@y??%Q&Q{8^mx04$UNIJ=kj4;(bO!$$4`{|~*4p(w#r1@S8S#RrKcUBQammmHre^rQ8^lOnXcJ**j z4`v;)H650y^ZJD=)on_*i79>LkNpSAS8MSc!4*gImBh3p2i&BW$mmB0(>RmtFte-zPIug5D96?oHs8Bq=pMN^)U6A5Q_oU5swdAj7;F?cq z|5%E0V`Vwx`(Q=vgIAf{w=_$8D{&@T;*x?)=XjgFe9x$isl=wAnr{we&F{xSM;q?HP}zB+8@ zkh68IneAV;8TszOA+?va9e`{2godq|XO^=A`{?{T~w_*6YSklhAW9 zV^i18rw-mLha*{56VDGnu$5MRrt-v%WtS>zXEdt0Ua0upBxN0@kKv6<=1N>|{Vmk? ze@5{xa=imVPoblIr1WenvKpO;KKde2EgEz^*jYe74W%sO3$Qz!ONOjAi9!tnB0N zzRuXdHE<-YS=mmVq)fCEt@StMDd6Ywr#RbAsuJ&2Fb#QQZ+-m7b4cH&1!=OOPEK6h zWW44DMB-x3XALZKWsLBcAyZk3Hp;HL6@X{fQhK(#6hzy;8sEtWTM{g z+aJ^UBt!UnqhQnE8ly4x*p3HEft*hk=E5M|o#4qEkKW(X29BKQmCsfg3wU8~%j-^N zG69ow!`3FB>ENT0{5{<;W4P0#ojCoNR<6;%O+oNMf~oQ62eBQ81&;%gW7yvNO3~*W z8LhqioB#N4-@?;1nUOLUp?6LGE3~Sg2KHRuQpI8LRPV&Ky~s860j9;5Tvq7k-3H?{OdV{7h!ugqvue%FwuLgE#z@ zg>m-*n2w5ZwFiS)VDC<|Yfh+3R?>fNVL)&*?dR?(N@K&nev|mx!tTq%el#YJ6qBKA zy>zdqTB}(!CKAyrxCL;C2Lze^V9ccxfTZ6j0WX1 zR_UtMMXw)ZDDLEj#eF+q&!3H?wd~Kg*gFdDe*2nvD%w!HA>aJ-rhJ?#>Oe_@*WfFu za(dvKj0LNs^*28#TQRS;=I$9BQa_lu>ySr^@HW`L;V~#ZZ!bsbXHZ}uwM6iJt5n*w zj_iTG^D0C7A<3;zDt~u=GmcU@7>lKKV|FlElzoSW1E9zH-09}$Lq_(;{n_X3Yggtw z5&Ac({o9U%JrxgA>bqI|qxV&q7^(J2o$%G0Z@jPi13YS^$2J2R!+s|x|BG=n7kNp# zX-MI2+WqfT&3Hy}LZ!-n$b9t-X_PBzvLJF(7dEGV%p8agjTlyy*%bc!>Dk20b$Xyt z|EZPedI43^dCDVwj>0mY1=(sj%$~QJ+NPO6us==lcbV>+de7&zr@ZN1{*$xs z!l-!s`|4Mkqed}@eDotv1)rtd+ZPfy#nE3j=y})L`lqV}2n@X6H0w_No|mXM260&Q z-CLOKymmqE?zqYP$T|=G(el1IEIG<3!fhne_xY~{$m7@P!y_eE2PthI$S>iTPN6_^Y}6kNK~s-K+;DH|HOmemC5-1Y(n&p(<(VB9~HemzCxE@GN&|>By^e zuM&<4;O9TF-PcQxzWUz3ft8N4m|V|CMp!HV{uO(fT>if1O?u(z*QD;>{~rAv>izQ+ z|M=F2>4@)T+@Gho&^a^Z7w;A>-+a18ie1?}|Ge)sqgVL8UN4pE)^tI}U#;hVH_NAr zcX0p-&-eLaJrJ6S5YzQRQN)*XTbya7R;oRZotFHmvvxY$-MCqt#Kv$sgHjHu?esVO zJWMoWq*ehCHUC7a1OKS?8<;51mZQ}x|haUm1KXe#a!~(m#Pp4}$ zn3LZMbAJqQ2zE={Pgwcqc=31ZC+1a=jIyb5;UUeZ(JzDDvYU)TaJ3V0@8@OhyH(OJ zVz`Y|CJ<7OR3;pXMC7TZ&{_SWR|wJ<9Xf|i9jX8(?;a^!d&|3#M9upezaG|{sIGUm zV>N&8b2nzecr-JI*ob$|R~wniff{#iLT8>0a!)m52lqSW%#Mo%ao^w8L3I6#8RE zj<6tQIjf}}b@{UJb7KaH9E&$RwGItg65ylI{>zUm&y1DJH$qK1m)jZyWcq_GeZthZkMWV{&V zv@d0$e_nx{20wRkIXavV8M~;W7VF>rMj3&k_?6~1BK)eM%r0*>&3*l1@T=R*x8M&x zb0QM`*&n5Hpn-y}j|FO!t9 zuR)hTiRRaGp|D&W(AQ5@jzthlkMf$#^OK2kLoPIr@tW*ECzI5!*IyXTfT8qL$+}vu zba{9!KG~_1`yx=D8hLFYtEp7$Ay@jBcx_ntRGJg18{@mncO|(~>0VlH%yW1h*)Ad% zhjwG#lGjyEAIOXta$~>1>#F{o%8H+Gqffbf2ZOs}L$%zYwKlqN+3D;oG!Ol2M3P*3 zCDx(E-Q-@kzJkW|)0P50mgl5J(d+!rJ8pU2xo z;5`si1mia6KP;u50FXWiugyAiLX@L%QYG7<*l8thJp zPSX_IpcIyWZ!kj3gjBoP!OWIXUrWCM3Nuno=IE9UB^Py!nu7+VOAwg34gnUjf&OQ1 zstLHKp5o`6KqIJ!0y?j!-t#8`bOeDpAWfJ(Y0K>UvF^@Q6%=OIX8*k*=!jc9NVe0e zY#waDh_{U2Qqt38T$`=_kDrMQo(lv-6MKb3)WPBn0NOzK02lcQ?v} z!$#t!A6|9QJ6==EGt*>dm>88_k$K#p|6#P`L?Sn=z+S_vJKB2%6;hND`Qs`nXrFKa^=C_J>mXzcN<>ST)FmUO7DpjW=LpH%$E`IY0L> zlx>0d&>{7Ee#N3glB3AqUkOvRI4dpbLVe3pY4d3;=O34)1O{pKKoXIfaTm^)wH zQ7OMlZ1AG_S~u$EJbhOzWyQ^3E_#QtMI#N56Ht&1s|F(mkwoimh@Vp5w?=s~K%B#;U> znJF@8iji6)A@gxY{dY`DrscqO-ZlwlfMusiW9zmvclb8Y+XY_V~-!?Xs1my z>(ro`wE-K7t2qXt3{275;;NgWvJt7h8g~6?bH39PpePOmO$FH?(Nd8D@sc&oh8c!Y z{1RA=?8%&_2_A8*kzqd;vU|I~nXkViS< z(e{fe`ep=ALt!!p-d$Ir@gJzjb$-zx)ZAiP%Ue|AYyO^HkY_to8;@4eLs=rgws?$a z5XKQsIxP&g!4q4F!A8kwVR;i3Ku}Z;3!RU z)L$jkh7wAvZCr_y4^BXeV$n@TC{<3Bhz+_yOCz^M7Cocu8a7tmg0jvYHXf>nB@_Kn z_42#Ju*I>mP2L-iB9w?cI!O^N5(E;#17YMKID%B4NDz9H4mCp@8BtpD*+fo7)fp*8 zOI&SIDL4v-RZlt9(f|IvIv%|7(?fPWKBoiuEwVEXr)L#nPiZNI7pPpzF<(0JfV}ia6ZK^cMj-LsOwk7P zi(bQCi^lEQ5ur1I_$lDXd3~{w(UCIt;BZVP)M(V7R`Z+)+@XlTA;bsm=8L+~;UrEr zh#)@1lm`-%CzTSI)Dj1EDpM>?Abo%!s2}L9AG*c}Wf){EK@MuxBFvCab^~-`+z5S} zlQtXDv_}n!dIB&6I-;{aLYlYie5^nkHAeuxxJHT-NlDW>X*+uGVkj(Mp%n)EG&>=JkX^>*ZyjbUk~V(4sWG zY}OhBUs`CY)cwB}b`+L0qBV+<1x2iiN5Z30&YXH5OyyCou+B3=O&H8q^aqUOi7?Jk!@;mb;#RXWM0@X2uzT9h=c zp~NVXE0)h8lCQEBOhgjIX+csAi4(JC`Me4~kC((gAkB<*DQfhKL>FOgszh7Ih=aEM z;u{f0kS87JY!xW6izItFV*yCl-UUhkh)9j$jRXO?@tQcW(S3c4C>|w_AQdM!=IUEi z{H)XwU>jnvVk%lAa7c3$3L>JfF&YB#W@)m`D}U|pi{n2j!HJs_-7|r7J(=M+ob_}? z3K^qc*=Y0O!D0x9I5X53_#;v3sIxfZMS&vH8r3$opDtvKqim-#G@1+Fh+!GN=P^a= zPn-PFf6ew@3;`~~qJ-f@3w|M#JDWDh zWOanPS8hVbU6mJqc-c0GY9`J3M!M3y>ZdznQ{gvFeSlun+whZm6 zt$r@p$W{@Zh7QA9a)E>x>EZrseY;irJq`XKm%3h$UkQrJl&*vLP`W9~DY^OtLw)iyeKJdYB>R=0Mtg^)uD#;+ z5#`(K!VgO)?n%h+=|Q*O7?FzWp%lnbkMO|J7*dH7)J4o}u{RdjI-ZrNAw!ggiW?iJ zQ!7QAOPNn3Dy9if0t0I)W#!xB42-fZtgT&9&u9CohK8iPwT*iRTUJzIdMLd~q%5MA zsP!~h1nRY6ZUS4hpgEcH#fowOQt1lxvO5YBHBxLLZlm09Gi*El45hn>)Q-&4vYnLE z1B(ZtI6amXl1XR9`^nRVq!4|w08$%gQW*qBJQ*b{PC6Qf(SHn>Co1L@YQi zB+ZPLR1NV=eibO*KWUZh2falW+>2ie*XPh4R}ZAA7FZB_6{!v?Kav8o~tav;VTAetR^f!4`rOL3Hp zfJHqKueZU-(W0f2HAN~g1`UHMHee&~*RFVsb_1zg0s2OS^K|nWaU<Wf{#Dj-C$vKSVlfnJpcz|Jht4#Wk=2TGjyO8a9rCXlUGAiGGEHUTI;iGfF=EGrbI z8u$(52|4xZYR;g~HKfuAJMaAu8c7qPi;>Di8C2wJ0lr`A;RMB9qypTN?A}dwM?#rkFEk#V^X(vVup5h=pOd5xhH~RndjAJh|-rIS(_q4`S*~W9tc0lJts2X;L}id+!bTpBC$#%D*C1 zD2Mjw>RDY0!-m)EH_)iT?CzyTQ2G=ZTJgO`a*O5G_baKOd(WyZ6a+wo14Jdlfor?-$C2w7U;t?DOF)-IIh_$fR|y|E#+LYI1ELom|+=C_VC2GoAT# zLZU-wzC|1-?h*V{=T3_>(s^tdO8J9Rr#9pc9k<~foJHF%dWz1In$reHQwyyb{=j2Y z8NfgOc*&?jx>IPc8@emWC!X$YYZmtIWrZ+aXiA4v_&=N`ZfN*UwWApi+*#mGl{@83 ztrEJ(X&{U;y;jd2mX!SiLdQPnM#WKwL!{r?#p$rtl2D4_s9Y&UTo0$2V7AU05D^z~ zI!ea&%Y;!_D*>t})OsV(o+j$-o&7GQdF{-RIq>qu2n&8PXB?L5Jgp<>lRK>gt1bD@ zP7twZrY{%)FiVBvbAb?;_2h;&>`|`S7+2R~JBB_fx1Ex&*8Pr-a4o!@4CZANqDSBA z@PdNNh7hvA-aLUcjQ{u7YY`DmFOZ!;_Az^yGm9XZCenDAKN=nsw?1CLJU*Bx+&rW~ z$=8e{q2x_Q4`951J)0gEvc?AM2-Z#_A$)nA&@^WF;F&h;S#q{E4ADt+C|0sp`SEm_ z-YsT|#;qH0Jgbqs#Taec{+?}iawF9Tch5YPqnWRLl-pijF^%1(2AW)(hr5%=9JgxA zs6llxR*$%K^EU;n<5Y91XPcCKTF&uVLT1=7!nyJui}i6fm@_+OY6NN>GX*yHs<|^} z8ryI&40VNzoYLR*Ivu9h(!bEAhgR3s4s|Pxd*L9aXZ;r@b`)WdScwB-qMwsFl z1Ai|0udS0A*wJo2USsYau+)sht0%5%_>|(m{38)~xliNxIZ7w`8;Ny%(0@FC;7ns> zcUF-%Td+Uzf2RH^st2jl#gzSJ3XeH>gn%ucJZGWrT@IM|2RRS0xm|HYuz#ddHvZ$u z)GSr^ag_S4JLtG8EN$ICyUynC|E~U3irxJB%5XpW>b#@e>*nm&C(fHz4YourXy2n7g3?H&&^uI-8Men^ow|$h;=vO)ySg(EeUu)!x z4#%?bMeUU>vG}Exhrf2mw4a1zmHHL3sTtbnJZb$Av8&}l_bG|2)q*C(7sc8$A)EBZ zr-sra*?Vn*Pd#IoKfs?8#KKuwo|-BeRct7N!<6xx`9}(If+_Du3+A|BG#MD zuI!P4Sst%NABG@0+188zDjw~Hc+M#^IkXmyKY2-9dXXM7?yi5_`MlR568E}pI|EQGVNg}VT>r%aw3xBzc2SWkN@rq`wOzbz z+1-WGSzhybWHPOzGxScYa~>?DQplmE<(?}XBw`m#t`+Ihjq`pWg6q7oRL65MbYb7J zPgW4mkCoIVE* z6iNi}f=tH0;a)re%xK!i@%cFa)jK5+{h(=vhy_R|&KbGn-hq*?d1Xb!D!Y%d5NU69 zDmjJV2MVr&b)p+WB=fDy)HQ#H{EG@e1E(0=DMD?$}@yF95V{sb&aaHaGoI;{*6 zDAj@#=xx28q?qNcdXF%0}P<$4n^*;{W#>>2m(vrB$N2030Oxw3GqmPi}U3Z z6?m-ciCWGicOCF=%XzuT12H7Dk?>(K@2^bL^Nw*Q=1RB)$T$8nm`r)V*^DH*;#93X+mUCa-)r?B5VO{do=pbgL zi70CLAZweWB@`B%Xdw=y#p9S55h5koPM-Aq`WTLn2p%|ou*o_Z#2AELkZyr`COMN< zGYpUizaON^8AS$!a3$$E57OD=HR%-($#DSIo2MlrqdIiZ-0{X*YIlKR80$1-AoxQS zB~!x#>5U{+kvzY{C=f9E7(5o7@!i4iEup(BJAZV5(!*3wXBJ8(Wdx<-RnTNvZi~zU z#;K9Bf-dM&BdYg-w`F8LYnUqQC7`I&s#aHyh)J#18n@R*zeWGdtXJ*_k%#}?<2V=B z_{01$u)gg}7BRK>qmeVt-uhbZv?p&?<36FEYx0%-Yy9)$K|Feo z#VC->JBmc-;(E&ZW^d`{`uw%pzcVkj^PNXGerZBg*#@e=l5 z${Ix+=jm7)C(}Ku?N4N8oRrI)WCPmzfcy9NXn&9oAD*+`cH|&0a{@4}%Y0s=dS=5= zqp=f&epfpg-!{+*rqMO!8ezM8CwxY6&ip4Lo0hKP-^pSj2v2w&hNe$@&3TtKNhufuc#6Z8Tp14XtfuwCD+3IH0XVa;?v14mn4MQRlJ>E$SH!Vf0K0Q!>P}>i*ORI{!GngRO*>KTUeS`A zQ6aSv<2#}G+cC>KR$sj0uC{~r>tjN^;=}pFfenxU?I7qH5X=I8LY_#708(<-o_-f) z{e5#Ai;VBUvZZ*$@p}u!g@L zT5P)-qU0#Hdm3Ew>RDI2SwJ5w#UA#!L3|b{JUgJt$Au~T>N1NYAswI~9mqBF$+O$b zbM?vh^bv0WrcZCA4|AMpCFJ`06c+6j+BK4dH3lqm;(9pPXVvdj?3GM6<|`&hCz}>a z?$OVa2+!`71NU<&-mxk^{JN>?U5uCNGuSAzHlJvejYQRjNR+zs4?kZ(p{Y3 zJyrsVIDtZM?-r>#*c;whwoih9gZ1_(^!9W40EPWcg(1iSSYz_B3tI!Q&{q&-BnU#> z5J>(PA_O4dK)}HZX1@lAUxOr~sg=-i)l@i-eDXFjz=KtQW$oQ;7xr=I87O zxv2nhsskc@NCHoQ#Q1@U=%F`4uB0iyl^|v#Ov&D~ccIJC3$N!RRP({{bj{CG;dmVa zA+?#D2s=_CYLG&2b%dUK`n-I&|L^GF_nbNxPO!(s2MjoPnoe!z=9>`SiQ`})8{h-dMKv$Fi`!15kXn%TIh>=;S z73Ntkc{FRcM?tm!&b4VOg!A}(?~RGzN3)~C9KrtWFV8eY$uiYxGj7z`(g(zX_VbX> z3eS93&6>o623c9Ntr9suc;@t;4-j30mRRIyn+7o|PLvb2A*8;+cf27B`=)sOP4al1 zJ&=A^g9VEm1HkkI_8?~gUlS8}`1hZ6gJ(J#+%*~*>5qOVKH^3^;>LS&~ zA*Du>=uDD|qwllHNp?^M@SMF04~vw;+h$2_*F7j(*#< z$02*qPE=7qjH|Z?g!F&4hadp(|7AwA{(ojv^_%t!=yS&p`P!@hml>t;?@A+5q>M7D z4rA@Lh6V5QeL9lQ3dalNL-$t|#66{+!k>7=C>U3aSB+$zIgHP`Occ@^U#$Q4qi)3K zeX6fWs*Ip@hV3(1Hl^^Tj&goukKY=p1;$u|m(V$(pks*|_aBlM`ggGOW^UoNy-^E( z>w~tGp~g`*&)rHry^74Ln@#A=Ui+s$_QfB6ewMg59c$FXYt!F5`?Jwpl25nBR$J;} z310ZiG+yb8a)uRkv19cY)6Wxa;f~!&M{%AduN8Eg??3Sw&>lC;SI|fiBNhH5b$0ym zZTyXN+RwCB)!ENIapd-$<3p=nY30wOm+p)D)<8bCIC6zdhI8qDMSNP)y(2gnFl84{ zD!a?*^fcfBnP3a`)*1$Xig^#KIVV{RVobbb^tHvSuWQq%Hn^HkHG1Ab2@j9bIq`yd zzhx+?>)p*%-ay;=-n$T}@p(UMGlkVlt+`{T&bL>iE5Y=8Gxt+z9&?_J#*lTsgRF&R zfpenZHqJd&!B`rojk1<*YC!U-&ot2O7=-lO^4*{EPskNQP~~dVHvtq)%bMD%h6C7N zKtGfkX+H%QWj0l&!UHI3yozjTEqqFw^q8rOOND0kYR2_u1dH+%?f9$ZJswyTXPVt8 z`jnx7MNQ52G5dA(_MJ-y()O&?sbwwh6wS>g4FmgznN>aq)g#vmhc&n^{iC*M`hD$A zpbE2J?UbTWhGd`XYk$McGTYXQwlDO}b$t}gkm4Vn%zhnB{w&Q^^(NI5-Mf$#pP~T@ zJ8ViaX6k&8_1QO&*r?=Ze=zU)O5j4E3+o$c55hpQC==eE9V> zoUH%VnrHkeh9Q~1^>QO!?)dT>Ru@KG66?Ux@zp_T=&{0K=R)A0BmB;B&rZj|@t^MmG7jbMgA9+ZPe%((V$LSyzV{xzSNk7k zG>tv>g2;?sUo1y_k3C)m-PAMNVmV@dw^eiWTy4kSL|xXun$kV!SvwtOeAtX6G4s=hTcS>@AENAW63!EZ^jS}$$`b2V867|CE1 z+0?d#+dQj;M99Wu6qR%-O#T-kfam0~Q!?mx=Omewh6ZKNB4#IuKRo%Z6RbedP$6}Fq@sW7Ed+$DD{~SM=L)2kGaXuz+`nK?zFvE=aIX`t5x3S z&JL2oV-HW0xAPZMot@p6*Mq}eykDyrwyE3H!YTc9AeWc0cwa}&Tw7Plm851@cowjl1}|mv;#il=*!GY5Ool|-pOtL z3oJMOOiD8LW2zKtA?3biHUFmHrh383V}>O?X|{R`7Zh#2o;N_U?Ch0Jd{P;H7#Mjw zb8J8T-k4Po#<1xlNaK+^6ph|8-I_>|sOn;74Ql0ldDGD7g?oR6)i&3(CP=r;z0&QP zY_8Idvx47;i$0Fmbf#knifMp*p)-0&a?Nx=eY_&udl<;iV3ZrH_z&Fw%} zS&Wk6L8TLVF6dV@Q^zL7z`jEu8+j)I!jCYiJU;g|WVQ0SnZRuM7$E@d(^S>V)zxa7_)D#jc z()WJ-qY}A9kUi%yo|h?~w*ezaHMtUcof zW}$f@AM+hAg4-n9VW~l&w=1KPr>|cAHvsdI+a^uXU42B$T=tXqlRB#^CH3EN`EAdu z-HnQpEaUzPe|YW_l#dZi&kS@VqbpGdBdJd{K&lFt-wq&obE3#MQHs%8+g`XK(K zt!@3Qfym=_K*s$$BRNW*lS&vUb&Cf`lKl6U9{xSb z%jy4?#S*n{<@zny>~J$b?Wfd+U75Mirt)(L1K{O@MyPOBcY{~}W(IRw%l!E1=P;njE7{;+*A zU#BoXH%KI)!rxMu9XDc1?c(>^0;&B4M_o5Jp|BU6K`qsBTFcBF^vrLi!4wJz-o=dG zV4^<*T|+1O8pN;sL{X);cgxIfG|Z`9$r{VdVaQm1bkw_|2bCXDd%{L9l)$i)B#Jb~ zr;E8Q6>8kgEOr+5@h9e@)A?IujBhF!O%u9K0U1G<;}bCk%RmB6_)8HS3q;?Ol+f8> zeH|NmdB>(vUSkQUnoy;lc5K9f*LD!XJ~Rl|{v4*a9A`A1+zqmHK`N^iDjpc9Q|}a= zFT!n7k3nh$8g%j?FO0IEywA}`pzK3U$DdXX6kt3O;b)!p7y~Xp0a_KBtfoHD=fdlZ zMS69|VGUK~u)2mP*4x;4H&Q|+8c*#UDsP#lqVb*w*3~QEf5+DG8&DZEPDv_B&OGGYXr_} zGk9ruUCN9jXS>l@24b_^h(>hn@ohfJl^n(yLTSH-Q`^oW--x#*@%cu;qTo2b+ zuL4;OYp%B^m@k4Fb~J3e;!S>-5-6avx;!^j)UuuS7(R4Ho^W&{Z@VR0=;8!)I!_3r z$yMih@NgNEr-b(rb!n(J4=hlX5Oq1LbXr}s+5lm$ap%5QDqu6pKG-VoHS`Dl1b!rf zWa~g535u@%%5D_qgJtF|%)|8!;785$$>R`7L)RA|*T`QkL!3$6U4>yc)!3Gc>V=9D zOYS776n9w_r#RfkmlTuQiZkCh$NnlF{aBn=?;>GeGIXQ3_>Em@Pszr7N!f#9B2Q_$ zN-4kqSKdf`1|Kg_w)sA9CrxV4YnjpPsRn-&IvZ^BEh$PwC8WV5z(yCPQs0~E0 zHq6m>-zMlUq%b^PZQ0i?SlFLIH^&%cEYxm&UYTA|rJ;V|jkrh1W_q9;NX@UK0|r*C z>Q=0di?f@SwAlr<#26Cj)cy+QO)MF+Qg^{uQ9b#S;1j!vIX>CF?FM1cy-~|wki)gt4vXF(sm{2O%~_VcsHk< zlRONqMWAgwX^l4CW*v4`6P@-%jElj80w26;wV(g2P6u<9wVeXBd3fIrYNu$E^rcM| zzk-^GuyYEy?LHYC99Ufez=pU5!>78dn%kt)05_e`U%b_d#5W8bP$`-f?J zT^W5{Ss7h9PF=aTy7B|7??ZcnAL_BvyTQ%^M>~Plx^9If)OA*{7b!kqK`S&dT{b4p zh3v-4p)dUjoR?DaGlKLq+9-JxXpw4&@iq4%gM>%X-UQPT>ykm9yA`4-i-O?L4UiMc zY`nc${}Y%%0*X`vC&DfA9=M52nx0(@Slk^2y~6r2UZ$R}-|dz*FO!c1rN%9$Xx*?u zhSL+CVG(i>h^1RPQbJmEDWObUn%gy`{RO?rMdg^4J-s@KLh^CA}MLV26O{V^{a|5HE^g4y7u=M!t2s~#- zdYv+;;>0v{(!|K7P2nl@W=U2aw|AhIW)`;bn|-D$0z{*bUm>WOSC?04?4?R?*)LC6 zjFeQryC}+9u3!E)6YMS!X475&{kvkye`H}+^2!Mtx~Bwx7~2n0iy=7 z(YF6pstR9Cx>n_QtKH{%yEWVI*K8SMdG=YU&QpOLg!$Mp3hxwc+SFU|%uqt!tn<`r z?9}_%>77T@yN%Ox{Zq@0c?Y~RpLu8YnaodPXX?Ud&L7R32hIHHpZU8s^YjYk&z~9E zI11!3h4DFsX`RCImjdIPWmlW!aG`3)v)qqouRNdSU7x-7cNWe!$Iq8((MhrJX%l!n zC)PA0$~+5Lr_2xZS^CUKUBta~3C}o?rzkw1yW=uTK!C##U^a;bCKuyYO>iCxWU*~_ zz%l*$6)2eo(xVA&6G^e?YFK(3tM+`6?eF{?neh>PL9wsFGk8(dWvP)&K`TK}Bt~ll zV;>Q^;-nAv_Tx>Xafd-jDA2erD4qoTY0#%WvWR_7(P(0fJb+ptpb?Z6ZN3Gqbs%9K zn4JY4gfk28gJ=>N`VzhUHUJ4QNH7^3m`E2$1ojYV@HDh`i4bKNgc0ejjs)6l08s~! z)B|vkGzho;miF(w1(~4+&is-HeFjMAX~L^?ld z2#LVd1cM}PFiy}wQDi7Hk;dlvd)a@+%-0q|h>VlL;072|7@3iQ%9nQFpQ}<_>(UUBuD~+CIK;t45SMZuoae0-HuHp zfk=d%b_63H$q+&Tk`BN<6kxHYdOC4iwz=)q-;LhHHNf;r00LTtT6=T=dgTIjK|uS1 zSA2=U)?dAjggq~U2Zi3Ka~kNq0cw3?L>UG$Dp-mGcV++0XWxA@ExC}rzv4+*(c=4% z!q;MOHIu)up(ws-H9m9T%>To?{i5ctzk}OUU%gemWhM9c+t=oA+t)-$V`%c4uK&Np)?{)x6IDnKNFupvX%fYc+9KiSw*)IA(CtV#;YhUnNG#;r?Z0m!O>H7sxThD}>+*%S5h z$8t~S(Zu6h?`IbZDD5$nFb+L}mu`w8$m_h{GTev2@%8Dd*RH$)-L{vGa|IzG2nN4$kQ0(2QIjSS4l1O9 zX3#)Vq%=v1AW;+^f&_&efHPrW>V8Er3{o1NGK~ zw35J1G|*24j4c#Ksot}fZVLiD;7kxKbn_7pAdOiNbMMb1wjH237v5!*L|bKOQhF=B zf5(#E=V3En5sg+W5Sm{kP8u#KuwlxmwhW&Wjkc=iXq0jc(%YRIHP`*$?4jerjs-P) zsDCnVV8?6d$T69uD?B|T=hCj3b-Z;Kfq5$JZkcak!L869Ii<=m%HAm9Gfy*kw1X(U zogGQ5YHiH9_A-Mk8VcNDs;W-AEalVBoyRZbw)V(fxrF(uq_1S(b)7eN%b#h#IXS$M zI`yAoQ17FGp;6YWF2SE3JvbKLyUj2FC-kypClSabV+;Uf%J&<3 zF-f-~E4j6#CX%5tXI>YZESiHmLs=5VWPyx}^!E0a9mToiR%O*680h||4FMLBHx#<| zTU&@5x!1oVhO*@6C<2)hn}*oTO_nsz3?0+{${dMrJ7R1q!^*l`nsdrG3T391hnW=q ztZe4VuZ(ZPSf@FA-Nrn!KkzSEB zdE*t6yq}67RC<*nV5#}Uo5iIxCqQgMwI(P}wrrh{$0X6131L^U-%id-U&PBxNR8Wn zlDSii^vuv*z+dEh$*DixW|V2ZtHZPmSGmFF_tsD_qpjqCj!E3_xi?gPy2{j2;Viv{ zTzY)X*hOO7k8~UI7yez05%VHS{R-PFx-5D4n`Bd2_{3(5jA-x;W{JB&H=wfGujyEo z0tD|qADKto$e^^Le=sjPu->mM=d|MvGxlBjefnd&xLH+cd;DJCw--a+*@vh@#_zx2 zr5{@tm31;RWz@w#4hc`3eee1ee{S5Byl~tje`oWynbPl1m~nZ!{|Y`vo+eGIwZ8id z%aOGz;tJ`E)Y4IZA#)zHLz0yLBJz3&Fxxy2Z1Bo?;NdxR{^tP3JK-KpYt5YBD%cFlQFWGkt)Q#$K022bA)^ zrUA)qxFdTJeB2b$6M5?!&=9m$N@F2VrT@A`FPisC?BD>451YWg{}5LKD%g(whf664=0F@R)PLhL{M!al$p*mX zM1$dE&t;U@xC!lFO{TP?Cy4DLP)F`}Jl%=V?}oU1vpj%g<6=3u)q=_2kbb|FfRjvg z_jKq6tkP8I3cvPcbEwmQJ52evs^3@T7GOvH)D?n6Bx7#{Y4I%%W{*SM!2_=j9-`9cNM z*n8Kq&7k0d1in5rV1B~6TTyYD%0-c8L$0x_-_bP@_>y)_x8?*_^MTgLUcAAgXmIHh zpQvgf9n6{E3iJck(d4*b9@ETYciM8fS!ZYl`7_#nSlG5D!#l{6@At~cxy?mu!s8(C zn^604pU9i6!#cidza1zkw(XTd!Ty0^jte!m9Z$W31F3UwE2EJel}%ZG3NcP=+qPYO zTfre*AMM_QemWcB#H=KpIG*2QYa6r?zh7v)@JZW7O;1MLq5w0odu^+?JFLO-uN?Tt zCw-*|Q5dQ(ap8%0NSuy?Xy~raqaUjJqTlYO|5}Txt|VynPq@@2Mxwyrrmdn0&Pvk*-|D#=6dq;X>XY<^Jfat_v8xys`aNTN7xQvs-Fy%u}s3dTwL5F$tQgac4Gadb7_n1=4sQ$l99OfI`= zy8v@5afI9Puu%4d_R_R^b2yi9}JMC zv(~<;MkG4Gh9o(^Y)8G;(n~6~O23TQjkO|YR zE6GAzblvUxWsXtb$uM%*p-59xi#!OO*U zx&n165V?&f-1VX$2``xxXX!!CfHR$v%U4pRos*ek;PE#tuR~}1l3)eoVWDAEhJ(1k z<-Tr!L?pRpv0>NtWM94qr`{fYYncU{Xb|XyO5yen3q!#s*DqtOA&q z0W97hG&--9(0r)a&8;L|LZ&k7fnpaBcfd=3_Ci5+dA1lZ~Y|lJ($Ni4}}aH(7imgBpKR@1`?`3&1%H4eIG14q)?NCmSXT-SEKNLUcUg zHFnBuu1r*r)5Pi};v5oz0eE$NO%1sfj6NAFK>}(~(_3V^2|;>CZm1JMO$!D{c!Q}l z1v-g>E=HS@HQ&;WF+gxCQq!UYTmb^BLp1^IfvR&j6GLjo4CAnpY%C2h zB534AW2MJ|YTfnXBzmeLs9r};EyWoVUc1l$RHwv9tS0haYo$=@ue=Zrg(vy-qZEZ^*MTvBdPe2Q} znZ#--qJiQgar$};)C13w@u=cD0pHEbGb__#1VfInUeJ9hPrsYVFY}nb_1W>SETyYA zQakJ`#?u#f2sr!ZWE%&71#9%0q@HIwLl0{yFyog%<2H)D&x3{crud&$hf>@d0U0R) zHp;LlJY}w77Ld zj_r4yI$WGOgPpqK9Ibn$1l(76@pYiV8hh=`0*?mQOvuuw2edv%_MV!X7;OnhYbS8*))A(5&o*_&GXPY zl>^4AXpEF*gX%#t?;h!Q@e(snI)wrUeX_%nu3RkHvl@SaZ6)VQac8mdtjym8+=1C$ zwgAvEl+V)GV@RS(JN$!lIWI@JCXC8M-2sfw>k3bR3tzfjCh5-m=`@t-rR}kbc= z6(A`V!cxJmaGfzckJw(}TFq%qbg zpfduXdthF9BqN1PmPca@xtU$lNcnV@^k1(ibz^>;U?dLZb6fdZ4i)r8L99acYCC}b zTOiF9x;c6PwVlg>#VM0*6pL{e*Y&Y3cK`n>_5 z%u2G=#B~LHm3>RUn#5M--5fVYtn!MY65)2k?HLm|R-yQ|$R9V=Njfc(s=o5P?h3GQ z07%sd4GsXVg}~c+ILmY_F#tD9Pi-Vp_26yk9Xxd{LFz0+?W|YF9_xa}xFlwv2a+vU zfU*cPY#*?!@+tp6HX{gUxwe)Zyk260P8bc)mr)${6jbz6b3P+0gqN$6AdZHLcHD}t z-N`11E`ABz#ccvs3Wj}A40I}{cOdtjQ0V$FA8$#2%H_dIArzxZfSwgN>aGG-lBY2S zt0sy|0NChtW1P|S_K=}jYs}+!7zw0#oCAiMKvOW3muSG`Z_|wyRCAed>@Yu+M-y+M zE(=5p1oH5$GaG3b_T8dBTDxhgiD#0L#;6<8W9NZXQ9p^hio2CrBoiQf7bj)dCw;~w zPQ8YB<_zIAlnJ0xoRBC;OVf{%FhQ3U|EL~|d-ax%nj}=B!K%{$qznP&NYR5sz)>$# zqcUcEmT3{y3eqO-5E)-9FrJ_QmWRV4zZgW4iYhDMp8eT%9(eCHMzqZM7$VDjZRw&1 z4>xZq14XmH>t?awnQ#!i-14Qs-Wrl0d~3g2>}6BVUc)`ILgUlH2G%#OO}mY(H*ck_ zNNy>QJ{xRk>CG8C;Q6y7{&N4?);PRvel#eS?Q{vgI3>~REq>hW^zU29#lH|5RupZj zxTm}mKm$c@jsm(J(1xJE2`ESoilO{qjorCz6Gjvr#Zyp>A-A5CV78AS5x7 z&fY>hkw&$c&Vq?wT{BUH3!rq6#EPaa@*j;wSD&D(-35o{i>n?mO14xaUsw{bOMjAs zy6L>mFbXRL(#3QxR7T&MWB*B7wl}Z29q&J4qOhos(NTbm}yTcIu5XJM4Byi}ZV#`vA;iAAlSQ zXNxBbL^Yb|(~6xbm@d=Z)nHai#L;bFG!1E$$n+5SDJ$7+M7u|Uj5SoI*M(r^i8C)e zF+f{-eFVVgbCVK&%CL?eg1`hx1H9}p8f4%ds)6}|PA?H7S0^MvqE|i(8#Ruoz5#HC z4;C5%)$Rdhh+mxQa-G~7(_mOSO&U6TUsZUbT5+-jiv9w)L&rg)GbyGc8PTev&m?>g zhg8{z{A`VT=wu&atf@`PG)qHPNx~H@pFyU>!CgseU6e+I`eON@n5wBtYOGCHr-MA$ zz_|dT%E+aVMwP%U+@|1x8g&DLsm36?Zbsbo>ou4bgvD3#_dPb;q;2!}XN})cE&MU9 zQZa2BG419tj5*(dAu(MEG2Ke2j`En^XEA**WBO-ep1+TI@jd3{MGToWc7Q*2@Zzjq zHFnrMcEl}qL@Jit1Q^eWohXl;d=~qv{LdFqES6FuNdVcL#Zr8M6g%K7>)%@NvCT^gCSt;P8ZR8W->EaKCM1_@4rg zzyJODGw!JT;^=+c@ymp@oP>8>03{lTp$mvz-0uKBh-KuG4ca-V&@qhoN?-4H=mCQ< zaSM`nWCmz+1PnZ^6%63R1!8usK@+6ut9*jDwChR9Ng!q|d21RTL0UW%d%1or*)v7f?e3^K4Pnah_bS5aL6RKPM37-X3~EBb-bu#R;Jxj zoTx=;tJ5Q>kyR`4&wMYnSN}QnC)8PK9e?|a5Ev=(l1S!$TH#4pX}>+ksnw12ozu4UtbO@xBsX1Cqwwne8_vB@IQaLD;u7D=a&}r z?q@S~J^!M#!f2-ZgC9d=kO$uyHii6>@YXu zZO3@Sm;{+K8w_vU$dX&Nzmcu9D|#bSdU964SB#Ot-WT{7EtqE{*5j22IK+A6>KHS? z1#KK32t9NNsNX7ZiT)*2?4GVtC0ycN`arnUzoADM6W{$y_|g4I6_Ljgt2agdW70kv z;fg!^B|=PMR28kjU11cx7XQhJUl2)|!wcpbYeTDZEu(MNlmztNtbOdE>MzhM+UpnP z$!lpOR$t@D@U)@#T&%HWQgyGfQ1@u0t|~M&^~&?}Qrs2txvF@}$dwrJ*75X)TQS~* zL-F?6|H&RMI>t1$zn1M4>RONf9o)5=ep^zTmiB+aW%~aQT$Z?Gh$0RoLs-R3$59nS zDKLKHOvC$6M$#GnJ6s*V@7d-Jm$`PsFcdkFD{S?|`9W*7agn&&WTw%jnyC_{z)fp^ zRLN*IZ@C(@=hBneR0AGimu?RCd5pQate$a)pkX=h-3VvJ6M?CE1!^Z*fb1Amf)^<4(hx>t({930!+^NBs0O zP6k@G_E6509L1VCdizSdNArE9((|JlvrhzWAv1tVjKjWXo9{e%{^zCG5aGIHLud6c#+W;{rVC0=1E^82;CK&v=sL2 zrQt>2-}AHYPW%5oD&ka_QcLBFKm2i0rrq)7)Xw$ZRDoMufm%1*XQGL7OtPwfAS3## zf^NaR>z7yT{EhVL%CVxWW6RN*{@7QZZs-pnm&gyk@YuK{zqk0eNkzqJHwQ%X<-=*n7$}C5}AOCAlL9UP)5a4EcOI_LY%E z+My+G4?`_GJrW`agC?AGgNnI#QJ_`V$5>E6iTRbRdVRi{?$HkfN6v=FL_uT6C)#j@ z%2`S77qcn(Zf57T)m4^`4Rs~|sz6*-ue(3UiA7$FKCHhayYhk9J}Fj+_K2=^RZnGsc_)D-4r#-oZ=iXoszNF&k~>Utr42IIr&wj9RI}>* zqqgcR<~n&4z+F%IS$e*v$yY-Sq1CT_-qg3H2f&()IeT52(yy3YD!_>~oFtv-k<_cw z<<*`B$}P;w&5%d^cp_}Bw1WB>tcr<( z3Pl~n{XA6q@;Wf#=h~jhvC6$!PdtIz;|C527n=x;%-qZJJe|h)D6^>6tNTt%9J|TG8m=%uu5IvshduB%R0yEadBPI9mXSlz1V9Br6yEQ$N3Hxfsa=bWtZe#3e zIqcE3qgQgrbSNkBPbC~+G_G}}m4LrfC2(nCTu-$%mk?Vec*AJINV1i=_;r=A(!_*W z^ie)>LGP+A!=z>DQ9&I?wV1)gq)l&YAt_c!#Exguc6ak(_v>oOsEJpu=SM|krW)x~ zqt_l+j*Gjzwz$F%aq7y)C6vq>`C6l?0LSCfmDe?jT@zFHqQgquXnd8&jHW|Nk00%r z)~YT~Oh@(}KR(E;y)!gndVl)3?Cf=|`p=1r8T3+H*V!e~0zgQJpv(bsVC z4cM@qwnl&t!w>%ecG1-4QXcVFc2}MA$)2w^C-w(cHZz}3v%Ij86k zwf7D%SM=*s$m*B4dJhI&OG<4b?_GYX^J7TyU;{{MwrZim-2CliptG|Ai?i~O$vOe*-G($O-men_ro~xY#(%491c7ffx zKa&WR9CmMWBVfWlui8hcch+eBNVfZRKCQl?1)Uz&yE;mymVD?~`|S55$6q)f_o z_HOro7_)9@nh!Eysm za$}G+7vfSZoE`JTddcol!p_q zBLM$x@q*v(uCVgII8x!iY9at)=347rzT4GND<$#G`QvKJ)6R~PUYgLlqWS>q zDEETk$AMh$2(M5tR7;}NesKA$FLfCARyfpr!S$Iev@2Rw>)6zr6h8h+ymq@zIPRut z<&NZnXA)y+uTyUS`2fr59?nrQ4mJC;$vx9Os>E`T z9rNeo|AEU#*`5pUg)Yn=bYq&19y%3mN#;CIwU7+UoA2Kic&Re2)qMOo=1;GlgraSR z*jy$1dh6&t|C%`UnWj^%Lavm0(bTw;irviy=O2<0V_yPml=!wk4dXabTA%=fzLJ0) z?by_Brcwu2s$~QAJ97WxKKxT&btMD1>h>cNlKB=L>l)GP2w!C@TNa`k;99@D^3no0sZ>z_vHSA1+^UN%%kRar@t8) zN^s5r-#XO($SdlQtXBOmy*Rm<-@m^<=_(5u83{9azRhmV{nEwmxhj9)1EpAZrbE52 z4J#Wd;%5T`$!c*IybBvZo~(iWijg`l{4L*K4S$EGv0-U%P_9bS%d9nbpP%&XTf1yL z`E&0lf7KQ^CMV^|m-<9GJ);R;$`vMdwE@1KOzbVPKnfGCK}QFP{bapvTiO}7i) z8%y*Uc5cTq*w=CapT$?_&9*20y>G) z-m+o~>|5yC7X^AY>T}lR#fVRG(RBL+wA<8k{_LIj;wLzk2G?1FG!7cK5&y9$S#K#TVFVPf3Hq-Zg!&OzCWLXIctX0N9yp9-m&3kjwnBa3 zS4i$OG9Ovu#Q8ZBGU|p#dSr8XJk4|N{ESA_cm|71{^cciB!-)HW0m zCRI|nP65fjVO}Q!F+I$U6W&cXi&Y;KF9Q?DMx$o1*v?<+);m~}vn;XH!mr)T5!By& z{YUF$!do)*Z6Y+{pfC(kJR|g9U2(e32rx;-!C5~$BJok!feRI_zdA~gxp)(epRh5G zDmLN@Z!*Zx##s(-->ow8 z!bC72Yi=ozy_&!_QOM#@>B>Mv7FK*;1cypT|EC!3xNH+qgG6h3*ny+Xi=5FkUhTrh zZQCGEX=60OS^eCpXS=d}>!#^yg&mijO>YtRX`b?feC6m$?@4#s$$WDzd*1_K)=!X{ z9*AbCLi((7LJ#D3*+*m7EnYgX`ZT}`6%m549aRV%5OOs3u$s6Sv6@f-h0-uQj{;eV zRl;zE4kh*8r8NphWq<6<%tgTWmVxDOKsOa_+#_wC?1Dp3HlEUT?x$9KlMj;|osEw` zPgFr!yKcse3}{4vh61Q^8JPalY6M4kxm2WRTukaI{Bl-Ug><-+?(B;Qc;98Wlp3&@ z9^D3FXln2XIk1ZQ5fBQi&tznnN6Sll3-ww{ z8b1pW;N2AnZf-n7c_b|o{cLYEL*3+YDQD~24{uu&yE)azme7Wh$PU-HZ96<9rx$)MoRrrM6a zMow8yuPXZx4oat(C_P`LEieifZ`Xl*NWHGNf!!o%AE!^iwhO-2H-9hlv5mWjkXxs( z*Hwq=Yb#0C50E?FG5;X0n-Q+ZKwtI9?%*@~^ox<_hkAs1pkGIXElUju^Mn5dnDEX3 z8O8&4*vJ|0h%cxMzO(DXi`!{%sLF8D|qT!e!rFCuXM;^knuVz04^* z#HT36+Gn*zA?f&pW!onVbm9~z+E%V?WkbYIOx`jyi3AHEYp z_Co#v*Ho%szpk(>45U724cxLab&Q^>vi@}jDo%MNyVF$1Rchg!HoZa-`UUio4(tG0 z+kFOm5Z}k*f2wh%dC0UObJeDLX*P1N^Lb4V%w+VIqMfM%DgCNhl2|Oc+rwXhBo$$z zr4XS5v~laS56TKyhzMmDkFX6!1l0`(bu6o{b+qnSHy*mhu6H*V4_`7V6Ui9iKOd<= z4;Mu*Cr*VYULAhQwN#L`oE`V(kNlfbiO$Dyix2<4`8)ik^zLd=@M=NUs#fDF{?#gW zZ#4<}HhwPz_jfruZq=W==gHrQR^DhC?S_?=|CYylwZ7yUWV~(tnjkX>YR7qfUQX^~ z!t{Wx--~#<5|EjXJAeIWuP+S#c~O`bO7vqtZK(2&u{@2w!tLMkczXQ|7(f#*?c;G# z0d3)O!|gijKLkR!{W^hfeDN=*&pcxudH}gS*2Z35%({h2y9ISZRqN2>Vjb*{+^79) zAvGWo{Sw!M2B@p^3rjEVb-#9yqmbca^Tk1q>_v2xSLq@c%;F!$yQcSF`khRtA>oiu z!Yxn#TEDm)QMPXe?(MQ-@{ScBwtIv!Ec;~q;?p`u^udqxMQYbdY0LWCw5@uyC;XWW z%X6D|TdrnXo*PXc8n)bAx8;Jj{mQljUTg=cZ~6AT_LH*sLl^2NLP$n4Kat~)95JNS#To%9zwc-JZ1^yh?9XTa1>f$Nut@n7=FzLdWB^61@{ zvVUKQ*LD-iz7)Cc*2M2tUfXSWv0MJHHg|d#u)h;#wi`or6XN%}@9mIY?DhZK?Ys7+ zUh+#A%XGTgUQhg2-1Oe$i{0F>dyU_A!<)Z^{p-7rm}-4T3A^TqjoKf7x8H2m@ao#P zxo^b5YkSXFzHYdJDe8NJ(-k*dm|{?1t!`vXyjSx#P&x_NM1mY&{xU8!weoGhhUMFw z<zRLuboz?mc9d(-N3_i1Qb$sOz&;*CTe%v5}yAezf7?c(T#3O)7(sT|KFbWAwAVL#RU?dE3@$RVb-GQ{!u8;~? zDTHzE02+dT4kDmoRL~vyGeU}~5dlWeFhszabT4WY+UWWCaJo z5KK` z0trnz05=hsT4})J2pWjAcgy?JHvVrBFea$m$sj-Q5&VCUdPOPb8X|Cz1~wSLU?pVg z$fx1*N8EH}jAkojwJ#hv4CDsN5ko2GYiU=$2z{*x>|IA<&HhF&kHg3H?vPAWXd zbNQCO$Zp$lB=^$$G}##Jak~%N=U%aYYSKhf!D)wA;+Q2>g1Y@a2#91~@M<{!X(?9lHL_@~Pp2tKkKE1BJOLy~2vCLMg zFwW~m>~Gwsb&&|y_x~tk%$4S!`3qz(WNj}6HWE?2Uus&ywNVuSo)b^4-vW&xYK)gw zpS}DiPQRFdGLatQ2s4#^C4X!x zKW`m&SMe=J{@_-uV~C;Z_n{->JKqXb#ZP8M zf5k#ZjCeXuM#Qf#TF*jnHl0`^!0XmlMr>J!^YoWLwvQd1&Lb*Lg@tA-TD2cZ-E@4) z8!>Nb=e@WrhdTb!UA_jNX8qKStjtsv@c78Ixq|Yn@LflYXUX-}HDxGwZzN~>_Ytx( z4>qB9HVdQPDV^_B$|yA_ZgFZX5P%QG&k6KJ60dgvoDK_+O6Z;D zl}(t^3Q`a%VQDdxW#eT8WR-p`3*fY)X<2gSoyE1=nJ0(?a>R!V6*rew(7!U}?EhIf zE6{)OYf>+751o= z!00+Iz=lL%orj4K6C^Fn&TvG4M8Ll+Nn*RmgNjS%Uf^$kz3z3xi7!>T>V+X+fJSyL6)TdhAYs3sG`wS*RF(=DQc$*Zx#dUcT!*}o_;QbF; zT*0C`S3?b3IVw^pq|lvML<-$Z>5r(0hhEp=LH$3f z&ib#ZKj7Pg1%nX->5x>A99@zlMmo9%f^>+Z6niXabfg1OM@j2Iz)?DSU?BpIPyqqK zL`4LP=X~$``Qdr~fWeEs;KR;2@9Vmh^{r&H1d>@#IA!6*WD)OeP<>ZkUsfl{UQW8t> z9Q}PrBL9ATnDQ_cs+*pHAb`l?Qy{njPKiGNPSToWQ0(b8VP{N+|I2ryhQknzlY`>Y zTrkaH6#oncEidSinRY@G&=f*O?jT|MsAWMr#0ha4up=GzDChPJlTiFNf|_ax>I6>7 z#1sd~2e1;0o&`lv3XdUPQ6QE@k?cZd*%?d;WOfqVOq> zt@I+5@7^L8@*+?kZv$@Is0=oC0lV($9H`-TSVjnbNc{8CV1%U}M)91SL=Ep~*P*=H z!}jj7p&Kw<%XUpjgPo+P?|91R!LS4jM1@V@sg0@6S(BNU^al9j)E+sQIxBc}|0sWMAa3~T z^pk{hVb?X&TE&4hiDiPK@WmKA`KJsxhRr47s`eq^D?Ur7b`}8DNo(zRxIS6YKdLcW z@IyIV2W2C0hOrouoe9;aW(ee=Bo!FHDIIZ1tv9|MKs@w!GQx=@Mi3MiSFqwM8)=I7 z9&t;}W@Z{#pFo7NZMy<}%ksOH`QCUBNzM~`j3X2g)NGRUV1-sho4!DZe}i;8J=28j zFW`ESBn?#47m-gw{dc2Ip1d9;@#E)31u6DB*%?9WD z3hl|GZSwgrF2+5W@O}3>zMCuPtjg8YJz8(<-@`0B#b@VdF9db1chx-qV=GfJGoGNR zdW!3ILD!O)vuVcwP#Im8sUG(>>fjQH+1PGL!p%(ERu49PCP^|-F4ntg{9^xz(w{SX zbVC*S6?ZzDZw=SDSp5d93F9AERrObE6OFrv?tK{@gyD%*k~NgCi6D<${iCh|m}UoY z@d3;a;xb<-t4VT-0KHZ5qc@-drj5(XLvQKxzvN#OdtHBDNGC(_X}Qw)}tg3d$7<5BY^ z4-RZr_z&kr_hq{+LgBGE0sT*5x~a=B?WF|)q#-E@ahsAwP&7&gfhEPOGUs*_`H%bC zNwVmu%k?(=rsNH|Y)hXro!k`kF3e99FE0Jg|+iJ%qD8oM5X8^ceDOk5t;KlWlbs2gLdc*V#&%>g7^L z2khS?v0+!_HPH$NXoHp_?4Yeptj)e@?0}@^z`x&v1w=Vr{s%+Ng(f97X4_Wo-Du&* zXyh>Z1|F@M&vLzf#ZrMQcY>#OpLu14Qz@XxfyCtrm@I0lEpXSEShCku6DtDQT}0}BLl3^KlXp&$n_Uj zQQN}*5QSltmfKzeb{B>y8@;9`V9bWW?af{a)*cxK_92c)Zj*G_L?e^Y_yHDZTwe!c z=WkjSLGBydl@pWVo9{;YeFqTQr@;=vIjqw(W9=BZXT-7-#i3oA)8{oOm> z)?g!$jy9`7gJEwCBJHECZ~QDLX(Azh8%;)VaVuaYx=X~UT{EVZKYG-wi2-ZVtEUGJ zXN7{V<7@gdAV#!96?SFb=2wie3(}=J9n8U;L2kgyywP+>o87HL{cqNXMhM?fZ+_nm z*zNo0a;gH(fdhB#VG(GXBO1Ca%KRhZqYuC~dK?W0W-TP%yaF_aq*4KHYXB>W9Q+*cAizwj5Z zKy^U3c!wZB#lWA?(mn`r#e)4<+AL5VICR9WHv7`ZhunrcYr3SXx;C9?_4OYu^q0*Oy z>Bc5xpBNxc&uvD9*e^*}4Fc+YCt$v;!={+iDLxoT5DS_)K=EcltT?1#D%76P`*4mJ z1dg1xMfAY|9EvHHY`_KrPvq5IZa}zigMnnLXYN1M1a@5%9JSJ$NjcCe5C^QJ z85BQ)P|FM zOh^_W2sHrWN2lnEK%DVz25JCzO7>=Z0Lm0kH3|w(F~^cEITo>`r<%ACBP7_s`o`8E zu`r=rYf?b?H+SR$cZVqWxY9u2HZgabq{)Up)B_u{NP9}sW3HqC5G0ritl7CWStJ8C z@kt>is*UU$3NfNn0#Lvt4q@X@VQEk>oJQx+HcuwE4p0)>sxxL#oC*JhG7KbNYEFVp z;hgLkC#@wSb+6XZ9VOtCl720}RBT?VR97}>|l_TeP6bSW~N zG2KY=?o%}NGDv(p?EUz9LNa(yn(yYw(O5GucTM?p63LiK4q`WG(~aYE%HG6`2P=T} zOltl%nnc=kfW`%0sTlyzNq>2EWP&DU)g(@p>m{5ma-xkcw?O~{mmknU z-DnY9J%6jNX5>8${7(PY!yjNBQ<5?M!Jw89D_bH{7ZJa#T)|&v4C2RZ-KxlVFm5rJ zUXEM&Z8`kJv9cw1E^SY~0>109!a;kOgmixBQ;{;16Lm#BENia>SH& zG-gWtq<-H1D(F~yr?~xx!1yr0TO+hGPSnGL8>epFk*i)*2zg~K7z6nCnA|736(cjM zBJXK@Lut!+_~K0RH0ks4&kHPVI~F(UwG=$&*y8r#i=t%Kf}DtuiZ1#Ga9QM1WC1qt zH*#UKKX5}#nfG--ceQD#Q+8l~N#OrF*bu9I=B!10#N8!Rau^tl{|laQY0Xn<0*YSa zV6asTcWglXo#(_%ceMDpEv_ij%=s_i(&xx-gjk^ zoh4n5^-?_9-8+2{*U%RR)?_ULu#X1EsX^B&Ax@HyaVBJ4F^DdQVuyrScTxgEA@J!ONaW>^pAO_Q(VS4)_mTAo*m!3?@(< ze8B#A5-yu;uK=-41IMu_0{xV0`Ckcd8shUR8(U`S2nLF ztxgMhO^dBoDXKee7G@Rd>t}W+h1Fi{rKu3#)!iEHqh0w;XbQH1eZN zc!6?KymllEGK#G|mGTF9Km@~e=G6A<;n1U7Ts**P*~)u%NJP_yKg_XH-5O&i<*G7_ zJ&V`P8b0=A+^g}d-q0jT?YpfQkQEET_}-Ie51$RC+U}Q zZF)e!5U*ld(f)5wk)Y{#{sF+3+9geqY(^f9w zEGHRPf)BHaKCoT@fV0bfWUAJ0hw^JTdx>GGCs+Shq3PkbRMG!N6)VvXrgXAI?z8M%*oe_)e) zG7M}d+2(^JRS%MMJlz69!J2~7PHHgR7Pk$)tN3ib{j(g?&^rb!k^{3lD_~5EiNRqi zLJPq6HKEp_s_h-B+?6Bx9IP{gf@VQm+sV3Avj0CXHb7FK_&sL016UAa8pR+6Y{#K^ zn~;Ms?Vv+*z z0J!iUQlS+CHGbvVFblvZP?s36(8d3dihz)YVD@^j3AokLbrb>*PVPbe?{FFZH?{G_ zq|k6Sve#g~i0!ImNB~iE-$LEW?1Nb#XOhFqYOOF1laHkFSllRBa_Xb)dY%%l)cMB| z3RL{AMsr|TQd*rT&F&OjE-r1{rwP}X*q>2*Xr?;&{Ns+f75K9Xod8sKPPofs#lX^t z0nhLwZj!EN4t_cksqy$ADwnl-uB7>@gke#{W^!rdu`+bG`aVU)Ja=_=FJ|-HxSqx+HiPLmK7bBdC zM_uGm{*Z9KgNO6wwZra2EPopwJdqB&g6vMpl*LVNRJn#<@Q11JFLNj| zmPN}o`3FT(9i*Z!BvGW2t&<&Olh|!*Inft(VN&up2lgpt%2Sd+UPVPJGC%Brnqnni zutTw({)`PpMlVK!st^$)5snOup`UsR$*IoKZc?pIo~A9-X1|Zc z)@BL@uF}IrYhx?x1~H0uV(ztZQK?<;v(V)pJ16We&8BMHIA`YEoOj`~(`2po`swJq zLp$f<>9^GpAJCnA=cOnOJ!Z={CIaJ6wj#~WY28mU+x~QK$l1uqsBVt+7 z?OB3~IUF#RnV+!e!57!#d4lE|YW%a31|?|Dt&Ie?g+qfowF63t7gpQ~wMITM{zx z3mQK2i`G1F7ME2hov4im+RijJfjJaO=3gjSh+ByaqK-e^zSc2UJ|Nc1B5SY+JoYWz z{0#P>6d9upF`trpb>KkDa$aq$$j67%B|hI2n==Eu>&txPhY%rttb_R&eUFfFFlj3N?_W z&$1KDC4m2RMc)70hCFZzh`O>sna+0KM6O}by4nLnmL1Ovgue}KBRvShYS!Yt{zE*d zj4?YpNCdtM*1RK}sSg+0Kj4K#Z;Bqd+oEeH7y_!2T~+4!6)_-mjcPC6j?FzWJY0-S zMN4uQ!bEM9B(mWo@xb&mtnvt!sIu#c2Hi&jprCd&c4B+R5;;%Pdy`FqF zJEw=+_EdN9|#YBhD!fQzh*kb=ns<--;jh%6!ss+n~SEEhYEG4Z#uxjo(MG zB=zYkkzGtNyZkO6(3Ra5GS`w#v-fR_xMWjZm-#XFz23?i3ZKvg6#; zcUlA8f^<;i4<#tLcD0xEw?yja%{__hYKN(j<>G8$i>Mu3N(@PkNS~i+@9MmBQ7a+5 zIZzc(?5OMXmGfSP%zf*+{~+?D);j*_!eFByWmhY?_;;WWr;I7=oS@}PUwq?yrpE>j zOWf+2HLdmSQV0cs4Oj~hSys=ZlXp_0DOs;3#QB6KSs(*!h639Uyfy=Z6Y(IViUQZR z1tDDnw6vdl?S3V@`1F_=kI!})mykaf*iHc;bQHK`6m-Bl*9lw+=};aM5Lg{W5QT_@JthTFf`6eHZmnt{nD=>ZP8O;T1;2Jr@8kz@!2!q9mz|dnL0#?e zg9_XlAB+dlf<%K|zHZc+Fu~`BI`p%7uSUM@1t)$=q#x)H+-y3bz-ttrI0rPFUas7_ zn%QB{^I^rw%NX9_lT@X+>K|q@aIfT(X0%tq`^V0+yaQ~q!Q^iz%Xql)6n3QbRKbVf zcNH%md^TiUF8FZtqv7<+CXM#uV83PVN1WTX@eXHmQGKRQ=Vl)mb=_QSp+eZFMe_g3r6*%!U9KS%wn>z|1uwBonI;=a|xR;CkP zcajTTh{8P_rtdf^lVyE(-3XYMrU3KO?|;@$5%zrlGU}=h^lvy=nN1bn*{%Txze-H_ z1%9UWBU!Z|eu5AFe}(%3|G#kmnq1If>JsZeZpDC&3LBybD%)1>GOF$JM0MgGvkMgl zqWWxe`R6{)>0gzxIPE%~T<4OH3L3p|#7lW1Qo%7-^Q`BgQ3{ykE6Udq>QUuTeAwQ3 zI_yQAd#RCybmRA6W}o&NZOaBd*_llE@dr+r7Q^ zqRi{q1GV({dzEpg3ybvcM@PP3dfa{8+IuGcN$;=eq?+4#Cl;>AywiRXly>SJf#-l= z?E6R8&61AiMJ1fsd;RXo5NZF6#$Us`OStqxJ;Ac`c3-Hiwh~sCFU$?xefwGO$8EP; z+w(K_g}z%C{oZ73|4lm{@?v~;M6#Eew0PP`%wK}IbI9bTPoNJ{Y$E#8G9X_t{gy5fEAZKKOfr}Z zpDpx0d^RFLE^PLMdu@#FA`X)oaH!}+WbL%$lVJ+t$jN-sc^W?Oh-#VHN~x4z@>iwx z%B0VY^!TK+o$u%u#n1UgXF^L0Y8Fiso0-aZ>V^1q`9%}&M)6PD^JdSIRAOix!zi}lrvv7cvJG@ z-2nISl6zn`8@?n zjY@9Ez9%DE9#~%lEE}7aDftE~#O6tfsyK~Lx}TbqkON=bUu4~zYWntB|BJSMLI31A zjp7T72ftI8FB}VH52Lcind4`sqYaZ$CN18bNPfIh-JB~i)iBL73~?*IXML#oo5K|MSw-aF4j+G4$FgPc*7KN`W1SOIbeC2G z$j|0Y>n7KNq-n$R{YKBjNc)J?gStV#MIYMVyFEG?)X2Zx@89(N^t6bK<`cG;hGoI) zwVr~{D`OkBjEAwxa_3y9Psp?`@k0$;hdAmjxt-Ft4w^3>x}}X@sJZ98OW^+P{Rw;c zi1)`W(N|hqUr+sbaQ?H8AWgQ7Ch+vajYod=7Xv4FpDk}65x!IVJ)pYh;*XfKZ;tLP z=DGjdUSF8`_iJna;N@T2=9E8u!|PY~{|$Wric9|x3Lu`{hunOVfSZHPeSmEZF~ev4 z1>+8OC=SHBGKhc+9(trL`$pYj zgxTFaioSJt<=8YuwgahnG=@ur zFYca@U%_YEtqk7&o1_YSs(cb3_oC*N?1nC>iDG$yOCpd3m6`|2+zgwFq)BdxEe1lX zPq7&{Y45AJ4AUC6sYpyG$uL=z$gY`|v`+w)Fgc^kwz+$0>4V2Bf{)e)x5UX%wBLbq z&+2TwYBv6;vgmQoMpy13nAR%VW;GPRnuF-gj*&T?l&LMdBao0ylCV7QZS|2`q<4!H z^_74y-lumI3yn}@cizKHcfAma_#vr9tQT-GE0C}>7`Mk4^tdOZ`by{Fi2gmOv2{(& zVlU_J5{%Kq$dl^TaC_%rGXbwr8tF9+`{L%IE65zNVr*LCCvw z+NU))@=N0Q){D38875y&#wNJLKi#;U(v$mV(1_kvaE@qjy@vqN9{ip8fK)TfsBzHf_W?p#UJ4Ac4$sGm}N z>uKkmGfzH*{QmWlCD_Hta!YWxm73~uH#)+#Hxgz3dv5YdS4X|ur?{Zs^PHz$UH6}S z(rMqze1X&pGUcWz(KE&P7H`}F>UxrUFIBo55{ z6Erd8(%vGf7B9h$rJoVLvz7U%cvf2>!aXt{}_ib_IY%JVp&DPZ?4=H5i+Nu{Zc8y`vX z37YPS6Jh-8`R^r|NS?%ludWBbf=cE81B`FR&#kRYM%{AqKCM)bByGjIn9utdrw#}m z-)%~IiwYdRS#>Y_0yg;qaZ#6s|5$<{b8=1wlm*2KOVU~5KJ4c z8A;feWfKrD-&^dSf;Z!A%txEAgx$#<(X=1in(OZJ5v;C%7$PNqK3wEr`Ki#r9%|rG zF`h_d^v6R%>04eEtFV&_JW0st8>>9LX`x{ef$U*FK@M!tK0|wr2S>=5Q$4ShjWg}CyFu{5zM1&u)WHuIcE!J@C6l9HL#w3+Tk&H2Mb~Jp)X>xlR z5D|-W<&c|p$k>=TPZLVDFU2=K?huXAmI*vG@(k{Fgeb*s7TkY7F!@)uOnCKda z`yW-j6_0Z%#~ad_y{kh0a60UOUlxC)mpMGemYrk5LrAjA6;bt?oXmYXnLD|adk3D^ zE}7Sno+r-}#-t$pJBg0>-5vn<>Bfl1@tzmyPMOftg7t2=CH|+o`IC|bQ)&fmY^eQC z&NazEv^}f`$wSBroc;-&`bkKJd8EuhleTanKXHj8P_@pm5I-2zA3sk4lhnN`#->?f}rJwD=hhM0JB`xvXct?;~=Na_zX6{qZ2cvL3V#Lo- zVgv)Be26G8R;aXBDDPCHXj=3XPNm(>%M$auWgo)R7}o6vJ64~zrs_Ln7^p23_}8bf z!ZC+-XAzn;II+g zgFb)~69_!tXFR{oTnkAn3#OH+bPK$i%w52j?=uBbmiVuk@;J?vq->^Z-6vjx0a}_0 z;Y>F@8gbs6^hm9Iub~`g9k#A&{ZzFezj7nf)f*9K}*q_&pi6+fzgFI}$$!r@tW1jM`9{gy zUN--s${Vw!irevD8{J38W1opuropcN70Si_);>(e6UKZWYt=BGR7EODikKOD4KY9Otg{24?B`qykQ8wK{Z?11+=s zbiX|KD{>+srt5^4pmyaHyR_uGH0*I1*XVgvMXeo!h3Q-FM0Lo zI~!#^d`0oy*TLtn&iMqS^5%Xh!RQ!Q<;^m#GjDkI#H^fi*_jqNIVq4%Z~Hd~45r#; z&D(*tQZ1@oQKr3?&UjgSL%JtNWFblYrF+qCOy&M*%3{PZjb1nNg?pw873K>SpI+YN zf8@oo3y?Ye}WPw|<+E%bRamWe-b9bQL#~9Mo>PR=V6SxsvMF#?EVH+c#br zV=BzRgb(q6yv{!@!B{#+ODwqih&#+e#wzzqdZ?ofvL+6!W&oRX4aRy2!TXH)?p~S+ zv)%DK$w)D)z@nWSjeZ^Ti3+R~%Fmnl>-Mg=guLx*672L5+&G<~?&mJcR>`gwNcZY9q+Rj} z;Cz%?!94wHpKdhQ=p%kc%x7Ha2Vp8NFxzf$b^zw=_jIiOm{@<)jY8UcO`4bQ(_`!P zf-^jVl4t%7Jih(IM_6qt$#3|J_t@Hg-!Z`>{jxMH>lc=t#&&Z)wwe&w7u!~8%jSZ`0j}2F6 zwk&Utnn^Gb|P#1TT)tEk3-l*rT%e_)|9f z?_y``jdHbDw1{Z;LwCE4x|?rgUD>akqBaew?&j%poI)5>U*p9q`TlBhe!Xj+n?L=0 zGO+`ZUYNfjGb8N&{@3%vA$p^%v9uHPkrydY#V2d9&6uKd8V~v_0@N%bK8fK5&-iw| zgBJ4OgcEVAk^ZmT$Zn@IN9T?&Ukj;;^h_BEZ2r+lGYrh;Jr~ZOh5DSBCYO>mjfwUN zQq%I4{3MlI8hH^_Y!`Jo!ng2Z5NsjgZP;|pXj>T3b4(e3U|+?V^^ME0>Lg)0c(F$29&q+-{~7Y?}r69 zQt(ex6h5MJH=EzT6Eduw!tz`^$WscW20&afR39b_`YI2Rggo2(zg!7{Uwy9TfD`7FQdd7vM)ytwCq7pgIO0 zNCAi)@Y0ZQ5*;3W?Y*+jHXI?|MM05 zd?~}kRnGI8QM0D%Ke?VRz{QM*H}BiQCh=yq!AqTmd-3_G*fh(yuP4?EWQ+rTElIs_ zsP-_9OSK_xJ6x$SO5mh&tvb5P8$~~`{>7R3;Kv9%@^o|1$>#>OiH-T-8SUyG8~v(j zV!TtMRzH!Qx>=M~UHS0RFYd1SGk5Kb4?NqlP@er7&OW~I)FvoOa7{05A|f%UJ0)mb zMD^PfwTkN4ftvB!D~t0#;;quKXO4uob?t9zH-~*$f3@)Q)Y1S&NHt_}H)(aeR44jh z;bzLl^SWd8A+LU=eVpq&_3rhn-`nfUBUe?Azy5P}dvoS)^qbe=C$DVvPMmpou*2@b zo<}rUrJ^xzfW3Rn;E%5|zT=<&2V&#j_vkwa)2Gz9!Ir0t$w9s3A-Jv9A~hSK^+zGR z4cN~;sKbLG^cCZ2 zJX%8MDN~tWuN~=n#84ABDmAxEz*KaX$d4)kaW~tK<72^7~Ob*P+MU9>cSAh z5PlC{WFgt6QV`_acIcX>gMu=Dpl{oLWEm<{>aBp^?b5dNvpmBjo9v-RA(NgCn&I=CBbU(*RpKEJk7 zk+L9e+WNkqZs1&`tE+X%TA|Y*9W7#-DOW0B8sVgT%}2ZN5W*iNHJoSV5}+bseA=l_ zRR00TFnD=&vQ9wsSV?Zz@ULoNd+pQ#^!*o_0d~Urfk|uPeqDIVHEZ8O6)``_fRR$1 zr_)MQS0=xZjcX*ITz8WCVMy_MY){1wm_ zy2AR~p5OS7_Jsn($sZFHez5`gTYfXd&y_qAg|A9^DC*)$u2yQdZNA!op!-LoxDw}C zKl4=dY+u};6H$38xzB~PnQS+~9Dl3AyXR6!r|e9b?I;JM75v)}ZShB+tf5fl*6L-g zm+%zaIVWNkp*rZXtU&>$kP1}puI^tRp;diA{%)|3VW!}aEE2R_6 zyjNa}j|SmVhc#_K7g+tv2hbZznklm?5aIf43tL`7m0(Xdo6CJF)dpFoAOi8&Xzg8&Dv`07`3ao%n!WhdE`CEF?SkEwR z6hTq=_7qfdbn8AzbC7>#Ej>w}i1S8E6rjN3O^Ps0a+Q!6f8EQ2 zv8HYNd&f}m8rMIs5X_7Ym5(a$L=!Xk3$U}$7uE>PbqFY9W!0Zuv9_2Z0^3Z5*bjp z%Q5wM6uL?|;?SO$U=k%c55lVNaUqcJxy7B?LvcXK>Ld!y#x$Zue?SqJ^}}QVcE+n| zfInyhESV}i5Iey|is39HpGTVB$j`idiUXB+I(ig2gF*DNM&=`C#`73Y)wu>2e)zvM zV~R(WHiP+9R;@FKT!*cjDxPN(b6yGuj962~1@;uW75`Of3I;R^V~_gP^s(ah&q?Z1 z6EE?|^STY|Tt0hzv9G>q7+cGKzOBXEu0-tp#V6?j1y5pk9gPlnyyu_2_dK6(*G;=m zt23R2{;@@?^8slPc}*@rQ&ibllapcf>C}mPmLmM1Wuc3I{N>X zF!PvbUbf>uKD*Pz{lLxgq6b(Um5o4chv|Oru*d!jP!A-B;gbQz;IkA=^uz%FNMe#VFAou`23^vfH&u`fsb;fuKYB=3=t|A=$C3M@(bXpy8ZvM9PFclV*zD)5l z1&dG70Fh}1uW%Y#-7Xbw9BPBd*`kj;MAd1=R5=!4Ntd1>fll-Q-En{F8s*UUz#v|1 zOK0v(Yv>xqh)U~^!JwtS!eN?yiei_)6SY2=*B5rdm1Aqw7CPYfOyuee2YOrP8YOO9bgLP;WxqR-{TGP*}KP=b1I@#b)xFxMc#M&`7I|DMh?ybu)flJ#jQX9#c`F7AR*{?|4ejz{_XVr538T#6}#up51sD4-1nh>?)>ZP z#Xgg82i22>nBlxL!dLTl3^u#tw$`5r_Z_(VB{uka?(FIEiF)`te{(mPPkU$D?T`(x z`th+nCH$ZKo7;#$vkw7Q361Cb(!uYA-iwJ^35f-zXPq_s3Ev-5;9S!&iEfCL>|(*> z>TLwt`UYhmQz>W9g&|VZioLWfvUJ#hL?5Lf)j_Y;ra2Q{kqSM#2vFQ2Ut0Zd{Lhwa zEWyji1ywyy$Z8HlGyCIozB@i|#dBqwv!Iw5rujrMhERB~QU2PToL0IlTHVl!p!pAB zrSwf;cbteOkexV+4REW&=_E5c6g5da&rRy1LG1LzR&v1BEV8Kw2}iH;wI*p2!3VBW zK2}h)s8E{*aZM)0Je1_jBx_&`Q4DAvH#u#A7=$9(sZq4jNuG4F{(nkgk|yBXmn2~@ z5cpYePy<;TMDm{T=)2(V5 zQ$KpXfQ}>ur&ppuBm*@O6bpK;2YhrxiB%3ZWGmDw+&o(i4gyJN;sIGXxq(fLdJYc2 zQ+!!uO$^1^nuNhZP*h4l14Nerk*NY}szLqyAv#P-fIk$N&|4Fr037Jck`7{XN6eAX z9B}<0<%BELi2>0?mHDVat*Mk@0t8qD+M0k}Kob7+dT$P;b$}coDecoo!f>Fd2I-&} z3W^DBdS3H}$wDm=&-aj?mxFaoAX=DV2M{?C3>IrE%E`^H_`oebOxBsCSY(5Pn9=}H z0gw^~bnreZv>x~p^=H-mHn?-b$l}x7rW~*py~2J=3V;nlr@37jKcuxBW^zzM292_OVQ04L!iNwQ!;f$gO=)2XO~?874anAirf(Wj^F{XnIT z4UmA{`&Y92^3)WaL10}P$(#u`XaEOez*cIVMi{Vu!|-`-vYp8RMjs2aL3MAV)H%tT z5}=y?Pykl|gziq9f$>7JaW>>|i)4`s#GgQM8zMV`z-6+)g7N?Wtze6wx-lg{qQehM zk{l$5iJ+aCL~{b!YJ=$Pk5&~Gv&XnjYuaivDXqd_R5wWj%P^of?AwF>^T`9sUxO{= zn@}w&Co>kI+brFk6AoVQId})$Dj~O{g*9>TG@Wh&gM{ zpMkjjhfRIafEwGqQ`+2HKqDRYcslp%hRAr)Nl$|Zdbc3``T#GXtt$q5BJbnT+=wsq zG0i?=$Q<2L`nBBr5KmGl1qdZ6M#N+;QWe0Hbg=IGTW=4-b-iBWC+{eChkoGpREG{* zH#Xu)Mw3u00@OF4)EJ4~`^MeJmJ!+{`p^d~vnj$UMPe4pu|uSv(=t|)e5OdUhBe7l zH`fx#BH+Q-2Elt~V4Wp|F^Ys?6LGt|mgo79GctGBSFwi#0gMs1Ooo#d9dgs&?T7)%lThMGmj#%l_zucd)1nhB z2o7L%6dav4NWNMWTXl*vn_&(TcV$vEkt7#2D24&SS$75$mAL@a0LMRwLn>IL92d)L zslc`|y!7d$SQR&=A&MhF`=G$sB!F;&0zbJn8|ug*0bo<$t|%%Ss>_1<%9WwF=2ug} zesrkBysICTqN4`YBv6b{BYq#seNiM-0@NNy@y0-ze;;1Zf(8SD1`L2<0KdGm`xZ># zWn>qiQxQYaM{)pre%FrxI}~ZG72-;TSYyC@JqrwY@Av|I1wry=hzS1y1o~v720m*n z$q^-ColOFQ6BcZuK?7Nbb#Hh6`VV^mY`CMQNHQY$mrcCUif95VDe$;r_8hl-J6&O% zTcd;ABQ-=~kw};-b9N<)MYiAQv~8!0aI0u0kl@LXwd;%e)+I(P?!tlBci0Pe7hcOl zg~i&$azTY4&uaY!3EsV;CjJ`>%iObyV4;k{&)v6PW|T^6Pl|>~evn$>jm?)Na-@v3 z8kx(dR*JOX;$J??R3_-^6w!5HIu#_PGi@rqWBxoT$1qCN!)d z2SYWD>RFEMzmoFy1?KIQd&q4mqgN>w_2ymEHQ{|D+2#7ZcT@QL1s)AGAI!&_j4Ui* zEDs8g!<}CXe7e|uH)!>kgMmEM=wbL3_nio=rMZOm+A7`heS8GtfJwm3$iVe%@2EBJ z9JAojaM9A|!Lw$ef>B`y*Bcj*b0$%LtfL|iAD!c@Mcp*BIvf=Xn20X*6wo5`=#~MQ zk%^zPgGSeuCv(bwYx}^WiyFH_WqP|GHFf6+Fo&{F8@)pZMV__n_Sji1YJQi>b(G~& z5S7`7P)0mpyv+}K`*HyrE)#dsB(#65{Vf;Q%~gzn5!I9q;-`m_ z%uMdm&ObE;#Xbh-dbt-WXwwA?C435VrKL_tE^{j!WjVg_E%hkKaaQ2W`m^i-hW>muOXih6VZ;iDBK%`I+~W#OTZ z6>X$jV_}YlR0u#I1%nuIdnL8~L>=Ul`=gYl;dp;F%Izu3ed35QL;CF_XaJLJ+(6cv zByyQUUOXl~?^Hn1OB^Tby(cN!8%ip%Hylvn+Dr#O0$Bq?8qR^Fn_u}tB%e@FRQk}! ztI@8Ru8LCV)MPp0H^HNY04YRz-41W1`R@m0lc((5U6-H+{*)kW5l$`BoDMUbJanA` zwIj?)d6D&Fq^%f`9(SLdM;ZM?5UbLe^gSSM1yaI~FrRc&1FoPycqBaXs zK1?y5B*wq$(A*fXSEG2s$-&lO(WN_UnEFYabdk zasK3_3jh&Ear~ldKgpdN0CmJdsy#?v9)ceafCC(x(6mE6!$jrcI=Svg+zU$feRxx= z7mHeo;b~BV1t=&2vRMr25q40krFb_~`A9wu-VnPN;q2c4@pugNQ>!|eLsGU0bifQ> z9)@J`p5#Cq(nLv)=@0|8H0yMTN9ALE>gx+5%Jmn>A7(t3Y445aVvc6#{vWd5GOX$N z;oF`Y8!=0YO4UKvYn4_x{)MzmMm6 zuIDW;_JRZU`|i8*{G77$>BV-W4ghc5%x|JqJ{>)d@`cG28cK5nDAWG=r<24dN{=$b zfti1FDFt%~U_>q+(AP7A^GuQ?eMx%`7Tlr zlrh6g{(<(a^aUo2yP6Cn=O&~I!tQiTS zfln4hKlwsPq#SnpUvGu5yX+VQeOfG3?DR;q?I26gz+>7e_$|ti9>uAhC+IEaOfSv0 z>U8=2^CXQ!w_D{772$M&`1sElBJmM2F;(CmQb89@YF4dB-?bYFF|XI~fjN+TIx%{x zU&Q}*f!mXB4XtnPaU+gOD1ljg@ZzK0nJyJ(3y16F0*y)7!YFg@WVC0(Yxz1(WeKKo zxovXkaEv@d$=2K&wXGOFrfV^eB)1PWLFOb&DMIi2&IgBG>FH%1^>l+R&9fS{JGHzL zYpz6grn$_4iy+7%mmPXg19*Rmv~TKWo2s(s5r!<+LI(9&vP!`(8IZ4pa? zkrP+TW4gqQ?n|Y0$A-SNqpBna)lG53JeGL}Lv=E_n*nAvG2my*U}neDJ9l^<4m&4v z5W$nCI4v=h#3Ur}y%gs53Kaw=yJE!RV+aqDhRY%5V2tr$%dR$a(D;I;J!3VeO0@k zd-1gc^+N6}-z(`c1?I4;gs=1KhwVx9xxUMV?}ldjU$?tqw!(J7wpTN0MlUL2j< zIhI&N?%M#-T_*G(8fpW@mTY))9s4}mx{D66Y^ zba)^CeK~C*BZ8Jl3IW(Znf+XSCE5LKW_ANskRi#NDK1}|6j(uqlH75gd?krada&@1 zspP57pCZ}DXPDD0aYy;D9bft)zZTHv5k8NnYNn`ZQto`m-&@od^9}Rl-xQ0-;a1d! zRP()&BVv|7z%dgS`t~e`IY+iiyqopMP2g%J=E#Hv00g~Ta#a1qL~zmfRduZ&cm418 zcVW2)1cwj4tIoI_%YR_8a86hl5g{U_xbsUT2f&NJLu98=1wsJ*>?2%-X;> z-y6DxCHwN1V{&sPL{T+MJD|JlKyn`TI4V*#@c9_vo4W~!R7QoIu;Na@m2t2DEEzy} zBpUOzKANWiA?yf~aCl8kMFGBmORiNyq%Z@3=r+? zxDb!o^flr!{!)IQN~5rUuj#&q9?E?rHVz+cd-2`kfk4eb@{y%pS-(OBpE~eeVs=)A zy*T*&DqQNgJ~J(VbbikSe#vI?elfrj8q0)xaPo@v&nAWzFR>!izdB^Jivp zoubCro)WCuZ)2IkP$#j!?tH#XEu~VF6>{4}GMXn#<%);PU-`^R zH-uljG-!~I^|5^Y4E=OcztOI?LBIOMGABJRTI8OujB~g}duu@nQ#&(Xs4X|%TY1|Y z-s{_lJX|dyM?<@=|Ld*1LnkYqIw9VV_R<+OEgUB?Fyy9An7wO#+AHWG-nc$vOGi4Z zTWOo6ZFCfxD3cL6%xTv6|9C5<8@eo2WX+RQu9YY7qk=nBj@Lqg2!X9#st(Mk;#uIw zK)bD{VW_~B8OADs?PIf!uGL=Q@HV^cGO>WeawB>^zkTXR_G|mFmA3t4 z+d>8KUy%X$zeEON79DiO0D_2`-+mljIg~=dtmHe|ST&M9^GxwET}$=Y6L$4<($1j0 zkqk!ZZ2O7U+NmO-v`0-ORkc<&EaYTsB4mBoquXc0V!f?yp_(H8g@k2_wO*M{wVoz_ zzK5oHhjgnTn_>;Bj0y;OX@KUd%>oNV!Gs#(UnGRg6gMVP@t z_eOEykZ+OaDyBBw@ie8VsIn9B<;?fplTz82izE*nuO8Tsg-y;IP4q<1Hc061HXxog z{`e*m55a98)I#;nkL>tqpY=}+!W9+|Q6vsPya^E6N$(1UbK)-w33 zFa|k`L|iix7DnP8X&%`(nfSEJQH?&lk2kA;89YImt)wgKQ9KqSYRJZ&+_^92QvpAc zkZIUEEZ55>;w}m3+DD}~s9e5Em(%-%dJ^^1>!opOm$ygllv5{ZMQj{nt#E^514*H% z7H%WAUWKIIt(eG%kFH8djcLDrs)pn=kL8ZfK{@y2-qXI}ENg~OHv*O9` z`bp+#5~OFAoKdwNv+wVt!#9(81%4S{IEP)*#(E+RDtJ~O@4fc$U*0SBf7#gVL(58o z&ehC2GDqGpF*;-ab-9~lwnSf3xD-mV&>1k2#GpsaI6kAtSmJ3#Q`xdv#Qb^6S?nkI zJIX!|&o{UMQ)xuCi35SpmH;oCU#bJKrp`{!2Rl2F8UYntz`(wSACfeLW`p=d}I3|DUhrPZIx}_53>f^R40w`R(~IeL&3l*n>B>m+jEG z+wb$*<&Q6)M+pD@F)#n*@6WAY&Alg&;N{WGT{&!h*O;P@zi*CGzRCXHZv3Zs@@V>w z?vGa;yM)Za=)@G3(kQm0ro%o!FnN4g2#A%07dvnHjWkZD^v~6M6k)J%+@T*HCEwWk|cC0g}dKv4Vv&T{+ zV|ZQCOy;n*&-DH!SUPWjj1T|0a7@=ggdiy2Zw?Azm(VLZqKRa0IefxnJDG)FuU~rJJo4A~YC^lC z{@H;*QqMI~E-3_|R8A{dS7QU|W&)ubk7$CY3dgC_FUT7v+6193d$=9%P`PbL%v%BW zJJQukv-JT<5pNr>8?3FnjOL>cTpu0+nfrSBcAGWA_9eF`*Up5VMuS3K+_;&$ht1kr zv__gdimumYqNSpq|84S0q2E||_B5ha@wJcd1BEr>pKsAwul+prH#cw_Ki^?yUi(ML zZ%+FQhhWK?15@<3_FViM%Eg<5i>9_d%SF7M&uR{RrN4b*`>PB4_+EHNqg-q7ukM=f z!jWU8_LtAzhwLeeL@qTtp0#%LuEhp$9msVhXWxyxo)L+$d+>42aHTcUs}a<@E(=(t zFU#6u;rq4eu;e~kfFwKh=nKT}p@}6NB3!`GZdnJG%a|0}a=IHvINM$lnpDXlUOr;a zEL#<758xCwnV1&&ok;o!aGz}sld%TNC)*WpW$B6>6c#g!@5XS^_ZGjS76`866W&hO zKPHsEY|X&1a8tRSB+DGBO@*8Sc`wjVvFTv(7J^!ys5JXohDBVRr_)g8Tde-lzW8L- zmv5g*>ro0)AvsMo)l9Q!1CBjlWo)sTnlyZNU^TC%NyAIpd>lnRC^Li7I7+%8?cxgv z*5kZQVmL7Ha9j*6cRe~_ACb{U4W3QqRNPmxBb|k(=Vo6lyU9$z+>8#_Lm~bgq|_5A z(d!(jufu0S4(H*=eTihYXl&Ngc2a@@P^PrDflrYt{YG-@8~ML8{o&WmR4=F= zcH1b0^#`DN)F%qks1B;>LM%T%_r8e7m;7@U4HfM*nfdD6q@XOby=uyj1qqDH|5IO zTe5T;CDng(8QdH)|MT{h0xs$zNjP+oE;hCYC3LLT{l53#;{5NdCA-cuRZpT%=O>|QtQ^NLSw z+&dKrS3J!eWd3)aYTUE;d;naY{;j2j=7*q-p&u-r@p;>+8e`-2SLZW9WPbCh{1wBSV60dDr8@$snTaQdD=FQHTF zjkOQ{l;y_p$I7_VA1S@3sto3K=_N0B+hd(aj4>6DDkR)=tr9vPs9~fbZ)x;N2*O{k zKz_atZ#;~dE=v3np?gFfp#jkf!1_3V{d3NBD_(gx>=4dDG;tt3hd`r+pMFaay^oUd z3-8G`Rl=!j!Cum)n}ElgXv5SFva0GZ^Fe>!r_Ns>F7h=Is6uO_aR-|5aMe2SJemx% zLz-g}xw!+GMH_~ggezaiEdPqsE|Qa4i%}&avm$ytB~9oSiVA`eI*-S+(91nvQL=at zNMIevzM8^E5KaX*G#`(d$AUvtw3Xq6UY;mfoJ{y87O^mvsABmrfha79I~8$c^8G>V zHbwG$AWII>W99?WiULDM9b}}A+;ejSzXWG$4a=?&$N_>7#$~NXsOcK0?4V-&oZ8YL zRVIqdF7e0&RUDr|A3JXyiNTjMq#pk&aP|HU@itfGUxWBjxOTrv@&Tz@a1&CvS^6Ld z!apESSV4AavZ{AoqF+S(q*uxx&op~14HLnPMMuI2?6|Nt>*O z`o4N{<(WDK52yD?{t;%pL+8msKpc&0cXpt#^hc}8muOR7C%OOdV=XaYC3gGxKL2<; z=UE4%+YX@#H=!$qsslSAo@?G8SLQ8IxEX)KkQy&Y{8)25Js{A)A7BZTwT#uW^xx6u zxJr^|EO4KBAnpnI-fjA~-}O8bqV+W*o!9e3jtdK} ztzK4ZG+RRItWDuzHWrqFrJs};KHEK;kZra!v(r_~frW<`C%);(E0plgn@GR<0m1zU zEt3tT=L+kXNCAbXWuy_}J01NuX#+Rl0phZNd9ps@GHglN)2r}6YnvhSXH|uvEh_hjAHxhtD; z17x}UtMbYGl&bG3Y&9uGn3T%nVB7c3Z6Qz25ca!_5qND-Uc>BY)H;UN_bZ(ee(WPU zB|=U5as6ugAb~%Rr5}fe=g#N2IXXfOl&7;MVfFNl#M;^5%H>N4% zV-F9eN>8R&60VmP9)wN?p^?Z!&AAy3>j9fxBVw9H_%z7N_B(mp3VWcS#R^71Ir zB&vnDnHUA6y#aN{8{PI58K4zh*n0mvyhCn=+_1eN)9W?s0YpB%dZpRmg~P? zPmnx6(g6AAd7d5F6-oZk(R#h9u@@Iva3(!S1fr8vLoIp0Bq$}rS(6KMOjTmiP8`%*P!pO zYu$}145~1aeQ6|*E6Kn89veiV^r}G0GfiK)6up~Y9Otcms~-0^Bzs&!UzR7^YNdIg zDEpY`jWu!m$uOLiM62a#E2Tz8X+Aod>y7D;bhjOSkK@Y`cTzJu(mhXv6thTTKZnQ`JG;AM*E&Q3@1hC5G`U~_3?dm`EJI=i#A*0 zVoXicB2l(Gz;cb(;0uX@Eg`XtL}^u&#j~`YntX$_33d3dhu$btnGFcyn_1|`; z|MgY4{nP)34?C=n9j3+-WMY9$Slkr$?-%SX@xX7sfot7?AKn9(vLRogfrbzIPopY& zys`PZPdy1V72TC050Pi9kWtl)ee(ggG>w#KE!t$g&}co&S`}s#p-GKS`?7{hps zmZL_!%0_*f?6@_vyj^<&{d)LM-XNdqczn^1ws`ug{V~Y9kdkIBfn_{NVH{~co*Xlt zS~i}J>lsfJ%uT!+&*^!0iP87fp9nUANLx+BB}{Y=zw5Smm%}nyr7&4zKbb>1nWzD2 z=$ULVm}tJ8M6*n_DonKq-m4NUZYrB;Cr^(l zO!sF_%(F~mrzhI&X9`GX274xF1*b>-WcGTd7_?pct) zy`F6_NCA+|xxom(+|K?TB0}dt!fXrq7*r{TF~m@)4Vomv#IM+3dAaAEnBvNz{Svd{ zbchN>UyLv;aJhII^ZGVv=r$>=f@H&f)>ptI9R^H?feQomr&pEjRUq~h(de50=^r@h zb<;okK<`=bc)~()#p?A!u>#>D1?eCK>Dxe-u}a!BIAQ4ZTFCj@AUm1D%&hke7;Hi^ zfd+e^!GU-TdmikoLd0J|gxMjwk0#^`1V^6}COUy*&mq1}c!V9C$PR&15D6--i8-th zXRY9S2R>I&2Ym7XOB`kbofRUBtJuP)8YX8*LIT%IvQ|Hif!kHUL^vm6zZ^(Co*N7V zgLg>0VPG2*K#>#VKiGN&(A5N-4uC4{K*ZUh5ip<`1@Xe@JM7H7G2hmWVDU$K@S+J5 zo`}bD@kD0?4JKPFf1yoy`ksQ6GJBo%>zsqhdv7!-6hMSXAO-^<@&KYB7%)Nw)GG?~ zQX%ZjAuXaHipNv=J0vj)q!bB&7J{8S{}w<-J3D@J3`QxbueVIG|Ce89|DXH;1^6vH zsb2QF?DLsFAi`!W#Ft_-6d!58Gx337cNMT51)!51vW`dC697I5z~UU}{dox64oM!C z(9DG7!Tu-Z4|9!z`|5pB{yY0Y^ZS;#W+)0vJb(qKIzktBwu~L2u7T^ouS;e05UUDc zVg=OuoG@L5(1V@GE)f44fx57R(-Vjic1RwhA-({kBzADEAz_6f;j8xDc=97v;iFZB z=`a(fehRQvGjv4p80rX(WG5YQAT%;M&WStzE=d0&!plKQ3;09Zor2J1KW>^!>m(H# zY~{Xh{l2U3%Pq@M-@h+?ET;-Wg!T@E=fdj_PW$$TDI~({368~@4p~~gQKg69EY`nK zwnueytseQ$m-L+N3QjL@tR=0l%$`mTI9`;+oGE23)(OrRWiLMIxq!qic9)%BPEX#O zIVYQ&fn{C%+`43ZGz$}%Il-~a&>3D5Ji7dqdC8(UD<1G&3HSY==}hk7lx6IU`Rgf} zHHq0@m)H;Y)Az}bVC7$-4}XP!{E_r;(X@9WqWnq)_lv>s$Jg7*gooG353fj-ueIW@ ziIu-+KU}#G{QhU_yO-iss_{+cn=6y@iz3p=?w;uvB5N$)rtSso@R42AD|~e{zAkxl z`Pg{spFv^t`nP<8!tD6v%+gh9tE^J`Rlf1diJsq0AAb+UxTZzjj+ft3Xv`Yd>xA;C zsaiM_Z@yo3d^a-Ox-U#mv9I|7r=1sFquJTKKG=UH$Ai>I@0OMaZ@A^U zwq=@1#S+yA(L(5o1=3qpOz!g(HmO?=JK-IN)j~?Y^9tAyWR^oHwbh9V^o6Whe`NWJ z@}#|Hp(qhdIBT5VbWg3kEAe5`l*qBtpXb~IAE5Y22qVP_pLk6 zG=S~ei_GxI4;UcL_%yCi(h=JfJd$j}r*CuWQ~B1@k}fBX8pOJ_CF^puK>bG+ahO3@ zf-2G0?5ibv{uvJHQ<&}P;eaj|xP;9EO(P{(Xo+SkH zMm)6%zHlwFWI6`kl~wDSkR>V4KN}pRS*j%yzQv+4#3kfE$!G1)t3j19^WZ!pO|i)= zvtZ&gas!ww7t}6t07=Z`ED9nuprITh6&0@3B-IjL2WM$J1%atme0uKZDgp`WdrJ71 z^I)XiHOF-#eW{-^lP5!mTEvFr?`JE)3+5H1Td|)+MV3>mGoEc7ags|eS1e`7*Hfn} z%#ND4&PxBj#tlAET8^yNEcJ<=tPv8hoX|ILO*+Zw=67{1a$uJi&7L0=_zErmP!l?x zzvhJK5qp+?-jXwz|A|y=lG&%temfPWAvH<#B#X#+F-*LWbC|l;p6~5)twFWrDb#_b zJ4{RpALVHOHl7M9lCtB{CD#dMtgg@3kUP$59d-JZMYx$Td^b{3oPX8j0$cq?c*6_P zV>cmxUrm~lzvcP?Z}52m_8dD_R5p2|-XnP$p2AAv}v=g;%$l$lM{ zGbDxqIAj`g%RKk2rh!#)XNqw;1}2#DJ1myh$-kRFAQh)m9U_yY z)4iYVGC0raA-J5wLaIU=U!CPLWaNEXHvQ8zyX_C=OAB?&k_-K=aSSQF1&T_xLC@(f zVow6F&Ykr{SPqn@zUN1fA%bCW^a3XE?}}y;4XCKdVy$$B3YPdgiLx71-%nQ1^@r&;Dr6Me@AwhY*a2Nzv9iU6=Jy+)refF`WrtPC^C+veu(V<$f(KRr z4Rw0Jg6xbRhjrWgI`{{ALny-FplbRU3jJ0teycTfx-&QS9Zd%6z*B898t z5H|n;!{QED!DAr7qN$2jKS{ILPn16*X!=z+Wy($vhs2n=V}qX<%?!(ds756%qeL6p z+MA19hj^k;4Vgp1=VyaoFL`sd&o8A?<*G)hH!z+sl{|08TV_Autj2fG1UKns-o?wa z$q#3g9!^Z6ZZE}z1`D7bojbid}ERnw2WdhE*4+J;^ zpL0sSk*zdRdr)c@%ATTdb#ErpfOk00E`9o~>PXKnG}a5jtn#v0)Gd)L0H)6LAt6Pg zc$Z97)`sr3BKhP>m3{%C!Lcx}Ui{9P^Px;7+w{DaWDU(-uq1C0MY@Wgi*D(1$@6zi zRj*OU-XY!7#dN0#(=4|;WX@=?@EM>^40DH~c5R&FokbN5~sbazHDIO`QM`L_$AEy{e-deTuZqlNjsJMxwhe~YKkV5N^!$`vQlnP%Hcm;5TWW$t&wCSYVX`$$ncu+H#%K?OO>oB=MkOP z(-QIXaneURNU#0qRLhtFw_Jhe!g(05E$j|ioEL}=3mA&0?7(Pi@+W5tw2Ct{7{$5- zB35=#7scWMaFvJjdJCpPPLVK&ymkFn=`uAph=@uy&Gy}FkS(bKg%UGN=Ev*{D6qnCGzQ;4)p~4!GUZvrEzuYYT8MzMZ9AQYUH|x zq!C7*B!y8Sr4TVz=oh0cRo~w#u zs!fmNFI3ltH_Lg+@Uqu7nkJVR7`QLT{Hm-tPlEeB(p{1^!oatrhAU&p(Mc~aBY(qk zBftMlQnEzxi(EN!%_dVyFZ+3I{&Lj9)QhmTj16!3hqfCU&D$*dPX3&S>09suOY_@X z|Hv`B58q#Obdbq?bFGDbD5CS~|NA!}fzW;j^dJ&9@P~{T`M`b`>KQq7?_Xf5cFZn; z@pZpp-UyMU9XHbh;jyoOgYFpHt*O)fJR6S8XYz2vu%6&b~6p zmTAy6uetl@^+{qEYX$Im?8*D%Z-~OE$x+tH9y468(fjyydxvcHWBt2SLF%z*A)W~O zVv~OHt${ps1uAANAeFRx%`#m+NYFH?L=pc^kC`Vb8DC14KNnNTnNMN_1c_aGPFqIv z$Bzbr1(oN?_!vPG)sJXlZk*J2brF_W)H5|AAsw(zFj$DFkzM~m6;bt!4=ZMk#fc+d zR0i2cB-VGuG{L}?m`fk{-_i9mcFC8VFGc!vNE>%h~; z7I@^D0zulCB!q_`RXFh_27I1j1|L4ap#CPHEY1t9ywp@8U&s@I3{*fi3E=zz0_#YG zMIb6a5qvR;vWNstCxGGeD7yqOP8SA3=YVXnh-wOQc%-NSW>64Q>0rXCg#k+7S$i*( zI=*>;RW*P!8sO!i^F+D496l1Mw#`nN&ZHmXC0{Z~@OA^f5y1n0U9?{NLUf>SvrLGA zz#7j1%7E+=P*&%(lDuH?3Xok6ST_g7(FGE$02|;t8U!FoG=WeKNFx&8s#kX?2HP=E zY2sP)V~`fn(5DK7#Ttm67~#XGCh7$?I0s(ngYEF?1@?Y?!a@&AfVU0sM#pOvJe7zN z@)|L#K_%n0SUvAY*8(2 zi{QLy5DwQxUHAofg%?wbL7F>6_z`*XV-Ozlh69>~;9$58(gp*x9S1A$qV&-yZ7hM1 z3`iA#wBkj%06;bsC?NoH2aA+118ei5nlsICV($|!L|v4s;LA96(ufcl-KeYo_ELTAn+*+gX=PB;%-EZoP0z1lk+#3 z6dcM}rKtrm(F6`jKy#s4n(Prt%^J{V{Jvly;+Yv1#tWt|MM+#I=>Y^q6Oi+JWN?*S z#o{q>ILZu@Byj{1XGglgMXcw`G%y5;{9sWNgpCuj&%f zH46*0$KY46lcWN{c56vLRXLk$U|2Io@oS*OHP9{;WD5f+n!ZXZ8-CW^MY5PWHZJe7 zkS`lpC>xo16N2c|msLw@qBsWTUuP4OJaJ*lrMQzO$_IyDCgbQ!qB$Ae|3)=9{8lFhZN;;&J8X-)j3dOn+c;i&^3Loe4{r@j z7Ym_9s;AYZw^qy-?fRI-FDd9S6pJP-u8EV}#`IKf>Oa3PiwhN(4VUk9k(Cnx5M1i# zTBlWj3_%nv=2!Udp>nz12T_`Gz0bT$D=Df`1I5|L6u3-8o*3d5n(M$sEf|TAA)?6? zCAM1x%h3wRr-7DA*-yp`ant=W^Y`uH7Bjpr>s{nK&CTIqrmsuIgjLj3j_Ot`4O(nD zHD$PzF+fA6Nol}p(O{AcMI|1|RV70zse)vS`TBA|Wb!MSMGnMmNY0u~13b;7H5uYiK=cgN~id4B_c9wosTK={Uo&^bZ`g9oA;2iAwqh&tf+ z;5L7;d>J5>3QfF51Ybi49SIoZj3{~y;n%})`uH*fzA}}Hl1~6@M&ke4!5SE#Jr<~e zRkg0u)}KeM$q&^5s#m1!_Wli1oaH`=oJ>JkqVN|*GRf&cR9Rh8wPg6B2`spB-X%i z0D&XJlnel>m5PcD{f{@nw*}J1;0rCN;sKOk9TEn}dh1pqj>iAnqjW03j%zl`|EV&d z@Fo^s^TBHil4z7*G3t(Fi5+{E6%pb%4Jkq~Zl!~Q=@2}rD7TrI^6Rg#z zTd*UAFkme}wvG-8C-+*S^`2wfkQuTT@j`(Bo{Eq207WDa_V_*tzQjO5AnJtG!+^8H zG*x($%~S{u3iR`*!Fs7k38K54Jt*J=*ftQQl(S{;g|NaPS1(faVFXPV_4q&y~9N)V-p1@^xs0n)y)HYMM? zx7#UCtV7g5E(to8&{UBDiLitIn52ppr^@e)Wcj=o-mxM&PD&%}7S zIiRzJiSh;hBn2~qRzDR;Gaz6xcytLQ^o3)U8Bu7H4`ZKaF-w&?ZxV*j@FpRp*z2V_ zxp0-bh$1!dT_HG?lukkFJ3rat2ss8@=a*{c(guq)l(K0KRWzjdy7YR!wM{;Y7_-M> zp$8L*k~;Ii1a}R4@nt0G<&mIJD*wZhm!fI36%3RviTtMSpwE$(GD-)%O{UaVl7d-^ zi|WKCjttU&dN)J5ExO$WQLna{dnhZFH+|h*Iq0p(dEYTNqfF@>-nGeS9Z*?y=_M`} zAv}CsI=_hZKBczvaQrMA{<$NhtIUa9ap|+)i#h*)UH(&fk|^^q$HOq;!{AZ+aIH>n zb2|GtMa1KS$E-4Jw7en*o;-yz3FKahtVbzRhw)2Y&D5E4I!7cy?g`OeDcN4BFT8MR z&0gt!UKz7TDenqGvpt`99J+)YmS@OD3wT#Ecm~mV2aFaJ%zAj%ix*pYTV)hKWpzy2 z@+gUGYvF*?jdZ<;TWb7r+_Y5nV#-_h3spaZUD;H(Uz@y1mmL0wg$#Ai0ZOhsy$z%J zc5yG=OT@xB?z(FiGeG4wffE_xcvW1`G{PD~@$DDdc|}DSHvfjz7AX zbRMaEhM7zXIY`xIs`qH%|R{qA}ex{_=18IUK%V$72+#X7<{}5qyhsyL4uwA zPy+KPxKj?k6;*0TB!@)^5}ZuxBwA?x#ZiJ4gqe~F7KwZTHqWggnmYEK69Xv zO_Gu}Gm)em2!bDh%uEp~7y=Evm5D~e*MQRo2*o4SneBB69RmG8l%CTT_#FY>DWEh* z>ZMZK$mDCPJkt*(uvr`Z(TBvRzErVEI%}X0f~bF1Suru7j+rEx9eiQ}HI;)>l}60} zEo*)%3Cds5f*}_5klSV~bGnGXK?oRcy+i_%hYBH!zteqwF2jD(=nK-sX6Pp%EmhPU z6H4srpyIr!-xmn{@x(<3d=?J2 zPLkEFCvZDca{6(~5hd1X)oFlK&|@(e2WxC3RdM7A?0`pFo;BerrQl$L9Ha~uD7lQ1 zDnc#{PA$dx(m$HpuKbc5X-r)>XDCeFg?r#AC*@int~^5r1wVy*6MaR~>YtgoFxF{z zFE?=VTmsVE2T92v7Y4Q}XQ{p{^hx#G?H`zPJ0zi0=BB>5`tdNul5xb_GkYnAwcCN? zM4-#Z`k!Ka+`&VmUPRkp-1ZcQW>~M?nRK&~*Y$ZOJ znGI_6zFyq2mbXRUJEu=_)$aX?&+LNe zY1xePpNbbq|MQnHRW^=blFwWVPxg_}b8;chIfhfI=*^nEE;vUsnWTeHBNr;lb2ug# zuDpVsOA_NqSg%0!(CK2)hm%d-<~%iJauJuO$KM~!S11L{(mc!eqOaB~IT66?|J^3N9hISdt6Y>pjQmN-&X_ZVpuh2+)bh!B1_m}X8p6Hc4E@DeA zyMAt32#*5%{KK$M3r^1R^jdU(Jfr?Y)}++F+eA8}-OA~W_)$SYEmL@D&Lj2udiBkN zo;=CZwZe`DRz6Q|1LdRxuGksoMc?&D<&clQn9zy3aTJuz@Fo6!G_E2d4e=$@f5Eo- z%g?rZ@-CmBsq=7sTUBtnm=^8WuhL&-6kb`XSv=6{V3Bqe!od9myD57zZOLsdr^ zd-w?MF*_6lL6|$pcv%C2SgHWDM97v5L9mW$0u$M&Dj`9j3K~V{3jh!T?6!U_Bhy|Z z$C&-cFCeT^zjq;AU0$YI%nwyKoikf5K0^pPEjXbZarPmEVoK~uQ2gCiK3K%Jsbxgc z=bTE19i!rjv&oIjZE>Yb!m3TtK6avlFnGIF67i%Vopt$yS>Zgsv=A3{cAHZw2<@Yt zJrbZlCTOIvyD1k)w_ewx&kn%cxmO-#>6I+d?X;)I;Kpl4%z*X_f-n>T)*z83N#Pzb zttu)gA#0P1WV%|49j&ZXnsY)nK8)(v8?%b}hQ{#i&!cpq7?-Jgsq=|ioGI8mHj%

=>8?_CEJ-d*~POxD@y2y(`tj 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

Hnhz&`@^u?@GW$fkTuZea)x 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 yYI3+E~3r@rB=n2+)&eaN>x0T)V(T4&P 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