9
9
import android .os .Build .VERSION_CODES ;
10
10
import android .os .Handler ;
11
11
import android .os .Looper ;
12
+ import android .util .Log ;
12
13
import androidx .annotation .NonNull ;
13
14
import com .google .common .util .concurrent .FutureCallback ;
14
15
import com .google .common .util .concurrent .Futures ;
15
16
import com .google .common .util .concurrent .SettableFuture ;
16
17
import com .google .common .util .concurrent .ThreadFactoryBuilder ;
17
18
import io .flutter .embedding .engine .plugins .FlutterPlugin ;
19
+ import io .flutter .plugin .common .BinaryMessenger ;
18
20
import io .flutter .plugin .common .MethodCall ;
19
21
import io .flutter .plugin .common .MethodChannel ;
20
22
import io .flutter .plugin .common .MethodChannel .MethodCallHandler ;
21
23
import io .flutter .plugin .common .MethodChannel .Result ;
24
+ import io .flutter .plugin .common .MethodCodec ;
25
+ import io .flutter .plugin .common .StandardMethodCodec ;
22
26
import io .flutter .util .PathUtils ;
23
27
import java .io .File ;
28
+ import java .lang .reflect .Constructor ;
29
+ import java .lang .reflect .Method ;
24
30
import java .util .ArrayList ;
25
31
import java .util .List ;
26
32
import java .util .concurrent .Callable ;
27
33
import java .util .concurrent .Executor ;
28
34
import java .util .concurrent .Executors ;
29
35
30
36
public class PathProviderPlugin implements FlutterPlugin , MethodCallHandler {
31
-
37
+ static final String TAG = "PathProviderPlugin" ;
32
38
private Context context ;
33
39
private MethodChannel channel ;
34
- private final Executor uiThreadExecutor = new UiThreadExecutor ();
35
- private final Executor executor =
36
- Executors .newSingleThreadExecutor (
37
- new ThreadFactoryBuilder ()
38
- .setNameFormat ("path-provider-background-%d" )
39
- .setPriority (Thread .NORM_PRIORITY )
40
- .build ());
40
+ private PathProviderImpl impl ;
41
+
42
+ /**
43
+ * An abstraction over how to access the paths in a thread-safe manner.
44
+ *
45
+ * <p>We need this so on versions of Flutter that support Background Platform Channels this plugin
46
+ * can take advantage of it.
47
+ *
48
+ * <p>This can be removed after https://github.com/flutter/engine/pull/29147 becomes available on
49
+ * the stable branch.
50
+ */
51
+ private interface PathProviderImpl {
52
+ void getTemporaryDirectory (@ NonNull Result result );
53
+
54
+ void getApplicationDocumentsDirectory (@ NonNull Result result );
55
+
56
+ void getStorageDirectory (@ NonNull Result result );
57
+
58
+ void getExternalCacheDirectories (@ NonNull Result result );
59
+
60
+ void getExternalStorageDirectories (@ NonNull String directoryName , @ NonNull Result result );
61
+
62
+ void getApplicationSupportDirectory (@ NonNull Result result );
63
+ }
64
+
65
+ /** The implementation for getting system paths that executes from the platform */
66
+ private class PathProviderPlatformThread implements PathProviderImpl {
67
+ private final Executor uiThreadExecutor = new UiThreadExecutor ();
68
+ private final Executor executor =
69
+ Executors .newSingleThreadExecutor (
70
+ new ThreadFactoryBuilder ()
71
+ .setNameFormat ("path-provider-background-%d" )
72
+ .setPriority (Thread .NORM_PRIORITY )
73
+ .build ());
74
+
75
+ public void getTemporaryDirectory (@ NonNull Result result ) {
76
+ executeInBackground (() -> getPathProviderTemporaryDirectory (), result );
77
+ }
78
+
79
+ public void getApplicationDocumentsDirectory (@ NonNull Result result ) {
80
+ executeInBackground (() -> getPathProviderApplicationDocumentsDirectory (), result );
81
+ }
82
+
83
+ public void getStorageDirectory (@ NonNull Result result ) {
84
+ executeInBackground (() -> getPathProviderStorageDirectory (), result );
85
+ }
86
+
87
+ public void getExternalCacheDirectories (@ NonNull Result result ) {
88
+ executeInBackground (() -> getPathProviderExternalCacheDirectories (), result );
89
+ }
90
+
91
+ public void getExternalStorageDirectories (
92
+ @ NonNull String directoryName , @ NonNull Result result ) {
93
+ executeInBackground (() -> getPathProviderExternalStorageDirectories (directoryName ), result );
94
+ }
95
+
96
+ public void getApplicationSupportDirectory (@ NonNull Result result ) {
97
+ executeInBackground (() -> PathProviderPlugin .this .getApplicationSupportDirectory (), result );
98
+ }
99
+
100
+ private <T > void executeInBackground (Callable <T > task , Result result ) {
101
+ final SettableFuture <T > future = SettableFuture .create ();
102
+ Futures .addCallback (
103
+ future ,
104
+ new FutureCallback <T >() {
105
+ public void onSuccess (T answer ) {
106
+ result .success (answer );
107
+ }
108
+
109
+ public void onFailure (Throwable t ) {
110
+ result .error (t .getClass ().getName (), t .getMessage (), null );
111
+ }
112
+ },
113
+ uiThreadExecutor );
114
+ executor .execute (
115
+ () -> {
116
+ try {
117
+ future .set (task .call ());
118
+ } catch (Throwable t ) {
119
+ future .setException (t );
120
+ }
121
+ });
122
+ }
123
+ }
124
+
125
+ /** The implementation for getting system paths that executes from a background thread. */
126
+ private class PathProviderBackgroundThread implements PathProviderImpl {
127
+ public void getTemporaryDirectory (@ NonNull Result result ) {
128
+ result .success (getPathProviderTemporaryDirectory ());
129
+ }
130
+
131
+ public void getApplicationDocumentsDirectory (@ NonNull Result result ) {
132
+ result .success (getPathProviderApplicationDocumentsDirectory ());
133
+ }
134
+
135
+ public void getStorageDirectory (@ NonNull Result result ) {
136
+ result .success (getPathProviderStorageDirectory ());
137
+ }
138
+
139
+ public void getExternalCacheDirectories (@ NonNull Result result ) {
140
+ result .success (getPathProviderExternalCacheDirectories ());
141
+ }
142
+
143
+ public void getExternalStorageDirectories (
144
+ @ NonNull String directoryName , @ NonNull Result result ) {
145
+ result .success (getPathProviderExternalStorageDirectories (directoryName ));
146
+ }
147
+
148
+ public void getApplicationSupportDirectory (@ NonNull Result result ) {
149
+ result .success (PathProviderPlugin .this .getApplicationSupportDirectory ());
150
+ }
151
+ }
41
152
42
153
public PathProviderPlugin () {}
43
154
155
+ private void setup (BinaryMessenger messenger , Context context ) {
156
+ String channelName = "plugins.flutter.io/path_provider" ;
157
+ // TODO(gaaclarke): Remove reflection guard when https://github.com/flutter/engine/pull/29147
158
+ // becomes available on the stable branch.
159
+ try {
160
+ Class methodChannelClass = Class .forName ("io.flutter.plugin.common.MethodChannel" );
161
+ Class taskQueueClass = Class .forName ("io.flutter.plugin.common.BinaryMessenger$TaskQueue" );
162
+ Method makeBackgroundTaskQueue = messenger .getClass ().getMethod ("makeBackgroundTaskQueue" );
163
+ Object taskQueue = makeBackgroundTaskQueue .invoke (messenger );
164
+ Constructor <MethodChannel > constructor =
165
+ methodChannelClass .getConstructor (
166
+ BinaryMessenger .class , String .class , MethodCodec .class , taskQueueClass );
167
+ channel =
168
+ constructor .newInstance (messenger , channelName , StandardMethodCodec .INSTANCE , taskQueue );
169
+ impl = new PathProviderBackgroundThread ();
170
+ Log .d (TAG , "Use TaskQueues." );
171
+ } catch (Exception ex ) {
172
+ channel = new MethodChannel (messenger , channelName );
173
+ impl = new PathProviderPlatformThread ();
174
+ Log .d (TAG , "Don't use TaskQueues." );
175
+ }
176
+ this .context = context ;
177
+ channel .setMethodCallHandler (this );
178
+ }
179
+
44
180
@ SuppressWarnings ("deprecation" )
45
181
public static void registerWith (io .flutter .plugin .common .PluginRegistry .Registrar registrar ) {
46
182
PathProviderPlugin instance = new PathProviderPlugin ();
47
- instance .channel = new MethodChannel (registrar .messenger (), "plugins.flutter.io/path_provider" );
48
- instance .context = registrar .context ();
49
- instance .channel .setMethodCallHandler (instance );
183
+ instance .setup (registrar .messenger (), registrar .context ());
50
184
}
51
185
52
186
@ Override
53
187
public void onAttachedToEngine (@ NonNull FlutterPluginBinding binding ) {
54
- channel = new MethodChannel (binding .getBinaryMessenger (), "plugins.flutter.io/path_provider" );
55
- context = binding .getApplicationContext ();
56
- channel .setMethodCallHandler (this );
188
+ setup (binding .getBinaryMessenger (), binding .getApplicationContext ());
57
189
}
58
190
59
191
@ Override
@@ -62,52 +194,28 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
62
194
channel = null ;
63
195
}
64
196
65
- private <T > void executeInBackground (Callable <T > task , Result result ) {
66
- final SettableFuture <T > future = SettableFuture .create ();
67
- Futures .addCallback (
68
- future ,
69
- new FutureCallback <T >() {
70
- public void onSuccess (T answer ) {
71
- result .success (answer );
72
- }
73
-
74
- public void onFailure (Throwable t ) {
75
- result .error (t .getClass ().getName (), t .getMessage (), null );
76
- }
77
- },
78
- uiThreadExecutor );
79
- executor .execute (
80
- () -> {
81
- try {
82
- future .set (task .call ());
83
- } catch (Throwable t ) {
84
- future .setException (t );
85
- }
86
- });
87
- }
88
-
89
197
@ Override
90
198
public void onMethodCall (MethodCall call , @ NonNull Result result ) {
91
199
switch (call .method ) {
92
200
case "getTemporaryDirectory" :
93
- executeInBackground (() -> getPathProviderTemporaryDirectory (), result );
201
+ impl . getTemporaryDirectory ( result );
94
202
break ;
95
203
case "getApplicationDocumentsDirectory" :
96
- executeInBackground (() -> getPathProviderApplicationDocumentsDirectory (), result );
204
+ impl . getApplicationDocumentsDirectory ( result );
97
205
break ;
98
206
case "getStorageDirectory" :
99
- executeInBackground (() -> getPathProviderStorageDirectory (), result );
207
+ impl . getStorageDirectory ( result );
100
208
break ;
101
209
case "getExternalCacheDirectories" :
102
- executeInBackground (() -> getPathProviderExternalCacheDirectories (), result );
210
+ impl . getExternalCacheDirectories ( result );
103
211
break ;
104
212
case "getExternalStorageDirectories" :
105
213
final Integer type = call .argument ("type" );
106
214
final String directoryName = StorageDirectoryMapper .androidType (type );
107
- executeInBackground (() -> getPathProviderExternalStorageDirectories ( directoryName ) , result );
215
+ impl . getExternalStorageDirectories ( directoryName , result );
108
216
break ;
109
217
case "getApplicationSupportDirectory" :
110
- executeInBackground (() -> getApplicationSupportDirectory (), result );
218
+ impl . getApplicationSupportDirectory (result );
111
219
break ;
112
220
default :
113
221
result .notImplemented ();
0 commit comments