Bloquearse cuando la selección de archivo de descargas

MEDIA PENSIÓN. :

Estoy usando esta clase fileutils al seleccionar un archivo desde el dispositivo:

public class FileUtils {
private FileUtils() {
}

private static final String TAG = "FileUtils";
private static final boolean DEBUG = false;

private static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

private static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

private static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}


private static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}

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()) {
            if (DEBUG)
                DatabaseUtils.dumpCursor(cursor);

            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}

@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {

    if (DEBUG)
        Log.d(TAG + " File -",
                "Authority: " + uri.getAuthority() +
                        ", Fragment: " + uri.getFragment() +
                        ", Port: " + uri.getPort() +
                        ", Query: " + uri.getQuery() +
                        ", Scheme: " + uri.getScheme() +
                        ", Host: " + uri.getHost() +
                        ", Segments: " + uri.getPathSegments().toString()
        );

    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];

            // This is for checking Main Memory
            if ("primary".equalsIgnoreCase(type)) {
                if (split.length > 1) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                } else {
                    return Environment.getExternalStorageDirectory() + "/";
                }
                // This is for checking SD Card
            } else {
                return "storage" + "/" + docId.replace(":", "/");
            }

        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {
            final String id = DocumentsContract.getDocumentId(uri);
            if (id.startsWith("raw:")) {
                String[] data = new String[2];
                data[0] = id.replaceFirst("raw:", "");
                data[1] = null;
                return data[0];
            }
            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;
}

Yo llamo a esta clase de onActivityResultla siguiente manera:

String sourcePath = FileUtils.getPath(this, data.getData());

Por alguna razón estoy recibiendo el siguiente choque:

Caused by java.lang.IllegalArgumentException: Unknown URI: content://downloads/public_downloads/230
   at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:165)
   at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
   at android.content.ContentProviderProxy.query(ContentProviderNative.java:418)
   at android.content.ContentResolver.query(ContentResolver.java:760)
   at android.content.ContentResolver.query(ContentResolver.java:710)
   at android.content.ContentResolver.query(ContentResolver.java:668)
   at com.HBiSoft.ProGolf.Utils.FileUtils.getDataColumn(FileUtils.java:50)
   at com.HBiSoft.ProGolf.Utils.FileUtils.getPath(FileUtils.java:116)
   at com.HBiSoft.ProGolf.MainActivity.onActivityResult(MainActivity.java:652)
   at android.app.Activity.dispatchActivityResult(Activity.java:7638)
   at android.app.ActivityThread.deliverResults(ActivityThread.java:4515)
   at android.app.ActivityThread.handleSendResult(ActivityThread.java:4563)
   at android.app.ActivityThread.-wrap21(Unknown Source)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1779)
   at android.os.Handler.dispatchMessage(Handler.java:106)
   at android.os.Looper.loop(Looper.java:164)
   at android.app.ActivityThread.main(ActivityThread.java:7000)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)

el accidente sólo ocurre cuando se selecciona un archivo de la carpeta de descargas.

Por favor alguien puede ayudarme a resolver esto?

MEDIA PENSIÓN. :

He creado una gistque resuelve este problema, aquí está el enlace .


¡¡IMPORTANTE!!

Cuando se selecciona un archivo de Google Drive o Dropbox por lo que recibirá el siguiente error:

Caused by java.lang.IllegalArgumentException: column '_data' does not exist

Para resolver esta realidad se tiene que hacer una copia temporal del archivo que está intentando seleccionar.

Primero hay que comprobar si el content://URI es de Google Drive, se puede hacer esto haciendo lo siguiente:

public boolean isGoogleDrive(Uri uri) {
    return String.valueOf(uri).toLowerCase().contains("com.google.android.apps");
}

Esto devolverá verdadero si es un archivo de Google Drive. Si es así, voy a llamar una AsyncTask, como se muestra a continuación:

//The data.getData() below refers to the uri you get in onActivityResult
if (isGoogleDrive(data.getData())) {
    DownloadAsyncTask asyntask = new DownloadAsyncTask(data.getData(), this);
    asyntask.execute();
    asyntask.callback = this;
}

En la AsyncTaskvamos a utilizar el Uriabrir una InputStreamy obtener la parte posterior de bytes de datos que utilizaremos para hacer una copia del archivo.

Aquí está la AsyncTaskclase (He añadido los comentarios para que sea más comprensible):

class DownloadAsyncTask extends AsyncTask<Uri, Void, String> {
    private Uri mUri;
    CallBackTask callback;
    Context mContext;
    private AlertDialog mdialog;

    DownloadAsyncTask(Uri uri, Context context) {
        this.mUri = uri;
        mContext = context;
    }

    // In the onPreExecute() I'm displaying a custom dialog, this is not necessary, but recommended for when the user selects a large file
    @Override
    protected void onPreExecute() {
        final AlertDialog.Builder mPro = new AlertDialog.Builder(new ContextThemeWrapper(mContext, R.style.myDialog));
        @SuppressLint("InflateParams") 
        //Get reference to dialog layout
        final View mPView = LayoutInflater.from(mContext).inflate(R.layout.dialog, null);
        //Get reference to dialog title
        final TextView title = mPView.findViewById(R.id.txtTitle);
        //Get reference to dialog description
        final TextView desc = mPView.findViewById(R.id.txtDesc);

        //Set title text
        title.setText("Please wait..");
        //Set description text
        desc.setText("Drive files needs to be imported, this might take some time depending on the file size.");

        mPro.setView(mPView);
        mdialog = mPro.create();
        mdialog.show();

    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    protected String doInBackground(Uri... params) {
        //This will be the file we will use (the one that will be copied)
        File file = null;
        try {
            //Create a temporary folder where the copy will be saved to
            File temp_folder = mContext.getExternalFilesDir("TempFolder");

            //Use ContentResolver to get the name of the original name
            //Create a cursor and pass the Uri to it
            Cursor cursor = mContext.getContentResolver().query(mUri, null, null, null, null);
            //Check that the cursor is not null
            assert cursor != null;
            int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            cursor.moveToFirst();
            //Get the file name
            String filename = cursor.getString(nameIndex);
            //Close the cursor
            cursor.close();

            //open a InputStream by passing it the Uri
            //We have to do this in a try/catch
            InputStream is = null;
            try {
                is = mContext.getContentResolver().openInputStream(mUri);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }

            //We now have a folder and a file name, now we can create a file
            file = new File(temp_folder + "/" + filename);

            //We can now use a BufferedInputStream to pass the InputStream we opened above to it
            BufferedInputStream bis = new BufferedInputStream(is);
            //We will write the byte data to the FileOutputStream, but we first have to create it
            FileOutputStream fos = new FileOutputStream(file);

            byte data[] = new byte[1024];
            long total = 0;
            int count;
            //Below we will read all the byte data and write it to the FileOutputStream
            while ((count = bis.read(data)) != -1) {
                total += count;
                fos.write(data, 0, count);
            }
            //The FileOutputStream is done and the file is created and we can clean and close it
            fos.flush();
            fos.close();

        } catch (IOException e) {
            Log.e("IOException = ", String.valueOf(e));
        }

        //Finally we can pass the path of the file we have copied
        return file.getAbsolutePath();


    }

    protected void onPostExecute(String result) {
        //We are done and can cancel the dialog
        if (mdialog != null && mdialog.isShowing()) {
            mdialog.cancel();
        }
        //I'm using a callback to let my Activity know that the AsyncTask is done. I pass the path along.
        callback.getResultFromAsynTask(result);


    }
}

Verá que en el onPostExecute()anterior tengo callback.getResultFromAsynTask(result);. Como ya he mencionado en el comentario, estoy usando un método de devolución de llamada para que el know Actividad que he terminado y me pase la ruta a la devolución de llamada.

En la actividad se tiene que aplicar la devolución de llamada, así:

public class MainActivity extends AppCompatActivity implements CallBackTask {

y CallBackTaskse verá así:

interface CallBackTask {
    void getResultFromAsynTask(String result);
 }

Ahora usted tiene que ponerlo en práctica en su Activitypara obtener el resultado en su Activity:

@Override
public void getResultFromAsynTask(String result) {
    // Do what you need with the result like starting your new Activity and passing the path
    final Intent intent = new Intent();
    intent.setClass(MainActivity.this, Player.class);
    intent.putExtra("path", result);
    startActivity(intent);
}

GRAN , ahora tiene una Uride una File://(en lugar de content://) que ha copiado de forma temporal. Sin embargo, no se olvide de eliminar el archivo cuando haya terminado con él , de lo contrario su tamaño de la aplicación va a seguir creciendo más grande.

A continuación, voy a borrar el TempFolderque hemos creado antes, voy a hacer esto en las Actividades onBackPressed(esto debe hacerse en OnDestroy () también):

@Override
public void onBackPressed() {
    super.onBackPressed();
    File dir = getBaseContext().getExternalFilesDir("TempFolder");
    deleteRecursive(dir);
}

void deleteRecursive(File fileOrDirectory) {
    if (fileOrDirectory.isDirectory())
        for (File child : fileOrDirectory.listFiles())
            deleteRecursive(child);

    fileOrDirectory.delete();
}

Esto es mucho leer, pero ... Al hacerlo de esta manera, usted nunca tendrá problemas con ningún content:// Uri's.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=211785&siteId=1
Recomendado
Clasificación