How to open file via intent right after downloading? - java

I need to open downloaded file by any relevant activity outside my app.
I download file via DownloadManager to default folder Environment.DIRECTORY_DOWNLOADS
I registered BroadcastReceiver in my activity, which shall to open file right after download via intent:
#Override
public void onReceive(Context context, Intent intent) {
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
DownloadManager downloadManager = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
if (downloadManager != null) {
Cursor c = downloadManager.query(new DownloadManager.Query().setFilterById(downloadId));
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));
Intent openIntent = new Intent(Intent.ACTION_VIEW);
openIntent.setDataAndType(Uri.parse(uriString), getMimeType(uriString));
openIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(Intent.createChooser(openIntent, "Выберите приложение"));
}
}
}
}
}
But right after downloading I got an exception:
java.lang.RuntimeException: Error receiving broadcast Intent
caused by android.os.FileUriExposedException: file:///storage/emulated/0/Download/sample-20.pdf exposed beyond app through ClipData.Item.getUri()
What's wrong?

Correct way to open downloaded file with FileProvider
#Override
public void onReceive(Context context, Intent intent) {
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
DownloadManager downloadManager = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
if (downloadManager != null) {
Cursor c = downloadManager.query(new DownloadManager.Query().setFilterById(downloadId));
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));
Intent openIntent = new Intent(Intent.ACTION_VIEW);
File file = new File(URI.create(uriString));
Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileprovider", file);
openIntent.setDataAndType(uri, getMimeType(uriString));
openIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(Intent.createChooser(openIntent, "Выберите приложение"));
}
}
}
}
}
String getMimeType(String path) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(path);
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
return type;
}

Related

Android CursorIndexOutOfBoundsException

public static String getRealPath(Uri uri, Context context) {
File file = new File(uri.getPath());
String[] filePath = file.getPath().split(":");
String fileId = filePath[filePath.length - 1];
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null,
MediaStore.Images.Media._ID + " = ? ",
new String[]{fileId},
null);
if (cursor != null) {
cursor.moveToNext();
int columnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
String realPath = cursor.getString(columnIndex);
cursor.close();
return realPath;
}
return null;
}
this is My code ( uri to path )
When bringing up an image, it brings the absolute path well. But when I call the file, I can't call it.
When i called file Like this..
Intent fileChoose = new Intent(Intent.ACTION_OPEN_DOCUMENT);
fileChoose.setType("*/*");
fileChoose.setAction(Intent.ACTION_GET_CONTENT);
fileLauncher.launch(fileChoose);
and Receive Like this..
private final ActivityResultLauncher<Intent> fileLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
if (result != null) {
if (result.getData() != null) {
File file = new File(Objects.requireNonNull(CommFunc.getRealPath(result.getData().getData(), FileChooserActivity.this)));
}
}
}
});
and i called Image Like this..
Intent galleryIntent = new Intent();
galleryIntent.setType("image/*");
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
setResult(RESULT_OK, galleryIntent);
galleryLauncher.launch(Intent.createChooser(galleryIntent, "Select Picture"));

Error Receiving broadcast Intent while installing the apk programatically with in the custom app

Im building an application in which im downloading an apk from firebase using download manager and want to automatically install apk within the app after completing download. but i got an parse error so i researched for some correct code and used it but than it throw an error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.amazoneindia.amazone_india, PID: 25402
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.DOWNLOAD_COMPLETE flg=0x80010 pkg=com.amazoneindia.amazone_india (has extras) } in com.amazoneindia.amazone_india.AppDetail$5#288a748
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1654)
at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:227)
at android.app.ActivityThread.main(ActivityThread.java:7822)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1026)
Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
at android.app.ContextImpl.startActivity(ContextImpl.java:978)
at android.app.ContextImpl.startActivity(ContextImpl.java:944)
at android.content.ContextWrapper.startActivity(ContextWrapper.java:394)
at com.amazoneindia.amazone_india.AppDetail$5.onReceive(AppDetail.java:287)
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1623)
at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2) 
at android.os.Handler.handleCallback(Handler.java:883) 
at android.os.Handler.dispatchMessage(Handler.java:100) 
at android.os.Looper.loop(Looper.java:227) 
at android.app.ActivityThread.main(ActivityThread.java:7822) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1026) 
here is my install apk code
private final String APP_INSTALL_PATH = "\"application/vnd.android.package-archive\"";
public void installAPK(String destination, Uri uri, Context context) {
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
Uri fileProvider = FileProvider.getUriForFile(
context,
BuildConfig.APPLICATION_ID + ".provider",
new File(destination));
Intent install = new Intent(Intent.ACTION_VIEW);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
install.setData(fileProvider) ;
context.startActivity(install);
context.unregisterReceiver(this);
} else {
Intent install = new Intent(Intent.ACTION_VIEW);
install.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setDataAndType(
uri,
APP_INSTALL_PATH
);
context.startActivity(install);
context.unregisterReceiver(this);
}
}
};
context.registerReceiver(broadcastReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
here is code for downloadapk():
//installtion permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!getPackageManager().canRequestPackageInstalls()) {
startActivityForResult(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).setData(Uri.parse(String.format("package:%s", getPackageName()))), 1234);
} else {
}
}
//Storage Permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
final ProgressDialog progressBarDialog= new ProgressDialog(this);
progressBarDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressBarDialog.setTitle("Downloading...");
progressBarDialog.setProgress(0);
String destination = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/";
String fileName = Common.Apkname+".apk";
destination += fileName;
final Uri uri = Uri.parse("file://" + destination);
//Delete update file if exists
File file = new File(destination);
if (file.exists())
//file.delete() - test this, I think sometimes it doesnt work
file.delete();
String url = Common.Url;
DownloadManager.Request r = new DownloadManager.Request(Uri.parse(url));
r.setDestinationInExternalFilesDir(this,Environment.DIRECTORY_DOWNLOADS, Common.Apkname+".apk");
r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
DownloadManager dm = (DownloadManager)getApplicationContext().getSystemService(Context.DOWNLOAD_SERVICE);
r.setDestinationUri(uri);
final long downloadId =dm.enqueue(r);
String finalDestination = destination;
new Thread(new Runnable() {
#Override
public void run() {
boolean downloading = true;
while (downloading) {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadId);
Cursor cursor = dm.query(q);
cursor.moveToFirst();
int bytes_downloaded = cursor.getInt(cursor
.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false;
}
final double dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);
runOnUiThread(new Runnable() {
#Override
public void run() {
progressBarDialog.setProgress((int) dl_progress);
progressBarDialog.setCanceledOnTouchOutside(false);
}
});
cursor.close();
}
progressBarDialog.dismiss();
installAPK();
}
}).start();
progressBarDialog.show();

Android: How to avoid downloading a file again which is currently downloading

public class RemoteApkInstaller {
public void install(String url) {
listenForDownloadCompleteEvent();
downloadApk(url);
}
private void listenForDownloadCompleteEvent() {
IntentFilter downloadCompleteIntentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
downloadCompleteReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (isInitiatedApkDownload(intent)) {
if (isDownloadSuccessful()) {
handleDownloadComplete();
} else {
Toast.makeText(context, R.string.download_error, Toast.LENGTH_SHORT).show();
logFailure();
}
context.unregisterReceiver(downloadCompleteReceiver);
}
}
};
context.registerReceiver(downloadCompleteReceiver, downloadCompleteIntentFilter);
}
private void downloadApk(String url) {
Uri uri = Uri.parse(url);
apkFileName = uri.getLastPathSegment();
if (isFileExistsInDownloadDir()) {
handleDownloadComplete();
return;
}
DownloadManager.Request request = getDownloadRequest(uri);
downloadID = getDownloadManager().enqueue(request);
}
private boolean isFileExistsInDownloadDir() {
File directory = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
File file = new File(directory, apkFileName);
return file.exists();
}
private void handleDownloadComplete() {
doOperationsOnDownloadedPackage()
installApk(context);
}
private void doOperationsOnDownloadedPackage() {
PackageManager packageManager= getApplicationContext().getPackageManager();
String appName = (String) packageManager.getApplicationLabel(packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA));
...
}
private void installApk(Context context) {
File directory = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
File file = new File(directory, apkFileName);
String mimeType = downloadID == UNSET_DOWNLOAD_ID ? MIME_TYPE_FOR_APK_FILE : getDownloadManager().getMimeTypeForDownloadedFile(downloadID);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
Uri apkUri = FileProvider.getUriForFile(context, "my.package.fileProvider", file);
installIntent.setDataAndType(apkUri, mimeType);
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(installIntent);
} else {
Uri apkUri = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, mimeType);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
}
Basically when I click a weblink, an instance of this class is created and the install() method invoked. The problem is when I click the weblink again while the previous download is still only partially complete. I'm trying to check the downloads folder to determine if file already exists and if so, proceed with next set of action.
Even if the previous download is partially complete, the flag is true so in this case I'm executing the doOperationsOnDownloadedPackage() method on an apk file which is not 100% downloaded and I see crashes obviously.
What I'm looking for is a way to avoid initiating a repeat download if the same file is currently downloading.
Any help appreciated.
Thanks

Select multiple images from Photo Gallery on Android using Intents NullPointerException

I try to select multiple images from photo gallery and save it in my custom folder on sdCard.
I wrote some code but i have nullPintException
this is a my source
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"), PICK_FROM_GALLERY);
and this is OnActivityResultCode
if(data!=null)
{
ClipData clipData = data.getClipData();
for (int i = 0; i < clipData.getItemCount(); i++)
{
Uri selectedImage = clipData.getItemAt(i).getUri();
if (selectedImage != null) {
mCurrentPhotoPath = getRealPathFromURI(selectedImage);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, options);
// bitmap=getResizedBitmap(bitmap,1280,720);
String partFilename = currentDateFormat();
if (bitmap != null) {
SaveImage(bitmap, partFilename);
}
}
}
public String getRealPathFromURI(Uri uri) {
Cursor cursor = CarRecieveActivity.this.getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
return cursor.getString(idx);
}
private void SaveImage(Bitmap finalBitmap,String fileName) {
File myDir = new File(rootDirectory + "/"+vinNumber.getText().toString());
myDir.mkdirs();
String fname = fileName+".jpg";
File file = new File (myDir, fname);
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
this is my source .i have two errors.
first when i click only one image in my gallery clipData is null and second,when i choose multiple images from gallery and click ok button i have this error
java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it
error is in this function getRealPathFromURI()
how i can solve both problems?
thanks
Select images from device
//Uri to store the image uri
private List<Uri> filePath;
public String path[];
public static List<ImageBeen> listOfImage;
//Image request code
private int PICK_IMAGE_REQUEST = 1;
private int PICK_IMAGE_REQUEST_MULTI = 2;
// select multiple image
private void pickImages() {
filePath = new ArrayList<>();
listOfImage = new ArrayList<>();
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST_MULTI);
}else {
intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST);
}
}
Activity result
//handling the image chooser activity result
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST_MULTI && resultCode == RESULT_OK && data != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ClipData imagesPath = data.getClipData();
if (imagesPath != null) {
path = new String[imagesPath.getItemCount()];
for (int i = 0; i < imagesPath.getItemCount(); i++) {
filePath.add(imagesPath.getItemAt(i).getUri());
path[i] = getPath(imagesPath.getItemAt(i).getUri());
ImageBeen imageBeen = new ImageBeen(imagesPath.getItemAt(i).getUri());
imageBeen.setPath(path[i]);
listOfImage.add(imageBeen);
initViewPager();
}
}else {
path = new String[1];
path[0] = getPath(data.getData());
ImageBeen imageBeen = new ImageBeen(data.getData());
imageBeen.setPath(path[0]);
listOfImage.add(imageBeen);
initViewPager();
}
} else if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {
path = new String[1];
path[0] = getPath(data.getData());
ImageBeen imageBeen = new ImageBeen(data.getData());
imageBeen.setPath(path[0]);
listOfImage.add(imageBeen);
initViewPager();
}
}
genarate images path using Image URI
//method to get the file path from uri
public String getPath(Uri uri) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
String path = null;
if(cursor!=null) {
if (cursor.moveToFirst()) {
String document_id = cursor.getString(0);
document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
cursor.close();
cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
cursor.moveToFirst();
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
return path;
}
}
return path;
}
This is image bean where stored image URI and Image path
public class ImageBeen {
private Uri fileUri;
private String path;
public ImageBeen(Uri fileUri)
{
this.fileUri=fileUri;
}
public String getPath() {
return path;
}
public void setPath(String path)
{
this.path=path;
}
public Uri getFileUri() {
return fileUri;
}
}
For display image use Picasso
compile 'com.squareup.picasso:picasso:2.5.2'
Picasso.with(context)
.load(imageBeen.getFileUri())
.placeholder(R.drawable.not_vailable)
.error(R.drawable.not_vailable)
.into(holder.image);

Listening for downloads from browser/getting name of downloaded file

Is there any way to listen for/detect a file being downloaded in Android? Also, can I programmatically get the name of the downloading file?
You have to use a BroadcastReceiver (After api 9). Like this:
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);
Query query = new Query();
query.setFilterById(enqueue);
Cursor c = dm.query(query);
if (c.moveToFirst()) {
int columnIndex = c
.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (DownloadManager.STATUS_SUCCESSFUL == c
.getInt(columnIndex)) {
ImageView view = (ImageView) findViewById(R.id.imageView1);
String uriString = c
.getString(c
.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
view.setImageURI(Uri.parse(uriString));
}
}
}
}
};
registerReceiver(receiver, new IntentFilter(
DownloadManager.ACTION_DOWNLOAD_COMPLETE));
HERE is the complete sample. Take a look and if you don't understand something just ask.

Categories

Resources