Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OPEN_DOCUMENT and CREATE_DOCUMENT intents support #3953

Draft
wants to merge 2 commits into
base: release/4.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.OPEN_DOCUMENT" />
<data android:mimeType="*/*" />
<category android:name="android.intent.category.OPENABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.CREATE_DOCUMENT" />
<data android:mimeType="*/*" />
<category android:name="android.intent.category.OPENABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

<intent-filter tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="application/zip" />
Expand Down
272 changes: 135 additions & 137 deletions app/src/main/java/com/amaze/filemanager/filesystem/FileUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,157 +110,155 @@ public static final void writeUriToStorage(
@NonNull final String currentPath) {

MaybeOnSubscribe<List<String>> writeUri =
(MaybeOnSubscribe<List<String>>)
emitter -> {
List<String> retval = new ArrayList<>();

for (Uri uri : uris) {

BufferedInputStream bufferedInputStream = null;
try {
bufferedInputStream =
new BufferedInputStream(contentResolver.openInputStream(uri));
} catch (FileNotFoundException e) {
emitter.onError(e);
return;
}

BufferedOutputStream bufferedOutputStream = null;
emitter -> {
List<String> retval = new ArrayList<>();

for (Uri uri : uris) {

BufferedInputStream bufferedInputStream = null;
try {
bufferedInputStream = new BufferedInputStream(contentResolver.openInputStream(uri));
} catch (FileNotFoundException e) {
emitter.onError(e);
return;
}

BufferedOutputStream bufferedOutputStream = null;

try {
DocumentFile documentFile = DocumentFile.fromSingleUri(mainActivity, uri);
String filename = documentFile.getName();
if (filename == null) {
filename = uri.getLastPathSegment();

// For cleaning up slashes. Back in #1217 there is a case of
// Uri.getLastPathSegment() end up with a full file path
if (filename.contains("/"))
filename = filename.substring(filename.lastIndexOf('/') + 1);
}

try {
DocumentFile documentFile = DocumentFile.fromSingleUri(mainActivity, uri);
String filename = documentFile.getName();
if (filename == null) {
filename = uri.getLastPathSegment();
String finalFilePath = currentPath + "/" + filename;
DataUtils dataUtils = DataUtils.getInstance();

// For cleaning up slashes. Back in #1217 there is a case of
// Uri.getLastPathSegment() end up with a full file path
if (filename.contains("/"))
filename = filename.substring(filename.lastIndexOf('/') + 1);
}
HybridFile hFile = new HybridFile(OpenMode.UNKNOWN, currentPath);
hFile.generateMode(mainActivity);

String finalFilePath = currentPath + "/" + filename;
DataUtils dataUtils = DataUtils.getInstance();

HybridFile hFile = new HybridFile(OpenMode.UNKNOWN, currentPath);
hFile.generateMode(mainActivity);

switch (hFile.getMode()) {
case FILE:
case ROOT:
File targetFile = new File(finalFilePath);
if (!FileProperties.isWritableNormalOrSaf(
targetFile.getParentFile(), mainActivity.getApplicationContext())) {
emitter.onError(new NotAllowedException());
return;
}

DocumentFile targetDocumentFile =
ExternalSdCardOperation.getDocumentFile(
targetFile, false, mainActivity.getApplicationContext());

// Fallback, in case getDocumentFile() didn't properly return a
// DocumentFile
// instance
if (targetDocumentFile == null) {
targetDocumentFile = DocumentFile.fromFile(targetFile);
}

// Lazy check... and in fact, different apps may pass in URI in different
// formats, so we could only check filename matches
// FIXME?: Prompt overwrite instead of simply blocking
if (targetDocumentFile.exists() && targetDocumentFile.length() > 0) {
emitter.onError(new OperationWouldOverwriteException());
return;
}

bufferedOutputStream =
new BufferedOutputStream(
contentResolver.openOutputStream(targetDocumentFile.getUri()));
retval.add(targetFile.getPath());
break;
case SMB:
SmbFile targetSmbFile = SmbUtil.create(finalFilePath);
if (targetSmbFile.exists()) {
emitter.onError(new OperationWouldOverwriteException());
return;
} else {
OutputStream outputStream = targetSmbFile.getOutputStream();
bufferedOutputStream = new BufferedOutputStream(outputStream);
retval.add(HybridFile.parseAndFormatUriForDisplay(targetSmbFile.getPath()));
}
break;
case SFTP:
// FIXME: implement support
AppConfig.toast(mainActivity, mainActivity.getString(R.string.not_allowed));
emitter.onError(new NotImplementedError());
return;
case DROPBOX:
case BOX:
case ONEDRIVE:
case GDRIVE:
OpenMode mode = hFile.getMode();

CloudStorage cloudStorage = dataUtils.getAccount(mode);
String path = CloudUtil.stripPath(mode, finalFilePath);
cloudStorage.upload(path, bufferedInputStream, documentFile.length(), true);
retval.add(path);
break;
case OTG:
DocumentFile documentTargetFile =
OTGUtil.getDocumentFile(finalFilePath, mainActivity, true);

if (documentTargetFile.exists()) {
emitter.onError(new OperationWouldOverwriteException());
return;
}

bufferedOutputStream =
new BufferedOutputStream(
contentResolver.openOutputStream(documentTargetFile.getUri()),
GenericCopyUtil.DEFAULT_BUFFER_SIZE);

retval.add(documentTargetFile.getUri().getPath());
break;
default:
return;
switch (hFile.getMode()) {
case FILE:
case ROOT:
File targetFile = new File(finalFilePath);
if (!FileProperties.isWritableNormalOrSaf(
targetFile.getParentFile(), mainActivity.getApplicationContext())) {
emitter.onError(new NotAllowedException());
return;
}

int count = 0;
byte[] buffer = new byte[GenericCopyUtil.DEFAULT_BUFFER_SIZE];
DocumentFile targetDocumentFile =
ExternalSdCardOperation.getDocumentFile(
targetFile, false, mainActivity.getApplicationContext());

while (count != -1) {
count = bufferedInputStream.read(buffer);
if (count != -1) {
// Fallback, in case getDocumentFile() didn't properly return a
// DocumentFile
// instance
if (targetDocumentFile == null) {
targetDocumentFile = DocumentFile.fromFile(targetFile);
}

bufferedOutputStream.write(buffer, 0, count);
}
// Lazy check... and in fact, different apps may pass in URI in different
// formats, so we could only check filename matches
// FIXME?: Prompt overwrite instead of simply blocking
if (targetDocumentFile.exists() && targetDocumentFile.length() > 0) {
emitter.onError(new OperationWouldOverwriteException());
return;
}
bufferedOutputStream.flush();

} catch (IOException e) {
emitter.onError(e);
bufferedOutputStream =
new BufferedOutputStream(
contentResolver.openOutputStream(targetDocumentFile.getUri()));
retval.add(targetFile.getPath());
break;
case SMB:
SmbFile targetSmbFile = SmbUtil.create(finalFilePath);
if (targetSmbFile.exists()) {
emitter.onError(new OperationWouldOverwriteException());
return;
} else {
OutputStream outputStream = targetSmbFile.getOutputStream();
bufferedOutputStream = new BufferedOutputStream(outputStream);
retval.add(HybridFile.parseAndFormatUriForDisplay(targetSmbFile.getPath()));
}
break;
case SFTP:
// FIXME: implement support
AppConfig.toast(mainActivity, mainActivity.getString(R.string.not_allowed));
emitter.onError(new NotImplementedError());
return;
} finally {
try {
if (bufferedInputStream != null) {
bufferedInputStream.close();
}
if (bufferedOutputStream != null) {
bufferedOutputStream.close();
}
} catch (IOException e) {
emitter.onError(e);
case DROPBOX:
case BOX:
case ONEDRIVE:
case GDRIVE:
OpenMode mode = hFile.getMode();

CloudStorage cloudStorage = dataUtils.getAccount(mode);
String path = CloudUtil.stripPath(mode, finalFilePath);
cloudStorage.upload(path, bufferedInputStream, documentFile.length(), true);
retval.add(path);
break;
case OTG:
DocumentFile documentTargetFile =
OTGUtil.getDocumentFile(finalFilePath, mainActivity, true);

if (documentTargetFile.exists()) {
emitter.onError(new OperationWouldOverwriteException());
return;
}
}

bufferedOutputStream =
new BufferedOutputStream(
contentResolver.openOutputStream(documentTargetFile.getUri()),
GenericCopyUtil.DEFAULT_BUFFER_SIZE);

retval.add(documentTargetFile.getUri().getPath());
break;
default:
return;
}

if (retval.size() > 0) {
emitter.onSuccess(retval);
} else {
emitter.onError(new Exception());
int count = 0;
byte[] buffer = new byte[GenericCopyUtil.DEFAULT_BUFFER_SIZE];

while (count != -1) {
count = bufferedInputStream.read(buffer);
if (count != -1) {

bufferedOutputStream.write(buffer, 0, count);
}
}
bufferedOutputStream.flush();

} catch (IOException e) {
emitter.onError(e);
return;
} finally {
try {
if (bufferedInputStream != null) {
bufferedInputStream.close();
}
if (bufferedOutputStream != null) {
bufferedOutputStream.close();
}
} catch (IOException e) {
emitter.onError(e);
}
};
}
}

if (retval.size() > 0) {
emitter.onSuccess(retval);
} else {
emitter.onError(new Exception());
}
};

Maybe.create(writeUri)
.subscribeOn(Schedulers.io())
Expand Down
Loading