Ankesh kumar Jaisansaria
Ankesh kumar Jaisansaria

Reputation: 1591

Convert file PATH to TreeUri (Storage Access Framework)

In my application of image gallery I use media content provider image to inflate recycler view . On long press on an image, I give user option to rename that image file. So I have complete file path (Ex:- /storage/sdcard1/DCIM/100ANDRO/ak.jpg ) for each image in recycler view. Then I want to rename that file.

Now the issue is that as the file path provided is that of External SD Card, and for Android 5 & up, SAF(Storage Access Framework) is required to write a file.

So generally we use this code for renaming a file using SAF:-

public void onActivityResult(int requestCode, int resultCode, Intent resultData){
    if (resultCode == RESULT_OK) {
        Uri treeUri = resultData.getData();
        getContentResolver().takePersistableUriPermission(treeUri,
                Intent.FLAG_GRANT_READ_URI_PERMISSION |
                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
        DocumentFile newFIle = pickedDir.createFile("text/plain","MyFile")
        // or rename as
        pickedDir.renameTo("fdtd.jpg");
    } else {
        Log.d("test","NOt OK RESULT");
    }
}

But that is in the case when we know the TreeUri. Here in my case I know fle path and hence want to convert that into TreeUri.

Upvotes: 3

Views: 4760

Answers (4)

user13947194
user13947194

Reputation: 402

I have similar problems but I think I may have a solution. As per my experience using Windows MTP api. Which is very similar to Android SAF.

With SAF android doesnt want you to have direct access to files and instead gives you an ID to the files. If you check DocumentsContract.Document, you notice there is no column for the file path, only a display name.

However with recursion I think we can find the matching Uri. Sorry I cant give an example, but just simply walking the file tree using SAF api until you get all brances of your file path is the idea.

Upvotes: 0

nnyerges
nnyerges

Reputation: 583

If you dont want to use ACTION_OPEN_DOCUMENT_TREE or ACTION_OPEN_DOCUMENT to get an Uri, you can convert FILE to Uri (SAF) using the following method valid from API19(Android4.4-Kitkat) to API28(Android8-Oreo). The returned Uri's are the same that return the dialog and its valid for API 28 security restrictions (SAF permissions), if you want to access external removable storage outside your application...

 /**
 * Ing.N.Nyerges 2019 V2.0
 *
 * Storage Access Framework(SAF) Uri's creator from File (java.IO),
 * for removable external storages
 *
 * @param context Application Context
 * @param file File path + file name
 * @return Uri[]:
 *   uri[0] = SAF TREE Uri
 *   uri[1] = SAF DOCUMENT Uri
 */
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static Uri[] getSafUris (Context context, File file) {

    Uri[] uri = new Uri[2];
    String scheme = "content";
    String authority = "com.android.externalstorage.documents";

    // Separate each element of the File path
    // File format: "/storage/XXXX-XXXX/sub-folder1/sub-folder2..../filename"
    // (XXXX-XXXX is external removable number
    String[] ele = file.getPath().split(File.separator);
    //  ele[0] = not used (empty)
    //  ele[1] = not used (storage name)
    //  ele[2] = storage number
    //  ele[3 to (n-1)] = folders
    //  ele[n] = file name

    // Construct folders strings using SAF format
    StringBuilder folders = new StringBuilder();
    if (ele.length > 4) {
        folders.append(ele[3]);
        for (int i = 4; i < ele.length - 1; ++i) folders.append("%2F").append(ele[i]);
    }

    String common = ele[2] + "%3A" + folders.toString();

    // Construct TREE Uri
    Uri.Builder builder = new Uri.Builder();
    builder.scheme(scheme);
    builder.authority(authority);
    builder.encodedPath("/tree/" + common);
    uri[0] = builder.build();

    // Construct DOCUMENT Uri
    builder = new Uri.Builder();
    builder.scheme(scheme);
    builder.authority(authority);
    if (ele.length > 4) common = common + "%2F";
    builder.encodedPath("/document/" + common + file.getName());
    uri[1] = builder.build();

    return uri;
}

Upvotes: 2

Anku Agarwal
Anku Agarwal

Reputation: 469

To convert file path to uri use this:-

DocumentFile fileuri = DocumentFile.fromFile(new File(filepath));

Then you can perform delete,rename operations on this fileuri.

Upvotes: 5

Gorio
Gorio

Reputation: 1646

you have to set fullpath in renameTo method.

Use my example to work.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) {
        Uri selectedImage = data.getData();
        String[] filePathColumn = {MediaStore.Images.Media.DATA};

        Cursor cursor = getContentResolver().query(selectedImage,
                filePathColumn, null, null, null);

        if (cursor != null) {
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            String picturePath = cursor.getString(columnIndex);
            cursor.close();

            ImageView imageView = (ImageView) findViewById(R.id.image);
            imageView.setOnClickListener(this);

            Bitmap bmp = null;
            try {
                bmp = getBitmapFromUri(selectedImage);
            } catch (IOException e) {
                e.printStackTrace();
            }

            imageView.setImageBitmap(bmp);

            //get file
            File photo = new File(picturePath);

            //file name
            String fileName = photo.getName();

            //resave file with new name
            File newFile = new File(photo.getParent() + "/fdtd." + fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()) );

            photo.renameTo(newFile);
        }

    }
}

Remember that in my example i consider maintain the default extension of original file, because if you try to rename PNG to JPG you can have problem.

Upvotes: 0

Related Questions