Search code examples
javaandroidscoped-storage

How to move/copy any type of file from asset file to scoped storage ANDROID Q in JAVA?


I have already succeeded with this operation with images, but I cannot do it with other type of file, in my case I try to insert a database.

Here is an example of the code for the images:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
        try {
            try {
                pictures = assetManager.list("photos/dataset1");
            } catch (IOException e) {
                Log.e("tag", "Failed to get asset file list.", e);
            }
            if (pictures != null) {
                for (String filename : pictures) {
                    InputStream in;
                    OutputStream out;
                    InputStream inputStream = assetManager.open("photos/dataset1/"+filename);
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    saveImageToGallery(bitmap);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

This method below works for the images :

public void saveImageToGallery(Bitmap bitmap) {
    OutputStream outputStream;
    Context myContext = requireContext();
    try {
        if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.Q){
            ContentResolver contentResolver = requireContext().getContentResolver();
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME,"Image_"+".jpg");
            contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
            Uri imageUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
            outputStream = contentResolver.openOutputStream(Objects.requireNonNull(imageUri));
            bitmap.compress(Bitmap.CompressFormat.JPEG,100, outputStream);
            Objects.requireNonNull(outputStream);

        }
    }catch (FileNotFoundException e) {

        e.printStackTrace();
    }
}

and there my try for the other type of file :

        AssetManager assetManager = Objects.requireNonNull(requireContext()).getAssets();
    Context myContext = requireContext();
    //Essential for creating the external storage directory for the first launch
    myContext.getExternalFilesDir(null);
    File databasesFolder = new File(myContext.getExternalFilesDir(null).getParent(), "com.mydb.orca/databases");
    databasesFolder.mkdirs();

 if (files!= null) {
        for (String filename : files) {
            InputStream in;
            OutputStream out;
            try {
                in = assetManager.open("database/test/" + filename);
                File outFile = new File(databasesFolder, filename);
                out = new FileOutputStream(outFile);
                copyFile(in, out);
                in.close();
                out.flush();
                out.close();
            } catch (IOException e) {
                Log.e("tag", "Failed to copy asset file: " + filename, e);
            }
        }
    } else {
        Log.e("Error NPE", "files is null");
    }



    private void copyFile(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[1024];
    int read;
    while ((read = in.read(buffer)) != -1) {
        out.write(buffer, 0, read);
    }
}

This code above is not working, I mean, I don't get any errors or the desired result. I want something like this or a function similary as the function for my images but for any type of file. When I run my application I have no error however nothing happens


Solution

  • I finally find a solution, I pretty sure it's not the best way but it work. I give me access to all files acccess by this way :

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
      try {
            Intent intentFiles = new Intent();
            intentFiles.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
            Uri uriFiles = Uri.fromParts("package", myContext.getPackageName(), null);
            intentFiles.setData(uriFiles);
            myContext.startActivity(intentFiles);
           } catch (Exception e)
           {
            Intent intentFiles = new Intent();
            intentFiles.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
            myContext.startActivity(intentFiles);
           }
    

    add this line to your manifest:

        <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    

    after that, this code below work :

    AssetManager assetManager = Objects.requireNonNull(requireContext()).getAssets();
    Context myContext = requireContext();
    //Essential for creating the external storage directory for the first launch
    myContext.getExternalFilesDir(null);
    File databasesFolder = new File(myContext.getExternalFilesDir(null).getParent(), "com.mydb.orca/databases");
    databasesFolder.mkdirs();
    
     if (files!= null) {
        for (String filename : files) {
            InputStream in;
            OutputStream out;
            try {
                in = assetManager.open("database/test/" + filename);
                File outFile = new File(databasesFolder, filename);
                out = new FileOutputStream(outFile);
                copyFile(in, out);
                in.close();
                out.flush();
                out.close();
            } catch (IOException e) {
                Log.e("tag", "Failed to copy asset file: " + filename, e);
            }
        }
    } else {
        Log.e("Error NPE", "files is null");
    }
    
    
    
    private void copyFile(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[1024];
    int read;
    while ((read = in.read(buffer)) != -1) {
        out.write(buffer, 0, read);
    }
    

    }

    if someone have a best solution it should be nice

    I tested on android 11 and it work