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..3e6111f0f00b 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,147 @@ 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; + + 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); + } + + 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); + } + }); + } + } + + 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 +183,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"