This post provides codes for downloading Bitmap image to Downloads folder and for copying image file from Assets or Cache to Downloads folder.
1. Download Bitmap image to Downloads folder
Create a new java file ImageDownloader.java and put following codes in it. Add your package name at the top.
import android.content.ContentResolver;
import android.content.ContentValues;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class ImageDownloader {
/**
* Save bitmap to Downloads folder (API 29+ uses MediaStore, older uses File API)
*/
public static boolean saveBitmapToDownloads(Context context, Bitmap bitmap, String fileName) {
if (bitmap == null) {
return false;
}
// Add timestamp to make filename unique
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
String finalFileName = (fileName != null ? fileName : "image") + "_" + timeStamp + ".jpg";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// For Android 10+ (API 29+) use MediaStore
return saveBitmapViaMediaStore(context, bitmap, finalFileName);
} else {
// For older versions use File API
return saveBitmapViaFile(context, bitmap, finalFileName);
}
}
@RequiresApi(Build.VERSION_CODES.Q)
private static boolean saveBitmapViaMediaStore(Context context, Bitmap bitmap, String fileName) {
ContentResolver resolver = context.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
Uri imageUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
if (imageUri == null) {
return false;
}
try (OutputStream outputStream = resolver.openOutputStream(imageUri)) {
if (outputStream != null) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
return true;
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private static boolean saveBitmapViaFile(Context context, Bitmap bitmap, String fileName) {
// Check for storage permission for Android 6.0+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (context.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Permission not granted
return false;
}
}
File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
if (!downloadsDir.exists()) {
downloadsDir.mkdirs();
}
File imageFile = new File(downloadsDir, fileName);
try (FileOutputStream outputStream = new FileOutputStream(imageFile)) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
outputStream.flush();
// Notify media scanner about the new file
scanFile(context, imageFile);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
private static void scanFile(Context context, File file) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(Uri.fromFile(file));
context.sendBroadcast(mediaScanIntent);
}
}
To use it in Activity, if you have a Bitmap image called bitmap, use following codes on button click event.
boolean success = ImageDownloader.saveBitmapToDownloads(
this,
bitmap,
"my_image"
);
if (success) {
Toast.makeText(this, "Image saved to Downloads", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Failed to save image", Toast.LENGTH_SHORT).show();
}2. Copy image from Assets or Cache to Downloads folder.
Create a new java file FileCopier.java and put following codes in it. Put your package name at the top.
import android.content.Context;
import android.content.res.AssetManager;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
public class FileCopier {
/**
* Copy file from Assets folder to Downloads folder
*/
public static boolean copyFromAssetsToDownloads(Context context, String assetFileName, String destFileName) {
AssetManager assetManager = context.getAssets();
try (InputStream inputStream = assetManager.open(assetFileName)) {
return copyInputStreamToDownloads(context, inputStream, destFileName);
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* Copy file from Cache directory to Downloads folder
*/
public static boolean copyFromCacheToDownloads(Context context, String cacheFileName, String destFileName) {
File cacheFile = new File(context.getCacheDir(), cacheFileName);
if (!cacheFile.exists()) {
return false;
}
try (InputStream inputStream = new java.io.FileInputStream(cacheFile)) {
return copyInputStreamToDownloads(context, inputStream, destFileName);
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* Copy file from Internal Storage to Downloads folder
*/
public static boolean copyFromInternalStorageToDownloads(Context context,
String sourceFileName,
String destFileName) {
File internalFile = new File(context.getFilesDir(), sourceFileName);
if (!internalFile.exists()) {
return false;
}
try (InputStream inputStream = new java.io.FileInputStream(internalFile)) {
return copyInputStreamToDownloads(context, inputStream, destFileName);
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
private static boolean copyInputStreamToDownloads(Context context, InputStream inputStream, String destFileName) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// For Android 10+
return copyViaMediaStore(context, inputStream, destFileName);
} else {
// For older versions
return copyViaFileAPI(context, inputStream, destFileName);
}
}
@RequiresApi(Build.VERSION_CODES.Q)
private static boolean copyViaMediaStore(Context context, InputStream inputStream, String fileName) {
ContentResolver resolver = context.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
// Detect MIME type from file extension
String mimeType = getMimeType(fileName);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
Uri fileUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
if (fileUri == null) {
return false;
}
try (OutputStream outputStream = resolver.openOutputStream(fileUri)) {
if (outputStream != null) {
copyStream(inputStream, outputStream);
return true;
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private static boolean copyViaFileAPI(Context context, InputStream inputStream, String fileName) {
// Check permission for older Android versions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (context.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
}
File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
if (!downloadsDir.exists()) {
downloadsDir.mkdirs();
}
File destFile = new File(downloadsDir, fileName);
try (FileOutputStream outputStream = new FileOutputStream(destFile)) {
copyStream(inputStream, outputStream);
// Notify media scanner
scanFile(context, destFile);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
private static void copyStream(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[1024];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.flush();
}
private static void scanFile(Context context, File file) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(Uri.fromFile(file));
context.sendBroadcast(mediaScanIntent);
}
private static String getMimeType(String fileName) {
String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
switch (extension) {
case "jpg":
case "jpeg":
return "image/jpeg";
case "png":
return "image/png";
case "gif":
return "image/gif";
case "webp":
return "image/webp";
case "pdf":
return "application/pdf";
case "txt":
return "text/plain";
default:
return "application/octet-stream";
}
}
}To use it in Activity, use following codes in on button click event.
Copy image file (name sample_image.jpg) from Assets folder to Downloads folder with name copied_image.jpg.
// Copy from Assets to Downloads
boolean success = FileCopier.copyFromAssetsToDownloads(
this,
"sample_image.jpg", // File name in assets folder
"copied_image.jpg" // Destination file name
);
if (success) {
Toast.makeText(this, "File copied from Assets", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Failed to copy file", Toast.LENGTH_SHORT).show();
}
Copy image file (name cached_image.jpg) from cache folder to Downloads folder with name restored_image.jpg.
// Copy from Cache to Downloads
boolean success = FileCopier.copyFromCacheToDownloads(
this,
"cached_image.jpg", // File name in cache directory
"restored_image.jpg" // Destination file name
);
if (success) {
Toast.makeText(this, "File copied from Cache", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Failed to copy file", Toast.LENGTH_SHORT).show();
}3. Permissions required
In AndroidManifest.xml file
<!-- For Android 9 and below -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<!-- Optional: For Android 10+ if you want to access files after saving -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<!-- For Android 13+ -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />Runtime permissions for WRITE_EXTERNAL_STORAGE required in Android M and above.
- Android 10+ (API 29+): Uses MediaStore API with scoped storage
- Android 9 and below: Uses traditional File API with WRITE_EXTERNAL_STORAGE permission