Reputation: 1591
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
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
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
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
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