I am trying to get the path of the image the user selects from the gallery. So far I have made the button and used the following code to get the user to select the image from gallery:
public void image(View v) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), SELECT_PICTURE);
}
Now, I'm trying to get the path of this image so that I can store it in the database to be used to retrieve it later. I know how to insert the path into the DB but just don't know how to get the path name.
Also, I want to copy the image the user has selected and paste into a new folder, where all the images will be.
Any help will be appreciated.
Thanks
So far I have made the button and used the following code to get the user to select the image from gallery
No, you are asking the user to select an image. Any number of apps can offer an activity that supports ACTION_GET_CONTENT for image/* data, not just something that you consider to be a gallery.
Now, I'm trying to get the path of this image so that I can store it in the database to be used to retrieve it later
There is no path, and there is nothing that you can store that you can necessarily use later. The Uri that you get back (via the Intent passed into onActivityResult()) will work for a short time. It is reminiscent of a URL you might get to an image in a Web site, where the URL only works while the user is authenticated. Either use the Uri right away, or plan on having the user pick the image again in the future. Or, switch to the Storage Access Framework and hope that you get a Uri that is durable and has persistable permissions (and set your minSdkVersion to 19 or higher).
I want to copy the image the user has selected and paste into a new folder, where all the images will be
It is unclear what "copy the image the user has selected and paste into a new folder" means to you. If you mean what computer users would refer to as "copy the file", use ContentResolver and openInputStream() to get an InputStream on the image. Then, use standard Java I/O to copy that to some file under your control. The path to that file you could store in your database, as you are now managing that copy of the file. However, this causes duplication of data (two copies of the image), which the user may or may not want.
You can store image in bytearray format in sqlite database.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 60, baos);
byte[] byteArray=baos.toByteArray();
and then use this byteArray to insert image in Sqlite. :)
Hope this helps to you.
Related
I have an android app where the user selects a file which creates a URI.
The URI is then used to read the file into a buffer.
I can get the URI-string by doing uri.toString();
The URI-string looks like:
content://com.android.providers.downloads.documents/document/msf%3A12858
To make things quicker, for development purposes, I want to hardcode the URI-string and use it in reverse order to generate the URI.
Is this possible?
EDIT1:
Here is the code to get the data_uri for the selected file:
// at this point the user has the uri (after clicking on the button and selecting file)
Uri uri = intent.getData();
InputStream stream = context.getContentResolver().openInputStream(uri);
byte[] byteArray = JasonHelper.readBytes(stream);
String encoded = Base64.encodeToString(byteArray, Base64.NO_WRAP);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("data:image/jpeg;base64,");
stringBuilder.append(encoded);
String data_uri = stringBuilder.toString();
I can get the data_uri after I select a file.
EDIT2:
The problem is that I want to start with hardcoded uri (for development purposes).
I run the program once and get the value of the content uri string.
I then hardcode the uriStr and set uri1 from it:
String uriStr = "content://com.android.providers.downloads.documents/document/msf%3A13819";
Uri uri1 = Uri.parse(uriStr);
I restart the program but the value of uri1 is different from the value of the uri from the original run.
For example: the values of the fields authority, fragment, path are null where before they had some values (see snapshot).
According to here Uri Access Lifetime is only for the duration of the app (and even shorter).
In my case, the origin is a file uri and I assume that the file does not move.
Can I hard-code anything such that the file can be opened after the program restarts without having to select the file again?
I got nothing on whatever you said, but you should probably be using Uri.parse(...)
Something like Uri.parse(myURL)
From here
I now understand that content uri cannot be used when the app restarts.
But if the content is saved to the file system, e.g. to the internal storage of the app, then assuming the read permissions are ok, the file can be openned programatically by providing the file path.
I have code that launches a file picker by issuing a createChooser with an ACTION_OPEN_DOCUMENT intent.
Here is the code, which works:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*.*");
startActivityForResult(Intent.createChooser(intent, "Choose .xyz file"), RQS_OPEN_XYZ_FILE);
This opens a file picker that allows the user to select any type of file.
I would like to have the file picker limit the user's choices to only files that end in ".xyz".
If this were a "standard" file type, I could filter it by MIME type. For example, if I add a setType("media/jpeg"), only jpeg files will be able to be selected in the file picker. But, in this case, there is no MIME type that corresponds to ".xyz".
It was suggested to me that I try using a Data Path filter, but I have not been able to figure out how to implement that.
Is it possible to accomplish this? If so, how do I do it?
Thanks!
I've been trying for several hours to open an image from Android's external storage with Intent.ACTION_VIEW. And as you might have figured out already, I'm still not able to do that.
I've searched all over Google and I've tried a lot of ways to make this work, however none of them did. All what I could find are questions that are up to 1 year old. I tried using FileProvider and here's what I ended up with:
File imagePath = new File(Environment.getExternalStorageDirectory(), "LyceeLamartine/cache");
File newFile = new File(imagePath, "calendrier.png");
Uri contentUri = FileProvider.getUriForFile(MainActivity.this, "ml.toufic.lyceelamartine.fileprovider", newFile);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(contentUri, "image/*");
startActivity(intent);
The code above opens Google Photos successfully but it shows a black screen and the path seems to be: content://ml.toufic.lyceelamartine.fileprovider/name/calendrier.png and this seems like an internal storage path.
The image I want to access is stored at: "/storage/emulated/0/LyceeLamartine/cache/calendrier.png" and I'm using a phone with Android O (8.0).
I'm still a beginner in Java and any help would be greatly appreciated!
the path seems to be: content://ml.toufic.lyceelamartine.fileprovider/name/calendrier.png and this seems like an internal storage path.
That is not a path. That is a Uri. It has a scheme (content). It points to your FileProvider (ml.toufic.lyceelamartine.fileprovider). It seems fine — if there were a problem with the Uri, FileProvider would have thrown an exception when you tried to create it.
The code above opens Google Photos successfully but it shows a black screen
There are two problems with your Intent.
First, do not use a wildcard MIME type. It is your file. You know what the MIME type is. Use the actual MIME type (in this case, image/png).
Second, call addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) on the Intent as part of setting it up, before calling startActivity(). Right now, no app has rights to use your content.
How should I notify images Content Provider, that I just saved a file in Pictures directory? I expect e.g. Gallery-like apps to be able to see my new file.
Uri uri = Uri.fromFile(file);
getContext().getContentResolver().notifyChange(uri, null);
which I found somewhere (Vogella?) does not seem to work. Or is it a wrong approach from the start?
The image notification is done after the image is inserted into media database. This is usually done by the android system media scanner when it finds the image.
You can write your own code to insert the image into the media database and then call getContext().getContentResolver().notifyChange(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null); to notify that some image has changed without beeing specific exatly which image.
If you modified an image that is already in the media database you have to translate the file uri into a content: uri. getContext().getContentResolver().notifyChange(imageContentUri, null); .
If you are implementing for android-4.4 or later You can ask the media scanner to (re)analyse your file. For details see How to trigger MediaScan on Nexus 7? . in pre android-4.4 this might not work as expected (i.e. on my android-4.2 it starts a complete rescan)
My application creates photo and then inserts it into stock camera's bucket of gallery. (I want photos to be stored near other photos taken by standard camera)
Following code does this:
ContentValues values = new ContentValues();
values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, taken_at);//msec
values.put(MediaStore.Images.ImageColumns.DATE_ADDED, taken_at/1000);//sec
values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, taken_at/1000);//sec
values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.ImageColumns.TITLE, fileName);
values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.ImageColumns.ORIENTATION, orientation);// << ORIENTATION
values.put(MediaStore.Images.ImageColumns.DATA, dir+"/"+fileName);
uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
OutputStream os = getContentResolver().openOutputStream(uri);
// WRITE JPEG BINARY DATA
When I select last two photos (one taken by stock camera, second - by my app) from MediaStore.Images.Media.EXTERNAL_CONTENT_URI, I get following:
fields:
_id, bucket_id, date_added, date_modified, datetaken, _display_name,
orientation, title
fields values of photo taken by stock camera:
4471, 856031460, 1323942742, 1323942742, 1323942742189, 2011-12-15 15.52.22.jpg,
90, 2011-12-15 15.52.22.jpg
values of photo taken by my app:
4470, 856031460, 1323942722, 1323942722, 1323942722545, 2011-12-15 15.52.02.jpg
90, 2011-12-15 15.52.02.jpg
So far, so good. It displays in gallery correctly. Problem appears when I remount sdcard and media scanner finishes his work:
stock camera's photo after re-mounting sdcard
1241, 856031460, 1323942742, 1323942742, 1323942742189, 2011-12-15 15.52.22.jpg
90, 2011-12-15 15.52.22.jpg
my app's photo after re-mounting sdcard
1242, 856031460, 1323943033, 1323942722, 1323942722000, 2011-12-15 15.52.02.jpg
0, 2011-12-15 15.52.02
// WTF? orientation defaulted, date_added and date_modified were updated
It look like these photos are re-inserted, BUT NOW my app's photo is re-inserted with default values of fields(including orientation) while stock camera's photo values didn't change(excepting _id)!
Now my app's photos are displayed in gallery incorrectly (rotated, because orientation was reset), while stock camera's are OK.
How does media scanner recognize relation between record in media db and file it scans now? Looks like it can't do that in my case, removes old record, "linked to nonexistent file" and inserts new "never inserted before" record.
Any ideas, how to fix this?
PS: both photos are located in same directory
MediaScanner scans files in directories, and in case of photos, it scans photo's header, that contains EXIF tags, and takes ORIENTATION, DATE_TAKEN, DATE_MODIFIED tags from it.
If this data is not equal to data in database then database data is replaced.
If you faced this problem, you need to update ORIENTATION exif tag manually with valid value.
Also I must mention that Android exif manager is very buggy and you might want to use org.apache.sanselan library that works great.