55import android .content .Context ;
66
77import java .io .File ;
8+ import java .io .FileOutputStream ;
9+ import java .io .IOException ;
10+ import java .io .InputStream ;
811import java .util .Map ;
912import java .util .HashMap ;
1013
2629import com .google .android .gms .tasks .OnFailureListener ;
2730import com .google .android .gms .tasks .OnSuccessListener ;
2831
32+ import com .google .firebase .storage .StorageException ;
33+ import com .google .firebase .storage .StreamDownloadTask ;
2934import com .google .firebase .storage .UploadTask ;
3035import com .google .firebase .storage .FirebaseStorage ;
3136import com .google .firebase .storage .StorageMetadata ;
@@ -49,6 +54,18 @@ class FirestackStorageModule extends ReactContextBaseJavaModule {
4954 private static final String FileTypeRegular = "FILETYPE_REGULAR" ;
5055 private static final String FileTypeDirectory = "FILETYPE_DIRECTORY" ;
5156
57+ private static final String STORAGE_UPLOAD_PROGRESS = "upload_progress" ;
58+ private static final String STORAGE_UPLOAD_PAUSED = "upload_paused" ;
59+ private static final String STORAGE_UPLOAD_RESUMED = "upload_resumed" ;
60+
61+ private static final String STORAGE_DOWNLOAD_PROGRESS = "download_progress" ;
62+ private static final String STORAGE_DOWNLOAD_PAUSED = "download_paused" ;
63+ private static final String STORAGE_DOWNLOAD_RESUMED = "download_resumed" ;
64+ private static final String STORAGE_DOWNLOAD_SUCCESS = "download_success" ;
65+ private static final String STORAGE_DOWNLOAD_FAILURE = "download_failure" ;
66+
67+ private ReactContext mReactContext ;
68+
5269 public FirestackStorageModule (ReactApplicationContext reactContext ) {
5370 super (reactContext );
5471
@@ -60,6 +77,118 @@ public String getName() {
6077 return TAG ;
6178 }
6279
80+
81+ public boolean isExternalStorageWritable () {
82+ String state = Environment .getExternalStorageState ();
83+ if (Environment .MEDIA_MOUNTED .equals (state )) {
84+ return true ;
85+ }
86+ return false ;
87+ }
88+
89+ @ ReactMethod
90+ public void downloadFile (final String urlStr ,
91+ final String fbPath ,
92+ final String localFile ,
93+ final Callback callback ) {
94+ Log .d (TAG , "downloadFile: " +urlStr +", " +localFile );
95+ if (!isExternalStorageWritable ()) {
96+ Log .w (TAG , "downloadFile failed: external storage not writable" );
97+ WritableMap error = Arguments .createMap ();
98+ final int errorCode = 1 ;
99+ error .putDouble ("code" , errorCode );
100+ error .putString ("description" , "downloadFile failed: external storage not writable" );
101+ callback .invoke (error );
102+ return ;
103+ }
104+ FirebaseStorage storage = FirebaseStorage .getInstance ();
105+ String storageBucket = storage .getApp ().getOptions ().getStorageBucket ();
106+ String storageUrl = "gs://" + storageBucket ;
107+ Log .d (TAG , "Storage url " + storageUrl + fbPath );
108+
109+ StorageReference storageRef = storage .getReferenceFromUrl (storageUrl );
110+ StorageReference fileRef = storageRef .child (fbPath );
111+
112+ fileRef .getStream (new StreamDownloadTask .StreamProcessor () {
113+ @ Override
114+ public void doInBackground (StreamDownloadTask .TaskSnapshot taskSnapshot , InputStream inputStream ) throws IOException {
115+ int indexOfLastSlash = localFile .lastIndexOf ("/" );
116+ String pathMinusFileName = localFile .substring (0 , indexOfLastSlash ) + "/" ;
117+ String filename = localFile .substring (indexOfLastSlash +1 );
118+ File fileWithJustPath = new File (pathMinusFileName );
119+ if (!fileWithJustPath .mkdirs ()) {
120+ Log .e (TAG , "Directory not created" );
121+ WritableMap error = Arguments .createMap ();
122+ error .putString ("message" , "Directory not created" );
123+ callback .invoke (error );
124+ return ;
125+ }
126+ File fileWithFullPath = new File (pathMinusFileName , filename );
127+ FileOutputStream output = new FileOutputStream (fileWithFullPath );
128+ int bufferSize = 1024 ;
129+ byte [] buffer = new byte [bufferSize ];
130+ int len = 0 ;
131+ while ((len = inputStream .read (buffer )) != -1 ) {
132+ output .write (buffer , 0 , len );
133+ }
134+ output .close ();
135+ }
136+ }).addOnProgressListener (new OnProgressListener <StreamDownloadTask .TaskSnapshot >() {
137+ @ Override
138+ public void onProgress (StreamDownloadTask .TaskSnapshot taskSnapshot ) {
139+ WritableMap data = Arguments .createMap ();
140+ data .putString ("ref" , taskSnapshot .getStorage ().getBucket ());
141+ double percentComplete = taskSnapshot .getTotalByteCount () == 0 ? 0.0f : 100.0f * (taskSnapshot .getBytesTransferred ()) / (taskSnapshot .getTotalByteCount ());
142+ data .putDouble ("progress" , percentComplete );
143+ FirestackUtils .sendEvent (mReactContext , STORAGE_DOWNLOAD_PROGRESS , data );
144+ }
145+ }).addOnPausedListener (new OnPausedListener <StreamDownloadTask .TaskSnapshot >() {
146+ @ Override
147+ public void onPaused (StreamDownloadTask .TaskSnapshot taskSnapshot ) {
148+ WritableMap data = Arguments .createMap ();
149+ data .putString ("ref" , taskSnapshot .getStorage ().getBucket ());
150+ FirestackUtils .sendEvent (mReactContext , STORAGE_DOWNLOAD_PAUSED , data );
151+ }
152+ }).addOnSuccessListener (new OnSuccessListener <StreamDownloadTask .TaskSnapshot >() {
153+ @ Override
154+ public void onSuccess (StreamDownloadTask .TaskSnapshot taskSnapshot ) {
155+ final WritableMap data = Arguments .createMap ();
156+ StorageReference ref = taskSnapshot .getStorage ();
157+ data .putString ("fullPath" , ref .getPath ());
158+ data .putString ("bucket" , ref .getBucket ());
159+ data .putString ("name" , ref .getName ());
160+ ref .getMetadata ().addOnSuccessListener (new OnSuccessListener <StorageMetadata >() {
161+ @ Override
162+ public void onSuccess (final StorageMetadata storageMetadata ) {
163+ data .putMap ("metadata" , getMetadataAsMap (storageMetadata ));
164+ callback .invoke (null , data );
165+ }
166+ })
167+ .addOnFailureListener (new OnFailureListener () {
168+ @ Override
169+ public void onFailure (@ NonNull Exception exception ) {
170+ final int errorCode = 1 ;
171+ WritableMap data = Arguments .createMap ();
172+ StorageException storageException = StorageException .fromException (exception );
173+ data .putString ("description" , storageException .getMessage ());
174+ data .putInt ("code" , errorCode );
175+ callback .invoke (makeErrorPayload (errorCode , exception ));
176+ }
177+ });
178+ }
179+ }).addOnFailureListener (new OnFailureListener () {
180+ @ Override
181+ public void onFailure (@ NonNull Exception exception ) {
182+ final int errorCode = 1 ;
183+ WritableMap data = Arguments .createMap ();
184+ StorageException storageException = StorageException .fromException (exception );
185+ data .putString ("description" , storageException .getMessage ());
186+ data .putInt ("code" , errorCode );
187+ callback .invoke (makeErrorPayload (errorCode , exception ));
188+ }
189+ });
190+ }
191+
63192 @ ReactMethod
64193 public void downloadUrl (final String javascriptStorageBucket ,
65194 final String path ,
@@ -90,16 +219,7 @@ public void onSuccess(Uri uri) {
90219 public void onSuccess (final StorageMetadata storageMetadata ) {
91220 Log .d (TAG , "getMetadata success " + storageMetadata );
92221
93- WritableMap metadata = Arguments .createMap ();
94- metadata .putString ("getBucket" , storageMetadata .getBucket ());
95- metadata .putString ("getName" , storageMetadata .getName ());
96- metadata .putDouble ("sizeBytes" , storageMetadata .getSizeBytes ());
97- metadata .putDouble ("created_at" , storageMetadata .getCreationTimeMillis ());
98- metadata .putDouble ("updated_at" , storageMetadata .getUpdatedTimeMillis ());
99- metadata .putString ("md5hash" , storageMetadata .getMd5Hash ());
100- metadata .putString ("encoding" , storageMetadata .getContentEncoding ());
101-
102- res .putMap ("metadata" , metadata );
222+ res .putMap ("metadata" , getMetadataAsMap (storageMetadata ));
103223 res .putString ("name" , storageMetadata .getName ());
104224 res .putString ("url" , storageMetadata .getDownloadUrl ().toString ());
105225 callback .invoke (null , res );
@@ -109,7 +229,8 @@ public void onSuccess(final StorageMetadata storageMetadata) {
109229 @ Override
110230 public void onFailure (@ NonNull Exception exception ) {
111231 Log .e (TAG , "Failure in download " + exception );
112- callback .invoke (makeErrorPayload (1 , exception ));
232+ final int errorCode = 1 ;
233+ callback .invoke (makeErrorPayload (errorCode , exception ));
113234 }
114235 });
115236
@@ -129,6 +250,18 @@ public void onFailure(@NonNull Exception exception) {
129250 });
130251 }
131252
253+ private WritableMap getMetadataAsMap (StorageMetadata storageMetadata ) {
254+ WritableMap metadata = Arguments .createMap ();
255+ metadata .putString ("getBucket" , storageMetadata .getBucket ());
256+ metadata .putString ("getName" , storageMetadata .getName ());
257+ metadata .putDouble ("sizeBytes" , storageMetadata .getSizeBytes ());
258+ metadata .putDouble ("created_at" , storageMetadata .getCreationTimeMillis ());
259+ metadata .putDouble ("updated_at" , storageMetadata .getUpdatedTimeMillis ());
260+ metadata .putString ("md5hash" , storageMetadata .getMd5Hash ());
261+ metadata .putString ("encoding" , storageMetadata .getContentEncoding ());
262+ return metadata ;
263+ }
264+
132265 // STORAGE
133266 @ ReactMethod
134267 public void uploadFile (final String urlStr , final String name , final String filepath , final ReadableMap metadata , final Callback callback ) {
@@ -191,9 +324,9 @@ public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
191324
192325 if (progress >= 0 ) {
193326 WritableMap data = Arguments .createMap ();
194- data .putString ("eventName" , "upload_progress" );
327+ data .putString ("eventName" , STORAGE_UPLOAD_PROGRESS );
195328 data .putDouble ("progress" , progress );
196- FirestackUtils .sendEvent (getReactApplicationContext (), "upload_progress" , data );
329+ FirestackUtils .sendEvent (getReactApplicationContext (), STORAGE_UPLOAD_PROGRESS , data );
197330 }
198331 }
199332 })
@@ -204,13 +337,14 @@ public void onPaused(UploadTask.TaskSnapshot taskSnapshot) {
204337 StorageMetadata d = taskSnapshot .getMetadata ();
205338 String bucket = d .getBucket ();
206339 WritableMap data = Arguments .createMap ();
207- data .putString ("eventName" , "upload_paused" );
340+ data .putString ("eventName" , STORAGE_UPLOAD_PAUSED );
208341 data .putString ("ref" , bucket );
209- FirestackUtils .sendEvent (getReactApplicationContext (), "upload_paused" , data );
342+ FirestackUtils .sendEvent (getReactApplicationContext (), STORAGE_UPLOAD_PAUSED , data );
210343 }
211344 });
212345 } catch (Exception ex ) {
213- callback .invoke (makeErrorPayload (2 , ex ));
346+ final int errorCode = 2 ;
347+ callback .invoke (makeErrorPayload (errorCode , ex ));
214348 }
215349 }
216350
@@ -221,7 +355,8 @@ public void getRealPathFromURI(final String uri, final Callback callback) {
221355 callback .invoke (null , path );
222356 } catch (Exception ex ) {
223357 ex .printStackTrace ();
224- callback .invoke (makeErrorPayload (1 , ex ));
358+ final int errorCode = 1 ;
359+ callback .invoke (makeErrorPayload (errorCode , ex ));
225360 }
226361 }
227362
0 commit comments