Archivo de documentos de Android 5.0 desde el árbol URI

Muy bien, he buscado y buscado y nadie tiene mi respuesta exacta, o lo extrañé. Tengo mis usuarios seleccionar un directorio por:

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); startActivityForResult(intent, READ_REQUEST_CODE); 

En mi actividad quiero capturar el camino real, que parece imposible.

 protected void onActivityResult(int requestCode, int resultCode, Intent intent){ super.onActivityResult(requestCode, resultCode, intent); if (resultCode == RESULT_OK) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M){ //Marshmallow } else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){ //Set directory as default in preferences Uri treeUri = intent.getData(); //grant write permissions getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); //File myFile = new File(uri.getPath()); DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri); 

La carpeta que seleccioné está en:

 Device storage/test/ 

He intentado todas las maneras siguientes de conseguir un nombre exacto de la trayectoria, pero en vano.

 File myFile = new File (uri.getPath()); //returns: /tree/1AF6-3708:test treeUri.getPath(); //returns: /tree/1AF6-3708:test/ pickedDir.getName() //returns: test pickedDir.getParentFile() //returns: null 

Básicamente, necesito activar /tree/1AF6-3708: en /storage/emulated/0/ o lo que sea que cada dispositivo llame a su ubicación de almacenamiento. Todas las demás opciones disponibles return /tree/1AF6-37u08: también.

Hay 2 razones por las que quiero hacerlo de esta manera.

1) En mi aplicación de almacenamiento de la ubicación del archivo como una preferencia compartida, ya que es específico del usuario. Tengo un poco de datos que serán descargados y almacenados y quiero que el usuario pueda colocarlo donde quieran, especialmente si tienen una ubicación de almacenamiento adicional. Yo sí establecer un valor predeterminado, pero quiero versatilidad, en lugar de la ubicación dedicada de:

 Device storage/Android/data/com.app.name/ 

2) En 5.0 quiero permitir al usuario obtener permisos de lectura / escritura a esa carpeta y esto parece la única manera de hacer eso. Si puedo obtener permisos de lectura / escritura de una cadena que solucionaría este problema.

Todas las soluciones que he podido encontrar se refieren a Mediastore, que no me ayuda exactamente. Tengo que estar perdiendo algo en alguna parte o debo haber vidriado sobre él. Cualquier ayuda sería apreciada. Gracias.

    2 Solutions collect form web for “Archivo de documentos de Android 5.0 desde el árbol URI”

    Esto le dará la ruta real de la carpeta seleccionada (suponiendo que la carpeta seleccionada resida en un almacenamiento externo o una tarjeta SD externa)

     Uri treeUri = data.getData(); String path = FileUtil.getFullPathFromTreeUri(treeUri,this); 

    donde FileUtil es la siguiente clase

     import java.io.File; import java.io.IOException; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.ArrayList; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.os.storage.StorageManager; import android.provider.DocumentsContract; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.util.Log; @SuppressLint("NewApi") public final class FileUtil { static String TAG="TAG"; private static final String PRIMARY_VOLUME_NAME = "primary"; public static boolean isKitkat() { return Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT; } public static boolean isAndroid5() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; } @NonNull public static String getSdCardPath() { String sdCardDirectory = Environment.getExternalStorageDirectory().getAbsolutePath(); try { sdCardDirectory = new File(sdCardDirectory).getCanonicalPath(); } catch (IOException ioe) { Log.e(TAG, "Could not get SD directory", ioe); } return sdCardDirectory; } public static ArrayList<String> getExtSdCardPaths(Context con) { ArrayList<String> paths = new ArrayList<String>(); File[] files = ContextCompat.getExternalFilesDirs(con, "external"); File firstFile = files[0]; for (File file : files) { if (file != null && !file.equals(firstFile)) { int index = file.getAbsolutePath().lastIndexOf("/Android/data"); if (index < 0) { Log.w("", "Unexpected external file dir: " + file.getAbsolutePath()); } else { String path = file.getAbsolutePath().substring(0, index); try { path = new File(path).getCanonicalPath(); } catch (IOException e) { // Keep non-canonical path. } paths.add(path); } } } return paths; } @Nullable public static String getFullPathFromTreeUri(@Nullable final Uri treeUri, Context con) { if (treeUri == null) { return null; } String volumePath = FileUtil.getVolumePath(FileUtil.getVolumeIdFromTreeUri(treeUri),con); if (volumePath == null) { return File.separator; } if (volumePath.endsWith(File.separator)) { volumePath = volumePath.substring(0, volumePath.length() - 1); } String documentPath = FileUtil.getDocumentPathFromTreeUri(treeUri); if (documentPath.endsWith(File.separator)) { documentPath = documentPath.substring(0, documentPath.length() - 1); } if (documentPath.length() > 0) { if (documentPath.startsWith(File.separator)) { return volumePath + documentPath; } else { return volumePath + File.separator + documentPath; } } else { return volumePath; } } private static String getVolumePath(final String volumeId, Context con) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { return null; } try { StorageManager mStorageManager = (StorageManager) con.getSystemService(Context.STORAGE_SERVICE); Class<?> storageVolumeClazz = Class.forName("android.os.storage.StorageVolume"); Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList"); Method getUuid = storageVolumeClazz.getMethod("getUuid"); Method getPath = storageVolumeClazz.getMethod("getPath"); Method isPrimary = storageVolumeClazz.getMethod("isPrimary"); Object result = getVolumeList.invoke(mStorageManager); final int length = Array.getLength(result); for (int i = 0; i < length; i++) { Object storageVolumeElement = Array.get(result, i); String uuid = (String) getUuid.invoke(storageVolumeElement); Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement); // primary volume? if (primary && PRIMARY_VOLUME_NAME.equals(volumeId)) { return (String) getPath.invoke(storageVolumeElement); } // other volumes? if (uuid != null) { if (uuid.equals(volumeId)) { return (String) getPath.invoke(storageVolumeElement); } } } // not found. return null; } catch (Exception ex) { return null; } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private static String getVolumeIdFromTreeUri(final Uri treeUri) { final String docId = DocumentsContract.getTreeDocumentId(treeUri); final String[] split = docId.split(":"); if (split.length > 0) { return split[0]; } else { return null; } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private static String getDocumentPathFromTreeUri(final Uri treeUri) { final String docId = DocumentsContract.getTreeDocumentId(treeUri); final String[] split = docId.split(":"); if ((split.length >= 2) && (split[1] != null)) { return split[1]; } else { return File.separator; } } } 

    En mi actividad quiero capturar el camino real, que parece imposible.

    Eso es porque no puede haber un camino real, y mucho menos uno puede acceder. Hay muchos proveedores de documentos posibles, pocos de los cuales tendrán todos sus documentos localmente en el dispositivo, y pocos de los que sí tendrán los archivos en el almacenamiento externo, donde se puede trabajar con ellos.

    Tengo un poco de datos que serán descargados y almacenados y quiero que el usuario sea capaz de colocarlo donde quieran

    A continuación, utilice las API de Framework de acceso a almacenamiento , en lugar de pensar que los documentos / árboles que se obtienen de Storage Access Framework siempre son locales. O bien, no utilice ACTION_OPEN_DOCUMENT_TREE .

    En 5.0 quiero permitir al usuario obtener permisos de lectura / escritura para esa carpeta

    Esto es manejado por el proveedor de almacenamiento, como parte de cómo el usuario interactúa con ese proveedor de almacenamiento. No estás involucrado.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.