Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f0ff624a authored by Jorge Ruesga's avatar Jorge Ruesga
Browse files

Select content uris vs file uris when open or send files

Change-Id: I1e576ccc3d14f9e02bd0148f530133065bfc20bf
JIRA: CYAN-2649
Issue: https://jira.cyanogenmod.org/browse/CYAN-2649


Signed-off-by: default avatarJorge Ruesga <jorge@ruesga.com>
parent d60e42f5
Loading
Loading
Loading
Loading
+17 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.content.IntentFilter;
import android.content.res.Configuration;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
@@ -78,6 +79,7 @@ import com.cyanogenmod.filemanager.util.DialogHelper;
import com.cyanogenmod.filemanager.util.ExceptionUtil;
import com.cyanogenmod.filemanager.util.ExceptionUtil.OnRelaunchCommandResult;
import com.cyanogenmod.filemanager.util.FileHelper;
import com.cyanogenmod.filemanager.util.MediaHelper;
import com.cyanogenmod.filemanager.util.ResourcesHelper;

import java.io.ByteArrayInputStream;
@@ -907,7 +909,7 @@ public class EditorActivity extends Activity implements TextWatcher {
        this.mReadOnly = false;

        // Read the intent and check that is has a valid request
        String path = getIntent().getData().getPath();
        String path = uriToPath(this, getIntent().getData());
        if (path == null || path.length() == 0) {
            DialogHelper.showToast(
                    this, R.string.editor_invalid_file_msg, Toast.LENGTH_SHORT);
@@ -1509,4 +1511,18 @@ public class EditorActivity extends Activity implements TextWatcher {
        theme.setTextColor(this, editor, "text_color"); //$NON-NLS-1$
    }

    /**
     * Method that resolves the content uri to a valid system path
     *
     * @param ctx The current context
     * @param uri The content uri
     * @return String The system path
     */
    private static String uriToPath(Context ctx, Uri uri) {
        File file = MediaHelper.contentUriToFile(ctx.getContentResolver(), uri);
        if (file == null) {
            file = new File(uri.getPath());
        }
        return file.getAbsolutePath();
    }
}
+9 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
@@ -60,6 +61,7 @@ import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnFilePickedListene
import com.cyanogenmod.filemanager.util.DialogHelper;
import com.cyanogenmod.filemanager.util.ExceptionUtil;
import com.cyanogenmod.filemanager.util.FileHelper;
import com.cyanogenmod.filemanager.util.MediaHelper;
import com.cyanogenmod.filemanager.util.MimeTypeHelper;
import com.cyanogenmod.filemanager.util.StorageHelper;

@@ -428,7 +430,7 @@ public class PickerActivity extends Activity
            // Return the picked file, as expected (this activity should fill the intent data
            // and return RESULT_OK result)
            Intent result = new Intent();
            result.setData(getResultUriForFileFromIntent(src, getIntent()));
            result.setData(getResultUriForFileFromIntent(getContentResolver(), src, getIntent()));
            setResult(Activity.RESULT_OK, result);
            finish();

@@ -490,8 +492,12 @@ public class PickerActivity extends Activity
        return file.getParentFile();
    }

    private static Uri getResultUriForFileFromIntent(File src, Intent intent) {
        Uri result = Uri.fromFile(src);
    private static Uri getResultUriForFileFromIntent(ContentResolver cr, File src, Intent intent) {
        // Try to find the preferred uri scheme
        Uri result = MediaHelper.fileToContentUri(cr, src);
        if (result == null) {
            result = Uri.fromFile(src);
        }

        if (Intent.ACTION_PICK.equals(intent.getAction()) && intent.getData() != null) {
            String scheme = intent.getData().getScheme();
+21 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.cyanogenmod.filemanager.ui.policy;

import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnDismissListener;
@@ -37,6 +38,7 @@ import com.cyanogenmod.filemanager.ui.dialogs.AssociationsDialog;
import com.cyanogenmod.filemanager.util.DialogHelper;
import com.cyanogenmod.filemanager.util.ExceptionUtil;
import com.cyanogenmod.filemanager.util.FileHelper;
import com.cyanogenmod.filemanager.util.MediaHelper;
import com.cyanogenmod.filemanager.util.MimeTypeHelper;
import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory;
import com.cyanogenmod.filemanager.util.ResourcesHelper;
@@ -99,9 +101,9 @@ public final class IntentsActionPolicy extends ActionsPolicy {
            String mime = MimeTypeHelper.getMimeType(ctx, fso);
            File file = new File(fso.getFullPath());
            if (mime != null) {
                intent.setDataAndType(Uri.fromFile(file), mime);
                intent.setDataAndType(getUriFromFile(ctx, file), mime);
            } else {
                intent.setData(Uri.fromFile(file));
                intent.setData(getUriFromFile(ctx, file));
            }

            // Resolve the intent
@@ -138,7 +140,7 @@ public final class IntentsActionPolicy extends ActionsPolicy {
            intent.setAction(android.content.Intent.ACTION_SEND);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setType(MimeTypeHelper.getMimeType(ctx, fso));
            Uri uri = Uri.fromFile(new File(fso.getFullPath()));
            Uri uri = getUriFromFile(ctx, new File(fso.getFullPath()));
            intent.putExtra(Intent.EXTRA_STREAM, uri);

            // Resolve the intent
@@ -199,7 +201,7 @@ public final class IntentsActionPolicy extends ActionsPolicy {
                lastMimeType = mimeType;

                // Add the uri
                uris.add(Uri.fromFile(new File(fso.getFullPath())));
                uris.add(getUriFromFile(ctx, new File(fso.getFullPath())));
            }
            if (sameMimeType) {
                intent.setType(lastMimeType);
@@ -580,4 +582,19 @@ public final class IntentsActionPolicy extends ActionsPolicy {
        });
        return pref.get(0);
    }

    /**
     * Method that returns the best Uri for the file (content uri, file uri, ...)
     *
     * @param ctx The current context
     * @param file The file to resolve
     */
    private static Uri getUriFromFile(Context ctx, File file) {
        ContentResolver cr = ctx.getContentResolver();
        Uri uri = MediaHelper.fileToContentUri(cr, file);
        if (uri == null) {
            uri = Uri.fromFile(file);
        }
        return uri;
    }
}
+119 −3
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.net.Uri;
import android.os.UserHandle;
import android.provider.BaseColumns;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.text.TextUtils;

import java.io.File;
@@ -33,6 +34,13 @@ import java.util.Map;
 */
public final class MediaHelper {

    private static final String EMULATED_STORAGE_SOURCE = System.getenv("EMULATED_STORAGE_SOURCE");
    private static final String EMULATED_STORAGE_TARGET = System.getenv("EMULATED_STORAGE_TARGET");
    private static final String EXTERNAL_STORAGE = System.getenv("EXTERNAL_STORAGE");

    private static final String INTERNAL_VOLUME = "internal";
    private static final String EXTERNAL_VOLUME = "external";

    /**
     * URIs that are relevant for determining album art;
     * useful for content observer registration
@@ -98,9 +106,117 @@ public final class MediaHelper {
        return null;
    }

    private static final String EMULATED_STORAGE_SOURCE = System.getenv("EMULATED_STORAGE_SOURCE");
    private static final String EMULATED_STORAGE_TARGET = System.getenv("EMULATED_STORAGE_TARGET");
    private static final String EXTERNAL_STORAGE = System.getenv("EXTERNAL_STORAGE");
    /**
     * Method that converts a file reference to a content uri reference
     *
     * @param cr A content resolver
     * @param file The file reference
     * @return Uri The content uri or null if file not exists in the media database
     */
    public static Uri fileToContentUri(ContentResolver cr, File file) {
        // Normalize the path to ensure media search
        final String normalizedPath = normalizeMediaPath(file.getAbsolutePath());

        // Check in external and internal storages
        Uri uri = fileToContentUri(cr, normalizedPath, EXTERNAL_VOLUME);
        if (uri != null) {
            return uri;
        }
        uri = fileToContentUri(cr, normalizedPath, INTERNAL_VOLUME);
        if (uri != null) {
            return uri;
        }
        return null;
    }

    /**
     * Method that converts a file reference to a content uri reference
     *
     * @param cr A content resolver
     * @param path The path to search
     * @param volume The volume
     * @return Uri The content uri or null if file not exists in the media database
     */
    private static Uri fileToContentUri(ContentResolver cr, String path, String volume) {
        final String[] projection = {BaseColumns._ID, MediaStore.Files.FileColumns.MEDIA_TYPE};
        final String where = MediaColumns.DATA + " = ?";
        Uri baseUri = MediaStore.Files.getContentUri(volume);
        Cursor c = cr.query(baseUri, projection, where, new String[]{path}, null);
        try {
            if (c != null && c.moveToNext()) {
                int type = c.getInt(c.getColumnIndexOrThrow(
                        MediaStore.Files.FileColumns.MEDIA_TYPE));
                if (type != 0) {
                    // Do not force to use content uri for no media files
                    long id = c.getLong(c.getColumnIndexOrThrow(BaseColumns._ID));
                    return Uri.withAppendedPath(baseUri, String.valueOf(id));
                }
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return null;
    }

    /**
     * Method that converts a content uri to a file system path
     *
     * @param cr The content resolver
     * @param uri The content uri
     * @return File The file reference
     */
    public static File contentUriToFile(ContentResolver cr, Uri uri) {
        // Sanity checks
        if (uri == null || uri.getScheme() == null || uri.getScheme().compareTo("content") != 0) {
            return null;
        }

        // Retrieve the request id
        long id = 0;
        try {
            id = Long.parseLong(new File(uri.getPath()).getName());
        } catch (NumberFormatException nfex) {
            return null;
        }

        // Check in external and internal storages
        File file = mediaIdToFile(cr, id, EXTERNAL_VOLUME);
        if (file != null) {
            return file;
        }
        file = mediaIdToFile(cr, id, INTERNAL_VOLUME);
        if (file != null) {
            return file;
        }
        return null;
    }

    /**
     * Method that converts a content uri to a file system path
     *
     * @param cr The content resolver
     * @param id The media database id
     * @param volume The volume
     * @return File The file reference
     */
    private static File mediaIdToFile(ContentResolver cr, long id, String volume) {
        final String[] projection = {MediaColumns.DATA};
        final String where = MediaColumns._ID + " = ?";
        Uri baseUri = MediaStore.Files.getContentUri(volume);
        Cursor c = cr.query(baseUri, projection, where, new String[]{String.valueOf(id)}, null);
        try {
            if (c != null && c.moveToNext()) {
                return new File(c.getString(c.getColumnIndexOrThrow(MediaColumns.DATA)));
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return null;
    }

    /**
     * Method that converts a not standard media mount path to a standard media path