From Uri to Path and back to Uri - android

I’m using some big pictures that are stored in External Memory. I decode them, resize them and set the small bitmaps to various imageviews.
I keep track of those large images by storing their Uri’s. When the app stops, I convert Uri to paths and save them as Strings is a SQLite base:.
File myFile = new File(provider.getImageUri().toString());
cv.put(DBHelper.DB_IMAGEPATH, myFile.getAbsolutePath());
At this point the path to the image looks like:
/content/media/.. and everything works ok.
When the app resumes I read the path from database and convert it to Uri:
File tempFile = new File(cursor.getString(imagePathColIndex);
mUri = (Uri.fromFile(mFile));
Now the path in new mUri looks like:
File:///content/... And there is a IONotFound exception.

You should try with
File tempFile = new File(cursor.getString(imagePathColIndex));
mUri = Uri.parse(tempFile.getAbsolutePath());
Testing with the following code
String path = "/content/media";
Uri uri = Uri.fromFile(new File(path));
Log.e(TAG, uri.toString()); //print file:///content/media
uri = Uri.parse(path);
Log.e(TAG, uri.toString()); //print /content/media
EDIT
To read the image can you try
BitmapFactory.decodeStream(new FileInputStream(Uri.parse(path)));

Related

Display apps folder in dallery and images/video inside it like other popular apps

Hi I am new to android development and have been trying to accomplish the above said functionality.
I am testing app on Android 9, API 28. I am able to save captured image to folder but not been able to display it in gallery (Like WhatsApp).
I have tried:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
OutputStream os;
String[] split = imagePathNew.split("\\.");
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, split[0] + ".jpg");
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + "Test");
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
os = (OutputStream) resolver.openOutputStream(Objects.requireNonNull(imageUri)); // imageLocalUri is the uri of captured image in folder
Bitmap bitmap = MediaStore.Images.Media.getBitmap(resolver, imageLocalUri);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
Objects.requireNonNull(os);
} else {
Intent updateInGallery = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
updateInGallery.setData(imageLocalUri); // imageLocalUri is the uri of captured image in folder
context.sendBroadcast(updateInGallery);
}
Can someone please help me with what am I doing wrong here?
Nothing is wrong with the posted code.
In the addition use following class
https://developer.android.com/reference/android/media/MediaScannerConnection#scanFile(java.lang.String,%20java.lang.String)
From docs
provides a way for applications to pass a newly created or downloaded media file to the media scanner service. The media scanner service will read metadata from the file and add the file to the media content provider.

Saving media file path or URI to SQLite and getting it, best practice

My goal is to:
Save media file to External Storage (in my case it's photo).
Get file path or URI of saved data.
Save it to SQLite (either file path or content URI or smth else).
Be able to get correct URI to this content at any point in the future.
It's very similar to what other very popular application do - they create their directory in 'Pictures' folder and store there photos and use them in their applications while they're also available for viewing using gallery/file explorer etc.
As I understand recommended way to save media content (image, f.e.) is to use MediaStore API and as a result I get content URI, which I can use later.
But then I read that these content URIs might be changed after re-scan of Media happens, so it looks it's not reliable. (For example if SD card is used and it's taken out and inserted again)
At the same time usage of absolute file paths is not recommended and there's tendency to deprecate APIs which use absolute file paths to work with External Storage. So it doesn't look reliable either.
I can only imagine the following solution:
Use unique auto-generated file name while saving (like UUID).
When I need to get content URI (f.e. want to render photo in ImageView) - I can use ContentResolver and search for content URI using file name filter.
Problem with this approach is that I have a lot of photos (gallery) and querying it using ContentResolver can affect performance significantly.
I feel like I'm over complicating things and missing something.
You are indeed overcomplicating things.
Store file to the needed folder in the filesystem(it is better to name the folder under your app name)
Store this path or URI path - whatever you like. (Do not hardcode passes though in your app - device vendors may have different base paths in their devices)
As long as the folder is named the same and files in it named the same(as in your db) - you will be able to access them even if the sdcard was taken out and then put back in.
There are possible complications after reindexing - but for the eight years I work as Android dev I encountered it only once, thus you can easily ignore this stuff.
If you want to have more control over what you store and want to limit access to it - store data into the inner storage of your app - this way you will be 100% sure of where the data is and that it is not tampered with.
Starting from Android 10 you have scoped storage - it is like internal storage but it may be even on an external sdcard.
Here is a small overview of possible storage locations.
And don't overthink it too much - it is a default usecase of the phone and it works just as you would expect - pretty ok and pretty stable.
first, you have to apply for external storage permission in manifest and Runtime Permission Also.
after creating a directory for saving an image in this directory.
you have to also add file provider in XML and code side because it's required.
now it's time to code check my code for saving an image in the folder also these image in the gallery and get the path from a file path.
convert URI to bitmap
http://prntscr.com/10dpvjj
save image function from getting bitmap
private String save(Bitmap bitmap) {
File save_path = null;
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
try {
File sdCard = Environment.getExternalStorageDirectory();
File dir = new File(sdCard.getAbsolutePath() + "/SaveDirectory");
dir.mkdirs();
File file = new File(dir, "DirName_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime()) + ".png");
save_path = file;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
FileOutputStream f = null;
f = new FileOutputStream(file);
MediaScannerConnection.scanFile(context, new String[]{file.getAbsolutePath()}, null, null);
if (f != null) {
f.write(baos.toByteArray());
f.flush();
f.close();
}
} catch (Exception e) {
// TODO: handle exception
}
Share(save_path); // call your Function Store into database
Log.e("PathOFExec----", "save: " + save_path);
}
get store image location into your database if you wish
private void Share(File savePath) {
if (savePath != null) {
Uri uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", savePath);
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/*");
share.putExtra(Intent.EXTRA_TEXT, "TextDetail");
share.putExtra(Intent.EXTRA_STREAM, uri);
context.startActivity(Intent.createChooser(share, "Share Image!"));
//after getting URI you can store the image into SQLite databse for get uri
}
}
I would recommend using Intent.ACTION_OPEN_DOCUMENT for your demand.
1. Create Photo Picking Intent:
val REQUEST_CODE_PICK_PHOTO = 1
fun pickAndSavePhoto(requestCode: Int) {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.type = "image/*"
startActivityForResult(intent, requestCode)
}
2. Handle Result:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_PICK_PHOTO && resultCode == RESULT_OK) {
val imageUri = data!!.data!!
//save this uri to your database as String -> imageUri.toString()
}
}
3. Get Image back and Display on ImageView:
fun getBitmapFromUri(context: Context, imageUri: Uri): Bitmap? { //uri is just an address, image may be deleted any time, if so returns null
val bitmap: Bitmap
return try {
val inputStream = context.contentResolver.openInputStream(imageUri)
inputStream.use {
bitmap = BitmapFactory.decodeStream(it)
}
bitmap
} catch (e: Exception) {
Log.e("getBitmapFromUri()", "Image not found.")
null
}
}
val bitmap = getBitmapFromUri(context, imageUri) //get uri String from database and convert it to uri -> uriString.toUri()
if (bitmap != null) {
imageView.setImageBitmap(bitmap)
}
Only ACTION_OPEN_DOCUMENT can access file uri permanently:
Android Retrieve Image by Intent Uri Failed: "has no access to content..."
Demo: https://www.youtube.com/watch?v=LFfWnt77au8

How to save captured photo in application directory in Android

Hello I want to save captured photo in application directory where SQLite etc reside. I don't want to make any folder and any hidden file in the SD Card. How this can be save the captured photo in application directory.
I am trying this below but it is saving in the SD card that is hidden file but I don't want this approach.
Intent cameraIntent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
String capturedPhotoName = "." + System.currentTimeMillis() + ".png";
File photo = new File(Environment.getExternalStorageDirectory(),
capturedPhotoName);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
imageUri = Uri.fromFile(photo);
startActivityForResult(cameraIntent, CAMERA_INTENT_REQUEST);
Thanks in advance !
Try this method to save captured image in application storage
public Uri setImageUri() {
ContextWrapper cw = new ContextWrapper(getApplicationContext());
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
File file = new File(directory,System.currentTimeMillis() + ".png");
Uri imgUri = Uri.fromFile(file);
this.imgPath = file.getAbsolutePath();
return imgUri;
}
Image will store at this location
/data/data/com.your.packagename/app_data/imageDir
get URI from onActivityResult() and convert it into bytes store bytes in Database.
byte[] UserPic = null;
UserPic = Base64.decode(result.getData(), 0);
save userPic in DataBase

Get uri of picture taken by camera

When the user takes a picture with the camera, I want the image displayed in an ImageView and I want to save the Uri to an online database. I heard saving the Uri of a picture is better than saving the path.
So this is how I start the camera:
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getFile(getActivity())));
String a = String.valueOf(Uri.fromFile(getFile(getActivity())));
intent.putExtra("photo_uri", a);
startActivityForResult(intent, PICK_FROM_CAMERA);
where
private File getFile(Context context){
File sdCard = Environment.getExternalStorageDirectory();
File directory = new File (sdCard.getAbsolutePath() + "/Myapp");
if (!directory.exists()) {
directory.mkdirs();
}
String filename = "bl" + System.currentTimeMillis() + ".jpg";
File newFile = new File(directory, filename);
return newFile;
}
In onActivityResult:
Bundle extras = data.getExtras();
String photo_uri = extras.getString("photo_uri"); //null
This is always null. Btw before sending the intent the Uri looks like file://... instead of content:// which is the uri when I open an image from the gallery. I don't know if that's a problem.
Also, should I save the path instead of the Uri to the database? I read that the Uri can be complicated in certain phones or Android versions. When I let the user select an image from the gallery, I save the Uri to the database, so I think the best way is saving the Uri in this case as well.
I tried out many variations, but I get null every time I try to pass a variable with the intent...
After starting the intent:
Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intentPicture,PICK_FROM_CAMERA);
In onActivityResult:
case PICK_FROM_CAMERA:
Uri selectedImageUri = data.getData();
InputStream imageStream = null;
try {
imageStream = getContentResolver().openInputStream(selectedImageUri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream);
break;
That's all.

Cannot save video to specific folder

I am trying to save video to specific folder like
Intent captureVideoIntent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
File videosFolder = new File(Environment.getExternalStorageDirectory(), "Videos");
if (!videosFolder.exists()) {
videosFolder.mkdirs(); // <----
}
String sfx = getNextName(ConstantData.RESPONSE_TYPE_VIDEO);
videoUri = Uri.fromFile(new File(videosFolder, sfx));
captureVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT,videoUri);
captureVideoIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivityForResult(captureVideoIntent,1277);
videoUri is fine, folder Videos is created and on result when I try to read file like
InputStream inputStream = this.getContentResolver().openInputStream(videoUri);
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(8 * 8192);
....
I am getting exception FileNotFound, what is true, there is Videos folder but there is no saved video inside. Does anybody know what is problem and why I cannot save video to specific folder ? Video has extension .3gp and folder is always empty.
You can specify your new file name instead of the "sfx"
remove the below line and put "test.mp4" instead of the "sfx" variable, it will work
String sfx = getNextName(ConstantData.RESPONSE_TYPE_VIDEO);

Categories

Resources