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).
Problem 1: I have a pdf stored in
Environment.getExternalStorageDirectory() --> /storage/emulated/0/appname/downloads/sample.pdf
I'm sending it using normal way as shown:
File iconsStoragePath = Environment.getExternalStorageDirectory();
final String selpath = iconsStoragePath.getAbsolutePath() + "/appname/downloads/";
Intent intent = new Intent(Intent.ACTION_SEND);
Uri selectedUri = Uri.parse(selpath + "/" + item.getFilename());
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(selectedUri.toString());
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);
intent.setType(mimeType);
intent.putExtra(Intent.EXTRA_STREAM, selectedUri);
startActivity(Intent.createChooser(intent, "Share File"));
Now the result is
The problem is file is sharing without the filename.
Problem 2: When I'm trying to use the file provider the pdf is not sharing gives me an error:
Unable to share. Please try again
Environment.getFilesDir() --> /data/data/com.myapp.name/files/myapp/downloads/sample.pdf
Manifest File:
<application>
<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/nnf_provider_paths" />
</provider>
</application>
xml/nnf_provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<files-path
name="root"
path="myapp/downloads" />
Code:
File path = new File(getFilesDir(), "downloads");
File file = new File(documentsPath + "/" + filename);
Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), AUTHORITY, file);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, contentUri);
intent.setType("application/pdf");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
Which is the better way of doing it ?
I would personally prefer #2. Read this article on how to use ShareCompat to create ShareIntents
Regarding your problem with approach #2, I guess you're missing .setData or .setDataAndUri:
This is a sample snippet which works for me for sharing images via FileProviders:
public static void shareImage(Activity context) {
Log.d(TAG, "initializing share image");
File imgPath = new File(context.getCacheDir(), DEFAULT_TEMP_DIR_NAME);
File newFile = new File(imgPath, DEFAULT_TEMP_FILENAME);
String authority = context.getPackageName() + ".fileprovider";
Log.d(TAG, "authority: " + authority);
Uri contentUri = FileProvider.getUriForFile(context, authority, newFile);
if (contentUri != null) {
Intent shareIntent = ShareCompat.IntentBuilder.from(context)
.setType("image/png")
.setStream(contentUri)
.setSubject(context.getString(R.string.share_subject))
.setText(context.getString(R.string.share_message))
.setEmailTo(new String[]{"example#example.com"})
.getIntent();
shareIntent.setData(contentUri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(Intent.createChooser(
shareIntent, context.getString(R.string.share_chooser_title)));
}
}
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.
I want to open a saved image in gallery on Android Nougat but what I get is a black gallery page with message "Can't load the photo".
That's my code:
Manifest
<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>
provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
Path generated in DrawView
public static boolean save(Bitmap bitmap){
Date now = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MM-yyyy'_'HH:mm");
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "Crash");
if (!folder.exists()) {
folder.mkdirs();
}
FileOutputStream fos = null;
try {
lastImagePath = new File(Environment.getExternalStorageDirectory().toString() + "/Crash/" + simpleDateFormat.format(now) + ".jpg");
fos = new FileOutputStream(lastImagePath);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
fos = null;
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {}
}
}
}
Open Image Listener
private class OpenImageListener implements View.OnClickListener{
#Override
public void onClick(View v) {
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N){
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + DrawView.getLastImagePath().getAbsolutePath()), "image/*");
startActivity(intent);
} else {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri photoUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", DrawView.getLastImagePath());
intent.setData(photoUri);
startActivity(intent);
}
}
}
Maybe I generate a wrong path for the image, but with old version it works (I tried on Marshmallow and works great).
Can someone help me? Thanks.
In your else block in onClick(), after calling setData() on your Intent to set the Uri, call addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) on the Intent.
As it stands, the other app has no rights to work with the content identified by the Uri. Adding FLAG_GRANT_READ_URI_PERMISSION does this.
This is covered in the FileProvider documentation, along with modern books on Android app development.
I do expire the same issue with almost all apps I tried, my code is the same as yours and as far as the google docs say it looks to be correct...
The only "solution" I can offer you is to compile against version 23(https://source.android.com/source/build-numbers.html) to avoid the forced strict mode for file URIs.
Of course you also have to downgrade your Android support libs in case you are using them.
If someone has a better idea please share...
To view image from mobile emulated gallery is no more difficult but in nougat is quite different i have run time image created and wants to see that image its failed many times but finally its run with this code
1.after a long struggle i write this code , dont forget to add, fil provider in mainfest file as you may know .
MimeTypeMap map = MimeTypeMap.getSingleton();
String ext = MimeTypeMap.getFileExtensionFromUrl(file.getName());
String type = map.getMimeTypeFromExtension(ext);
if (type == null)
type = "*/*";
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// only for gingerbread and newer versions
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri photoUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
intent.setDataAndType(photoUri, type);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION|Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
}
else{
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.fromFile(file);
intent.setDataAndType(data, type);
context.startActivity(intent);
}
I have extracted image uri, now I would like to open image with Android's default image viewer. Or even better, user could choose what program to use to open the image. Something like File Explorers offer you if you try to open a file.
Accepted answer was not working for me,
What had worked:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + "/sdcard/test.jpg"), "image/*");
startActivity(intent);
If your app targets Android N (7.0) and above, you should not use the answers above (of the "Uri.fromFile" method), because it won't work for you.
Instead, you should use a ContentProvider.
For example, if your image file is in external folder, you can use this (similar to the code I've made here) :
File file = ...;
final Intent intent = new Intent(Intent.ACTION_VIEW)//
.setDataAndType(VERSION.SDK_INT >= VERSION_CODES.N ?
FileProvider.getUriForFile(this,getPackageName() + ".provider", file) : Uri.fromFile(file),
"image/*").addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
manifest:
<provider
android:name="androidx.core.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>
res/xml/provider_paths.xml :
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!--<external-path name="external_files" path="."/>-->
<external-path
name="files_root"
path="Android/data/${applicationId}"/>
<external-path
name="external_storage_root"
path="."/>
</paths>
If your image is in the private path of the app, you should create your own ContentProvider, as I've created "OpenFileProvider" on the link.
Ask myself, answer myself also:
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("content://media/external/images/media/16"))); /** replace with your own uri */
It will also ask what program to use to view the file.
Try use it:
Uri uri = Uri.fromFile(entry);
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
String mime = "*/*";
MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
if (mimeTypeMap.hasExtension(
mimeTypeMap.getFileExtensionFromUrl(uri.toString())))
mime = mimeTypeMap.getMimeTypeFromExtension(
mimeTypeMap.getFileExtensionFromUrl(uri.toString()));
intent.setDataAndType(uri,mime);
startActivity(intent);
Based on Vikas answer but with a slight modification: The Uri is received by parameter:
private void showPhoto(Uri photoUri){
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(photoUri, "image/*");
startActivity(intent);
}
This thing might help if your working with android N and below
File file=new File(Environment.getExternalStorageDirectory()+"/directoryname/"+filename);
Uri path= FileProvider.getUriForFile(MainActivity.this,BuildConfig.APPLICATION_ID + ".provider",file);
Intent intent=new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(path,"image/*");
intent.setFlags(FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION); //must for reading data from directory
A much cleaner, safer answer to this problem (you really shouldn't hard code Strings):
public void openInGallery(String imageId) {
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendPath(imageId).build();
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
All you have to do is append the image id to the end of the path for the EXTERNAL_CONTENT_URI. Then launch an Intent with the View action, and the Uri.
The image id comes from querying the content resolver.
All the above answers not opening image.. when second time I try to open it show the gallery not image.
I got solution from mix of various SO answers..
Intent galleryIntent = new Intent(Intent.ACTION_VIEW, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
galleryIntent.setDataAndType(Uri.fromFile(mImsgeFileName), "image/*");
galleryIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(galleryIntent);
This one only worked for me..
The problem with showing a file using Intent.ACTION_VIEW, is that if you pass the Uri parsing the path. Doesn't work in all cases. To fix that problem, you need to use:
Uri.fromFile(new File(filePath));
Instead of:
Uri.parse(filePath);
Edit
Here is my complete code:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(mediaFile.filePath)), mediaFile.getExtension());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Info
MediaFile is my domain class to wrap files from database in objects.
MediaFile.getExtension() returns a String with Mimetype for the file extension. Example: "image/png"
Aditional code: needed for showing any file (extension)
import android.webkit.MimeTypeMap;
public String getExtension () {
MimeTypeMap myMime = MimeTypeMap.getSingleton();
return myMime.getMimeTypeFromExtension(MediaFile.fileExtension(filePath));
}
public static String fileExtension(String path) {
if (path.indexOf("?") > -1) {
path = path.substring(0, path.indexOf("?"));
}
if (path.lastIndexOf(".") == -1) {
return null;
} else {
String ext = path.substring(path.lastIndexOf(".") + 1);
if (ext.indexOf("%") > -1) {
ext = ext.substring(0, ext.indexOf("%"));
}
if (ext.indexOf("/") > -1) {
ext = ext.substring(0, ext.indexOf("/"));
}
return ext.toLowerCase();
}
}
Let me know if you need more code.
I use this it works for me
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), 1);
My solution using File Provider
private void viewGallery(File file) {
Uri mImageCaptureUri = FileProvider.getUriForFile(
mContext,
mContext.getApplicationContext()
.getPackageName() + ".provider", file);
Intent view = new Intent();
view.setAction(Intent.ACTION_VIEW);
view.setData(mImageCaptureUri);
List < ResolveInfo > resInfoList =
mContext.getPackageManager()
.queryIntentActivities(view, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo: resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
mContext.grantUriPermission(packageName, mImageCaptureUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
view.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(mImageCaptureUri, "image/*");
mContext.startActivity(intent);
}
Almost NO chance to use photo or gallery application(might exist one), but you can try the content-viewer.
Please checkout another answer to similar question here
My solution
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath()+"/your_app_folder/"+"your_picture_saved_name"+".png")), "image/*");
context.startActivity(intent);
The uri must be content uri not file uri,
You can get contentUri by FileProvider as
Uri contentUri = FileProvider.getUriForFile(getContext(),"com.github.myApp",curFile);
Don't forget adding provider in Manifest file.
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.github.myApp"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>