mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 12:38:33 +00:00
Add virtual file support to file sharing.
This commit is contained in:
@@ -3,10 +3,14 @@ package org.thoughtcrime.securesms.mms;
|
|||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.UriMatcher;
|
import android.content.UriMatcher;
|
||||||
|
import android.content.res.AssetFileDescriptor;
|
||||||
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.provider.DocumentsContractCompat;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.BuildConfig;
|
import org.thoughtcrime.securesms.BuildConfig;
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
@@ -20,6 +24,7 @@ import org.thoughtcrime.securesms.providers.DeprecatedPersistentBlobProvider;
|
|||||||
import org.thoughtcrime.securesms.providers.PartProvider;
|
import org.thoughtcrime.securesms.providers.PartProvider;
|
||||||
import org.thoughtcrime.securesms.wallpaper.WallpaperStorage;
|
import org.thoughtcrime.securesms.wallpaper.WallpaperStorage;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
@@ -78,7 +83,7 @@ public class PartAuthority {
|
|||||||
case WALLPAPER_ROW: return WallpaperStorage.read(context, getWallpaperFilename(uri));
|
case WALLPAPER_ROW: return WallpaperStorage.read(context, getWallpaperFilename(uri));
|
||||||
case EMOJI_ROW: return EmojiFiles.openForReading(context, getEmojiFilename(uri));
|
case EMOJI_ROW: return EmojiFiles.openForReading(context, getEmojiFilename(uri));
|
||||||
case AVATAR_PICKER_ROW: return AvatarPickerStorage.read(context, getAvatarPickerFilename(uri));
|
case AVATAR_PICKER_ROW: return AvatarPickerStorage.read(context, getAvatarPickerFilename(uri));
|
||||||
default: return context.getContentResolver().openInputStream(uri);
|
default: return openExternalFileStream(context, uri);
|
||||||
}
|
}
|
||||||
} catch (SecurityException se) {
|
} catch (SecurityException se) {
|
||||||
throw new IOException(se);
|
throw new IOException(se);
|
||||||
@@ -223,4 +228,45 @@ public class PartAuthority {
|
|||||||
public static @NonNull AttachmentId requireAttachmentId(@NonNull Uri uri) {
|
public static @NonNull AttachmentId requireAttachmentId(@NonNull Uri uri) {
|
||||||
return new PartUriParser(uri).getPartId();
|
return new PartUriParser(uri).getPartId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static @Nullable InputStream openExternalFileStream(@NonNull Context context, @NonNull Uri uri) throws IOException {
|
||||||
|
if (isVirtualFile(context, uri)) {
|
||||||
|
return getInputStreamForVirtualFile(context, uri);
|
||||||
|
} else {
|
||||||
|
return context.getContentResolver().openInputStream(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isVirtualFile(@NonNull Context context, @NonNull Uri uri) {
|
||||||
|
if (!DocumentsContractCompat.isDocumentUri(context, uri)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Cursor cursor = context.getContentResolver().query(uri, new String[]{DocumentsContract.Document.COLUMN_FLAGS}, null, null, null, null)) {
|
||||||
|
if (cursor == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags = cursor.moveToFirst() ? cursor.getInt(0) : 0;
|
||||||
|
return (flags & DocumentsContractCompat.DocumentCompat.FLAG_VIRTUAL_DOCUMENT) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @noinspection resource*/
|
||||||
|
private static @Nullable InputStream getInputStreamForVirtualFile(@NonNull Context context, @NonNull Uri uri) throws IOException {
|
||||||
|
String[] openableMimeTypes = context.getContentResolver().getStreamTypes(uri, "*/*");
|
||||||
|
|
||||||
|
if (openableMimeTypes == null || openableMimeTypes.length < 1) {
|
||||||
|
throw new FileNotFoundException("No openable mime-types for virtual file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetFileDescriptor fileDescriptor = context.getContentResolver()
|
||||||
|
.openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null);
|
||||||
|
|
||||||
|
if (fileDescriptor == null) {
|
||||||
|
throw new FileNotFoundException("Couldn't open file descriptor for virtual file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileDescriptor.createInputStream();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user