android: how to add an image to an album - android

Can anyone share code (or point me to Android sample code) to help me add images to an album in the Media Store (Gallery).
In my app I download images from our server, and also take new images using the camera (via Intent).
I would like to organize those images in an app-specific album, similar to what the Facebook (and other apps) app does, keeping related images all neatly organized.
I looked into this a while ago, following the Media Store API docs, and it didn't work for me....so need some help.
Thanks

This is a method used to store an image in the public Picture folder, with a custom app folder in it.
public void saveImageToExternal(String imgName, Bitmap bm) throws IOException {
//Create Path to save Image
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES+appFolder); //Creates app specific folder
path.mkdirs();
File imageFile = new File(path, imgName+".png"); // Imagename.png
FileOutputStream out = new FileOutputStream(imageFile);
try{
bm.compress(Bitmap.CompressFormat.PNG, 100, out); // Compress Image
out.flush();
out.close();
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(context,new String[] { imageFile.getAbsolutePath() }, null,new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
} catch(Exception e) {
throw new IOException();
}
}

you can use:
MediaStore.Images.Media.insertImage(ContentResolver cr, Bitmap source, String title, String description);
and I'm sure that somewhere here http://developer.android.com/guide/ in some of the sub-menus shows a command asking the MediaStore to scan a determined folder, I just can't find it now.
edit:
found it:
MediaScannerConnection.scanFile(Context context, String[] path, null, null);

Here is the code I ended up using to do this:
public static Uri addToTouchActiveAlbum( Context context, String title, String filePath ) {
ContentValues values = new ContentValues();
values.put( Media.TITLE, title );
values.put( Images.Media.DATE_TAKEN, System.currentTimeMillis() );
values.put( Images.Media.BUCKET_ID, filePath.hashCode() );
values.put( Images.Media.BUCKET_DISPLAY_NAME, Constants.TA_PHOTO_ALBUM_NAME );
values.put( Images.Media.MIME_TYPE, "image/jpeg" );
values.put( Media.DESCRIPTION, context.getResources().getString( R.string.product_image_description ) );
values.put( MediaStore.MediaColumns.DATA, filePath );
Uri uri = context.getContentResolver().insert( Media.EXTERNAL_CONTENT_URI , values );
return uri;
}
It works for the Images I have in "getExternalStorage()" (/storage/sdcard0)
I'd also like to add images I have in a different folder (a cacheDir I create under the folder returned by Context.getExternalCacheDir()). Problem: I don't know their mime-type (does that matter?), the folder is a different one in a different location with a different name - and I can't figure out how to add to an "album" per se.....as the album name seems to come from the folder name....
Or to put it another way:
values.put( Images.Media.BUCKET_DISPLAY_NAME, Constants.TA_PHOTO_ALBUM_NAME );
doesn't seem to have any effect?

Related

Temporary creating bitmaps in Android then deleting them

So I am working on a project where if a manager registers a user he gets an email with a QR code (bitmap). The QR code is saved in cache. I want the QR code removed after the QR code is sent to the user, but a "cache" folder gets created (also shows up in gallery), and the image itself gets deleted but it remains there ( you cant see it, but its there as a grey square).
Any idea how to remove the created folder and the created bitmap compeletely?
My code:
BitmapSaver(Context mContext){
this.mContext=mContext;
this.cache = new DiskBasedCache(mContext.getCacheDir(), 1024 * 1024);
}
public static File saveImageToExternalStorage(Context context, Bitmap finalBitmap) {
destFolder =context.getCacheDir().getAbsolutePath();
String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
// myDir = new File(root + "/saved_images");
// myDir.mkdirs();
long n = System.currentTimeMillis() / 1000L;
fname = "Image-" + n + ".jpg";
//file2 = new File(destFolder);
file = new File(destFolder+"/"+fname);
if (file.exists())
file.delete();
try {
Log.i("path",destFolder+"/"+fname);
FileOutputStream out = new FileOutputStream(destFolder+"/"+fname);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
MediaScannerConnection.scanFile(context, new String[]{file.toString()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
url = Uri.parse(path);
Log.i("External",url.toString());
}
});
return file;
}
In Activity after email is sent:
BitmapSaver bms = new BitmapSaver(RegisterActivity.this);
bms.saveImageToExternalStorage(RegisterActivity.this, bitmap);
bms.file.delete();
First of all you need to know what MediaScannerConnection.scanFile does. It will update the file information to the current device, so other applications like gallery, file explorer, etc, can show the correct file information and content.
From your code, when you are saving the temporary file, you are also scanning it, because your app has changed the corresponding file, which is creating the file to be exact. So the file will be available to the other applications right away. But, since the file location is in your application cache directory, it will not accessible by other applications. Usually you must restart your device to update the file information if you don't call MediaScanner.scanFile. If you are creating a temporary file, I think you don't need to call MediaScanner.scanFile, since you will delete it right away.
Then after delete, you also need to re-scan the file again, so other applications will know that the file has been deleted.
Also, despite of using MediaScannerConnection.scanFile directly, if you are supporting android version < KitKat, you should broadcast with intent action Intent.ACTION_MEDIA_MOUNTED instead. And I also recommend that you are broadcasting the data directly, because from my experience MediaScannerConnection.scanFile failed from one of my test devices.
Intent mediaScanIntent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(Uri.fromFile(new File(imagePath)));
} else {
Uri fileUri = Uri.parse("file://" + imagePath);
mediaScanIntent = new Intent(Intent.ACTION_MEDIA_MOUNTED, fileUri);
}
context.sendBroadcast(mediaScanIntent);

Android - Why my saved image is not appearing in the default gallery of my phone?

I am trying to save an image from my application to the default gallery of my phone. The code below works perfectly if I have a SD card on the phone. The image saved appears in the phone's gallery and everything, as expected:
private Uri saveMediaEntry(File f, String title, String description, int orientation, Location loc) {
ContentValues v = new ContentValues();
v.put(Images.Media.TITLE, title);
v.put(Images.Media.DISPLAY_NAME, title);
v.put(Images.Media.DESCRIPTION, description);
v.put(Images.Media.ORIENTATION, orientation);
String nameFile = f.getName();
File parent = f.getParentFile() ;
String path = parent.toString().toLowerCase() ;
String nameParent = parent.getName().toLowerCase() ;
v.put(Images.ImageColumns.BUCKET_ID, path.hashCode());
v.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, nameParent);
v.put(Images.Media.SIZE,f.length()) ;
if( nameFile.toLowerCase().contains(".png") ){
v.put(Images.Media.MIME_TYPE, "image/png");
}else if( nameFile.toLowerCase().contains(".jpg") ||
nameFile.toLowerCase().contains(".jpeg") ){
v.put(Images.Media.MIME_TYPE, "image/jpeg");
}else{
v.put(Images.Media.MIME_TYPE, "image/jpeg");
}
String imagePath = f.getAbsolutePath();
v.put("_data", imagePath) ;
ContentResolver c = getContentResolver() ;
Uri uriOfSucessfulySavedImage = null;
uriOfSucessfulySavedImage = c.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, v);
return uriOfSucessfulySavedImage;
}
However, if I try to save the same image into the internal storage (for when the phone does not have a SD card), the image does not appear in the phone's gallery! To try to do that, I only change one line from the above code:
uriOfSucessfulySavedImage = c.insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, v);
The interesting thing about this, however, is that the variable uriOfSucessfulySavedImage is not null (it returns content://media/internal/images/media/x, where 'x' is a number). So, the image is being saved somewhere in the internal storage of the phone, but it is not getting displayed in the phone gallery's as when I use MediaStore.Images.Media.EXTERNAL_CONTENT_URI.
Does anybody have any clue what is going on? How can I save an image into the internal storage of the phone and have that image in the phone's gallery?
Update
I forgot one important information. The File "f" in the parameters of the method "saveMediaEntry" is coming from this other method for when the SD card is mounted (that is, for the first code):
public static File getCacheDirectory(String desiredNameOfTheDirectory){
File fileCacheDir = null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ){
fileCacheDir = new File( Environment.getExternalStorageDirectory(), desiredNameOfTheDirectory );
}
if(!fileCacheDir.exists()){
fileCacheDir.mkdirs();
}
return fileCacheDir;
}
and from the following code for when the SD card is not founded:
public static File getCacheDirectory(String desiredNameOfTheDirectory, Context context){
File fileCacheDir = null;
fileCacheDir = context.getCacheDir();
if(!fileCacheDir.exists()){
fileCacheDir.mkdirs();
}
return fileCacheDir;
}
Another easy way to do it. Add this after saving your file.
File imageFile = ...
MediaScannerConnection.scanFile(this, new String[] { imageFile.getPath() }, new String[] { "image/jpeg" }, null);
I haven't tried this, but I believe you need to run the Media Scanner to scan the internal storage directory so that the gallery can see your newly saved image. Check this post here.
Copy Past this Function in your Activity
private void scanner(String path) {
MediaScannerConnection.scanFile(FrameActivity.this,
new String[] { path }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("TAG", "Finished scanning " + path);
}
});
}
And then add this Line where you save your image
scanner(imageFile.getAbsolutePath());
Try this.
Write down this line once image stored in gallery.
File file = ..... // Save file
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
Uri.parse("file://"
+ Environment.getExternalStorageDirectory())));
} else {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://"
+ Environment.getExternalStorageDirectory())));
}

store images with MediaStore to specific folder

I was searching a bit on how to add images using the mediastore since I'm currently doing it manual with
final String myBitmap = "MyImage_"+ mFileDate + ".png";
File fileNumber = new File(APP_FILE_PATH, myBitmap);
out = new FileOutputStream( fileNumber );
final Bitmap mBitmap =getBitmap();
mBitmap.compress( Bitmap.CompressFormat.PNG, 85, out );
out.flush();
however I need the IDs that media manager uses to store since its easier to manage id rather than paths and such.
I tried adding it this way:
ContentValues values = new ContentValues();
values.put(Images.Media.TITLE, mFileName.getName());
values.put(Images.Media.DESCRIPTION, getString(R.string.bitdraw_description));
values.put(Images.Media.MIME_TYPE, "image/png");
Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);
out = getContentResolver().openOutputStream(uri);
mBitmap.compress( Bitmap.CompressFormat.PNG, 85, out );
out.flush();
however this adds the image to the folder where the photos are saved and not to the specific folder I want to.
Also tried this after the manual (first part):
Media.insertImage(getContentResolver(), mFileName.getPath(), mFileName.getName(), getString(R.string.description));
but this only generates duplicates since the image was saved first by the outputStream
A workaround I found on a thread here is to call a broadcast like this:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse ("file://"+ Environment.getExternalStorageDirectory())));
but this is rather inneficient and takes long, and I want it to be the fastest, and I'm quite unsure if this actually generates the IDs, and if it does, how could I make this to scan only a specific folder in the SD ??
Any help would be appreciated.

Create a custom album in the Android Gallery App

I want create a new 'album' in Android. I unserstood that you have to do it with your own ContentProvider. But i can't figure out how. If you take pictures, all the images appear in the album 'Camera'. If you have installed Google+ you'll see 2 extra albums: Instant Upload & Profile Picture.
We want to create something similar. We have an album per user online and we want that it appears as an album item in the Gallery app. Can someone point me in the right direction.
I already checked: http://developer.android.com/guide/topics/providers/content-providers.html
Actually im not really sure if it is possible.
You can use this way to create album in Gallery app. The name appears as 'app images'.
String path = Environment.getExternalStorageDirectory().toString();
File dir = new File(path, "/appname/media/app images/");
if (!dir.isDirectory()) {
dir.mkdirs();
}
File file = new File(dir, filename + ".jpg");
String imagePath = file.getAbsolutePath();
//scan the image so show up in album
MediaScannerConnection.scanFile(this,
new String[] { imagePath }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
if(Config.LOG_DEBUG_ENABLED) {
Log.d(Config.LOGTAG, "scanned : " + path);
}
}
});

Android MediaStore insertVideo

So our app has the option to take either a picture or a video. If the user takes a picture, we can use the MediaStore.Images.Media.insertImage function to add the new image (via a filepath) to the phone's gallery and generate a content:// style URI. Is there a similar process for a captured video, given that we only have it's filepath?
Here is an easy 'single file based solution':
Whenever you add a file, let MediaStore Content Provider knows about it using
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(imageAdded)));
Main advantage: work with any mime type supported by MediaStore
Whenever you delete a file, let MediaStore Content Provider knows about it using
getContentResolver().delete(uri, null, null)
I'm also interested, could you find a solution?
Edit: solution is RTFM. Based on the "Content Providers" chapter here is my code that worked:
// Save the name and description of a video in a ContentValues map.
ContentValues values = new ContentValues(2);
values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
// values.put(MediaStore.Video.Media.DATA, f.getAbsolutePath());
// Add a new record (identified by uri) without the video, but with the values just set.
Uri uri = getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
// Now get a handle to the file for that record, and save the data into it.
try {
InputStream is = new FileInputStream(f);
OutputStream os = getContentResolver().openOutputStream(uri);
byte[] buffer = new byte[4096]; // tweaking this number may increase performance
int len;
while ((len = is.read(buffer)) != -1){
os.write(buffer, 0, len);
}
os.flush();
is.close();
os.close();
} catch (Exception e) {
Log.e(TAG, "exception while writing video: ", e);
}
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
If your app is generating a new video and you simply want to give the MediaStore some metadata for it, you can build on this function:
public Uri addVideo(File videoFile) {
ContentValues values = new ContentValues(3);
values.put(MediaStore.Video.Media.TITLE, "My video title");
values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
values.put(MediaStore.Video.Media.DATA, videoFile.getAbsolutePath());
return getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
}
EDIT: As of Android 4.4 (KitKat), this method no longer works.
I was unable to get the Intent.ACTION_MEDIA_SCANNER_SCAN_FILE broadcast to work for me under API 21 (Lollipop), but the MediaScannerConnection does work, e.g.:
MediaScannerConnection.scanFile(
context, new String[] { path }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.d(TAG, "Finished scanning " + path + " New row: " + uri);
}
} );
Try this code. It seems working for me.
filePath = myfile.getAbsolutePath();
ContentValues values = new ContentValues();
values.put(MediaStore.Video.Media.DATA, filePath);
return context.getContentResolver().insert(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
Example of filePath -
/storage/emulated/0/DCIM/Camera/VID_20140313_114321.mp4

Categories

Resources