Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
f9bca2b
Add support for Android devices with multiple external storage options.
ened Dec 7, 2018
6414953
Merge branch 'master' into path-provider-android
Aug 20, 2019
e5fe50b
Update path_provider AGB & iOS project file
Aug 20, 2019
8c5b266
extend unit tests for new methods
Aug 20, 2019
8803465
[path_provider] Activate getApplicationSupportDirectory integration test
Aug 20, 2019
ecc8aca
Merge branch 'path_provider/integration_test' into path-provider-android
Aug 20, 2019
280f229
add integration tests
Aug 20, 2019
2a3e4d4
[path_provider] Activate getApplicationSupportDirectory integration test
Aug 20, 2019
d6f66f2
Merge branch 'path_provider/integration_test' into path-provider-android
Aug 20, 2019
72a943b
Add missing unit tests
Aug 20, 2019
b4459b3
Merge branch 'path_provider/integration_test' into path-provider-android
Aug 20, 2019
7323e37
Formatting
Aug 20, 2019
1cfb256
Merge branch 'path_provider/integration_test' into path-provider-android
Aug 20, 2019
2736545
Merge branch 'master' of https://github.com/flutter/plugins into path…
Aug 22, 2019
e05e869
Merge branch 'master' into path-provider-android
Sep 5, 2019
e577e50
Merge branch 'master' of https://github.com/flutter/plugins into path…
Sep 6, 2019
f2941d9
Merge branch 'master' of https://github.com/flutter/plugins into path…
Sep 9, 2019
cf475e1
[path_provider] Updates tests and copy Android environment names.
Sep 9, 2019
354c9fa
Bump version
Sep 9, 2019
b60142f
Revert unrelated PR changes.
Sep 9, 2019
1b5f73a
Resolve test issues introduced in #1953.
Sep 9, 2019
d08d778
Formatting.
Sep 9, 2019
11620f0
Remove unused import
Sep 9, 2019
6ce45b1
Merge branch 'master' into path-provider-android
ened Oct 4, 2019
e8c948b
{} nits and ' strings
ened Oct 4, 2019
a175402
Introduce a enum to specify the storage directory
ened Oct 4, 2019
30465c3
Refactor test driver and remove now unused uuid dependency.
ened Oct 4, 2019
b3c78db
Missing doc nit
ened Oct 4, 2019
499fbdb
dartfmt
ened Oct 4, 2019
321c331
add missing storage directory types
ened Oct 4, 2019
d368c80
dartfmt once more
ened Oct 4, 2019
9806d05
Merge branch 'master' into path-provider-android
ened Oct 7, 2019
8937f5d
Merge branch 'master' of https://github.com/flutter/plugins into path…
ened Oct 11, 2019
abf34d6
Activate JUnit
ened Oct 11, 2019
3d96cc9
Pass a dart enum (by index) directly to Android, update tests.
ened Oct 11, 2019
b7d4b58
Add unit tests for the storage directory enum.
ened Oct 11, 2019
30f49ab
nit
ened Oct 11, 2019
7c1be07
Formatting.
ened Oct 11, 2019
c8d7572
Formatting.
ened Oct 11, 2019
408a3bb
Merge branch 'master' into path-provider-android
ened Oct 15, 2019
4e9a465
Merge branch 'master' into path-provider-android
ened Oct 17, 2019
76029b6
add clear exception when documents directory is unsupported
ened Oct 17, 2019
bc55bb2
Bump to V1.4.0 due to public API changes
ened Oct 17, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/path_provider/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 1.4.0

* 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.1

* Define clang module for iOS.
Expand Down
5 changes: 5 additions & 0 deletions packages/path_provider/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ android {
disable 'InvalidPackage'
}
}

dependencies {
implementation 'androidx.annotation:annotation:1.1.0'
testImplementation 'junit:junit:4.12'
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@

package io.flutter.plugins.pathprovider;

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;
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) {
Expand All @@ -27,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());
Expand All @@ -38,6 +44,14 @@ public void onMethodCall(MethodCall call, Result result) {
case "getStorageDirectory":
result.success(getPathProviderStorageDirectory());
break;
case "getExternalCacheDirectories":
result.success(getPathProviderExternalCacheDirectories());
break;
case "getExternalStorageDirectories":
final Integer type = call.argument("type");
final String directoryName = StorageDirectoryMapper.androidType(type);
result.success(getPathProviderExternalStorageDirectories(directoryName));
break;
case "getApplicationSupportDirectory":
result.success(getApplicationSupportDirectory());
break;
Expand Down Expand Up @@ -65,4 +79,42 @@ private String getPathProviderStorageDirectory() {
}
return dir.getAbsolutePath();
}

private List<String> getPathProviderExternalCacheDirectories() {
final List<String> 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<String> getPathProviderExternalStorageDirectories(String type) {
final List<String> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
} else {
throw new IllegalArgumentException("Documents directory is unsupported.");
}
default:
throw new IllegalArgumentException("Unknown index: " + dartIndex);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
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());
}
}
}
1 change: 1 addition & 0 deletions packages/path_provider/example/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
65 changes: 64 additions & 1 deletion packages/path_provider/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class _MyHomePageState extends State<MyHomePage> {
Future<Directory> _appLibraryDirectory;
Future<Directory> _appDocumentsDirectory;
Future<Directory> _externalDocumentsDirectory;
Future<List<Directory>> _externalStorageDirectories;
Future<List<Directory>> _externalCacheDirectories;

void _requestTempDirectory() {
setState(() {
Expand All @@ -61,6 +63,23 @@ class _MyHomePageState extends State<MyHomePage> {
return Padding(padding: const EdgeInsets.all(16.0), child: text);
}

Widget _buildDirectories(
BuildContext context, AsyncSnapshot<List<Directory>> 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();
Expand All @@ -85,6 +104,18 @@ class _MyHomePageState extends State<MyHomePage> {
});
}

void _requestExternalStorageDirectories(StorageDirectory type) {
setState(() {
_externalStorageDirectories = getExternalStorageDirectories(type: type);
});
}

void _requestExternalCacheDirectories() {
setState(() {
_externalCacheDirectories = getExternalCacheDirectories();
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
Expand Down Expand Up @@ -140,7 +171,39 @@ class _MyHomePageState extends State<MyHomePage> {
),
),
FutureBuilder<Directory>(
future: _externalDocumentsDirectory, builder: _buildDirectory)
future: _externalDocumentsDirectory, builder: _buildDirectory),
Column(children: <Widget>[
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(
StorageDirectory.music,
);
},
),
),
]),
FutureBuilder<List<Directory>>(
future: _externalStorageDirectories,
builder: _buildDirectories),
Column(children: <Widget>[
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cyanglaz I have followed the style in the current example code, but think the indentation could be shown better with a few additional "," here & there. Perhaps better to be added in a future PR?

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<List<Directory>>(
future: _externalCacheDirectories, builder: _buildDirectories),
],
),
),
Expand Down
1 change: 0 additions & 1 deletion packages/path_provider/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ dependencies:
sdk: flutter
path_provider:
path: ../
uuid: "^1.0.0"

dev_dependencies:
flutter_driver:
Expand Down
Loading