Android Gallery en Android 4.4 (KitKat) devuelve un URI diferente para Intent.ACTION_GET_CONTENT

18 minutos de lectura

Android Gallery en Android 44 KitKat devuelve un URI diferente
Michael Greifeneder

Antes de KitKat (o antes de la nueva Galería) el Intent.ACTION_GET_CONTENT devolvió un URI como este

contenido://media/external/images/media/3951.

Utilizando el ContentResolver y preguntando por
MediaStore.Images.Media.DATA devolvió la URL del archivo.

En KitKat, sin embargo, la Galería devuelve un URI (a través de “Último”) como este:

contenido://com.android.providers.media.documents/document/image:3951

¿Cómo manejo esto?

  • De manera improvisada, encontraría formas de usar el contenido que no requiera acceso directo al archivo. por ejemplo, que Uri debe poder abrirse como una secuencia a través de ContentResolver. Durante mucho tiempo he estado nervioso por las aplicaciones que asumen que un content:// Uri que representa un archivo siempre se puede convertir en un File.

    – CommonsWare

    7 de noviembre de 2013 a las 12:31

  • @CommonsWare, si quiero guardar una ruta de imagen en sqlite db para poder abrirla más tarde, ¿debo guardar el URI o la ruta de archivo absoluta?

    – Serpiente

    19 de diciembre de 2013 a las 20:45

  • @CommonsWare Estoy de acuerdo con tu nerviosismo. 🙂 Sin embargo, necesito poder pasar un nombre de archivo (para una imagen) al código nativo. Una solución es copiar los datos obtenidos mediante un InputStream sobre el ContentResolver a un lugar predesignado para que tenga un nombre de archivo conocido. Sin embargo, esto suena un desperdicio para mí. ¿Cualquier otra sugerencia?

    – darrenp

    15 de enero de 2014 a las 17:22


  • @darrenp: Ummm…, reescriba el código nativo para que funcione con un InputStream sobre JNI? Desafortunadamente, no hay tantas opciones para ti.

    – CommonsWare

    15 de enero de 2014 a las 17:34

  • Es útil saberlo. Gracias por su respuesta. Desde entonces, descubrí que ahora estamos pasando la imagen a C ++ en la memoria en lugar de a través de un archivo, por lo que ahora podemos usar un InputStream en lugar de un archivo (que es genial). Solo la lectura de etiquetas EXIF ​​es un poco complicada y requiere La biblioteca de Drew Noakes. Muchas gracias por tus comentarios.

    – darrenp

    15 de enero de 2014 a las 20:49


1646968103 249 Android Gallery en Android 44 KitKat devuelve un URI diferente
Pablo Burke

Esto no requiere permisos especiales y funciona con Storage Access Framework, así como con el no oficial ContentProvider patrón (ruta del archivo en _data campo).

/**
 * 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 context The context.
 * @param uri The Uri to query.
 * @author paulburke
 */
public static String getPath(final Context context, final Uri uri) {

    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    // 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() + "https://stackoverflow.com/" + 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 ("content".equalsIgnoreCase(uri.getScheme())) {

        // Return the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();

        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(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.
 */
public 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 index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } 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());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is Google Photos.
 */
public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}

Ver una versión actualizada de este método aquí.

  • Esto funcionó fantásticamente en una interfaz de usuario de documentos Nexus 5 4.4 y algunos otros dispositivos KitKat preferidos que usan las aplicaciones de galería estándar, ¡gracias Paul!

    – José

    14 de diciembre de 2013 a las 12:44

  • ¡Gracias por esto, me ha llevado mucho tiempo llegar tan lejos con SDK 19! Mi problema es que mi dispositivo está usando Google Drive como explorador de archivos. Si el archivo está en la ruta de la imagen del dispositivo, está bien, pero si el archivo está en la unidad, no se abre. Tal vez solo necesito tratar de abrir imágenes desde Google Drive. La cosa es que mi aplicación está escrita para usar la ruta del archivo y obtener una imagen usando un muestreo…

    – RuAware

    17 de diciembre de 2013 a las 21:18


  • @RuAware Cuando selecciona un archivo de Drive, devuelve Authority: com.google.android.apps.docs.storage y Segments: [document, acc=1;doc=667]. No estoy seguro, pero supongamos que el doc el valor es el Uri ID contra el que puede consultar. Es probable que necesite permisos para configurar como se detalla en “Autorizar su aplicación en Android” aquí: developers.google.com/drive/integrate-android-ui. Actualiza aquí si lo averiguas.

    –Paul Burke

    18 de diciembre de 2013 a las 15:21

  • ¡Esto es absolutamente horrible! no debe continuar propagando código que “hace trampa” como este. solo es compatible con las aplicaciones de origen para las que conoce el patrón, y el objetivo del modelo de proveedor de documentos es admitir fuentes arbitrarias

    – j__m

    29/09/2014 a las 20:01

  • los _data no funcionaría cuando ContentProvider no lo admita. Se recomienda seguir Instrucciones de @CommonsWare y ya no use la ruta completa del archivo, porque podría ser un archivo en la nube de Dropbox en lugar de un archivo real.

    – soshial

    27 de diciembre de 2016 a las 15:10

Prueba esto:

if (Build.VERSION.SDK_INT <19){
    Intent intent = new Intent(); 
    intent.setType("image/jpeg");
    intent.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(Intent.createChooser(intent, getResources().getString(R.string.select_picture)),GALLERY_INTENT_CALLED);
} else {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("image/jpeg");
    startActivityForResult(intent, GALLERY_KITKAT_INTENT_CALLED);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode != Activity.RESULT_OK) return;
    if (null == data) return;
    Uri originalUri = null;
    if (requestCode == GALLERY_INTENT_CALLED) {
        originalUri = data.getData();
    } else if (requestCode == GALLERY_KITKAT_INTENT_CALLED) {
        originalUri = data.getData();
        final int takeFlags = data.getFlags()
                & (Intent.FLAG_GRANT_READ_URI_PERMISSION
                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // Check for the freshest data.
        getContentResolver().takePersistableUriPermission(originalUri, takeFlags);
    }

    loadSomeStreamAsynkTask(originalUri);

}

Probablemente necesite

@SuppressLint(“Nueva API”)

por

takePersistableUriPermission

  • ¿Te importaría explicar qué está haciendo el código KitKat? ¿Esto requiere algún nuevo permiso? El código anterior a KitKat también me funciona en KitKat. Entonces, ¿por qué elegiría usar un código diferente para KitKat? Gracias.

    –Michael Greifeneder

    9 de noviembre de 2013 a las 18:19


  • parece que no podemos obtener la ruta de los nuevos sdks uri. También es una pena que Google haya hecho este tipo de cambio sin la documentación y el anuncio adecuados.

    – usuario65721

    17 de noviembre de 2013 a las 3:11


  • ¿Podría explicar cómo obtener la URL del archivo? Me gustaría obtener la ruta real en sdcard. Por ejemplo, si es una imagen, me gustaría obtener esta ruta /storage/sdcard0/DCIM/Camera/IMG_20131118_153817_119.jpg en lugar del documento Uri.

    – Álvaro

    20 de noviembre de 2013 a las 8:34

  • Basado en documentos de KitKat (desarrollador.android.com/about/versions/…) esto puede no ser lo que necesita el OP a menos que tenga la intención de usar/editar documentos que son propiedad de la(s) otra(s) aplicación(es). Si el OP quiere una copia o hacer las cosas de manera consistente con las versiones anteriores, la respuesta de @voytez sería más apropiada.

    – Colín M.

    27 de noviembre de 2013 a las 22:14

  • Esto no funciona para mí. Obtengo la siguiente excepción (en stock 4.4.2): E/AndroidRuntime(29204): Provocado por: java.lang.SecurityException: Solicitó indicadores 0x1, pero solo se permiten 0x0

    –Russell Stewart

    11 de febrero de 2014 a las 18:34

Android Gallery en Android 44 KitKat devuelve un URI diferente
Voytez

Tuve el mismo problema, probé la solución anterior, pero aunque funcionó en general, por alguna razón recibí una denegación de permiso en el proveedor de contenido de Uri para algunas imágenes, aunque tenía la android.permission.MANAGE_DOCUMENTS permiso añadido correctamente.

De todos modos, encontré otra solución que es forzar la apertura de la galería de imágenes en lugar de la vista de documentos de KITKAT con:

// KITKAT

i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(i, CHOOSE_IMAGE_REQUEST);

y luego carga la imagen:

Uri selectedImageURI = data.getData();
input = c.getContentResolver().openInputStream(selectedImageURI);
                BitmapFactory.decodeStream(input , null, opts);

EDITAR

ACTION_OPEN_DOCUMENT puede requerir que persista las banderas de permisos, etc. y, en general, a menudo da como resultado excepciones de seguridad …

Otra solución es usar el ACTION_GET_CONTENT combinado con c.getContentResolver().openInputStream(selectedImageURI) que funcionará tanto en pre-KK como en KK. Kitkat usará una nueva vista de documentos entonces y esta solución funcionará con todas las aplicaciones como Fotos, Galería, Explorador de archivos, Dropbox, Google Drive, etc.), pero recuerde que al usar esta solución debe crear una imagen en su onActivityResult() y guárdelo en la tarjeta SD, por ejemplo. Recrear esta imagen desde el uri guardado en el próximo lanzamiento de la aplicación arrojaría una Excepción de seguridad en la resolución de contenido incluso cuando agrega indicadores de permiso como se describe en los documentos de la API de Google (eso es lo que sucedió cuando hice algunas pruebas)

Además, las Directrices de la API para desarrolladores de Android sugieren:

ACTION_OPEN_DOCUMENT no pretende ser un reemplazo de ACTION_GET_CONTENT. El que debes usar depende de las necesidades de tu aplicación:

Use ACTION_GET_CONTENT si desea que su aplicación simplemente lea/importe datos. Con este enfoque, la aplicación importa una copia de los datos, como un archivo de imagen.

Use ACTION_OPEN_DOCUMENT si desea que su aplicación tenga acceso persistente a largo plazo a los documentos propiedad de un proveedor de documentos. Un ejemplo sería una aplicación de edición de fotos que permite a los usuarios editar imágenes almacenadas en un proveedor de documentos.

  • Esta respuesta contenía la información correcta para mis propósitos. El uso condicional de ACTION_PICK y EXTERNAL_CONTENT_URI en KitKat proporcionó la misma capacidad de obtener metadatos sobre las imágenes en la galería a través de ContentResolver, como es posible en versiones anteriores usando simplemente ACTION_GET_CONTENT.

    – Colín M.

    27 de noviembre de 2013 a las 22:16

  • @voytez, ¿Puede este URI devuelto a través de su mensaje convertirse en la ruta real completa de la imagen?

    – Serpiente

    19 de diciembre de 2013 a las 21:45

  • Creo que sí, debería funcionar como antes de KitKat, ya que este código fuerza la apertura de la galería de imágenes en lugar de la vista de documentos KK. Pero si tiene la intención de usarlo para crear una imagen, esta solución es mejor, ya que la conversión a la ruta real es un paso adicional innecesario.

    – voytez

    13 de enero de 2014 a las 13:23


  • Trabajó para mí también, en lugar de Intent.ACTION_GET_CONTENT. De todos modos me quedé con el Intent.createChooser() envoltorio en el nuevo Intent, para permitir que el usuario elija la aplicación para navegar, y funcionó como se esperaba. ¿Alguien puede ver los inconvenientes de esta solución?

    – lorenzo-s

    15 de abril de 2014 a las 7:30

  • Para cualquiera que se esté preguntando, la cita proviene de desarrollador.android.com/guide/topics/providers/…

    – gruñido

    4 de noviembre de 2017 a las 15:16

1646968104 423 Android Gallery en Android 44 KitKat devuelve un URI diferente
Michał Klimczak

Tal como mencionó Commonsware, no debe asumir que la transmisión que obtiene a través de ContentResolver es convertible en archivo.

Lo que realmente deberías hacer es abrir el InputStream desde el ContentProvider, luego cree un mapa de bits a partir de él. Y también funciona en 4.4 y versiones anteriores, sin necesidad de reflexión.

    //cxt -> current context

    InputStream input;
    Bitmap bmp;
    try {
        input = cxt.getContentResolver().openInputStream(fileUri);
        bmp = BitmapFactory.decodeStream(input);
    } catch (FileNotFoundException e1) {

    }

Por supuesto, si maneja imágenes grandes, debe cargarlas con inSampleSize: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html. Pero ese es otro tema.

1646968104 521 Android Gallery en Android 44 KitKat devuelve un URI diferente
LEÓN

Creo que las respuestas ya publicadas deberían hacer que la gente vaya en la dirección correcta. Sin embargo, esto es lo que hice que tenía sentido para el código heredado que estaba actualizando. El código heredado usaba el URI de la galería para cambiar y luego guardar las imágenes.

Antes de 4.4 (y Google Drive), los URI se verían así:
contenido://medios/externo/imágenes/medios/41

Como se indica en la pregunta, con mayor frecuencia se ven así:
contenido://com.android.providers.media.documents/document/image:3951

Como necesitaba la capacidad de guardar imágenes y no alterar el código ya existente, simplemente copié el URI de la galería en la carpeta de datos de la aplicación. Luego originó un nuevo URI a partir del archivo de imagen guardado en la carpeta de datos.

Aquí está la idea:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent), CHOOSE_IMAGE_REQUEST);

public void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);

    File tempFile = new File(this.getFilesDir().getAbsolutePath(), "temp_image");

    //Copy URI contents into temporary file.
    try {
        tempFile.createNewFile();
        copyAndClose(this.getContentResolver().openInputStream(data.getData()),new FileOutputStream(tempFile));
    }
    catch (IOException e) {
        //Log Error
    }

    //Now fetch the new URI
    Uri newUri = Uri.fromFile(tempFile);

    /* Use new URI object just like you used to */
 }

Nota: copyAndClose() solo hace E/S de archivo para copiar InputStream en un FileOutputStream. El código no está publicado.

  • muy inteligente. yo también necesitaba el archivo uri real

    – mayorRey

    15/03/2014 a las 20:25

  • eres mi héroe, ¡esto es exactamente lo que necesitaba! funciona muy bien para los archivos de Google Drive también

    – mishkin

    26 de mayo de 2015 a las 3:04

  • Piensa fuera de la caja, ¿verdad? 😀 Este código funciona exactamente como esperaba.

    – Neerkoli

    24/10/2015 a las 17:58

  • publique el código para copyAndClose, la respuesta no está completa

    – Bartek Pacia

    25 de noviembre de 2019 a las 20:45

Solo quería decir que esta respuesta es brillante y la estoy usando durante mucho tiempo sin problemas. Pero hace algún tiempo me encontré con un problema que DownloadsProvider devuelve URI en formato content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf y por lo tanto la aplicación se bloquea con NumberFormatException ya que es imposible analizar sus segmentos uri tanto tiempo. Pero raw: El segmento contiene un uri directo que se puede usar para recuperar un archivo al que se hace referencia. Así que lo he arreglado reemplazando isDownloadsDocument(uri) if contenido con lo siguiente:

final String id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
    return id.replaceFirst("raw:", "");
}
try {
    final Uri contentUri = ContentUris.withAppendedId(
            Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
    return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
    Log.e("FileUtils", "Downloads provider returned unexpected uri " + uri.toString(), e);
    return null;
}
}

  • muy inteligente. yo también necesitaba el archivo uri real

    – mayorRey

    15/03/2014 a las 20:25

  • eres mi héroe, ¡esto es exactamente lo que necesitaba! funciona muy bien para los archivos de Google Drive también

    – mishkin

    26 de mayo de 2015 a las 3:04

  • Piensa fuera de la caja, ¿verdad? 😀 Este código funciona exactamente como esperaba.

    – Neerkoli

    24/10/2015 a las 17:58

  • publique el código para copyAndClose, la respuesta no está completa

    – Bartek Pacia

    25 de noviembre de 2019 a las 20:45

1646968105 286 Android Gallery en Android 44 KitKat devuelve un URI diferente
Grzegorz Pawełczuk

Combiné varias respuestas en una solución de trabajo que da como resultado la ruta del archivo

El tipo Mime es irrelevante para el propósito del ejemplo.

            Intent intent;
            if(Build.VERSION.SDK_INT >= 19){
                intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
                intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
                intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
            }else{
                intent = new Intent(Intent.ACTION_GET_CONTENT);
            }
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setType("application/octet-stream");
            if(isAdded()){
                startActivityForResult(intent, RESULT_CODE);
            }

Resultado de manejo

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if( requestCode == RESULT_CODE && resultCode == Activity.RESULT_OK) {
        Uri uri = data.getData();
        if (uri != null && !uri.toString().isEmpty()) {
            if(Build.VERSION.SDK_INT >= 19){
                final int takeFlags = data.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION;
                //noinspection ResourceType
                getActivity().getContentResolver()
                        .takePersistableUriPermission(uri, takeFlags);
            }
            String filePath = FilePickUtils.getSmartFilePath(getActivity(), uri);
            // do what you need with it...
        }
    }
}

FilePickUtils

import android.annotation.SuppressLint;
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;

public class FilePickUtils {
    private static String getPathDeprecated(Context ctx, Uri uri) {
        if( uri == null ) {
            return null;
        }
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = ctx.getContentResolver().query(uri, projection, null, null, null);
        if( cursor != null ){
            int column_index = cursor
                    .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }
        return uri.getPath();
    }

    public static String getSmartFilePath(Context ctx, Uri uri){

        if (Build.VERSION.SDK_INT < 19) {
            return getPathDeprecated(ctx, uri);
        }
        return  FilePickUtils.getPath(ctx, uri);
    }

    @SuppressLint("NewApi")
    public static String getPath(final Context context, final Uri uri) {
        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        // 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() + "https://stackoverflow.com/" + 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 ("content".equalsIgnoreCase(uri.getScheme())) {
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(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.
     */
    public 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);
            }
        } 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());
    }

}

  • estaba enfrentando un problema… uri.getPath() devolvía uri con/externo y no devolvía la ruta. agregué este bloque else if (“content”.equalsIgnoreCase(uri.getScheme())) y esto funciona bien ahora … ¿puedes explicar qué hace?

    – Faisal Ahmed

    26 de abril de 2017 a las 10:21

  • filePath se vuelve nulo. En uri: content://com.android.externalstorage.documents/document/799B-1419%3AScreenshot%2FScreenshot_20181117_162826.png

    – Bhavesh Moradiya

    7 de diciembre de 2018 a las 9:11

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad