diff --git a/packages/path_provider/path_provider/CHANGELOG.md b/packages/path_provider/path_provider/CHANGELOG.md
index 764662d5d84b..568dd2fde499 100644
--- a/packages/path_provider/path_provider/CHANGELOG.md
+++ b/packages/path_provider/path_provider/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 2.0.6
+
+* Added support for Background Platform Channels on Android when it is
+ available.
+
## 2.0.5
* Update minimum Flutter SDK to 2.5 and iOS deployment target to 9.0.
diff --git a/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java b/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java
index 49360809e892..983f6ff8719f 100644
--- a/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java
+++ b/packages/path_provider/path_provider/android/src/main/java/io/flutter/plugins/pathprovider/PathProviderPlugin.java
@@ -9,18 +9,24 @@
import android.os.Build.VERSION_CODES;
import android.os.Handler;
import android.os.Looper;
+import android.util.Log;
import androidx.annotation.NonNull;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.SettableFuture;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
+import io.flutter.plugin.common.BinaryMessenger;
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.MethodCodec;
+import io.flutter.plugin.common.StandardMethodCodec;
import io.flutter.util.PathUtils;
import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
@@ -28,32 +34,158 @@
import java.util.concurrent.Executors;
public class PathProviderPlugin implements FlutterPlugin, MethodCallHandler {
-
+ static final String TAG = "PathProviderPlugin";
private Context context;
private MethodChannel channel;
- private final Executor uiThreadExecutor = new UiThreadExecutor();
- private final Executor executor =
- Executors.newSingleThreadExecutor(
- new ThreadFactoryBuilder()
- .setNameFormat("path-provider-background-%d")
- .setPriority(Thread.NORM_PRIORITY)
- .build());
+ private PathProviderImpl impl;
+
+ /**
+ * An abstraction over how to access the paths in a thread-safe manner.
+ *
+ *
We need this so on versions of Flutter that support Background Platform Channels this plugin
+ * can take advantage of it.
+ *
+ *
This can be removed after https://github.com/flutter/engine/pull/29147 becomes available on
+ * the stable branch.
+ */
+ private interface PathProviderImpl {
+ void getTemporaryDirectory(@NonNull Result result);
+
+ void getApplicationDocumentsDirectory(@NonNull Result result);
+
+ void getStorageDirectory(@NonNull Result result);
+
+ void getExternalCacheDirectories(@NonNull Result result);
+
+ void getExternalStorageDirectories(@NonNull String directoryName, @NonNull Result result);
+
+ void getApplicationSupportDirectory(@NonNull Result result);
+ }
+
+ /** The implementation for getting system paths that executes from the platform */
+ private class PathProviderPlatformThread implements PathProviderImpl {
+ private final Executor uiThreadExecutor = new UiThreadExecutor();
+ private final Executor executor =
+ Executors.newSingleThreadExecutor(
+ new ThreadFactoryBuilder()
+ .setNameFormat("path-provider-background-%d")
+ .setPriority(Thread.NORM_PRIORITY)
+ .build());
+
+ public void getTemporaryDirectory(@NonNull Result result) {
+ executeInBackground(() -> getPathProviderTemporaryDirectory(), result);
+ }
+
+ public void getApplicationDocumentsDirectory(@NonNull Result result) {
+ executeInBackground(() -> getPathProviderApplicationDocumentsDirectory(), result);
+ }
+
+ public void getStorageDirectory(@NonNull Result result) {
+ executeInBackground(() -> getPathProviderStorageDirectory(), result);
+ }
+
+ public void getExternalCacheDirectories(@NonNull Result result) {
+ executeInBackground(() -> getPathProviderExternalCacheDirectories(), result);
+ }
+
+ public void getExternalStorageDirectories(
+ @NonNull String directoryName, @NonNull Result result) {
+ executeInBackground(() -> getPathProviderExternalStorageDirectories(directoryName), result);
+ }
+
+ public void getApplicationSupportDirectory(@NonNull Result result) {
+ executeInBackground(() -> PathProviderPlugin.this.getApplicationSupportDirectory(), result);
+ }
+
+ private void executeInBackground(Callable task, Result result) {
+ final SettableFuture future = SettableFuture.create();
+ Futures.addCallback(
+ future,
+ new FutureCallback() {
+ public void onSuccess(T answer) {
+ result.success(answer);
+ }
+
+ public void onFailure(Throwable t) {
+ result.error(t.getClass().getName(), t.getMessage(), null);
+ }
+ },
+ uiThreadExecutor);
+ executor.execute(
+ () -> {
+ try {
+ future.set(task.call());
+ } catch (Throwable t) {
+ future.setException(t);
+ }
+ });
+ }
+ }
+
+ /** The implementation for getting system paths that executes from a background thread. */
+ private class PathProviderBackgroundThread implements PathProviderImpl {
+ public void getTemporaryDirectory(@NonNull Result result) {
+ result.success(getPathProviderTemporaryDirectory());
+ }
+
+ public void getApplicationDocumentsDirectory(@NonNull Result result) {
+ result.success(getPathProviderApplicationDocumentsDirectory());
+ }
+
+ public void getStorageDirectory(@NonNull Result result) {
+ result.success(getPathProviderStorageDirectory());
+ }
+
+ public void getExternalCacheDirectories(@NonNull Result result) {
+ result.success(getPathProviderExternalCacheDirectories());
+ }
+
+ public void getExternalStorageDirectories(
+ @NonNull String directoryName, @NonNull Result result) {
+ result.success(getPathProviderExternalStorageDirectories(directoryName));
+ }
+
+ public void getApplicationSupportDirectory(@NonNull Result result) {
+ result.success(PathProviderPlugin.this.getApplicationSupportDirectory());
+ }
+ }
public PathProviderPlugin() {}
+ private void setup(BinaryMessenger messenger, Context context) {
+ String channelName = "plugins.flutter.io/path_provider";
+ // TODO(gaaclarke): Remove reflection guard when https://github.com/flutter/engine/pull/29147
+ // becomes available on the stable branch.
+ try {
+ Class methodChannelClass = Class.forName("io.flutter.plugin.common.MethodChannel");
+ Class taskQueueClass = Class.forName("io.flutter.plugin.common.BinaryMessenger$TaskQueue");
+ Method makeBackgroundTaskQueue = messenger.getClass().getMethod("makeBackgroundTaskQueue");
+ Object taskQueue = makeBackgroundTaskQueue.invoke(messenger);
+ Constructor constructor =
+ methodChannelClass.getConstructor(
+ BinaryMessenger.class, String.class, MethodCodec.class, taskQueueClass);
+ channel =
+ constructor.newInstance(messenger, channelName, StandardMethodCodec.INSTANCE, taskQueue);
+ impl = new PathProviderBackgroundThread();
+ Log.d(TAG, "Use TaskQueues.");
+ } catch (Exception ex) {
+ channel = new MethodChannel(messenger, channelName);
+ impl = new PathProviderPlatformThread();
+ Log.d(TAG, "Don't use TaskQueues.");
+ }
+ this.context = context;
+ channel.setMethodCallHandler(this);
+ }
+
@SuppressWarnings("deprecation")
public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) {
PathProviderPlugin instance = new PathProviderPlugin();
- instance.channel = new MethodChannel(registrar.messenger(), "plugins.flutter.io/path_provider");
- instance.context = registrar.context();
- instance.channel.setMethodCallHandler(instance);
+ instance.setup(registrar.messenger(), registrar.context());
}
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
- channel = new MethodChannel(binding.getBinaryMessenger(), "plugins.flutter.io/path_provider");
- context = binding.getApplicationContext();
- channel.setMethodCallHandler(this);
+ setup(binding.getBinaryMessenger(), binding.getApplicationContext());
}
@Override
@@ -62,52 +194,28 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel = null;
}
- private void executeInBackground(Callable task, Result result) {
- final SettableFuture future = SettableFuture.create();
- Futures.addCallback(
- future,
- new FutureCallback() {
- public void onSuccess(T answer) {
- result.success(answer);
- }
-
- public void onFailure(Throwable t) {
- result.error(t.getClass().getName(), t.getMessage(), null);
- }
- },
- uiThreadExecutor);
- executor.execute(
- () -> {
- try {
- future.set(task.call());
- } catch (Throwable t) {
- future.setException(t);
- }
- });
- }
-
@Override
public void onMethodCall(MethodCall call, @NonNull Result result) {
switch (call.method) {
case "getTemporaryDirectory":
- executeInBackground(() -> getPathProviderTemporaryDirectory(), result);
+ impl.getTemporaryDirectory(result);
break;
case "getApplicationDocumentsDirectory":
- executeInBackground(() -> getPathProviderApplicationDocumentsDirectory(), result);
+ impl.getApplicationDocumentsDirectory(result);
break;
case "getStorageDirectory":
- executeInBackground(() -> getPathProviderStorageDirectory(), result);
+ impl.getStorageDirectory(result);
break;
case "getExternalCacheDirectories":
- executeInBackground(() -> getPathProviderExternalCacheDirectories(), result);
+ impl.getExternalCacheDirectories(result);
break;
case "getExternalStorageDirectories":
final Integer type = call.argument("type");
final String directoryName = StorageDirectoryMapper.androidType(type);
- executeInBackground(() -> getPathProviderExternalStorageDirectories(directoryName), result);
+ impl.getExternalStorageDirectories(directoryName, result);
break;
case "getApplicationSupportDirectory":
- executeInBackground(() -> getApplicationSupportDirectory(), result);
+ impl.getApplicationSupportDirectory(result);
break;
default:
result.notImplemented();
diff --git a/packages/path_provider/path_provider/pubspec.yaml b/packages/path_provider/path_provider/pubspec.yaml
index 5e9bc0b0e7c4..12a186902736 100644
--- a/packages/path_provider/path_provider/pubspec.yaml
+++ b/packages/path_provider/path_provider/pubspec.yaml
@@ -2,7 +2,7 @@ name: path_provider
description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories.
repository: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22
-version: 2.0.5
+version: 2.0.6
environment:
sdk: ">=2.14.0 <3.0.0"