First in my app I let system downloader app download an apk for me. Then I use This code to install the apk file downloaded by Android default download manager:
if (getFileId() == downloadId) {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + getFileName());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else {
Uri apkUri = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
This code automatically runs when download is finished and a download receiver is called. And it works well. Problem is if user clicks on the notification made by default system download manager (Download complete notification), in API >= 23, I get a "Can't open file" message, which is very annoying (For any reason user might want to click on the notification). I want user be able to install apk file when they click on the notification, which is already working at api<23. How can I solve this problem?
Most likely it has to do with the way that Android 7.0 handles permissions as compared to 6.0. You need to request permissions in a different way since Android 7.0. Try to tinker with the ContextCompat.checkSelfPermission() method. The message would be shown because the permission to open file is not requested with this method. Here's a little snippet to get you on the right track:
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
YourRequestCode);
}
Here, thisActivity is your current activity.
Related
I'm working an app where I'm downloading android apk files and installing them from within the app. After downloading the app, I have a method to Install the app.
This is the method below, The broadcast receiver is activated once the download is completed, and destination, is the file path in which the apk has been downloade
fun installApp (receiver: BroadcastReceiver, destination: String, uri: Uri) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val contentUri = FileProvider.getUriForFile(
context,
BuildConfig.APPLICATION_ID + PROVIDER_PATH,
File(destination)
)
val install = Intent(Intent.ACTION_VIEW)
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
.data = contentUri
context.startActivity(install)
context.unregisterReceiver(receiver)
} else {
val install = Intent(Intent.ACTION_VIEW)
install.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
install.setDataAndType(uri, APP_INSTALL_PATH)
context.startActivity(install)
context.unregisterReceiver(receiver)
}
}
But I need to be able to know if the user selects Install now or Install later. So that if install later is clicked, I can trigger a notification that will pop up, so the user can decide to click on the notification and install the app at a later time.
I've searched but can't really find suitable answers, maybe my search parameters, but if this has been answered already, I'll appreciate a redirection to that link.
I am trying to open a file manager that will show the folder that I send to it via Intent. The file manager should act like a file manager and not a file picker, i.e. it will not return to my app once I decide to select a file from the given folder, but it will present standard options that are normally available when file manager is launched from the launcher icon.
I have tried the following:
File folder = getOutputFolder();
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// I have tried: ACTION_VIEW, ACTION_GET_CONTENT, ACTION_OPEN_DOCUMENT
Uri uri;
if (Build.VERSION.SDK_INT >= 26) {
String authority = getString(R.string.app_fileprovider);
uri = FileProvider.getUriForFile(this, authority, folder);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
uri = Uri.fromFile(folder);
}
// this with ACTION_GET_CONTENT, works as *picker* on API 28
// on API 29 it does not open destination folder
// intent.setData(uri);
intent.setDataAndType(uri, "*/*");
// I have tried the following: image/*, file/*, */*, resource/folder
// and DocumentsContract.Document.MIME_TYPE_DIR
startActivity(Intent.createChooser(intent, getString(R.string.open_output_folder)));
All combinations that I have tried act as a file picker, and that's not what I am looking for. More than that, some combinations open the destination folder, some not. The behavior is different depending on API level as well.
Is there a standard way to achieve what I am looking for?
I have tried to open particular folder in gallary as below code but it didn't work for me, and getting error for Unable to find item.
fun openDirectoryInGallery(context: Context, directory: String) {
val intent = Intent(Intent.ACTION_VIEW)
val file = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), directory)
} else {
File(Environment.DIRECTORY_PICTURES.plus(File.separator).plus(directory))
}
intent.setDataAndType(Uri.withAppendedPath(Uri.fromFile(file), directory), "*/*")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(context, Intent.createChooser(intent, "Open folder"), Bundle())
}
There has never been support for this in the OS. This is a question of the installed apps on the device.
There has never been a requirement that a device have a gallery app that is able to respond to ACTION_VIEW for a directory.
Your app should be crashing with a FileUriExposedException on Android 7.0+, and the existence of that exception is why fewer and fewer apps are bothering to support the file scheme.
On Android 10+, the file scheme (and Uri.fromFile() by extension) is simply pointless, as if your app can access the file, other apps cannot.
Finally, Environment.DIRECTORY_PICTURES.plus(File.separator).plus(directory) is not a valid filesystem path.
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"SelectPicture"),PICK_IMAGE_REQUEST);
In my application I download an apk from a server and save it on the device. This apk is used to update the app. If the download is finished the user is prompted to do so by using the following code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(getApplicationContext(), BuildConfig.APPLICATION_ID + ".provider", updateAPK);
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
} else {
Uri apkUri = Uri.fromFile(updateAPK);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
This is working like it should, but my question is: Is ist possible to get the result of the intent, so I can check whether the user cancelled the installation or not?
Divide your scenario into three scenarios, not two.
On devices older than API Level 14, use ACTION_VIEW with a file Uri. Note that you do not need FLAG_ACTIVITY_NEW_TASK — or, more accurately, you should be consistent in either using it or not using it across all three scenarios.
On devices that are API Level 14-23, use ACTION_INSTALL_PACKAGE with a file Uri. Set EXTRA_RETURN_RESULT to true, and use startActivityForResult().
On devices that are API Level 24+, use ACTION_INSTALL_PACKAGE with a content Uri, as you are doing. Set EXTRA_RETURN_RESULT to true, and use startActivityForResult().
In those latter two scenarios, onActivityResult() will report whether the user installed the app (RESULT_OK) or not.
We've been trying to solve this issue for the past few hours, finally decided we should revert to StackOverflow.
Here goes -
We have an application that downloads a PDF file from a server to the app's cache directory and then opens it using the packet manager. Of course it goes through grantUriPermission() to give read (and write) permissions to all available packages.
Though it works great on most devices, today we encountered a device that has POLARIS Office 5 installed as the default PDF viewer.
Whenever we're opening the file, Polaris simply displays a message saying "This document cannot be opened".
I should say that when trying to open the file through Acrobat Reader, it works great.
Also, when we copied the file from the cache directory to an external directory (using Android's File manager) and then opened it in Polaris manually it worked great.
We would have given up on it, but since Polaris is the default viewer on many devices, we really would love solving that problem.
Here is the code -
public void onDownloadDone(String filepath) {
// Set a file object that represents the downloaded file
File file = new File(filepath);
// Set an intent for the external app
Intent intent = new Intent(Intent.ACTION_VIEW);
// Get mime type of the downloaded file
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(filepath);
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);
intent.setType(mimeType);
// Look for installed packges according to the file's mime type
PackageManager pm = context.getPackageManager();
Uri contentUri = FileProvider.getUriForFile(context, "myapp.fileprovider", file);
// Set the file uri in the intent
intent.setData(contentUri);
// Give permissions to the file to each external app that can open the file
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
for (ResolveInfo externalApp: activities){
String packageName = externalApp.activityInfo.packageName;
context.grantUriPermission(packageName, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
// Start the activities (or launch the menu) if any activity exists
if (activities.size() > 0){
context.startActivity(intent);
} else {
System.out.println("Warning!!! No app for file " + filepath);
}
}
Thank a lot!
I had exactly the same problem. The PDF files would open with ezPDF and Adobe but not with Polaris Viewer.
You have to set the data and type with:
intent.setDataAndType(uri, "application/pdf");
instead of using:
intent.setType("application/pdf");
intent.setData(uri);
For me the following is working fine with Polaris now:
Uri uri = FileProvider.getUriForFile(MyApplication.getContext(), MyApplication.getContext().getPackageName() + ".myfileprovider", destFile);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/pdf");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);