From f9bca2bd1d2ee6acb596fb58874fde97d5ad7247 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 7 Dec 2018 11:34:41 +0800 Subject: [PATCH 01/29] Add support for Android devices with multiple external storage options. --- packages/path_provider/CHANGELOG.md | 4 + packages/path_provider/android/build.gradle | 2 +- .../pathprovider/PathProviderPlugin.java | 51 ++++++++++++ .../example/android/build.gradle | 2 +- packages/path_provider/example/lib/main.dart | 80 +++++++++++++++---- packages/path_provider/lib/path_provider.dart | 48 +++++++++++ packages/path_provider/pubspec.yaml | 2 +- 7 files changed, 172 insertions(+), 17 deletions(-) diff --git a/packages/path_provider/CHANGELOG.md b/packages/path_provider/CHANGELOG.md index 537480b23d8c..bcb394c51f06 100644 --- a/packages/path_provider/CHANGELOG.md +++ b/packages/path_provider/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.2 + +* Support Android devices with multiple external storage options. + ## 0.4.1 * Updated Gradle tooling to match Android Studio 3.1.2. diff --git a/packages/path_provider/android/build.gradle b/packages/path_provider/android/build.gradle index 04beea282922..a163aeb52dd6 100644 --- a/packages/path_provider/android/build.gradle +++ b/packages/path_provider/android/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.3.0' } } diff --git a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java index d56cb2b60ca1..d566760d848d 100644 --- a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java +++ b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java @@ -4,6 +4,8 @@ package io.flutter.plugins.pathprovider; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; import android.os.Environment; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -11,8 +13,12 @@ import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.PluginRegistry.Registrar; import io.flutter.util.PathUtils; +import java.io.File; +import java.util.ArrayList; +import java.util.List; public class PathProviderPlugin implements MethodCallHandler { + private final Registrar mRegistrar; public static void registerWith(Registrar registrar) { @@ -38,6 +44,13 @@ public void onMethodCall(MethodCall call, Result result) { case "getStorageDirectory": result.success(getPathProviderStorageDirectory()); break; + case "getExternalCacheDirectories": + result.success(getPathProviderExternalCacheDirectories()); + break; + case "getExternalStorageDirectories": + final String type = call.argument("type"); + result.success(getPathProviderExternalStorageDirectories(type)); + break; default: result.notImplemented(); } @@ -54,4 +67,42 @@ private String getPathProviderApplicationDocumentsDirectory() { private String getPathProviderStorageDirectory() { return Environment.getExternalStorageDirectory().getAbsolutePath(); } + + private List getPathProviderExternalCacheDirectories() { + final List paths = new ArrayList<>(); + + if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { + for (File dir : mRegistrar.context().getExternalCacheDirs()) { + if (dir != null) { + paths.add(dir.getAbsolutePath()); + } + } + } else { + File dir = mRegistrar.context().getExternalCacheDir(); + if (dir != null) { + paths.add(dir.getAbsolutePath()); + } + } + + return paths; + } + + private List getPathProviderExternalStorageDirectories(String type) { + final List paths = new ArrayList<>(); + + if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { + for (File dir : mRegistrar.context().getExternalFilesDirs(type)) { + if (dir != null) { + paths.add(dir.getAbsolutePath()); + } + } + } else { + File dir = mRegistrar.context().getExternalFilesDir(type); + if (dir != null) { + paths.add(dir.getAbsolutePath()); + } + } + + return paths; + } } diff --git a/packages/path_provider/example/android/build.gradle b/packages/path_provider/example/android/build.gradle index bb8a303898ca..541636cc492a 100644 --- a/packages/path_provider/example/android/build.gradle +++ b/packages/path_provider/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.3.0' } } diff --git a/packages/path_provider/example/lib/main.dart b/packages/path_provider/example/lib/main.dart index 9311896128ba..96c62bd0bcde 100644 --- a/packages/path_provider/example/lib/main.dart +++ b/packages/path_provider/example/lib/main.dart @@ -37,6 +37,8 @@ class _MyHomePageState extends State { Future _tempDirectory; Future _appDocumentsDirectory; Future _externalDocumentsDirectory; + Future> _externalStorageDirectories; + Future> _externalCacheDirectories; void _requestTempDirectory() { setState(() { @@ -59,6 +61,23 @@ class _MyHomePageState extends State { return Padding(padding: const EdgeInsets.all(16.0), child: text); } + Widget _buildDirectories( + 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(', '); + text = Text('paths: $combined'); + } else { + text = const Text('path unavailable'); + } + } + return Padding(padding: const EdgeInsets.all(16.0), child: text); + } + void _requestAppDocumentsDirectory() { setState(() { _appDocumentsDirectory = getApplicationDocumentsDirectory(); @@ -71,13 +90,25 @@ class _MyHomePageState extends State { }); } + void _requestExternalStorageDirectories(String type) { + setState(() { + _externalStorageDirectories = getExternalStorageDirectories(type); + }); + } + + void _requestExternalCacheDirectories() { + setState(() { + _externalCacheDirectories = getExternalCacheDirectories(); + }); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), - body: Center( + body: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -92,10 +123,8 @@ class _MyHomePageState extends State { ), ], ), - Expanded( - child: FutureBuilder( - future: _tempDirectory, builder: _buildDirectory), - ), + FutureBuilder( + future: _tempDirectory, builder: _buildDirectory), Column( children: [ Padding( @@ -107,10 +136,8 @@ class _MyHomePageState extends State { ), ], ), - Expanded( - child: FutureBuilder( - future: _appDocumentsDirectory, builder: _buildDirectory), - ), + FutureBuilder( + future: _appDocumentsDirectory, builder: _buildDirectory), Column(children: [ Padding( padding: const EdgeInsets.all(16.0), @@ -122,11 +149,36 @@ class _MyHomePageState extends State { ), ), ]), - Expanded( - child: FutureBuilder( - future: _externalDocumentsDirectory, - builder: _buildDirectory), - ), + FutureBuilder( + future: _externalDocumentsDirectory, builder: _buildDirectory), + Column(children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: RaisedButton( + child: Text( + '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Storage Directories"}'), + onPressed: Platform.isIOS + ? null + : () => _requestExternalStorageDirectories(null), + ), + ), + ]), + FutureBuilder>( + future: _externalStorageDirectories, + builder: _buildDirectories), + Column(children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: RaisedButton( + child: Text( + '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Cache Directories"}'), + onPressed: + Platform.isIOS ? null : _requestExternalCacheDirectories, + ), + ), + ]), + FutureBuilder>( + future: _externalCacheDirectories, builder: _buildDirectories), ], ), ), diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index 905685b86586..ffbae276f384 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -61,3 +61,51 @@ Future getExternalStorageDirectory() async { } return Directory(path); } + +/// Paths to directories where application specific cache data can be stored. +/// These paths typically reside on external storage like separate partitions +/// or SD cards. Phones may have multiple storage directories available. +/// +/// The current operating system should be determined before issuing this +/// function call, as this functionality is only available on Android. +/// +/// On iOS, this function throws an UnsupportedError as it is not possible +/// to access outside the app's sandbox. +/// +/// On Android this returns Context.getExternalCacheDirs() or +/// Context.getExternalCacheDir() on API levels below 19. +Future> getExternalCacheDirectories() async { + if (Platform.isIOS) + throw UnsupportedError("Functionality not available on iOS"); + final List paths = + await _channel.invokeMethod('getExternalCacheDirectories'); + + return paths.map((dynamic path) => Directory(path)).toList(); +} + +/// 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. +/// +/// The current operating system should be determined before issuing this +/// function call, as this functionality is only available on Android. +/// +/// On iOS, this function throws an UnsupportedError as it is not possible +/// to access outside the app's sandbox. +/// +/// The parameter type is optional. If it is set, it must be one of the +/// "DIRECTORY" constants defined in `android.os.Environment`, e.g. +/// https://developer.android.com/reference/android/os/Environment#DIRECTORY_MUSIC +/// +/// On Android this returns Context.getExternalFilesDirs(String type) or +/// Context.getExternalFilesDir(String type) on API levels below 19. +Future> getExternalStorageDirectories(String type) async { + if (Platform.isIOS) + throw UnsupportedError("Functionality not available on iOS"); + final List paths = await _channel.invokeMethod( + 'getExternalStorageDirectories', + {"type": type}, + ); + + return paths.map((dynamic path) => Directory(path)).toList(); +} diff --git a/packages/path_provider/pubspec.yaml b/packages/path_provider/pubspec.yaml index 564bbf81a74a..5e10423a5bc3 100644 --- a/packages/path_provider/pubspec.yaml +++ b/packages/path_provider/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for getting commonly used locations on the Android & iOS file systems, such as the temp and app data directories. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider -version: 0.4.1 +version: 0.4.2 flutter: plugin: From e5fe50b6e1f254d5938245b84f220ba65c95ea4e Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 20 Aug 2019 12:26:02 +0100 Subject: [PATCH 02/29] Update path_provider AGB & iOS project file --- packages/path_provider/android/build.gradle | 2 +- .../example/android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 3 +- .../ios/Runner.xcodeproj/project.pbxproj | 39 +++++++------------ 4 files changed, 17 insertions(+), 29 deletions(-) diff --git a/packages/path_provider/android/build.gradle b/packages/path_provider/android/build.gradle index 191930fee299..27d5e80130b5 100644 --- a/packages/path_provider/android/build.gradle +++ b/packages/path_provider/android/build.gradle @@ -21,7 +21,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.4.2' } } diff --git a/packages/path_provider/example/android/build.gradle b/packages/path_provider/example/android/build.gradle index 541636cc492a..6b1a639efd76 100644 --- a/packages/path_provider/example/android/build.gradle +++ b/packages/path_provider/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.4.2' } } diff --git a/packages/path_provider/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/path_provider/example/android/gradle/wrapper/gradle-wrapper.properties index 019065d1d650..2609572dda74 100644 --- a/packages/path_provider/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/path_provider/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Tue Aug 20 12:25:19 BST 2019 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.1.1-all.zip diff --git a/packages/path_provider/example/ios/Runner.xcodeproj/project.pbxproj b/packages/path_provider/example/ios/Runner.xcodeproj/project.pbxproj index 43d34117f5fd..e37bb0dce798 100644 --- a/packages/path_provider/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/path_provider/example/ios/Runner.xcodeproj/project.pbxproj @@ -7,10 +7,9 @@ objects = { /* Begin PBXBuildFile section */ - 0675671949C15323862C164B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06B796751C0435964931B69B /* Pods_Runner.framework */; }; + 14E651F1ED3B0989BD4D13DF /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AD3D709B256064850151FD7 /* libPods-Runner.a */; }; 2D9222481EC32A19007564B0 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D9222471EC32A19007564B0 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 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 */; }; @@ -40,15 +39,16 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 06B796751C0435964931B69B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0254642752427BE3462BCD8D /* 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 = ""; }; 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 = ""; }; - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; 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 = ""; }; + 8AD3D709B256064850151FD7 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8E5BDEA33BEC8D3263327893 /* 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 = ""; }; @@ -67,7 +67,7 @@ files = ( 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 0675671949C15323862C164B /* Pods_Runner.framework in Frameworks */, + 14E651F1ED3B0989BD4D13DF /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -77,6 +77,8 @@ 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { isa = PBXGroup; children = ( + 0254642752427BE3462BCD8D /* Pods-Runner.debug.xcconfig */, + 8E5BDEA33BEC8D3263327893 /* Pods-Runner.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -86,7 +88,6 @@ children = ( 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -141,7 +142,7 @@ CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = { isa = PBXGroup; children = ( - 06B796751C0435964931B69B /* Pods_Runner.framework */, + 8AD3D709B256064850151FD7 /* libPods-Runner.a */, ); name = Frameworks; sourceTree = ""; @@ -160,7 +161,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */, - 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, ); buildRules = ( @@ -212,7 +212,6 @@ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, @@ -236,21 +235,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; }; - 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -263,7 +247,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { @@ -286,13 +270,16 @@ 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_ROOT}/../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"; + 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 */ From 8c5b266c3b7b08baf35eb8c7a2bcc7be5a6d7959 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 20 Aug 2019 13:29:34 +0100 Subject: [PATCH 03/29] extend unit tests for new methods --- packages/path_provider/lib/path_provider.dart | 12 ++++--- .../test/path_provider_test.dart | 36 +++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index 966d9e1bd248..b70f582b4a68 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -102,10 +102,12 @@ Future getExternalStorageDirectory() async { Future> getExternalCacheDirectories() async { if (Platform.isIOS) throw UnsupportedError("Functionality not available on iOS"); - final List paths = - await _channel.invokeMethod('getExternalCacheDirectories'); + final List paths = + await _channel.invokeListMethod('getExternalCacheDirectories'); - return paths.map((dynamic path) => Directory(path)).toList(); + return (paths ?? const []) + .map((String path) => Directory(path)) + .toList(); } /// Paths to directories where application specific data can be stored. @@ -127,10 +129,10 @@ Future> getExternalCacheDirectories() async { Future> getExternalStorageDirectories(String type) async { if (Platform.isIOS) throw UnsupportedError("Functionality not available on iOS"); - final List paths = await _channel.invokeMethod( + final List paths = await _channel.invokeListMethod( 'getExternalStorageDirectories', {"type": type}, ); - return paths.map((dynamic path) => Directory(path)).toList(); + return (paths ?? []).map((String path) => Directory(path)).toList(); } diff --git a/packages/path_provider/test/path_provider_test.dart b/packages/path_provider/test/path_provider_test.dart index 9da5a2568a9a..c4e425c49036 100644 --- a/packages/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/test/path_provider_test.dart @@ -58,4 +58,40 @@ void main() { final Directory directory = await getApplicationDocumentsDirectory(); expect(directory.path, equals(fakePath)); }); + + test('getExternalStorageDirectory test', () async { + response = null; + final Directory directory = await getExternalStorageDirectory(); + expect( + log, + [isMethodCall('getStorageDirectory', arguments: null)], + ); + expect(directory, isNull); + }); + + test('getExternalCacheDirectories test', () async { + response = null; + final List directories = await getExternalCacheDirectories(); + expect( + log, + [isMethodCall('getExternalCacheDirectories', arguments: null)], + ); + expect(directories, []); + }); + + test('getExternalStorageDirectories test', () async { + response = null; + final List directories = + await getExternalStorageDirectories("music"); + expect( + log, + [ + isMethodCall( + 'getExternalStorageDirectories', + arguments: const {'type': 'music'}, + ) + ], + ); + expect(directories, []); + }); } From 88034655bcc29f3eb13fbe8d7adfd8bee36ff4bb Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 20 Aug 2019 13:40:03 +0100 Subject: [PATCH 04/29] [path_provider] Activate getApplicationSupportDirectory integration test --- packages/path_provider/CHANGELOG.md | 4 ++++ .../example/test_driver/path_provider.dart | 19 +++++++------------ packages/path_provider/pubspec.yaml | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/path_provider/CHANGELOG.md b/packages/path_provider/CHANGELOG.md index 2e7f5ad33464..a9a44e77d24b 100644 --- a/packages/path_provider/CHANGELOG.md +++ b/packages/path_provider/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.2.0+1 + +* Correct the integration test for Androids `getApplicationSupportDirectory` call. + ## 1.2.0 * On Android, `getApplicationSupportDirectory` is now supported using `getFilesDir`. diff --git a/packages/path_provider/example/test_driver/path_provider.dart b/packages/path_provider/example/test_driver/path_provider.dart index 219d6660df7e..ca9ae8cf642a 100644 --- a/packages/path_provider/example/test_driver/path_provider.dart +++ b/packages/path_provider/example/test_driver/path_provider.dart @@ -36,18 +36,13 @@ void main() { }); test('getApplicationSupportDirectory', () async { - if (Platform.isIOS) { - final Directory result = await getApplicationSupportDirectory(); - final String uuid = Uuid().v1(); - final File file = File('${result.path}/$uuid.txt'); - file.writeAsStringSync('Hello world!'); - expect(file.readAsStringSync(), 'Hello world!'); - expect(result.listSync(), isNotEmpty); - file.deleteSync(); - } else if (Platform.isAndroid) { - final Future result = getApplicationSupportDirectory(); - expect(result, throwsA(isInstanceOf())); - } + final Directory result = await getApplicationSupportDirectory(); + final String uuid = Uuid().v1(); + final File file = File('${result.path}/$uuid.txt'); + file.writeAsStringSync('Hello world!'); + expect(file.readAsStringSync(), 'Hello world!'); + expect(result.listSync(), isNotEmpty); + file.deleteSync(); }); test('getExternalStorageDirectory', () async { diff --git a/packages/path_provider/pubspec.yaml b/packages/path_provider/pubspec.yaml index 2eed0ae7bd9d..3ca13d74398d 100644 --- a/packages/path_provider/pubspec.yaml +++ b/packages/path_provider/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for getting commonly used locations on the Android & iOS file systems, such as the temp and app data directories. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider -version: 1.2.0 +version: 1.2.0+1 flutter: plugin: From 280f229cc21a60c820bdf5fed39f849593ed51e2 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 20 Aug 2019 13:49:30 +0100 Subject: [PATCH 05/29] add integration tests --- .../example/test_driver/path_provider.dart | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/path_provider/example/test_driver/path_provider.dart b/packages/path_provider/example/test_driver/path_provider.dart index ca9ae8cf642a..3fe37e6df1d9 100644 --- a/packages/path_provider/example/test_driver/path_provider.dart +++ b/packages/path_provider/example/test_driver/path_provider.dart @@ -59,4 +59,40 @@ void main() { file.deleteSync(); } }); + + test('getExternalCacheDirectories', () async { + if (Platform.isIOS) { + final Future> result = getExternalCacheDirectories(); + expect(result, throwsA(isInstanceOf())); + } else if (Platform.isAndroid) { + final List directories = await getExternalCacheDirectories(); + for (Directory result in directories) { + final String uuid = Uuid().v1(); + final File file = File('${result.path}/$uuid.txt'); + file.writeAsStringSync('Hello world!'); + expect(file.readAsStringSync(), 'Hello world!'); + expect(result.listSync(), isNotEmpty); + file.deleteSync(); + } + } + }); + + test('getExternalStorageDirectories', () async { + if (Platform.isIOS) { + final Future> result = + getExternalStorageDirectories("music"); + expect(result, throwsA(isInstanceOf())); + } else if (Platform.isAndroid) { + final List directories = + await getExternalStorageDirectories("music"); + for (Directory result in directories) { + final String uuid = Uuid().v1(); + final File file = File('${result.path}/$uuid.txt'); + file.writeAsStringSync('Hello world!'); + expect(file.readAsStringSync(), 'Hello world!'); + expect(result.listSync(), isNotEmpty); + file.deleteSync(); + } + } + }); } From 2a3e4d480719f6e950ad81bcca26b9574024fbaf Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 20 Aug 2019 13:40:03 +0100 Subject: [PATCH 06/29] [path_provider] Activate getApplicationSupportDirectory integration test --- packages/path_provider/CHANGELOG.md | 4 ++++ .../example/test_driver/path_provider.dart | 19 +++++++------------ packages/path_provider/pubspec.yaml | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/path_provider/CHANGELOG.md b/packages/path_provider/CHANGELOG.md index 2e7f5ad33464..ccd0bd866585 100644 --- a/packages/path_provider/CHANGELOG.md +++ b/packages/path_provider/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.2.1 + +* Correct the integration test for Androids `getApplicationSupportDirectory` call. + ## 1.2.0 * On Android, `getApplicationSupportDirectory` is now supported using `getFilesDir`. diff --git a/packages/path_provider/example/test_driver/path_provider.dart b/packages/path_provider/example/test_driver/path_provider.dart index 219d6660df7e..ca9ae8cf642a 100644 --- a/packages/path_provider/example/test_driver/path_provider.dart +++ b/packages/path_provider/example/test_driver/path_provider.dart @@ -36,18 +36,13 @@ void main() { }); test('getApplicationSupportDirectory', () async { - if (Platform.isIOS) { - final Directory result = await getApplicationSupportDirectory(); - final String uuid = Uuid().v1(); - final File file = File('${result.path}/$uuid.txt'); - file.writeAsStringSync('Hello world!'); - expect(file.readAsStringSync(), 'Hello world!'); - expect(result.listSync(), isNotEmpty); - file.deleteSync(); - } else if (Platform.isAndroid) { - final Future result = getApplicationSupportDirectory(); - expect(result, throwsA(isInstanceOf())); - } + final Directory result = await getApplicationSupportDirectory(); + final String uuid = Uuid().v1(); + final File file = File('${result.path}/$uuid.txt'); + file.writeAsStringSync('Hello world!'); + expect(file.readAsStringSync(), 'Hello world!'); + expect(result.listSync(), isNotEmpty); + file.deleteSync(); }); test('getExternalStorageDirectory', () async { diff --git a/packages/path_provider/pubspec.yaml b/packages/path_provider/pubspec.yaml index 2eed0ae7bd9d..634ba1ce834b 100644 --- a/packages/path_provider/pubspec.yaml +++ b/packages/path_provider/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for getting commonly used locations on the Android & iOS file systems, such as the temp and app data directories. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider -version: 1.2.0 +version: 1.2.1 flutter: plugin: From 72a943bb9338bd69733411ace4c82ec32799235c Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 20 Aug 2019 14:08:04 +0100 Subject: [PATCH 07/29] Add missing unit tests --- .../test/path_provider_test.dart | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/packages/path_provider/test/path_provider_test.dart b/packages/path_provider/test/path_provider_test.dart index 9da5a2568a9a..134f258a00d7 100644 --- a/packages/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/test/path_provider_test.dart @@ -33,18 +33,38 @@ void main() { expect(directory, isNull); }); - test('getApplicationDocumentsDirectory test', () async { + test('getApplicationSupportDirectory test', () async { response = null; - final Directory directory = await getApplicationDocumentsDirectory(); + final Directory directory = await getApplicationSupportDirectory(); expect( log, [ - isMethodCall('getApplicationDocumentsDirectory', arguments: null) + isMethodCall('getApplicationSupportDirectory', arguments: null) ], ); expect(directory, isNull); }); + test('getApplicationDocumentsDirectory test', () async { + response = null; + final Directory directory = await getApplicationDocumentsDirectory(); + expect( + log, + [isMethodCall('getApplicationDocumentsDirectory', arguments: null)], + ); + expect(directory, isNull); + }); + + test('getExternalStorageDirectory test', () async { + response = null; + final Directory directory = await getExternalStorageDirectory(); + expect( + log, + [isMethodCall('getStorageDirectory', arguments: null)], + ); + expect(directory, isNull); + }); + test('TemporaryDirectory path test', () async { final String fakePath = "/foo/bar/baz"; response = fakePath; @@ -52,10 +72,24 @@ void main() { expect(directory.path, equals(fakePath)); }); + test('ApplicationSupportDirectory path test', () async { + final String fakePath = "/foo/bar/baz"; + response = fakePath; + final Directory directory = await getApplicationSupportDirectory(); + expect(directory.path, equals(fakePath)); + }); + test('ApplicationDocumentsDirectory path test', () async { final String fakePath = "/foo/bar/baz"; response = fakePath; final Directory directory = await getApplicationDocumentsDirectory(); expect(directory.path, equals(fakePath)); }); + + test('ExternalStorageDirectory path test', () async { + final String fakePath = "/foo/bar/baz"; + response = fakePath; + final Directory directory = await getExternalStorageDirectory(); + expect(directory.path, equals(fakePath)); + }); } From 7323e371aac57aad61ae9dfefbb76ad2929547b0 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Tue, 20 Aug 2019 14:15:32 +0100 Subject: [PATCH 08/29] Formatting --- packages/path_provider/test/path_provider_test.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/path_provider/test/path_provider_test.dart b/packages/path_provider/test/path_provider_test.dart index 134f258a00d7..ef62fe900bad 100644 --- a/packages/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/test/path_provider_test.dart @@ -50,7 +50,9 @@ void main() { final Directory directory = await getApplicationDocumentsDirectory(); expect( log, - [isMethodCall('getApplicationDocumentsDirectory', arguments: null)], + [ + isMethodCall('getApplicationDocumentsDirectory', arguments: null) + ], ); expect(directory, isNull); }); From cf475e1c2701304b66d1307c28d8de231e7c36af Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 9 Sep 2019 16:12:26 +0100 Subject: [PATCH 09/29] [path_provider] Updates tests and copy Android environment names. --- packages/path_provider/example/lib/main.dart | 2 +- .../example/test_driver/path_provider.dart | 32 +++++++++++----- packages/path_provider/lib/path_provider.dart | 27 +++++++++---- .../test/path_provider_test.dart | 38 +++++++++++++++++-- 4 files changed, 76 insertions(+), 23 deletions(-) diff --git a/packages/path_provider/example/lib/main.dart b/packages/path_provider/example/lib/main.dart index 166ba8c6b70b..6ae84caf4ae5 100644 --- a/packages/path_provider/example/lib/main.dart +++ b/packages/path_provider/example/lib/main.dart @@ -181,7 +181,7 @@ class _MyHomePageState extends State { onPressed: Platform.isIOS ? null : () { - _requestExternalStorageDirectories('Music'); + _requestExternalStorageDirectories(AndroidEnvironment.DIRECTORY_MUSIC); }, ), ), diff --git a/packages/path_provider/example/test_driver/path_provider.dart b/packages/path_provider/example/test_driver/path_provider.dart index b5f02e0c1d6a..6eab2ce3d925 100644 --- a/packages/path_provider/example/test_driver/path_provider.dart +++ b/packages/path_provider/example/test_driver/path_provider.dart @@ -95,18 +95,30 @@ void main() { test('getExternalStorageDirectories', () async { if (Platform.isIOS) { final Future> result = - getExternalStorageDirectories("music"); + getExternalStorageDirectories(null); expect(result, throwsA(isInstanceOf())); } else if (Platform.isAndroid) { - final List directories = - await getExternalStorageDirectories("music"); - for (Directory result in directories) { - final String uuid = Uuid().v1(); - final File file = File('${result.path}/$uuid.txt'); - file.writeAsStringSync('Hello world!'); - expect(file.readAsStringSync(), 'Hello world!'); - expect(result.listSync(), isNotEmpty); - file.deleteSync(); + final List allDirs = [ + null, + AndroidEnvironment.DIRECTORY_MUSIC, + AndroidEnvironment.DIRECTORY_PODCASTS, + AndroidEnvironment.DIRECTORY_RINGTONES, + AndroidEnvironment.DIRECTORY_ALARMS, + AndroidEnvironment.DIRECTORY_NOTIFICATIONS, + AndroidEnvironment.DIRECTORY_PICTURES, + AndroidEnvironment.DIRECTORY_MOVIES, + ]; + for (String type in allDirs) { + final List directories = + await getExternalStorageDirectories(type); + for (Directory result in directories) { + final String uuid = Uuid().v1(); + final File file = File('${result.path}/$uuid.txt'); + file.writeAsStringSync('Hello world!'); + expect(file.readAsStringSync(), 'Hello world!'); + expect(result.listSync(), isNotEmpty); + file.deleteSync(); + } } } }); diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index ccea3de20f41..fa813af7a1c0 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -125,9 +125,20 @@ Future> getExternalCacheDirectories() async { final List paths = await _channel.invokeListMethod('getExternalCacheDirectories'); - return (paths ?? const []) - .map((String path) => Directory(path)) - .toList(); + return paths.map((String path) => Directory(path)).toList(); +} + +/// Shadows directory values from Androids `android.os.Environment` class. +/// +/// https://developer.android.com/reference/android/os/Environment.html#fields_1 +class AndroidEnvironment { + static const String DIRECTORY_MUSIC = 'Music'; + static const String DIRECTORY_PODCASTS = 'Podcasts'; + static const String DIRECTORY_RINGTONES = 'Ringtones'; + static const String DIRECTORY_ALARMS = 'Alarms'; + static const String DIRECTORY_NOTIFICATIONS = 'Notifications'; + static const String DIRECTORY_PICTURES = 'Pictures'; + static const String DIRECTORY_MOVIES = 'Movies'; } /// Paths to directories where application specific data can be stored. @@ -140,12 +151,12 @@ Future> getExternalCacheDirectories() async { /// On iOS, this function throws an UnsupportedError as it is not possible /// to access outside the app's sandbox. /// -/// The parameter type is optional. If it is set, it must be one of the -/// "DIRECTORY" constants defined in `android.os.Environment`, e.g. -/// https://developer.android.com/reference/android/os/Environment#DIRECTORY_MUSIC -/// /// On Android this returns Context.getExternalFilesDirs(String type) or /// Context.getExternalFilesDir(String type) on API levels below 19. +/// +/// The parameter [type] is optional. If it is set, it *must* be one of the +/// constants defined in [AndroidEnvironment]. See [AndroidEnvironment] for +/// more information. Future> getExternalStorageDirectories(String type) async { if (_platform.isIOS) throw UnsupportedError("Functionality not available on iOS"); @@ -154,5 +165,5 @@ Future> getExternalStorageDirectories(String type) async { {"type": type}, ); - return (paths ?? []).map((String path) => Directory(path)).toList(); + return paths.map((String path) => Directory(path)).toList(); } diff --git a/packages/path_provider/test/path_provider_test.dart b/packages/path_provider/test/path_provider_test.dart index 23bed4846091..9b3964050f81 100644 --- a/packages/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/test/path_provider_test.dart @@ -99,7 +99,6 @@ void main() { test('getExternalStorageDirectory iOS test', () async { setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); - response = null; try { await getExternalStorageDirectory(); fail('should throw UnsupportedError'); @@ -108,22 +107,53 @@ void main() { } }); + test('getExternalCacheDirectories test', () async { + response = []; + final List directories = await getExternalCacheDirectories(); + expect( + log, + [isMethodCall('getExternalCacheDirectories', arguments: null)], + ); + expect(directories, []); + }); + + test('getExternalCacheDirectories iOS test', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); + + try { + await getExternalCacheDirectories(); + fail('should throw UnsupportedError'); + } catch (e) { + expect(e, isUnsupportedError); + } + }); test('getExternalStorageDirectories test', () async { - response = null; + response = []; final List directories = - await getExternalStorageDirectories("music"); + await getExternalStorageDirectories(AndroidEnvironment.DIRECTORY_MUSIC); expect( log, [ isMethodCall( 'getExternalStorageDirectories', - arguments: const {'type': 'music'}, + arguments: const {'type': AndroidEnvironment.DIRECTORY_MUSIC}, ) ], ); expect(directories, []); }); + test('getExternalStorageDirectories iOS test', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); + + try { + await getExternalStorageDirectories("music"); + fail('should throw UnsupportedError'); + } catch (e) { + expect(e, isUnsupportedError); + } + }); + test('TemporaryDirectory path test', () async { final String fakePath = "/foo/bar/baz"; response = fakePath; From 354c9faf79860153e944b1f90659f24441094f30 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 9 Sep 2019 16:15:38 +0100 Subject: [PATCH 10/29] Bump version --- packages/path_provider/CHANGELOG.md | 4 +++- packages/path_provider/pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/path_provider/CHANGELOG.md b/packages/path_provider/CHANGELOG.md index 6f78f5ecbed4..9de0e40397a5 100644 --- a/packages/path_provider/CHANGELOG.md +++ b/packages/path_provider/CHANGELOG.md @@ -1,6 +1,8 @@ ## 1.3.1 -* Support Android devices with multiple external storage options. +* Support retrieving storage paths on Android devices with multiple external + storage options. This adds a new class `AndroidEnvironment` that shadows the + directory names from Androids `android.os.Environment` class. ## 1.3.0 diff --git a/packages/path_provider/pubspec.yaml b/packages/path_provider/pubspec.yaml index 80c6bde28379..16245929b85e 100644 --- a/packages/path_provider/pubspec.yaml +++ b/packages/path_provider/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for getting commonly used locations on the Android & iOS file systems, such as the temp and app data directories. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider -version: 1.3.0 +version: 1.3.1 flutter: plugin: From b60142f11a35aa320d45fad7cabd2aa7c7d19a04 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 9 Sep 2019 16:19:49 +0100 Subject: [PATCH 11/29] Revert unrelated PR changes. --- packages/path_provider/android/build.gradle | 2 +- .../example/android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 3 +- .../ios/Runner.xcodeproj/project.pbxproj | 39 ++++++++++++------- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/packages/path_provider/android/build.gradle b/packages/path_provider/android/build.gradle index 27d5e80130b5..191930fee299 100644 --- a/packages/path_provider/android/build.gradle +++ b/packages/path_provider/android/build.gradle @@ -21,7 +21,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.4.2' + classpath 'com.android.tools.build:gradle:3.3.0' } } diff --git a/packages/path_provider/example/android/build.gradle b/packages/path_provider/example/android/build.gradle index 6b1a639efd76..541636cc492a 100644 --- a/packages/path_provider/example/android/build.gradle +++ b/packages/path_provider/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.4.2' + classpath 'com.android.tools.build:gradle:3.3.0' } } diff --git a/packages/path_provider/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/path_provider/example/android/gradle/wrapper/gradle-wrapper.properties index 2609572dda74..019065d1d650 100644 --- a/packages/path_provider/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/path_provider/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Aug 20 12:25:19 BST 2019 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-4.10.2-all.zip diff --git a/packages/path_provider/example/ios/Runner.xcodeproj/project.pbxproj b/packages/path_provider/example/ios/Runner.xcodeproj/project.pbxproj index e37bb0dce798..43d34117f5fd 100644 --- a/packages/path_provider/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/path_provider/example/ios/Runner.xcodeproj/project.pbxproj @@ -7,9 +7,10 @@ objects = { /* Begin PBXBuildFile section */ - 14E651F1ED3B0989BD4D13DF /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AD3D709B256064850151FD7 /* libPods-Runner.a */; }; + 0675671949C15323862C164B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06B796751C0435964931B69B /* Pods_Runner.framework */; }; 2D9222481EC32A19007564B0 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D9222471EC32A19007564B0 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 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 */; }; @@ -39,16 +40,15 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0254642752427BE3462BCD8D /* 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 = ""; }; + 06B796751C0435964931B69B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 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 = ""; }; + 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; 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 = ""; }; - 8AD3D709B256064850151FD7 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 8E5BDEA33BEC8D3263327893 /* 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 = ""; }; @@ -67,7 +67,7 @@ files = ( 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - 14E651F1ED3B0989BD4D13DF /* libPods-Runner.a in Frameworks */, + 0675671949C15323862C164B /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -77,8 +77,6 @@ 840012C8B5EDBCF56B0E4AC1 /* Pods */ = { isa = PBXGroup; children = ( - 0254642752427BE3462BCD8D /* Pods-Runner.debug.xcconfig */, - 8E5BDEA33BEC8D3263327893 /* Pods-Runner.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -88,6 +86,7 @@ children = ( 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -142,7 +141,7 @@ CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = { isa = PBXGroup; children = ( - 8AD3D709B256064850151FD7 /* libPods-Runner.a */, + 06B796751C0435964931B69B /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -161,6 +160,7 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */, + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, ); buildRules = ( @@ -212,6 +212,7 @@ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, @@ -235,6 +236,21 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; }; + 532EA9D341340B1DCD08293D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 95BB15E9E1769C0D146AA592 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -247,7 +263,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { @@ -270,16 +286,13 @@ 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"; + shellScript = "diff \"${PODS_ROOT}/../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"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ From 1b5f73a0aeabb08b7e73850cb60aad82ff3d5ae9 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 9 Sep 2019 16:33:39 +0100 Subject: [PATCH 12/29] Resolve test issues introduced in #1953. --- packages/path_provider/CHANGELOG.md | 1 + packages/path_provider/lib/path_provider.dart | 9 +++++++-- .../test/path_provider_test.dart | 19 ++++++++++++++++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/packages/path_provider/CHANGELOG.md b/packages/path_provider/CHANGELOG.md index 9de0e40397a5..ed83c264043d 100644 --- a/packages/path_provider/CHANGELOG.md +++ b/packages/path_provider/CHANGELOG.md @@ -3,6 +3,7 @@ * Support retrieving storage paths on Android devices with multiple external storage options. This adds a new class `AndroidEnvironment` that shadows the directory names from Androids `android.os.Environment` class. +* Fixes `getLibraryDirectory` semantics & tests. ## 1.3.0 diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index fa813af7a1c0..f7cbcfa15da9 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -61,7 +61,12 @@ Future getApplicationSupportDirectory() async { /// Path to the directory where application can store files that are persistent, /// backed up, and not visible to the user, such as sqlite.db. +/// +/// On Android, this function throws an [UnsupportedError] as no equivalent +/// folder exists. Future getLibraryDirectory() async { + if (_platform.isAndroid) + throw UnsupportedError("Functionality not available on Android"); final String path = await _channel.invokeMethod('getLibraryDirectory'); if (path == null) { @@ -129,7 +134,7 @@ Future> getExternalCacheDirectories() async { } /// Shadows directory values from Androids `android.os.Environment` class. -/// +/// /// https://developer.android.com/reference/android/os/Environment.html#fields_1 class AndroidEnvironment { static const String DIRECTORY_MUSIC = 'Music'; @@ -153,7 +158,7 @@ class AndroidEnvironment { /// /// On Android this returns Context.getExternalFilesDirs(String type) or /// Context.getExternalFilesDir(String type) on API levels below 19. -/// +/// /// The parameter [type] is optional. If it is set, it *must* be one of the /// constants defined in [AndroidEnvironment]. See [AndroidEnvironment] for /// more information. diff --git a/packages/path_provider/test/path_provider_test.dart b/packages/path_provider/test/path_provider_test.dart index 9b3964050f81..2835a041efa0 100644 --- a/packages/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/test/path_provider_test.dart @@ -86,8 +86,17 @@ void main() { expect(directory, isNull); }); - test('getLibraryDirectory test', () async { - response = null; + test('getLibraryDirectory Android test', () async { + try { + await getLibraryDirectory(); + fail('should throw UnsupportedError'); + } catch (e) { + expect(e, isUnsupportedError); + } + }); + test('getLibraryDirectory iOS test', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); + final Directory directory = await getLibraryDirectory(); expect( log, @@ -136,7 +145,9 @@ void main() { [ isMethodCall( 'getExternalStorageDirectories', - arguments: const {'type': AndroidEnvironment.DIRECTORY_MUSIC}, + arguments: const { + 'type': AndroidEnvironment.DIRECTORY_MUSIC + }, ) ], ); @@ -183,6 +194,8 @@ void main() { }); test('ApplicationLibraryDirectory path test', () async { + setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); + final String fakePath = "/foo/bar/baz"; response = fakePath; final Directory directory = await getLibraryDirectory(); From d08d7789356266d496b020f2edbebd137fc83315 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 9 Sep 2019 16:35:08 +0100 Subject: [PATCH 13/29] Formatting. --- packages/path_provider/example/lib/main.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/path_provider/example/lib/main.dart b/packages/path_provider/example/lib/main.dart index 6ae84caf4ae5..afd8cd87871e 100644 --- a/packages/path_provider/example/lib/main.dart +++ b/packages/path_provider/example/lib/main.dart @@ -181,7 +181,8 @@ class _MyHomePageState extends State { onPressed: Platform.isIOS ? null : () { - _requestExternalStorageDirectories(AndroidEnvironment.DIRECTORY_MUSIC); + _requestExternalStorageDirectories( + AndroidEnvironment.DIRECTORY_MUSIC); }, ), ), From 11620f0279cdb28ded3890602171a7de60964a35 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 9 Sep 2019 17:52:56 +0100 Subject: [PATCH 14/29] Remove unused import --- .../java/io/flutter/plugins/pathprovider/PathProviderPlugin.java | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java index 284b05c9aa5f..a96581e5d7fd 100644 --- a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java +++ b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java @@ -6,7 +6,6 @@ import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; -import android.os.Environment; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; From e8c948bd7c1ae8c44dfb635f7694f47012b01489 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 4 Oct 2019 10:12:42 +0100 Subject: [PATCH 15/29] {} nits and ' strings --- packages/path_provider/lib/path_provider.dart | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index f7cbcfa15da9..57c51e57f22b 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -65,8 +65,9 @@ Future getApplicationSupportDirectory() async { /// On Android, this function throws an [UnsupportedError] as no equivalent /// folder exists. Future getLibraryDirectory() async { - if (_platform.isAndroid) - throw UnsupportedError("Functionality not available on Android"); + if (_platform.isAndroid) { + throw UnsupportedError('Functionality not available on Android'); + } final String path = await _channel.invokeMethod('getLibraryDirectory'); if (path == null) { @@ -102,8 +103,9 @@ Future getApplicationDocumentsDirectory() async { /// /// On Android this uses the `getExternalFilesDir(null)`. Future getExternalStorageDirectory() async { - if (_platform.isIOS) - throw UnsupportedError("Functionality not available on iOS"); + if (_platform.isIOS) { + throw UnsupportedError('Functionality not available on iOS'); + } final String path = await _channel.invokeMethod('getStorageDirectory'); if (path == null) { @@ -125,8 +127,9 @@ Future getExternalStorageDirectory() async { /// On Android this returns Context.getExternalCacheDirs() or /// Context.getExternalCacheDir() on API levels below 19. Future> getExternalCacheDirectories() async { - if (_platform.isIOS) - throw UnsupportedError("Functionality not available on iOS"); + if (_platform.isIOS) { + throw UnsupportedError('Functionality not available on iOS'); + } final List paths = await _channel.invokeListMethod('getExternalCacheDirectories'); @@ -163,8 +166,9 @@ class AndroidEnvironment { /// constants defined in [AndroidEnvironment]. See [AndroidEnvironment] for /// more information. Future> getExternalStorageDirectories(String type) async { - if (_platform.isIOS) - throw UnsupportedError("Functionality not available on iOS"); + if (_platform.isIOS) { + throw UnsupportedError('Functionality not available on iOS'); + } final List paths = await _channel.invokeListMethod( 'getExternalStorageDirectories', {"type": type}, From a175402ee1bf20674db60ee6d9d4dd4ca0778e38 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 4 Oct 2019 10:28:01 +0100 Subject: [PATCH 16/29] Introduce a enum to specify the storage directory --- .../example/android/gradle.properties | 1 + packages/path_provider/example/lib/main.dart | 7 ++- .../example/test_driver/path_provider.dart | 22 ++++---- packages/path_provider/lib/path_provider.dart | 49 +++++++++++----- .../test/path_provider_test.dart | 56 ++++++++++++------- 5 files changed, 87 insertions(+), 48 deletions(-) diff --git a/packages/path_provider/example/android/gradle.properties b/packages/path_provider/example/android/gradle.properties index 8bd86f680510..7be3d8b46841 100644 --- a/packages/path_provider/example/android/gradle.properties +++ b/packages/path_provider/example/android/gradle.properties @@ -1 +1,2 @@ org.gradle.jvmargs=-Xmx1536M +android.enableR8=true diff --git a/packages/path_provider/example/lib/main.dart b/packages/path_provider/example/lib/main.dart index afd8cd87871e..ea12999bf415 100644 --- a/packages/path_provider/example/lib/main.dart +++ b/packages/path_provider/example/lib/main.dart @@ -104,9 +104,9 @@ class _MyHomePageState extends State { }); } - void _requestExternalStorageDirectories(String type) { + void _requestExternalStorageDirectories(StorageDirectory type) { setState(() { - _externalStorageDirectories = getExternalStorageDirectories(type); + _externalStorageDirectories = getExternalStorageDirectories(type: type); }); } @@ -182,7 +182,8 @@ class _MyHomePageState extends State { ? null : () { _requestExternalStorageDirectories( - AndroidEnvironment.DIRECTORY_MUSIC); + StorageDirectory.music, + ); }, ), ), diff --git a/packages/path_provider/example/test_driver/path_provider.dart b/packages/path_provider/example/test_driver/path_provider.dart index 6eab2ce3d925..d5d0d61d24b9 100644 --- a/packages/path_provider/example/test_driver/path_provider.dart +++ b/packages/path_provider/example/test_driver/path_provider.dart @@ -95,22 +95,22 @@ void main() { test('getExternalStorageDirectories', () async { if (Platform.isIOS) { final Future> result = - getExternalStorageDirectories(null); + getExternalStorageDirectories(type: null); expect(result, throwsA(isInstanceOf())); } else if (Platform.isAndroid) { - final List allDirs = [ + final List allDirs = [ null, - AndroidEnvironment.DIRECTORY_MUSIC, - AndroidEnvironment.DIRECTORY_PODCASTS, - AndroidEnvironment.DIRECTORY_RINGTONES, - AndroidEnvironment.DIRECTORY_ALARMS, - AndroidEnvironment.DIRECTORY_NOTIFICATIONS, - AndroidEnvironment.DIRECTORY_PICTURES, - AndroidEnvironment.DIRECTORY_MOVIES, + StorageDirectory.music, + StorageDirectory.podcasts, + StorageDirectory.ringtones, + StorageDirectory.alarms, + StorageDirectory.notifications, + StorageDirectory.pictures, + StorageDirectory.movies, ]; - for (String type in allDirs) { + for (StorageDirectory type in allDirs) { final List directories = - await getExternalStorageDirectories(type); + await getExternalStorageDirectories(type: type); for (Directory result in directories) { final String uuid = Uuid().v1(); final File file = File('${result.path}/$uuid.txt'); diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index 57c51e57f22b..f729f18bf1d2 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -139,14 +139,14 @@ Future> getExternalCacheDirectories() async { /// Shadows directory values from Androids `android.os.Environment` class. /// /// https://developer.android.com/reference/android/os/Environment.html#fields_1 -class AndroidEnvironment { - static const String DIRECTORY_MUSIC = 'Music'; - static const String DIRECTORY_PODCASTS = 'Podcasts'; - static const String DIRECTORY_RINGTONES = 'Ringtones'; - static const String DIRECTORY_ALARMS = 'Alarms'; - static const String DIRECTORY_NOTIFICATIONS = 'Notifications'; - static const String DIRECTORY_PICTURES = 'Pictures'; - static const String DIRECTORY_MOVIES = 'Movies'; +enum StorageDirectory { + music, + podcasts, + ringtones, + alarms, + notifications, + pictures, + movies, } /// Paths to directories where application specific data can be stored. @@ -161,18 +161,39 @@ class AndroidEnvironment { /// /// On Android this returns Context.getExternalFilesDirs(String type) or /// Context.getExternalFilesDir(String type) on API levels below 19. -/// -/// The parameter [type] is optional. If it is set, it *must* be one of the -/// constants defined in [AndroidEnvironment]. See [AndroidEnvironment] for -/// more information. -Future> getExternalStorageDirectories(String type) async { +Future> getExternalStorageDirectories({ + /// Optional parameter. See [StorageDirectory] for more informations on + /// how this type translates to Android storage directories. + StorageDirectory type, +}) async { if (_platform.isIOS) { throw UnsupportedError('Functionality not available on iOS'); } final List paths = await _channel.invokeListMethod( 'getExternalStorageDirectories', - {"type": type}, + {"type": _mapStorageDirectory(type)}, ); return paths.map((String path) => Directory(path)).toList(); } + +String _mapStorageDirectory(StorageDirectory directory) { + switch (directory) { + case StorageDirectory.music: + return 'Music'; + case StorageDirectory.podcasts: + return 'Podcasts'; + case StorageDirectory.ringtones: + return 'Ringtones'; + case StorageDirectory.alarms: + return 'Alarms'; + case StorageDirectory.notifications: + return 'Notifications'; + case StorageDirectory.pictures: + return 'Pictures'; + case StorageDirectory.movies: + return 'Movies'; + default: + return null; + } +} diff --git a/packages/path_provider/test/path_provider_test.dart b/packages/path_provider/test/path_provider_test.dart index 2835a041efa0..4213065bb1b2 100644 --- a/packages/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/test/path_provider_test.dart @@ -136,29 +136,44 @@ void main() { expect(e, isUnsupportedError); } }); - test('getExternalStorageDirectories test', () async { - response = []; - final List directories = - await getExternalStorageDirectories(AndroidEnvironment.DIRECTORY_MUSIC); - expect( - log, - [ - isMethodCall( - 'getExternalStorageDirectories', - arguments: const { - 'type': AndroidEnvironment.DIRECTORY_MUSIC - }, - ) - ], - ); - expect(directories, []); - }); + + const List> _mappings = >[ + [null, null], + [StorageDirectory.music, 'Music'], + [StorageDirectory.podcasts, 'Podcasts'], + [StorageDirectory.ringtones, 'Ringtones'], + [StorageDirectory.alarms, 'Alarms'], + [StorageDirectory.notifications, 'Notifications'], + [StorageDirectory.pictures, 'Pictures'], + [StorageDirectory.movies, 'Movies'], + ]; + + for (List mapping in _mappings) { + final StorageDirectory type = mapping[0]; + final String androidDirectory = mapping[1]; + + test('getExternalStorageDirectories test (type: $type)', () async { + response = []; + final List directories = + await getExternalStorageDirectories(type: type); + expect( + log, + [ + isMethodCall( + 'getExternalStorageDirectories', + arguments: {'type': androidDirectory}, + ) + ], + ); + expect(directories, []); + }); + } test('getExternalStorageDirectories iOS test', () async { setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios')); try { - await getExternalStorageDirectories("music"); + await getExternalStorageDirectories(type: StorageDirectory.music); fail('should throw UnsupportedError'); } catch (e) { expect(e, isUnsupportedError); @@ -219,8 +234,9 @@ void main() { test('ExternalStorageDirectories path test', () async { final List paths = ["/foo/bar/baz", "/foo/bar/baz2"]; response = paths; - final List directories = - await getExternalStorageDirectories("music"); + final List directories = await getExternalStorageDirectories( + type: StorageDirectory.music, + ); expect(directories.map((Directory d) => d.path).toList(), equals(paths)); }); } From 30465c3b5a166a7d27424617c2982e25832c1e17 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 4 Oct 2019 10:43:00 +0100 Subject: [PATCH 17/29] Refactor test driver and remove now unused uuid dependency. --- packages/path_provider/example/pubspec.yaml | 1 - .../example/test_driver/path_provider.dart | 105 +++++++----------- 2 files changed, 43 insertions(+), 63 deletions(-) diff --git a/packages/path_provider/example/pubspec.yaml b/packages/path_provider/example/pubspec.yaml index 9daa92b8c22e..015a4fb46e5d 100644 --- a/packages/path_provider/example/pubspec.yaml +++ b/packages/path_provider/example/pubspec.yaml @@ -6,7 +6,6 @@ dependencies: sdk: flutter path_provider: path: ../ - uuid: "^1.0.0" dev_dependencies: flutter_driver: diff --git a/packages/path_provider/example/test_driver/path_provider.dart b/packages/path_provider/example/test_driver/path_provider.dart index d5d0d61d24b9..ccbc62599e02 100644 --- a/packages/path_provider/example/test_driver/path_provider.dart +++ b/packages/path_provider/example/test_driver/path_provider.dart @@ -8,7 +8,6 @@ import 'dart:io'; import 'package:flutter_driver/driver_extension.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:uuid/uuid.dart'; void main() { final Completer allTestsCompleter = Completer(); @@ -17,43 +16,23 @@ void main() { test('getTemporaryDirectory', () async { final Directory result = await getTemporaryDirectory(); - final String uuid = Uuid().v1(); - final File file = File('${result.path}/$uuid.txt'); - file.writeAsStringSync('Hello world!'); - expect(file.readAsStringSync(), 'Hello world!'); - expect(result.listSync(), isNotEmpty); - file.deleteSync(); + _verifySampleFile(result, 'temporaryDirectory'); }); test('getApplicationDocumentsDirectory', () async { final Directory result = await getApplicationDocumentsDirectory(); - final String uuid = Uuid().v1(); - final File file = File('${result.path}/$uuid.txt'); - file.writeAsStringSync('Hello world!'); - expect(file.readAsStringSync(), 'Hello world!'); - expect(result.listSync(), isNotEmpty); - file.deleteSync(); + _verifySampleFile(result, 'applicationDocuments'); }); test('getApplicationSupportDirectory', () async { final Directory result = await getApplicationSupportDirectory(); - final String uuid = Uuid().v1(); - final File file = File('${result.path}/$uuid.txt'); - file.writeAsStringSync('Hello world!'); - expect(file.readAsStringSync(), 'Hello world!'); - expect(result.listSync(), isNotEmpty); - file.deleteSync(); + _verifySampleFile(result, 'applicationSupport'); }); test('getLibraryDirectory', () async { if (Platform.isIOS) { final Directory result = await getLibraryDirectory(); - final String uuid = Uuid().v1(); - final File file = File('${result.path}/$uuid.txt'); - file.writeAsStringSync('Hello world!'); - expect(file.readAsStringSync(), 'Hello world!'); - expect(result.listSync(), isNotEmpty); - file.deleteSync(); + _verifySampleFile(result, 'library'); } else if (Platform.isAndroid) { final Future result = getLibraryDirectory(); expect(result, throwsA(isInstanceOf())); @@ -66,12 +45,7 @@ void main() { expect(result, throwsA(isInstanceOf())); } else if (Platform.isAndroid) { final Directory result = await getExternalStorageDirectory(); - final String uuid = Uuid().v1(); - final File file = File('${result.path}/$uuid.txt'); - file.writeAsStringSync('Hello world!'); - expect(file.readAsStringSync(), 'Hello world!'); - expect(result.listSync(), isNotEmpty); - file.deleteSync(); + _verifySampleFile(result, 'externalStorage'); } }); @@ -82,44 +56,51 @@ void main() { } else if (Platform.isAndroid) { final List directories = await getExternalCacheDirectories(); for (Directory result in directories) { - final String uuid = Uuid().v1(); - final File file = File('${result.path}/$uuid.txt'); - file.writeAsStringSync('Hello world!'); - expect(file.readAsStringSync(), 'Hello world!'); - expect(result.listSync(), isNotEmpty); - file.deleteSync(); + _verifySampleFile(result, 'externalCache'); } } }); - test('getExternalStorageDirectories', () async { - if (Platform.isIOS) { - final Future> result = - getExternalStorageDirectories(type: null); - expect(result, throwsA(isInstanceOf())); - } else if (Platform.isAndroid) { - final List allDirs = [ - null, - StorageDirectory.music, - StorageDirectory.podcasts, - StorageDirectory.ringtones, - StorageDirectory.alarms, - StorageDirectory.notifications, - StorageDirectory.pictures, - StorageDirectory.movies, - ]; - for (StorageDirectory type in allDirs) { + final List _allDirs = [ + null, + StorageDirectory.music, + StorageDirectory.podcasts, + StorageDirectory.ringtones, + StorageDirectory.alarms, + StorageDirectory.notifications, + StorageDirectory.pictures, + StorageDirectory.movies, + ]; + + for (StorageDirectory type in _allDirs) { + test('getExternalStorageDirectories (type: $type)', () async { + if (Platform.isIOS) { + final Future> result = + getExternalStorageDirectories(type: null); + expect(result, throwsA(isInstanceOf())); + } else if (Platform.isAndroid) { final List directories = await getExternalStorageDirectories(type: type); for (Directory result in directories) { - final String uuid = Uuid().v1(); - final File file = File('${result.path}/$uuid.txt'); - file.writeAsStringSync('Hello world!'); - expect(file.readAsStringSync(), 'Hello world!'); - expect(result.listSync(), isNotEmpty); - file.deleteSync(); + _verifySampleFile(result, '$type'); } } - } - }); + }); + } +} + +/// Verify a file called [name] in [directory] by recreating it with test +/// contents when necessary. +void _verifySampleFile(Directory directory, String name) { + final File file = File('${directory.path}/$name'); + + if (file.existsSync()) { + file.deleteSync(); + expect(file.existsSync(), isFalse); + } + + file.writeAsStringSync('Hello world!'); + expect(file.readAsStringSync(), 'Hello world!'); + expect(directory.listSync(), isNotEmpty); + file.deleteSync(); } From b3c78dbffbae66aea93f1a4dfbe3d3504a28e1c5 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 4 Oct 2019 10:45:18 +0100 Subject: [PATCH 18/29] Missing doc nit --- packages/path_provider/lib/path_provider.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index f729f18bf1d2..cbf97aa779cd 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -114,9 +114,10 @@ Future getExternalStorageDirectory() async { return Directory(path); } -/// Paths to directories where application specific cache data can be stored. -/// These paths typically reside on external storage like separate partitions -/// or SD cards. Phones may have multiple storage directories available. +/// Paths to directories where application specific external cache data can be +/// stored. These paths typically reside on external storage like separate +/// partitions or SD cards. Phones may have multiple storage directories +/// available. /// /// The current operating system should be determined before issuing this /// function call, as this functionality is only available on Android. From 499fbdb6aef900eb51704644bb14f4585f86345d Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 4 Oct 2019 11:18:18 +0100 Subject: [PATCH 19/29] dartfmt --- packages/path_provider/lib/path_provider.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index cbf97aa779cd..eee8e6bc2404 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -115,8 +115,8 @@ Future getExternalStorageDirectory() async { } /// Paths to directories where application specific external cache data can be -/// stored. These paths typically reside on external storage like separate -/// partitions or SD cards. Phones may have multiple storage directories +/// stored. These paths typically reside on external storage like separate +/// partitions or SD cards. Phones may have multiple storage directories /// available. /// /// The current operating system should be determined before issuing this From 321c331734eca9f33b28c06457fc9bf8940288d0 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 4 Oct 2019 15:10:26 +0100 Subject: [PATCH 20/29] add missing storage directory types --- packages/path_provider/lib/path_provider.dart | 15 ++++++++++++++- .../path_provider/test/path_provider_test.dart | 3 +++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index eee8e6bc2404..01ca25ee4d14 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -148,6 +148,9 @@ enum StorageDirectory { notifications, pictures, movies, + downloads, + dcim, + documents, } /// Paths to directories where application specific data can be stored. @@ -179,6 +182,10 @@ Future> getExternalStorageDirectories({ } String _mapStorageDirectory(StorageDirectory directory) { + if (directory == null) { + return null; + } + switch (directory) { case StorageDirectory.music: return 'Music'; @@ -194,7 +201,13 @@ String _mapStorageDirectory(StorageDirectory directory) { return 'Pictures'; case StorageDirectory.movies: return 'Movies'; + case StorageDirectory.downloads: + return 'Downloads'; + case StorageDirectory.dcim: + return 'DCIM'; + case StorageDirectory.documents: + return 'Documents'; default: - return null; + throw ArgumentError('Unknown storage directory: $directory'); } } diff --git a/packages/path_provider/test/path_provider_test.dart b/packages/path_provider/test/path_provider_test.dart index 4213065bb1b2..8bbaa813b747 100644 --- a/packages/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/test/path_provider_test.dart @@ -146,6 +146,9 @@ void main() { [StorageDirectory.notifications, 'Notifications'], [StorageDirectory.pictures, 'Pictures'], [StorageDirectory.movies, 'Movies'], + [StorageDirectory.downloads, 'Downloads'], + [StorageDirectory.dcim, 'DCIM'], + [StorageDirectory.documents, 'Documents'], ]; for (List mapping in _mappings) { From d368c803450c3ed7b3a8ac122dbb34090560f40e Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 4 Oct 2019 15:14:00 +0100 Subject: [PATCH 21/29] dartfmt once more --- packages/path_provider/lib/path_provider.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index 01ca25ee4d14..fffc329e2238 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -185,7 +185,7 @@ String _mapStorageDirectory(StorageDirectory directory) { if (directory == null) { return null; } - + switch (directory) { case StorageDirectory.music: return 'Music'; From abf34d6f29aa56ac09f57ee4085e7d9b8a8aafdd Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 11 Oct 2019 13:53:57 +0100 Subject: [PATCH 22/29] Activate JUnit --- packages/path_provider/android/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/path_provider/android/build.gradle b/packages/path_provider/android/build.gradle index 191930fee299..dbbe3b804b57 100644 --- a/packages/path_provider/android/build.gradle +++ b/packages/path_provider/android/build.gradle @@ -45,3 +45,8 @@ android { disable 'InvalidPackage' } } + +dependencies { + implementation 'androidx.annotation:annotation:1.1.0' + testImplementation 'junit:junit:4.12' +} From 3d96cc91802c84e24102cc7cb4f5fe03dbdaf533 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 11 Oct 2019 13:55:39 +0100 Subject: [PATCH 23/29] Pass a dart enum (by index) directly to Android, update tests. --- packages/path_provider/lib/path_provider.dart | 35 ++----------------- .../test/path_provider_test.dart | 22 ++---------- 2 files changed, 5 insertions(+), 52 deletions(-) diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index fffc329e2238..e56478eac7be 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -137,7 +137,7 @@ Future> getExternalCacheDirectories() async { return paths.map((String path) => Directory(path)).toList(); } -/// Shadows directory values from Androids `android.os.Environment` class. +/// Corresponds to constants defined in Androids `android.os.Environment` class. /// /// https://developer.android.com/reference/android/os/Environment.html#fields_1 enum StorageDirectory { @@ -175,39 +175,8 @@ Future> getExternalStorageDirectories({ } final List paths = await _channel.invokeListMethod( 'getExternalStorageDirectories', - {"type": _mapStorageDirectory(type)}, + {'type': type?.index}, ); return paths.map((String path) => Directory(path)).toList(); } - -String _mapStorageDirectory(StorageDirectory directory) { - if (directory == null) { - return null; - } - - switch (directory) { - case StorageDirectory.music: - return 'Music'; - case StorageDirectory.podcasts: - return 'Podcasts'; - case StorageDirectory.ringtones: - return 'Ringtones'; - case StorageDirectory.alarms: - return 'Alarms'; - case StorageDirectory.notifications: - return 'Notifications'; - case StorageDirectory.pictures: - return 'Pictures'; - case StorageDirectory.movies: - return 'Movies'; - case StorageDirectory.downloads: - return 'Downloads'; - case StorageDirectory.dcim: - return 'DCIM'; - case StorageDirectory.documents: - return 'Documents'; - default: - throw ArgumentError('Unknown storage directory: $directory'); - } -} diff --git a/packages/path_provider/test/path_provider_test.dart b/packages/path_provider/test/path_provider_test.dart index 8bbaa813b747..7af37888492f 100644 --- a/packages/path_provider/test/path_provider_test.dart +++ b/packages/path_provider/test/path_provider_test.dart @@ -137,24 +137,8 @@ void main() { } }); - const List> _mappings = >[ - [null, null], - [StorageDirectory.music, 'Music'], - [StorageDirectory.podcasts, 'Podcasts'], - [StorageDirectory.ringtones, 'Ringtones'], - [StorageDirectory.alarms, 'Alarms'], - [StorageDirectory.notifications, 'Notifications'], - [StorageDirectory.pictures, 'Pictures'], - [StorageDirectory.movies, 'Movies'], - [StorageDirectory.downloads, 'Downloads'], - [StorageDirectory.dcim, 'DCIM'], - [StorageDirectory.documents, 'Documents'], - ]; - - for (List mapping in _mappings) { - final StorageDirectory type = mapping[0]; - final String androidDirectory = mapping[1]; - + for (StorageDirectory type + in StorageDirectory.values + [null]) { test('getExternalStorageDirectories test (type: $type)', () async { response = []; final List directories = @@ -164,7 +148,7 @@ void main() { [ isMethodCall( 'getExternalStorageDirectories', - arguments: {'type': androidDirectory}, + arguments: {'type': type?.index}, ) ], ); From b7d4b588dc9e3f26d4c6bfc9d62010f5b2435c25 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 11 Oct 2019 13:56:08 +0100 Subject: [PATCH 24/29] Add unit tests for the storage directory enum. --- .../pathprovider/PathProviderPlugin.java | 8 +-- .../pathprovider/StorageDirectoryMapper.java | 51 +++++++++++++++++++ .../StorageDirectoryMapperTest.java | 41 +++++++++++++++ 3 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java create mode 100644 packages/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java diff --git a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java index a96581e5d7fd..30b00d0e5532 100644 --- a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java +++ b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java @@ -6,6 +6,7 @@ import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; +import androidx.annotation.NonNull; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; @@ -32,7 +33,7 @@ private PathProviderPlugin(Registrar registrar) { } @Override - public void onMethodCall(MethodCall call, Result result) { + public void onMethodCall(MethodCall call, @NonNull Result result) { switch (call.method) { case "getTemporaryDirectory": result.success(getPathProviderTemporaryDirectory()); @@ -47,8 +48,9 @@ public void onMethodCall(MethodCall call, Result result) { result.success(getPathProviderExternalCacheDirectories()); break; case "getExternalStorageDirectories": - final String type = call.argument("type"); - result.success(getPathProviderExternalStorageDirectories(type)); + final Integer type = call.argument("type"); + final String directoryName = StorageDirectoryMapper.androidType(type); + result.success(getPathProviderExternalStorageDirectories(directoryName)); break; case "getApplicationSupportDirectory": result.success(getApplicationSupportDirectory()); diff --git a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java new file mode 100644 index 000000000000..5a2ae4f5c288 --- /dev/null +++ b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java @@ -0,0 +1,51 @@ +package io.flutter.plugins.pathprovider; + +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; +import android.os.Environment; + +/** + * Helps to map the Dart `StorageDirectory` enum to a Android system constant. + */ +class StorageDirectoryMapper { + + /** + * Return a Android Environment constant for a Dart Index. + * + * @return The correct Android Environment constant or null, if the index is null. + * @throws IllegalArgumentException If `dartIndex` is not null but also not matches any known + * index. + */ + static String androidType(Integer dartIndex) throws IllegalArgumentException { + if (dartIndex == null) { + return null; + } + + switch (dartIndex) { + case 0: + return Environment.DIRECTORY_MUSIC; + case 1: + return Environment.DIRECTORY_PODCASTS; + case 2: + return Environment.DIRECTORY_RINGTONES; + case 3: + return Environment.DIRECTORY_ALARMS; + case 4: + return Environment.DIRECTORY_NOTIFICATIONS; + case 5: + return Environment.DIRECTORY_PICTURES; + case 6: + return Environment.DIRECTORY_MOVIES; + case 7: + return Environment.DIRECTORY_DOWNLOADS; + case 8: + return Environment.DIRECTORY_DCIM; + case 9: + if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { + return Environment.DIRECTORY_DOCUMENTS; + } + default: + throw new IllegalArgumentException("Unknown index: " + dartIndex); + } + } +} diff --git a/packages/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java b/packages/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java new file mode 100644 index 000000000000..2002d7f6afe8 --- /dev/null +++ b/packages/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java @@ -0,0 +1,41 @@ +package io.flutter.plugins.pathprovider; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import android.os.Environment; +import org.junit.Test; + +public class StorageDirectoryMapperTest { + + @org.junit.Test + public void testAndroidType_null() { + assertNull(StorageDirectoryMapper.androidType(null)); + } + + @org.junit.Test + public void testAndroidType_valid() { + assertEquals(Environment.DIRECTORY_MUSIC, StorageDirectoryMapper.androidType(0)); + assertEquals(Environment.DIRECTORY_PODCASTS, StorageDirectoryMapper.androidType(1)); + assertEquals(Environment.DIRECTORY_MUSIC, StorageDirectoryMapper.androidType(2)); + assertEquals(Environment.DIRECTORY_RINGTONES, StorageDirectoryMapper.androidType(3)); + assertEquals(Environment.DIRECTORY_ALARMS, StorageDirectoryMapper.androidType(4)); + assertEquals(Environment.DIRECTORY_NOTIFICATIONS, StorageDirectoryMapper.androidType(5)); + assertEquals(Environment.DIRECTORY_PICTURES, StorageDirectoryMapper.androidType(6)); + assertEquals(Environment.DIRECTORY_MOVIES, StorageDirectoryMapper.androidType(7)); + assertEquals(Environment.DIRECTORY_DOWNLOADS, StorageDirectoryMapper.androidType(8)); + assertEquals(Environment.DIRECTORY_DCIM, StorageDirectoryMapper.androidType(9)); + } + + @Test + public void testAndroidType_invalid() { + try { + assertEquals(Environment.DIRECTORY_DCIM, StorageDirectoryMapper.androidType(10)); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Unknown index: " + 10, e.getMessage()); + } + } + +} \ No newline at end of file From 30f49abde8f520adb277d4ed09c28a7c532e86bd Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 11 Oct 2019 13:59:24 +0100 Subject: [PATCH 25/29] nit --- packages/path_provider/lib/path_provider.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart index e56478eac7be..3840121c8c4b 100644 --- a/packages/path_provider/lib/path_provider.dart +++ b/packages/path_provider/lib/path_provider.dart @@ -63,7 +63,7 @@ Future getApplicationSupportDirectory() async { /// backed up, and not visible to the user, such as sqlite.db. /// /// On Android, this function throws an [UnsupportedError] as no equivalent -/// folder exists. +/// path exists. Future getLibraryDirectory() async { if (_platform.isAndroid) { throw UnsupportedError('Functionality not available on Android'); From 7c1be07918212b1c548dc58d5299e75be606e516 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 11 Oct 2019 14:14:36 +0100 Subject: [PATCH 26/29] Formatting. --- .../plugins/pathprovider/StorageDirectoryMapper.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java index 5a2ae4f5c288..82024006ddc1 100644 --- a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java +++ b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java @@ -4,9 +4,7 @@ import android.os.Build.VERSION_CODES; import android.os.Environment; -/** - * Helps to map the Dart `StorageDirectory` enum to a Android system constant. - */ +/** Helps to map the Dart `StorageDirectory` enum to a Android system constant. */ class StorageDirectoryMapper { /** @@ -14,7 +12,7 @@ class StorageDirectoryMapper { * * @return The correct Android Environment constant or null, if the index is null. * @throws IllegalArgumentException If `dartIndex` is not null but also not matches any known - * index. + * index. */ static String androidType(Integer dartIndex) throws IllegalArgumentException { if (dartIndex == null) { From c8d7572d68b1d63fa500ba85e5ab154aed930d2c Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 11 Oct 2019 14:15:01 +0100 Subject: [PATCH 27/29] Formatting. --- .../plugins/pathprovider/StorageDirectoryMapperTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java b/packages/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java index 2002d7f6afe8..51695cf623aa 100644 --- a/packages/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java +++ b/packages/path_provider/android/src/test/java/io/flutter/plugins/pathprovider/StorageDirectoryMapperTest.java @@ -37,5 +37,4 @@ public void testAndroidType_invalid() { assertEquals("Unknown index: " + 10, e.getMessage()); } } - -} \ No newline at end of file +} From 76029b6e58aeec713cf5af45b58f04fd8045d531 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 17 Oct 2019 18:45:52 +0100 Subject: [PATCH 28/29] add clear exception when documents directory is unsupported --- .../io/flutter/plugins/pathprovider/StorageDirectoryMapper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java index 82024006ddc1..820509ba86ea 100644 --- a/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java +++ b/packages/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/StorageDirectoryMapper.java @@ -41,6 +41,8 @@ static String androidType(Integer dartIndex) throws IllegalArgumentException { case 9: if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { return Environment.DIRECTORY_DOCUMENTS; + } else { + throw new IllegalArgumentException("Documents directory is unsupported."); } default: throw new IllegalArgumentException("Unknown index: " + dartIndex); From bc55bb2c4c680042bc23bf2feed9e8ad308fb57a Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 17 Oct 2019 19:50:52 +0100 Subject: [PATCH 29/29] Bump to V1.4.0 due to public API changes --- packages/path_provider/CHANGELOG.md | 2 +- packages/path_provider/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/path_provider/CHANGELOG.md b/packages/path_provider/CHANGELOG.md index 579311f96231..af0ec9f7ca0d 100644 --- a/packages/path_provider/CHANGELOG.md +++ b/packages/path_provider/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.3.2 +## 1.4.0 * Support retrieving storage paths on Android devices with multiple external storage options. This adds a new class `AndroidEnvironment` that shadows the diff --git a/packages/path_provider/pubspec.yaml b/packages/path_provider/pubspec.yaml index ff5afe87b281..4517eba48246 100644 --- a/packages/path_provider/pubspec.yaml +++ b/packages/path_provider/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for getting commonly used locations on the Android & iOS file systems, such as the temp and app data directories. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider -version: 1.3.2 +version: 1.4.0 flutter: plugin: