diff --git a/.cirrus.yml b/.cirrus.yml index 8c632a076522..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,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/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/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index f6ff34d9db9e..c9f9dd0f8c58 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,11 @@ +## 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. + ## 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/camera/lib/camera.dart b/packages/camera/camera/lib/camera.dart index 91c6525072e1..3b2cd77c5757 100644 --- a/packages/camera/camera/lib/camera.dart +++ b/packages/camera/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/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index de7d8b56d035..7088faf227aa 100644 --- a/packages/camera/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+14 -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/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart new file mode 100644 index 000000000000..cc33b369f000 --- /dev/null +++ b/packages/camera/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'; +} 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); + }); }); } 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: 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: