Download Manager gets the error below on Android 10 devices. The target version is 29.
I added android:requestLegacyExternalStorage="true" tag to the Manifest, but it didn't work.
java.lang.SecurityException: Unsupported path /storage/emulated/0/Contents/Awesome App.apk
Here is the code
public static void startDownload(Context context, String url, String token, String subPath) {
DownloadManager.Request request;
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse(url); // A url to download a file
try {
request = new DownloadManager.Request(uri);
request.addRequestHeader("X-Auth-Token", token);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
}
request.setVisibleInDownloadsUi(true);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
try {
File downloadFileDir = new File(Environment
.getExternalStorageDirectory().getAbsolutePath() + "/Contents");
if (downloadFileDir != null) {
if (!downloadFileDir.exists()) {
downloadFileDir.mkdirs();
}
File file = new File(downloadFileDir.getAbsolutePath() + File.separator + subPath);
// subPath is name of the file to download. e.g. Awesome App.apk
if (file.exists()) {
file.delete();
}
Uri localUri = Uri.fromFile(file);
request.setDestinationUri(localUri);
if (localUri != null) {
request.setMimeType(MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(localUri.toString())));
}
}
} catch (SecurityException e) {
e.printStackTrace();
}
request.setTitle(subPath);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
try {
manager.enqueue(request);
} catch (SecurityException e) {
e.printStackTrace();
//Got exception here
}
}
/storage/emulated/0/Contents/Awesome App.apk
In an Android 10 device the DownloadManager will not download to your own directories on external storage.
You need to use one of the already available public directories like Document, Download, DCIM, Music and so on.
So you can let download to
/storage/emulated/0/Music/Contents/Awesome App.apk
No need to create your subdirectory yourself as the download manager will do it.
You app does not need any permission to let the download manager execute its task.
Related
I am writing a new Application on Android 11 (SDK Version 30) and I simply cannot find an example on how to save a file to the external storage.
I read their documentation and now know that they basicly ignore Manifest Permissions (READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE). They also ignore the android:requestLegacyExternalStorage="true" in the manifest.xml application tag.
In their documentation https://developer.android.com/about/versions/11/privacy/storage they write you need to enable the DEFAULT_SCOPED_STORAGE and FORCE_ENABLE_SCOPED_STORAGE flags to enable scoped storage in your app.
Where do I have to enable those?
And when I've done that how and when do I get the actual permission to write to the external storage? Can someone provide working code? I want to save .gif, .png and .mp3 files. So I don't want to write to the gallery.
Thanks in advance.
Corresponding To All Api, included Api 30, Android 11 :
public static File commonDocumentDirPath(String FolderName)
{
File dir = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
{
dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + FolderName);
}
else
{
dir = new File(Environment.getExternalStorageDirectory() + "/" + FolderName);
}
// Make sure the path directory exists.
if (!dir.exists())
{
// Make it, if it doesn't exit
boolean success = dir.mkdirs();
if (!success)
{
dir = null;
}
}
return dir;
}
Now, use this commonDocumentDirPath for saving file.
A side note from comments, getExternalStoragePublicDirectory with certain scopes are now working with Api 30, Android 11. Cheers! Thanks to CommonsWare hints.
You can save files to the public directories on external storage.
Like Documents, Download, DCIM, Pictures and so on.
In the usual way like before version 10.
**Simplest Answer and Tested ( Java ) **
private void createFile(String title) {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("text/html");
intent.putExtra(Intent.EXTRA_TITLE, title);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Uri.parse("/Documents"));
}
createInvoiceActivityResultLauncher.launch(intent);
}
private void createInvoice(Uri uri) {
try {
ParcelFileDescriptor pfd = getContentResolver().
openFileDescriptor(uri, "w");
if (pfd != null) {
FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
fileOutputStream.write(invoice_html.getBytes());
fileOutputStream.close();
pfd.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/////////////////////////////////////////////////////
// You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed
String invoice_html;
ActivityResultLauncher<Intent> createInvoiceActivityResultLauncher;
#Override
protected void onCreate(Bundle savedInstanceState) {
invoice_html = "<h1>Just for testing received...</h1>";
createInvoiceActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Uri uri = null;
if (result.getData() != null) {
uri = result.getData().getData();
createInvoice(uri);
// Perform operations on the document using its URI.
}
}
});
I'm using this method and it really worked for me
I hope I can help you. Feel free to ask me if something is not clear to you
Bitmap imageBitmap;
OutputStream outputStream ;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
ContentResolver resolver = context.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME,"Image_"+".jpg");
contentValues.put(MediaStore.MediaColumns.MIME_TYPE,"image/jpeg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH,Environment.DIRECTORY_PICTURES + File.separator+"TestFolder");
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues);
try {
outputStream = resolver.openOutputStream(Objects.requireNonNull(imageUri) );
imageBitmap.compress(Bitmap.CompressFormat.JPEG,100,outputStream);
Objects.requireNonNull(outputStream);
Toast.makeText(context, "Image Saved", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(context, "Image Not Not Saved: \n "+e, Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
manifest file (Add Permission)
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
I am downloading mp3 file from this url using DownloadManager. Here is my code.
// Downloading file from internet and save to internal storage.
private void downloadFromOnline() {
downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
DownloadManager.Request request = null;
request = new DownloadManager.Request(Uri.parse("https://alquran.technobdapis.com/quranallaudio/arabic_with_bangla/arbn_001.mp3"));
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
request.setAllowedOverRoaming(false);
request.setTitle("Downloading...");
request.setDescription("Downloading...arbn_001.mp3");
request.setVisibleInDownloadsUi(true);
File SDCardpath = getFilesDir();
File myDataPath = new File(SDCardpath.getAbsolutePath());
// Internal storage file path to save the downloaded file
// /data/data/com.technobd.internalstoragetest/files/arabic_with_bangla/arbn_001.mp3
if (!myDataPath.exists())
myDataPath.mkdir();
request.setDestinationInExternalFilesDir(getApplicationContext(), myDataPath.getPath() + "/arabic_with_bangla", "arbn_001.mp3");
long refid = downloadManager.enqueue(request);
id = refid;
}
I have tried to play the downloaded file in media player using this code. But unfortunately targetFile.exists() returns false although file exists in that path. Here is the code -
public BroadcastReceiver onComplete = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
File SDCardpath = getFilesDir();
File myDataPath = new File(SDCardpath.getAbsolutePath());
File targetFile = new File(myDataPath.getPath() + "/arabic_with_bangla/" +"arbn_001.mp3");
Log.d("FileExists", targetFile.exists() + " ");
// Downloaded file path
// /data/data/com.technobd.internalstoragetest/files/arabic_with_bangla/arbn_001.mp3
// Although target file exists in device It's targetFile.exists() returning false
// TODO: This is the main problem.
if(targetFile.exists()){
MediaPlayer mp = new MediaPlayer();
try {
mp.setDataSource(MainActivity.this, Uri.parse(targetFile.getParent()));
mp.prepare();
mp.start();
} catch (Exception e) {
e.printStackTrace();
}
}else{
// File Not Exists
Log.d("FileExists", targetFile.exists() + " ");
}
}
};
File exists in my device.
Want to store music file inside getFilesDir() using Uri. I had tried to store by this way
Uri Download_Uri = Uri.parse(songBean.vSongsFileName);
DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
request.setAllowedOverRoaming(false);
request.setTitle(songBean.vTitle);
request.setDescription("Downloading File");
try {
request.setDestinationUri(Uri.parse(createDirectory("tmp.mp3").getPath()));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
downloadReference = mDownloadManager.enqueue(request);
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
}, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
Method for the create directory inside internal storage
public File createDirectory(String filename) throws FileNotFoundException {
File file = new File(context.getFilesDir(), filename);
Log.i("Tag", "createDirectory: " + file.getAbsolutePath());
return file;
}
Not able to store the file in internal storage.request.setDestinationUri(Uri.parse(createDirectory("tmp.mp3").getPath())); throwing not a file uri error.Please help me out for this
The getFilesDir() is private internal storage for your app only. You cannot ask another app to put files there as it has no access.
For DownloadManager use external storage.
this is my code and i want to add resumable feature but i couldn't is it posible?
downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
Uri Download_Uri = Uri.parse("http://download.thinkbroadband.com/20MB.zip");
DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
//Restrict the types of networks over which this download may proceed.
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
//Set whether this download may proceed over a roaming connection.
request.setAllowedOverRoaming(false);
//Set the title of this download, to be displayed in notifications (if enabled).
request.setTitle("My Data Download");
//Set a description of this download, to be displayed in notifications (if enabled)
request.setDescription("Android Data download using DownloadManager.");
//Set the local destination for the downloaded file to a path within the application's external files directory
request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS,"20MB.zip");
//Enqueue a new download and same the referenceId
downloadReference = downloadManager.enqueue(request);
I was able to implement Pause/Resume functionality using the following implementation via the Android DownloadManager and Downloads Content Provider:
private boolean resumeDownload(Context context, String downloadTitle) {
int updatedRows = 0;
ContentValues resumeDownload = new ContentValues();
resumeDownload.put("control", 0); // Resume Control Value
try {
updatedRows = context
.getContentResolver()
.update(Uri.parse("content://downloads/my_downloads"),
resumeDownload,
"title=?",
new String[]{ downloadTitle });
} catch (Exception e) {
Log.e(TAG, "Failed to update control for downloading video");
}
return 0 < updatedRows;
}
private boolean pauseDownload(Context context, String downloadTitle) {
int updatedRows = 0;
ContentValues pauseDownload = new ContentValues();
pauseDownload.put("control", 1); // Pause Control Value
try {
updatedRows = context
.getContentResolver()
.update(Uri.parse("content://downloads/my_downloads"),
pauseDownload,
"title=?",
new String[]{ downloadTitle });
} catch (Exception e) {
Log.e(TAG, "Failed to update control for downloading video");
}
return 0 < updatedRows;
}
i'm trying to develop an app that shows video and you can download it on your mobile
the app is working perfectly, but my problem is that the download arrow doesn't appear in notification bar.
I'm using download manager class.
Here's my method:
public void downloadFileFromUrl(String url, String fileName, DownloadManager downloadManager) {
String filePath=Environment.getExternalStorageDirectory() + File.separator + "BlueNet";
try {
Uri downloadUri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(downloadUri);
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
request.setDestinationInExternalPublicDir("/BlueNet",fileName);
request.setNotificationVisibility(
DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setVisibleInDownloadsUi(true);
request.allowScanningByMediaScanner();
idDwnldMng= downloadManager.enqueue(request);
}
catch (Exception ex){
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show();
}
}
Can someone help me?
Seems like you missing the permission:
<uses-permission
android:name="WRITE_EXTERNAL_STORAGE" />