Android Q download PDF and open - java

I can not open a pdf file on andorid Q I do this :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
OutputStream fosTemp;
ContentResolver resolver = context.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, "mamy123");
contentValues.put(MediaStore.Files.FileColumns.MIME_TYPE, "application/pdf");
contentValues.put(MediaStore.Files.FileColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
Uri imageUri2 = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
fosTemp = resolver.openOutputStream(imageUri2);
byte[] pdfAsBytes = Base64.decode(base64, 0);
fosTemp.write(pdfAsBytes);
fosTemp.flush();
fosTemp.close();
openPDF(context, imageUri2);
}
I see a black screen and in logs I have :
java.lang.SecurityException: com.google.android.apps.docs has no access to content://media/external/downloads/49
public static void openPDF(Context context, Uri localUri) {
Intent i = new Intent( Intent.ACTION_VIEW );
i.setDataAndType( localUri, PDF_MIME_TYPE );
context.startActivity( i );
}
This is how I open pdf file on android Q I see a black file , a file is on folder Download

This is working for me. Tested on Android R (11). Create and save a PDF in the Downloads folder on Android Q (10) & R. I use this library to generate PDFs:
implementation 'com.uttampanchasara.pdfgenerator:pdfgenerator:1.3'
Create the PDF and call the writeFileToDownloads method in the OnSuccess callback. As a bonus, a download notification is created:
String root = mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString();
File file = new File(root, documentTitle + ".pdf");
if (root != null) {
new CreatePdf(mContext)
.setPdfName(documentTitle)
.openPrintDialog(false)
.setContentBaseUrl(null)
.setPageSize(PrintAttributes.MediaSize.ISO_A4)
.setContent(documentContent)
.setFilePath(root)
.setCallbackListener(new CreatePdf.PdfCallbackListener() {
#Override
public void onFailure(String s) {
Toast.makeText(mContext, mContext.getResources().getString(R.string.toast_an_error_occurred), Toast.LENGTH_LONG).show();
}
#Override
public void onSuccess(String s) {
DownloadManager downloadManager = (DownloadManager) mContext.getSystemService(DOWNLOAD_SERVICE);
downloadManager.addCompletedDownload(file.getName(), file.getName(), true, "application/pdf", file.getAbsolutePath(), file.length(), true);
writeFileToDownloads(file);
}
})
.create();
To save the PDF in the downloads folder, call the writeFileToDownloads method. This will check the that the Android version is greater than or equal to Q:
private void writeFileToDownloads(File file) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ContentResolver resolver = mContext.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, file.getName());
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "application/pdf");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
Uri uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
try {
int size = (int) file.length();
byte[] bytes = new byte[size];
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
buf.read(bytes, 0, bytes.length);
buf.close();
OutputStream fos = resolver.openOutputStream(uri);
fos.write(bytes);
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

Related

In Android 12 , how to fetch files, which is my apps generated subFolder in Public Download folder

In Android 12 , how to fetch files, which is generated by my own apps in Public Download folder like Download/MySubFolder/myfiles.jpg/.mp4 using MediaStore API, I want to list of content uris to show in recyclerview.
Codes are below
Uri imageUri=null;
ContentResolver contentResolver = getActivity().getContentResolver();
ContentResolver resolver = getActivity().getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, arrayList.get(position).getFileName());
if(arrayList.get(position).getFileName().endsWith(".mp4"))
{
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "Video/*");
}else
{
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "Image/*");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + File.separator + "MyFolder");
imageUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
}
try {
OutputStream outputStream = contentResolver.openOutputStream(imageUri);
InputStream inputStream = contentResolver.openInputStream(arrayList.get(position).getUri());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
FileUtils.copy(inputStream, outputStream);
}
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
In code, arrylist.get(pos) is the content uris, which are getting from other apps private sapace

The captured images does not save to the storage on some android devices

I am building an android application using java.
https://github.com/skydragon1115/Android_Camera
But the image does not save to the storage on the below devices.
Galaxy Feel2 SC-02L OS:Android 10
dtab Compact d-01J OS:Android 7.0
This function is working on the others.
try {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = timeStamp + ".jpg";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
values.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/Camera/");
values.put(MediaStore.MediaColumns.IS_PENDING, 1);
} else {
File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File file = new File(directory, "Camera/" + fileName);
values.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath());
}
Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
try (OutputStream output = getContentResolver().openOutputStream(uri)) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
}
} catch (Exception e) {
}
I found the reason.
try {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = timeStamp + ".jpg";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.Media.TITLE, fileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
values.put(MediaStore.Images.Media.DESCRIPTION, "captured image");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
final String relativeLocation = Environment.DIRECTORY_DCIM + File.separator + "Camera" + File.separator;
values.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);
values.put(MediaStore.MediaColumns.IS_PENDING, 0);
} else {
File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File file = new File(directory, "Camera/" + fileName);
values.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath());
}
Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
try (OutputStream output = getContentResolver().openOutputStream(uri)) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
}
} catch (Exception e) {
}

How to set a audio file as a ringtone in Android 11?

I use this below code but is working only down to android 10.
This is how I save the audio file.
File ringtoneuri = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES);
Random r = new Random();
int i1 = r.nextInt(450 - 280) + 280;
File newSoundFile = new File(ringtoneuri, name+i1+".mp3");
Uri mUri = Uri.parse(path);
The file is saved DIRECTORY_RINGTONES.
ContentResolver mCr = v.getContext().getContentResolver();
AssetFileDescriptor soundFile;
try {
soundFile = mCr.openAssetFileDescriptor(mUri, "r");
} catch (FileNotFoundException e) {
soundFile = null;
}
try {
byte[] readData = new byte[1024];
assert soundFile != null;
FileInputStream fis = soundFile.createInputStream();
FileOutputStream fos = new FileOutputStream(newSoundFile);
int i = fis.read(readData);
while (i != -1) {
fos.write(readData, 0, i);
i = fis.read(readData);
}
fos.close();
} catch (IOException ignored) {
}
My file is set as ringtone but is not working( I got something like 12165016516 instead of the sound name, in sound settings, this is happening only in android 11 )
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DATA, newSoundFile.getAbsolutePath());
values.put(MediaStore.MediaColumns.TITLE, newSoundFile.getName());
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mpeg");
values.put(MediaStore.MediaColumns.SIZE, newSoundFile.length());
values.put(MediaStore.Audio.Media.ARTIST, R.string.app_name);
values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
values.put(MediaStore.Audio.Media.IS_ALARM, false);
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
Uri uri = MediaStore.Audio.Media.getContentUriForPath(newSoundFile.getAbsolutePath());
Uri newUri = mCr.insert(uri, values);
Toast.makeText(v.getContext(),"Sound was set!",Toast.LENGTH_SHORT).show();
Every think is working i don t have erros.
try {
if (checkSystemWritePermission()) {
RingtoneManager.setActualDefaultRingtoneUri(popUp.this, RingtoneManager.TYPE_RINGTONE, newUri);
Toast.makeText(popUp.this, "Set as Ringtone successfully! ", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(popUp.this, "Allow modify system settings ==> ON ", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Log.i("rington",e.toString());
Toast.makeText(popUp.this, "Unable to set as Ringtone! ", Toast.LENGTH_SHORT).show();
}
I'm mentioning that requestLegacyExternalStorage is set to "true" in my manifert.xml file.
What is the problem Please Help!!

Why doesn't image saving work anymore on API 29

In my App the user is able to save images from a pciture gallery to the local device by clicking on a DL Button.
The Code does work on old devices but on API 29 it has the following behaviour:
While saving I tried to open the Gallery to have a look what happens: the gallery gets updated and for 1 second an empty images appears and disappears immediately after. I get noticed, that the image got saved but it doesn't appear, not even in the device explorer.
//DEXTER HERE
Picasso.get().load(dummyimage.getLarge()).placeholder(R.drawable.ic_img_error).error(R.drawable.ic_red).into(saveImageToDirectory);
final Target saveImageToDirectory = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
ProgressDialog mydialog = new ProgressDialog(getActivity());
mydialog.setMessage("saving Image to phone");
mydialog.show();
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
try {
String fileName = "myApp_" + timeStamp + ".JPG";
String dirName= "/myApp";
File file = new File(requireActivity().getApplicationContext().getExternalFilesDir(null).getAbsolutePath() + dirName, fileName);
//new File(path for the file to be saved, saving file name)
if (!file.exists()) {
//check if the file already exist or if not create a new file
//if exist the file will be overwritten with the new image
File filedirectory = new File(requireActivity().getApplicationContext().getExternalFilesDir(null).getAbsolutePath() + dirName);
filedirectory.mkdirs();
}
if (file.exists()) {
file.delete();
}
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, ostream);
Toast.makeText(getActivity(), "Picture saved to Gallery" + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
ostream.close();
mydialog.dismiss();
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "My Images");
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.RELATIVE_PATH,"/myApp");
// API LEVEL Q: values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put("_data", file.getAbsolutePath());
ContentResolver cr = getActivity().getContentResolver();
cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (Exception e) {
mydialog.dismiss();
Log.e("file creation error", e.toString());
}
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
As you may see, instead of
File filedirectory = new File(Environment.getExternalStorageDirectory() + dirName);
I'm already using
File filedirectory = new File(requireActivity().getApplicationContext().getExternalFilesDir(null).getAbsolutePath() + dirName);
I hope this shouldn't be the problem, but I'm a little stuck on this strange behaviour.
This is the error I'm getting out of my Logcat:
E/file creation error: java.lang.IllegalArgumentException: Primary
directory (invalid) not allowed for
content://media/external/images/media; allowed directories are [DCIM,
Pictures]
PS: I'm using Dexter to avoid problems with the permissions
Try this
private Uri saveImage(Context context, Bitmap bitmap, #NonNull String folderName, #NonNull String fileName) throws IOException
{
OutputStream fos;
File imageFile = null;
Uri imageUri = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ContentResolver resolver = context.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM" + File.separator + folderName);
imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
fos = resolver.openOutputStream(imageUri);
} else {
String imagesDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM).toString() + File.separator + folderName;
imageFile = new File(imagesDir);
if (!imageFile.exists()) {
imageFile.mkdir();
}
imageFile = new File(imagesDir, fileName + ".png");
fos = new FileOutputStream(imageFile);
}
boolean saved = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
if (imageFile != null) // pre Q
{
MediaScannerConnection.scanFile(context, new String[]{imageFile.toString()}, null, null);
imageUri = Uri.fromFile(imageFile);
}
return imageUri;
}
And add requestLegacyExternalStorage in your Manifest file
<application
android:allowBackup="true"
android:icon="#drawable/icon"
android:requestLegacyExternalStorage="true"
android:label="#string/app_name"
android:roundIcon="#drawable/icon"
android:supportsRtl="true"
android:theme="#style/AppTheme">
...
...
...
</application>

Opening a file present in assets folder using an intent

Hello I am tring to open a .pdf file present in a file using an intent but it is giving me 2 errors on the following line
File file = new File(getContext().getAssets().open("assets/test.pdf"));
Errors
1.Unhandled java.IO.Exception.
2.getAssets()may produce java.lang.NullPointerException
Here us the code in a fragment
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == 0) {
File file = new File(getContext().getAssets().open("assets/test.pdf"));
if (file .exists())
{
Uri path = Uri.fromFile(file );
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setDataAndType(path , "application/pdf");
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try
{
startActivity(pdfIntent ); }
catch (ActivityNotFoundException e)
{
Toast.makeText(getActivity(), "Please install a pdf file viewer",
Toast.LENGTH_LONG).show();
}
}
}
}
File fileBrochure = new File(Environment.getExternalStorageDirectory() + "/" + "abc.pdf");
if (!fileBrochure.exists())
{
CopyAssetsbrochure();
}
/** PDF reader code */
File file = new File(Environment.getExternalStorageDirectory() + "/" + "abc.pdf");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file),"application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try
{
getApplicationContext().startActivity(intent);
}
catch (ActivityNotFoundException e)
{
Toast.makeText(SecondActivity.this, "NO Pdf Viewer", Toast.LENGTH_SHORT).show();
}
}
//method to write the PDFs file to sd card
private void CopyAssetsbrochure() {
AssetManager assetManager = getAssets();
String[] files = null;
try
{
files = assetManager.list("");
}
catch (IOException e)
{
Log.e("tag", e.getMessage());
}
for(int i=0; i<files.length; i++)
{
String fStr = files[i];
if(fStr.equalsIgnoreCase("abc.pdf"))
{
InputStream in = null;
OutputStream out = null;
try
{
in = assetManager.open(files[i]);
out = new FileOutputStream(Environment.getExternalStorageDirectory() + "/" + files[i]);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
break;
}
catch(Exception e)
{
Log.e("tag", e.getMessage());
}
}
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
You cannot open the pdf file directly from the assets folder.You first have to write the file to sd card from assets folder and then read it from sd card
try with the file provider
Intent intent = new Intent(Intent.ACTION_VIEW);
// set flag to give temporary permission to external app to use your FileProvider
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// generate URI, I defined authority as the application ID in the Manifest, the last param is file I want to open
String uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID, file);
// I am opening a PDF file so I give it a valid MIME type
intent.setDataAndType(uri, "application/pdf");
// validate that the device can open your File!
PackageManager pm = getActivity().getPackageManager();
if (intent.resolveActivity(pm) != null) {
startActivity(intent);
}
To serve a file from assets to another app you need to use a provider.
Google for the StreamProvider of CommonsWare.

Categories