aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/utils/FileUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/eu/siacs/conversations/utils/FileUtils.java')
-rw-r--r--src/main/java/eu/siacs/conversations/utils/FileUtils.java252
1 files changed, 252 insertions, 0 deletions
diff --git a/src/main/java/eu/siacs/conversations/utils/FileUtils.java b/src/main/java/eu/siacs/conversations/utils/FileUtils.java
new file mode 100644
index 00000000..18014894
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/utils/FileUtils.java
@@ -0,0 +1,252 @@
+package eu.siacs.conversations.utils;
+
+import android.annotation.SuppressLint;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.provider.OpenableColumns;
+
+import java.io.File;
+import java.util.List;
+
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+
+import eu.siacs.conversations.entities.Transferable;
+
+public final class FileUtils {
+
+ /**
+ * Get a file path from a Uri. This will get the the path for Storage Access
+ * Framework Documents, as well as the _data field for the MediaStore and
+ * other file-based ContentProviders.
+ *
+ * @param uri The Uri to query.
+ * @author paulburke
+ */
+ @SuppressLint("NewApi")
+ public static String getPath(final Uri uri) {
+ if (uri == null) {
+ return null;
+ }
+
+ final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+ final Context context = ConversationsPlusApplication.getAppContext();
+ // DocumentProvider
+ if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+ // ExternalStorageProvider
+ if (isExternalStorageDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ if ("primary".equalsIgnoreCase(type)) {
+ return Environment.getExternalStorageDirectory() + "/" + split[1];
+ }
+
+ // TODO handle non-primary volumes
+ }
+ // DownloadsProvider
+ else if (isDownloadsDocument(uri)) {
+
+ final String id = DocumentsContract.getDocumentId(uri);
+ final Uri contentUri = ContentUris.withAppendedId(
+ Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
+
+ return getDataColumn(context, contentUri, null, null);
+ }
+ // MediaProvider
+ else if (isMediaDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ Uri contentUri = null;
+ if ("image".equals(type)) {
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ } else if ("video".equals(type)) {
+ contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
+ } else if ("audio".equals(type)) {
+ contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+ }
+
+ final String selection = "_id=?";
+ final String[] selectionArgs = new String[]{
+ split[1]
+ };
+
+ return getDataColumn(context, contentUri, selection, selectionArgs);
+ }
+ }
+ // MediaStore (and general)
+ else if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+ String path = getDataColumn(context, uri, null, null);
+ if (path != null) {
+ File file = new File(path);
+ if (!file.canRead()) {
+ return null;
+ }
+ }
+ return path;
+ }
+ // File
+ else if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
+ return uri.getPath();
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the value of the data column for this Uri. This is useful for
+ * MediaStore Uris, and other file-based ContentProviders.
+ *
+ * @param context The context.
+ * @param uri The Uri to query.
+ * @param selection (Optional) Filter used in the query.
+ * @param selectionArgs (Optional) Selection arguments used in the query.
+ * @return The value of the _data column, which is typically a file path.
+ */
+ private static String getDataColumn(Context context, Uri uri, String selection,
+ String[] selectionArgs) {
+
+ Cursor cursor = null;
+ final String column = "_data";
+ final String[] projection = {
+ column
+ };
+
+ try {
+ cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,null);
+ if (cursor != null && cursor.moveToFirst()) {
+ final int column_index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(column_index);
+ }
+ } catch(Exception e) {
+ return null;
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is ExternalStorageProvider.
+ */
+ public static boolean isExternalStorageDocument(Uri uri) {
+ return "com.android.externalstorage.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is DownloadsProvider.
+ */
+ public static boolean isDownloadsDocument(Uri uri) {
+ return "com.android.providers.downloads.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is MediaProvider.
+ */
+ public static boolean isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri.getAuthority());
+ }
+
+ public static String getRelevantExtension(String path) {
+ if (path == null || path.isEmpty()) {
+ return null;
+ }
+
+ String filename = path.substring(path.lastIndexOf('/') + 1).toLowerCase();
+
+ final String lastPart = FileUtils.getLastExtension(filename);
+
+ if (!lastPart.isEmpty()) {
+ // we want the real file extension, not the crypto one
+ final String secondToLastPart = FileUtils.getSecondToLastExtension(filename);
+ if (!secondToLastPart.isEmpty() && Transferable.VALID_CRYPTO_EXTENSIONS.contains(lastPart)) {
+ return secondToLastPart;
+ } else {
+ return lastPart;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param filename The filename to extract extension from
+ * @return last extension or empty string
+ */
+ public static String getLastExtension(final String filename) {
+ if (filename == null || filename.isEmpty()) {
+ return "";
+ }
+ final int lastDotPosition = filename.lastIndexOf('.');
+ final String lastPart = lastDotPosition != -1 ?
+ filename.substring(lastDotPosition + 1) : "";
+ return lastPart;
+ }
+
+ /**
+ * @param filename The filename to extract extension from
+ * @return second to last extension or empty string
+ */
+ public static String getSecondToLastExtension(final String filename) {
+ if (filename == null || filename.isEmpty()) {
+ return "";
+ }
+ final int lastDotPosition = filename.lastIndexOf('.');
+ final int secondToLastDotPosition = filename.lastIndexOf('.', lastDotPosition - 1);
+ final String secondToLastPart = secondToLastDotPosition != -1 ?
+ filename.substring(secondToLastDotPosition + 1, lastDotPosition) : "";
+ return secondToLastPart;
+ }
+
+ /**
+ * Retrieve file size from given uri
+ * @param context actual Context
+ * @param uri uri to file
+ * @return file size or -1 in case of error
+ */
+ private static long getFileSize(Context context, Uri uri) {
+ Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ return cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE));
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Check for given list of uris if corresponding file sizes are all smaller than given maximum
+ * @param context actual Context
+ * @param uris list of uris
+ * @param max maximum file size
+ * @return true if all file sizes are smaller than max, false otherwise
+ */
+ public static boolean allFilesUnderSize(Context context, List<Uri> uris, long max) {
+ if (max <= 0) {
+ return true; //exception to be compatible with HTTP Upload < v0.2
+ }
+ for(Uri uri : uris) {
+ if (getFileSize(context, uri) > max) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private FileUtils() {
+ // Utility class - do not instantiate
+ }
+}