Skip to content

Commit f9c132d

Browse files
committed
Adding more robust notation to start from an arbitrary file path
1 parent cd1cdd1 commit f9c132d

11 files changed

Lines changed: 270 additions & 33 deletions

File tree

AndroidFilePickerLightLibrary/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ android {
3131
defaultConfig {
3232
minSdkVersion 29
3333
targetSdkVersion 30
34-
versionCode 5
35-
versionName "1.0.4"
34+
versionCode 6
35+
versionName "1.0.5"
3636
}
3737

3838
compileOptions {

AndroidFilePickerLightLibrary/src/main/java/com/maxieds/androidfilepickerlightlibrary/BasicFileProvider.java

Lines changed: 130 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,13 @@ This program (the AndroidFilePickerLight library) is free software written by
3636
import org.apache.commons.lang3.ArrayUtils;
3737

3838
import java.io.File;
39+
import java.io.FileDescriptor;
40+
import java.io.FileInputStream;
3941
import java.io.FileNotFoundException;
4042
import java.io.IOException;
43+
import java.nio.ByteBuffer;
4144
import java.util.ArrayList;
45+
import java.util.Arrays;
4246
import java.util.Collections;
4347
import java.util.Comparator;
4448
import java.util.HashSet;
@@ -62,7 +66,18 @@ public class BasicFileProvider extends DocumentsProvider {
6266
private static final int MAX_ALLOWED_LAST_MODIFIED_FILES = 5;
6367

6468
private static BasicFileProvider fileProviderStaticInst = null;
69+
private static DocumentsProvider extDocsProviderStaticInst = null;
6570
public static BasicFileProvider getInstance() { return fileProviderStaticInst; }
71+
public static void setExternalDocumentsProvider(DocumentsProvider extDocsProvider) { extDocsProviderStaticInst = extDocsProviderStaticInst; }
72+
73+
public static void resetBasicFileProviderDefaults() {
74+
extDocsProviderStaticInst = null;
75+
if(fileProviderStaticInst != null) {
76+
fileProviderStaticInst.baseDirPath = null;
77+
}
78+
activeStartFilesIndex = 0;
79+
activeFilesListLength = DisplayFragments.DEFAULT_VIEWPORT_FILE_ITEMS_COUNT;
80+
}
6681

6782
private static int activeStartFilesIndex = 0;
6883
private static int activeFilesListLength = DisplayFragments.DEFAULT_VIEWPORT_FILE_ITEMS_COUNT;
@@ -185,8 +200,18 @@ public String getCWD() {
185200
return baseDirPath.getAbsolutePath();
186201
}
187202

203+
public void resetBaseDirectory() {
204+
baseDirPath = null;
205+
}
206+
188207
public boolean enterNextSubfolder(String subfolderPath) {
189-
File nextSubfolder = new File(baseDirPath, subfolderPath);
208+
File nextSubfolder = null;
209+
if(baseDirPath != null) {
210+
nextSubfolder = new File(baseDirPath, subfolderPath);
211+
}
212+
else {
213+
nextSubfolder = new File(subfolderPath);
214+
}
190215
boolean status = nextSubfolder.exists() && nextSubfolder.isDirectory();
191216
if(status) {
192217
baseDirPath = nextSubfolder;
@@ -258,6 +283,10 @@ public boolean onCreate() {
258283
@Override
259284
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
260285

286+
if(extDocsProviderStaticInst != null) {
287+
return extDocsProviderStaticInst.queryRoots(projection);
288+
}
289+
261290
final MatrixCursor mcResult = new MatrixCursor(resolveRootProjection(projection));
262291
final MatrixCursor.RowBuilder row = mcResult.newRow();
263292

@@ -283,6 +312,10 @@ public Cursor queryRoots(String[] projection) throws FileNotFoundException {
283312
@Override
284313
public Cursor queryRecentDocuments(String rootId, String[] projection) throws FileNotFoundException {
285314

315+
if(extDocsProviderStaticInst != null) {
316+
return extDocsProviderStaticInst.queryRecentDocuments(rootId, projection);
317+
}
318+
286319
// Create a cursor with the requested projection, or the default projection.
287320
final MatrixCursor mcResult = new MatrixCursor(resolveDocumentProjection(projection));
288321
final File parent = getFileForDocId(rootId);
@@ -328,6 +361,10 @@ public int compare(File i, File j) {
328361
@Override
329362
public Cursor querySearchDocuments(String rootId, String query, String[] projection) throws FileNotFoundException {
330363

364+
if(extDocsProviderStaticInst != null) {
365+
return extDocsProviderStaticInst.querySearchDocuments(rootId, query, projection);
366+
}
367+
331368
// Create a cursor with the requested projection, or the default projection.
332369
final MatrixCursor mcResult = new MatrixCursor(resolveDocumentProjection(projection));
333370
final File parent = getFileForDocId(rootId);
@@ -359,24 +396,41 @@ public Cursor querySearchDocuments(String rootId, String query, String[] project
359396
@Override
360397
public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHint,
361398
CancellationSignal signal) throws FileNotFoundException {
399+
400+
if(extDocsProviderStaticInst != null) {
401+
return extDocsProviderStaticInst.openDocumentThumbnail(documentId, sizeHint, signal);
402+
}
403+
362404
final File file = getFileForDocId(documentId);
363405
final ParcelFileDescriptor pfd =
364406
ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
365407
return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
408+
366409
}
367410

368411
@Override
369412
public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
413+
414+
if(extDocsProviderStaticInst != null) {
415+
return extDocsProviderStaticInst.queryDocument(documentId, projection);
416+
}
417+
370418
// Create a cursor with the requested projection, or the default projection.
371419
final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
372420
includeFile(result, documentId, null);
373421
return result;
422+
374423
}
375424

376425
@Override
377426
public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
378427
String sortOrder) throws FileNotFoundException {
379-
MatrixCursor mcResult = new MatrixCursor(resolveDocumentProjection(projection)); // ??? TODO: was previously marked as final ???
428+
429+
if(extDocsProviderStaticInst != null) {
430+
return extDocsProviderStaticInst.queryChildDocuments(parentDocumentId, projection, sortOrder);
431+
}
432+
433+
MatrixCursor mcResult = new MatrixCursor(resolveDocumentProjection(projection));
380434
if(updateDocsQueryFilesList || docsQueryFilesList == null) {
381435
final File parent = getFileForDocId(parentDocumentId);
382436
if(customFileFilter != null) {
@@ -409,6 +463,7 @@ else if(curFileIndex > lastFileIndex) {
409463
includeFile(mcResult, null, file);
410464
}
411465
return mcResult;
466+
412467
}
413468

414469
public int getFolderChildCount(String folderDocId) throws FileNotFoundException {
@@ -431,6 +486,10 @@ public int getFolderChildCount(String folderDocId) throws FileNotFoundException
431486
public ParcelFileDescriptor openDocument(final String documentId, final String mode,
432487
CancellationSignal signal) throws FileNotFoundException {
433488

489+
if(extDocsProviderStaticInst != null) {
490+
return extDocsProviderStaticInst.openDocument(documentId, mode, signal);
491+
}
492+
434493
final File file = getFileForDocId(documentId);
435494
final int accessMode = ParcelFileDescriptor.parseMode(mode);
436495

@@ -450,22 +509,36 @@ public void onClose(IOException e) {}
450509
} else {
451510
return ParcelFileDescriptor.open(file, accessMode);
452511
}
512+
453513
}
454514

455515
@Override
456516
public void deleteDocument(String documentId) throws FileNotFoundException {
517+
518+
if(extDocsProviderStaticInst != null) {
519+
extDocsProviderStaticInst.deleteDocument(documentId);
520+
return;
521+
}
522+
457523
File file = getFileForDocId(documentId);
458524
if (file.delete()) {
459525
Log.i(LOGTAG, "Deleted file with id " + documentId);
460526
} else {
461527
throw new FileNotFoundException("Failed to delete document with id " + documentId);
462528
}
529+
463530
}
464531

465532
@Override
466533
public String getDocumentType(String documentId) throws FileNotFoundException {
534+
535+
if(extDocsProviderStaticInst != null) {
536+
return extDocsProviderStaticInst.getDocumentType(documentId);
537+
}
538+
467539
File file = getFileForDocId(documentId);
468540
return getTypeForFile(file);
541+
469542
}
470543

471544
private static String[] resolveRootProjection(String[] projection) {
@@ -674,7 +747,6 @@ public String[] getPropertiesOfCurrentRow(MatrixCursor mcResult, boolean cursorT
674747
String.format(Locale.getDefault(), "%s", curWorkingFile.isHidden() ? "true" : "false")
675748
};
676749
} catch(IOException ioe) {
677-
//ioe.printStackTrace();
678750
try {
679751
String[] mcColumnNames = mcResult.getColumnNames();
680752
return new String[] {
@@ -692,14 +764,63 @@ public String[] getPropertiesOfCurrentRow(MatrixCursor mcResult, boolean cursorT
692764
}
693765
}
694766

695-
/* TODO: Later functionality for the local BasicFileProvider: */
696-
public StringBuilder readFileContentsAsString() {
697-
return null;
767+
private static final int BYTE_BUFFER_SIZE = 128;
768+
769+
public StringBuilder readFileContentsAsString(final String documentId) {
770+
try {
771+
ParcelFileDescriptor docDesc = openDocument(documentId, "r+", null);
772+
FileDescriptor fd = docDesc.getFileDescriptor();
773+
FileInputStream inputStream = new FileInputStream(fd);
774+
StringBuilder sbuilder = new StringBuilder();
775+
byte[] byteBuf = new byte[BYTE_BUFFER_SIZE];
776+
int bytesRead = inputStream.read(byteBuf, 0, BYTE_BUFFER_SIZE);
777+
while(bytesRead > 0) {
778+
byte[] bytesReadBuf = Arrays.copyOf(byteBuf, bytesRead);
779+
sbuilder.append(new String(bytesReadBuf));
780+
bytesRead = inputStream.read(byteBuf, 0, BYTE_BUFFER_SIZE);
781+
}
782+
inputStream.close();
783+
docDesc.close();
784+
return sbuilder;
785+
} catch(FileNotFoundException fnfe) {
786+
fnfe.printStackTrace();
787+
return null;
788+
} catch(IOException ioe) {
789+
ioe.printStackTrace();
790+
return null;
791+
}
698792
}
699793

700-
/* TODO: Later functionality for the local BasicFileProvider: */
701-
public byte[] readFileContentsAsBytesArray() {
702-
return null;
794+
public byte[] readFileContentsAsBytesArray(final String documentId) {
795+
try {
796+
ParcelFileDescriptor docDesc = openDocument(documentId, "r+", null);
797+
FileDescriptor fd = docDesc.getFileDescriptor();
798+
FileInputStream inputStream = new FileInputStream(fd);
799+
int actualSize = 0, bufCapacity = BYTE_BUFFER_SIZE;
800+
byte[] returnBuf = new byte[BYTE_BUFFER_SIZE], byteBuf = new byte[BYTE_BUFFER_SIZE];
801+
int bytesRead = inputStream.read(byteBuf, 0, BYTE_BUFFER_SIZE);
802+
while(bytesRead > 0) {
803+
byte[] bytesReadBuf = Arrays.copyOf(byteBuf, bytesRead);
804+
System.arraycopy(returnBuf, actualSize, bytesReadBuf, 0, bytesRead);
805+
actualSize += bytesRead;
806+
if(actualSize >= bufCapacity) {
807+
bufCapacity *= 2;
808+
byte[] nextReturnBuf = new byte[bufCapacity];
809+
System.arraycopy(nextReturnBuf, 0, returnBuf, 0, actualSize);
810+
returnBuf = nextReturnBuf;
811+
}
812+
bytesRead = inputStream.read(byteBuf, 0, BYTE_BUFFER_SIZE);
813+
}
814+
inputStream.close();
815+
docDesc.close();
816+
return Arrays.copyOf(returnBuf, actualSize);
817+
} catch(FileNotFoundException fnfe) {
818+
fnfe.printStackTrace();
819+
return null;
820+
} catch(IOException ioe) {
821+
ioe.printStackTrace();
822+
return null;
823+
}
703824
}
704825

705826
}

AndroidFilePickerLightLibrary/src/main/java/com/maxieds/androidfilepickerlightlibrary/DisplayFragments.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,8 @@ public void descendIntoNextDirectory(boolean initNewFileTree) {
210210
* from scratch (reinitializing objects, starting the initial root query, and launching the
211211
* RecyclerView pattern making compendia on a whole new dataset):
212212
*/
213-
public void initiateNewFolderLoad(FileChooserBuilder.BaseFolderPathType initBaseFolder) {
213+
private void initiateNewFolderLoadBase(DisplayTypes.DirectoryResultContext cwdFolderContext) {
214214
clearExistingRecyclerViewLayout();
215-
FileChooserActivity.getInstance().setTopLevelBaseFolder(initBaseFolder);
216-
DisplayTypes.DirectoryResultContext cwdFolderContext = DisplayTypes.DirectoryResultContext.probeAtCursoryFolderQuery(initBaseFolder);
217215
cwdFolderContext.setTopLevelFolder(true); // cannot go up higher in the filesystem from here
218216
setCwdFolderContext(cwdFolderContext);
219217
pathHistoryStack.clear();
@@ -224,6 +222,44 @@ public void initiateNewFolderLoad(FileChooserBuilder.BaseFolderPathType initBase
224222
updateFolderHistoryPaths(FileUtils.getFileBaseNameFromPath(getCwdFolderContext().getCWDBasePath()), true);
225223
}
226224

225+
public void initiateNewFolderLoad(FileChooserBuilder.BaseFolderPathType initBaseFolder, String relativePathOffset) {
226+
FileChooserActivity.getInstance().setTopLevelBaseFolder(initBaseFolder);
227+
BasicFileProvider fpInst = BasicFileProvider.getInstance();
228+
DisplayTypes.DirectoryResultContext cwdFolderContext = null;
229+
if(relativePathOffset != null) {
230+
fpInst.selectBaseDirectoryByType(initBaseFolder);
231+
cwdFolderContext = DisplayTypes.DirectoryResultContext.probeAtCursoryFolderQuery(relativePathOffset);
232+
if(cwdFolderContext == null) {
233+
String invPath = fpInst.getCWD() + FileUtils.FILE_PATH_SEPARATOR + relativePathOffset;
234+
throw new FileChooserException.InvalidInitialPathException(invPath);
235+
}
236+
}
237+
else {
238+
cwdFolderContext = DisplayTypes.DirectoryResultContext.probeAtCursoryFolderQuery(initBaseFolder);
239+
if(cwdFolderContext == null) {
240+
String invPath = fpInst.getCWD();
241+
throw new FileChooserException.InvalidInitialPathException(invPath);
242+
}
243+
}
244+
initiateNewFolderLoadBase(cwdFolderContext);
245+
}
246+
247+
public void initiateNewFolderLoad(FileChooserBuilder.BaseFolderPathType initBaseFolder) {
248+
initiateNewFolderLoad(initBaseFolder, null);
249+
}
250+
251+
public void initiateNewFolderLoad(String absStartPath) {
252+
FileChooserBuilder.BaseFolderPathType initBaseFolder = FileChooserBuilder.BaseFolderPathType.BASE_PATH_DEFAULT;
253+
FileChooserActivity.getInstance().setTopLevelBaseFolder(initBaseFolder);
254+
BasicFileProvider fpInst = BasicFileProvider.getInstance();
255+
fpInst.resetBaseDirectory();
256+
if(!fpInst.enterNextSubfolder(absStartPath)) {
257+
throw new FileChooserException.InvalidInitialPathException(absStartPath);
258+
}
259+
DisplayTypes.DirectoryResultContext cwdFolderContext = DisplayTypes.DirectoryResultContext.probeAtCursoryFolderQuery();
260+
initiateNewFolderLoadBase(cwdFolderContext);
261+
}
262+
227263
public void displayNextDirectoryFilesList(List<DisplayTypes.FileType> workingDirContentsList, boolean notifyAdapter) {
228264

229265
if(workingDirContentsList == null) {

AndroidFilePickerLightLibrary/src/main/java/com/maxieds/androidfilepickerlightlibrary/DisplayTypes.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,18 @@ public static DirectoryResultContext probeAtCursoryFolderQuery(String nextSubfol
270270
return probeAtCursoryFolderQueryGetNext();
271271
}
272272

273+
public static DirectoryResultContext probeAtCursoryFolderQuery() {
274+
BasicFileProvider fpInst = BasicFileProvider.getInstance();
275+
if(fpInst == null) {
276+
return null;
277+
}
278+
else {
279+
fpInst.setCustomFileFilter(DisplayFragments.getInstance().localFilesListFilter);
280+
fpInst.setCustomFolderSort(DisplayFragments.getInstance().localFilesListSortFunc);
281+
}
282+
return probeAtCursoryFolderQueryGetNext();
283+
}
284+
273285
public static DirectoryResultContext probePreviousFolder(int howManyBackwards) {
274286
BasicFileProvider fpInst = BasicFileProvider.getInstance();
275287
if(fpInst == null) {

AndroidFilePickerLightLibrary/src/main/java/com/maxieds/androidfilepickerlightlibrary/DisplayUtils.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ This program (the AndroidFilePickerLight library) is free software written by
3131
import android.util.TypedValue;
3232
import android.view.Gravity;
3333
import android.view.LayoutInflater;
34+
import android.view.MotionEvent;
3435
import android.view.View;
3536
import android.widget.ImageView;
3637
import android.widget.TextView;
@@ -343,6 +344,13 @@ public void run() {
343344
((TextView) toastProgressView.findViewById(R.id.progressBarText)).setText(statusBarMsg);
344345
GradientDrawable bgGradient = GradientDrawableBuilder.GetStockGradientFromBaseColor(progressBarTintColor);
345346
toastProgressView.setBackgroundDrawable(bgGradient);
347+
toastProgressView.setOnTouchListener(new View.OnTouchListener() {
348+
@Override
349+
public boolean onTouch(View view, MotionEvent motionEvent) {
350+
EnableProgressBarDisplay(false); // dismiss the toast when it is touched
351+
return false;
352+
}
353+
});
346354
progressBarToast.setView(toastProgressView);
347355
if(!toastsDismissed) {
348356
progressBarDisplayHandler.postDelayed(progressBarDisplayRunnable, STATUS_TOAST_DISPLAY_REFRESH_TIME);
@@ -355,6 +363,9 @@ public void run() {
355363
public static void EnableProgressBarDisplay(boolean enableRedisplay) {
356364
toastsDismissed = !enableRedisplay;
357365
if(toastsDismissed) {
366+
if(progressBarToast != null) {
367+
progressBarToast.cancel();
368+
}
358369
progressBarDisplayHandler.removeCallbacks(progressBarDisplayRunnable);
359370
}
360371
}

0 commit comments

Comments
 (0)