I can't open any file from Download Folder.
I can download a file and save in Download Folder with this:
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription(descricao);
request.setTitle(titulo);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, nome);
enq = downloadManager.enqueue(request);
After this, my file is correct saved at Directory Folder: Android >> Internal Shared Storage >> Download.
***This path I see manually opening the device's hd in ubuntu. As the image shows the path.
Android HD by ubuntu folder - see the path
And I try open this file with this:
downloadManager = (DownloadManager)getContext().getSystemService(DOWNLOAD_SERVICE);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(enq);
Cursor c = downloadManager.query(query);
if(c.moveToFirst()) {
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
if(DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
if (uriString.substring(0, 7).matches("file://")) {
uriString = uriString.substring(7);
}
File file = new File(uriString);
Uri uriFile = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID + ".fileprovider", file);
String mimetype = "application/pdf";
Intent myIntent = new Intent(Intent.ACTION_VIEW);
myIntent.setDataAndType(uriFile, mimetype);
Intent intentChooser = Intent.createChooser(myIntent, "Choose Pdf Application");
startActivity(intentChooser);
}
}
}
}
};
getContext().registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
I declare my file provider in manifest with this:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
and with this:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="Download" path="Download/"/>
</paths>
But when I click the button to download I receive this message: "This file coud be not accessed. Check the location or the network and try again."
Resuming:
1 - The file is downloaded and saved at the directory folder.
2 - The intent is started, but the file is not openned.
3 - Debug mode give me this at "new File(urlString)": "urlString=/storage/emulated/0/Download/name.pdf"
4 - At "FileProvider.getUriFromFile..." debug mode have this:
"uriFile = content://com.example.android.parlamentaresapp.fileprovider/Download/name.pdf"
Thank you.
Call addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) on the Intent that you use with startActivity() and the FileProvider Uri. Without that, the activity has no rights to access your content.
Related
I have written a method that check new version of my APP and when it exists, the application download and it should install that. But it can not install the downloaded application and it gives me this error:
There was a problem parsing the package.
But when I uninstall my app and install it again with the downloaded apk file. Everything works fine so my app downloads the file correctly.
But why this could not install it programmatically?
This is my Download code:
public long downloadFromUrl(String url, String fileName, String format) {
String fullFileName = fileName + format;
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url))
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)// Visibility of the download Notification
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fullFileName)// Uri of the destination file
.setTitle(fullFileName)// Title of the Download Notification
.setDescription("Downloading...");// Description of the Download Notification
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
long id = downloadManager.enqueue(request);
if (format.equals(APK_FORMAT)) {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fullFileName);
if(file.exists()){
DownloadReceiver downloadReceiver = new DownloadReceiver(file);
Intent intent = new Intent();
downloadReceiver.onReceive(context,intent);
context.registerReceiver(downloadReceiver,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
}
return id;
}
This is a receiver that when download is completed, runs:
#Override
public void onReceive(Context context, Intent intent) {
long receivedId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if (file != null) {
Uri uri = FileProvider.getUriForFile(context,context.getApplicationContext().getPackageName()+ ".provider",file);
intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
Uri uri;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", destination);
} else {
uri = Uri.fromFile(destination);
}
//Log.d("path",uri.getPath());
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivity(intent);
make sure you have added this permission to your manifest file
Also make sure both version of your APKs are signed and with same key.
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
I made it work with this code (destination is file object).
I'm trying to open downloaded pdf file trough implicit intent using FileProvider.
I'm using DownloadManager for downloading pdf file from remote server, It's working fine. Which is store at it's destination.
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(DownloadURL));
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
request.setAllowedOverRoaming(false);
request.setTitle(mFilename);
request.setDescription("Downloading...");
request.setVisibleInDownloadsUi(true);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "/FOLDER_NAME/" + mFilename);
After Finishing Download i want to open it.
public void OpenPdfFile(){
File sharedFile = new File(Environment.DIRECTORY_DOWNLOADS, "/FOLDER_NAME/" + mFilename);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri uri = FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID+ ".provider", sharedFile);
intent.setDataAndType(uri, "application/pdf");
PackageManager pm = mContext.getPackageManager();
if (intent.resolveActivity(pm) != null) {
mContext.startActivity(intent);
}
}
in Manifest file
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
and the provider_paths.xml as like
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external-path" path="." />
</paths>
it troughs me this error
java.lang.IllegalArgumentException: Failed to find configured root that contains /Download/FOLDER_NAME/demo_presentationfile.PDF
Any suggestions ?
File sharedFile = new File(Environment.DIRECTORY_DOWNLOADS, "/FOLDER_NAME/" + mFilename);
That evaluates to an impossible file system path. Which you would see if you inspected the value of sharedFile.getAbsolutePath().
Change to:
File sharedFile = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS), "FOLDER_NAME/" + mFilename);
I am downloading images from internet with DownloadManager and want to display them in Gallery app. I am saving the images to default 'Download' dir. Download works fine, I get notified of success. The gallery app opens, but doesn't display the image. What could be the problem?
Here's my code:
Cursor cursor = ((DownloadManager) getSystemService(DOWNLOAD_SERVICE)).query(ImageDownloadQuery);
if (cursor.moveToFirst()) {
String path = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
File file = new File(URI.create(path));
Uri uri = FileProvider.getUriForFile(ConversationDetailsActivity.this,
BuildConfig.APPLICATION_ID + ".fileprovider",
file);
Intent viewIntent = new Intent(Intent.ACTION_VIEW, uri);
viewIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
viewIntent.setType(cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE)));
if (getPackageManager().resolveActivity(viewIntent, 0) != null) { // checking if there is an app installed that can handle this type of files
startActivity(viewIntent);
} else { // app that can view this file type is not found
Toast.makeText(getBaseContext(), "Please install an application to view this type of files", Toast.LENGTH_SHORT).show();
}
}
FileProvider paths:
<paths>
<cache-path
name="cache"
path=""
/>
<external-path
name="download"
path="Download/"
/>
</paths>
And manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"
/>
</provider>
Here's a fix for those who are wondering. Remember to always set intent data and type. Setting one clears the other.
DownloadManager.Query ImageDownloadQuery = new DownloadManager.Query();
ImageDownloadQuery.setFilterById(referenceId);
Cursor cursor = ((DownloadManager) getSystemService(DOWNLOAD_SERVICE)).query(ImageDownloadQuery);
if (cursor.moveToFirst()) {
String path = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
File file = new File(URI.create(path));
Uri uri = FileProvider.getUriForFile(ConversationDetailsActivity.this,
BuildConfig.APPLICATION_ID + ".fileprovider",
file);
Intent viewIntent = new Intent(Intent.ACTION_VIEW);
viewIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
viewIntent.setDataAndType(uri, cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE)));
if (getPackageManager().resolveActivity(viewIntent, 0) != null) { // checking if there is an app installed that can handle this type of files
startActivity(viewIntent);
} else { // app that can view this file type is not found
Toast.makeText(getBaseContext(), "Please install an application to view this type of files", Toast.LENGTH_SHORT).show();
}
}
My bad. I set the intent type without setting data, so it cleared the Uri. Check original question for answer.
In my app I have a custom auto download and install APK it works like this
// auto register for the complete download
activity.registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
// Download the file through DownloadManager
String destination = Environment.getExternalStorageDirectory() + "/";
String fileName = "myfile.apk";
destination += fileName;
final Uri uri = Uri.parse("file://" + destination);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl));
request.setDescription("description");
request.setTitle("title");
request.setDestinationUri(uri);
final DownloadManager manager = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
final long downloadId = manager.enqueue(request);
onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
Intent install = new Intent(Intent.ACTION_VIEW);
// BEFORE working doing this
//install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//install.setDataAndType(uri,
// manager.getMimeTypeForDownloadedFile(downloadId));
// Using file provider it doesnt work
Uri apkUri = FileProvider.getUriForFile(AutoUpdate.this,
"com.myapp", file);
install.setDataAndType(apkUri,manager.getMimeTypeForDownloadedFile(downloadId));
activity.startActivity(install);
activity.unregisterReceiver(this);
}
};
Android manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.myapp"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
Provider_path (Sorry for some reason so cuts the path tag)
external-path name="myfolder" path="."/>
When the file finished to download the onComplete is called but the activiy doesn't start:
No Activity found to handle Intent { act=android.intent.action.VIEW
dat=content://com.myapp/myfolder/myfile.apk
typ=application/vnd.android.package-archive flg=0x4000000 }
When using the normal file:// it does work
Is there something I'm missing when using the file provider? Does the activity doesn't start because the file is not found ?
Do I need extra permission ? (at the moment I have INTERNET, READ and WRITE on external storage)
The package installer only supports content schemes starting on Android 7.0. Prior to that — and despite documentation to the contrary — the package installer only supports file schemes.
You will need to set the Uri on your Intent differently based on whether you are running on Android 7.0+ or not, such as by branching on Build.VERSION.SDK_INT.
Commonware is right,
For those looking for the code:
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
downloadButton.setEnabled(true);
downloadButton.setText("Terminado");
progressbar.setVisibility(View.GONE);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Uri apkURI = FileProvider.getUriForFile(
self,
self.getApplicationContext()
.getPackageName() + ".provider", file);
install.setDataAndType(apkURI,
manager.getMimeTypeForDownloadedFile(downloadId));
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(install);
} else{
String destination = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/";
String fileName = "surveyevent.apk";
destination += fileName;
Uri uri = Uri.parse("file://" + destination);
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setDataAndType(uri,
manager.getMimeTypeForDownloadedFile(downloadId));
startActivity(install);
}
unregisterReceiver(this);
finish();
}
};
Your provider is not found because
android:enabled="true"
is missing in your manifest.
But then it will not work either reading the other answer of CW.
I want to open an image from internal folder with the android default image viewer, on the Nexus 7 tablet.
I use the following code,but for some reason the image is not displayed. What I'm doing wrong? The path to the file is :
file:///data/data/com.example.denandroidapp/files/Attachments/photoTemp/photo.jpg
(this is what Uri.parse("file://" + file) returns).
ArticlePhoto photo = new ArticlePhoto(soapObject);
File f = new File(context.getFilesDir() + "/Attachments/photoTemp");
if(!f.exists())
f.mkdirs();
if (photo.ArtPhoto != null) {
Bitmap articlePhoto = BitmapFactory.decodeByteArray(photo.ArtPhoto, 0, photo.ArtPhoto.length);
ByteArrayOutputStream bytesFile = new ByteArrayOutputStream();
articlePhoto.compress(Bitmap.CompressFormat.JPEG, 100, bytesFile);
File file = new File(f + "/photo.jpeg");
try {
if(!file.exists())
file.createNewFile();
FileOutputStream outStream = new FileOutputStream(file);
outStream.write(bytesFile.toByteArray());
outStream.close();
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + file),"image/jpeg");
startActivity(intent);
} catch(Exception ex) {
AlertDialog alert = new AlertDialog.Builder(context).create();
alert.setTitle("Warning!");
alert.setMessage(ex.getMessage());
alert.show();
}
}
Try with this :
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.parse("file://" + file.getAbsolutePath());
intent.setDataAndType(uri,"image/*");
startActivity(intent);
Thanks.
The problem is that the image is internal to your application! So an external application (Image Viewer) has no access to the data that is internal to your application.
What you might have to do is create a Content Provider .
http://web.archive.org/web/20111020204554/http://www.marcofaion.it/?p=7
Android Manifest.xml
<provider android:authorities="com.example.denandroidapp" android:enabled="true" android:exported="true" android:name=<fully classified name of provider class>>
</provider>
Creating Intent
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.parse("content://com.example.denandroidapp/" + filename);
intent.setDataAndType(uri, "image/jpeg");
If a file is associated with your app (stored on the internal storage of your app space ), other apps can not access your file directly provided a valid file path. Instead, you have to create a file provider and generate a content uri.
First, add the file provider in your AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
Then you need to create an a file named file_paths in xml/file_paths.xml (the directory xml is not created by default, so create it).
file_paths.xml looks like
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="myFiles" path="./"/>
</paths>
add as much as paths you want your provider to access in .
atlast you need to create your intent
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
File imagePath = new File(context.getFilesDir(), "fileName");
Uri contentUri = FileProvider.getUriForFile(context, "com.mydomain.fileprovider", imagePath);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(contentUri,"image/*");
context.startActivity(intent);
Note: make sure the file path sepecefied in file_paths.xml and new File(context.getFilesDir(),"fileName"), matches. getFilesDir() will give you the root directory of your app.
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(outputFileName)),"image/jpeg");
startActivity(intent);
You can use FileProvider which extends ContentProvider
Check the link -
https://developer.android.com/reference/android/support/v4/content/FileProvider
To specify the FileProvider component itself, add a "provider" element to your app manifest.
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
You must specify a child element of "paths" for each directory that contains files for which you want content URIs. For example, these XML elements specify two directories
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_images" path="images/"/>
<files-path name="my_docs" path="docs/"/>
</paths>
After this you need to generate content URI for the file and then call the intent, refer the below link
https://developer.android.com/reference/android/support/v4/content/FileProvider#GetUri
Check this: https://stackoverflow.com/a/11088980/1038442;
File file = new File(filePath);
MimeTypeMap map = MimeTypeMap.getSingleton();
String ext = MimeTypeMap.getFileExtensionFromUrl(file.getName());
String type = map.getMimeTypeFromExtension(ext);
if (type == null)
type = "*/*";
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.fromFile(file);
intent.setDataAndType(data, type);
startActivity(intent);
PS: if your are trying to open .jpg files, try to
Replace String ext = MimeTypeMap.getFileExtensionFromUrl(file.getName());
With String ext = MimeTypeMap.getFileExtensionFromUrl(".jpg");
Good luck.
In my case, The gallery launched but did not show any images and went straight to the home page. My situation is quite different from what OP faced but I think it's worth mentioning here since the question is about images not being shown through implicit intent.
My problem came from the code below.
val intent = context.packageManager.getLaunchIntentForPackage(packageName ?: "")
The code above tells PackageManager to launch the entry point of the application, instead of the activity that shows the images.
If you look at the Logcat above, you can find that the intent launched with cat=[android.intent.category.Launcher] will go to SplashActivity. This happened because I created the intent with getLaunchIntentForPackage()
Alternative is to use Intent with setPackage() like the code in below
val intent = Intent()
val uri = Uri.fromFile(file) // You should probably replace with ContentProvider's uri
intent.apply {
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
action = Intent.ACTION_VIEW
setPackage(packageName)
setDataAndType(uri, "image/*")
}
context.startActivity(intent)