Setting Internal Read Write properties for an existing file - android

I'm having an issue with opening internal data files in native applications
Its properly important to point out that I'm fairly new to Android development but not new to programming
Setup
I have a mobile Air application which i am running on an Android device. To load PDF's/ play videos within the application I have written a native extension to load the files via their native application.
Problem
When testing the app i found that file's stored in the external storage were loading fine and files in the internal storage were presenting messages from the native applications like cannot play file or cannot open file.( files in internal storage are downloaded and saved on the Air application end ).
This lead me to think its the permission setup within Android.
I know that files within the internal storage are private by default
I have read how to write to a file setting its permission using openFileOutput
but as the file already exists this won't work. I could load the file in and spit it out again but this isn't ideal as will result in what might be unnecessary overhead.
I'm not sure how to proceed, do i need to set a manifest properties on the Air App side? Android App side? both sides? If so which one and where
Or is their a way to change it at run-time, i found the setReadable function but its at API level 9 and i am idealy aiming a little lower than that.
Any help is greatly appreciated
public static void openFile( Activity parentActivity, String filePath, String fileType, String mimeType ) {
//Create the file we are to create
File fileToOpen = new File(filePath);
//Check if the file exists
if( fileToOpen.exists() ) {
//The path of the file we want to open
Uri path = Uri.fromFile(fileToOpen);
//Create a new intent of the file we want to view
Intent intent = new Intent(Intent.ACTION_VIEW);
//Set the path and the mime type for the file
intent.setDataAndType(path, mimeType);
//Remove any other activities
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//Check that its within the try and catch block
try {
//Open the file by stating a new activity
parentActivity.startActivity(intent);
}
catch (ActivityNotFoundException e) {
//Make a pop-up informing that we don't have an application to open the file
Toast.makeText( parentActivity,"No Application Available to View " + fileType,Toast.LENGTH_SHORT).show();
}
} else {
//Display an alert which will show that the file dosn't exist
Toast.makeText( parentActivity, fileType+" file dosn't exist", Toast.LENGTH_SHORT).show();
}
}

Related

Check if file exist inside custom folder in Downloads - getExternalStoragePublicDirectory deprecated

What I'm trying to achieve is to check before download if the file exists so i don't have to re-download it again. For example, i have to open for the first time this pdf from the Internet "history-of-comics.pdf", in order to do so i have to download it and open inside my app, the second time i choose to re-read it, i have to be sure that "history-of-comics.pdf" if exists inside Downloads/MyDocs, i don't have to waste resources and let the user wait to download it again. Currently the app targetSdkVersion is 29 and what i have done so far is:
Give permissions for READ_EXTERNAL_STORAGE & WRITE_EXTERNAL_STORAGE
Included in manifest android:requestLegacyExternalStorage="true" inside application tag
Download the pdf file in the MyDocs inside Downloads folder
Below is a quick sample of my code (i have commented the other combinations i have tried):
private void checkIfPdfExists(String pdfFileName) {
String uriFile = String.valueOf(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS+File.separator+"MyDocs"+File.separator+pdfFileName+".pdf"));
File file = new File(uriFile);
//File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)+"/MyDocs", pdfFileName+".pdf");
//File file = new File(Environment.DIRECTORY_DOWNLOADS+File.separatorChar+"MyDocs"+File.separatorChar+pdfFileName+".pdf");
//File file = new File(Environment.DIRECTORY_DOWNLOADS+File.separatorChar+"MyDocs", pdfFileName+".pdf");
if (file.exists() && file!=null) {
Toast.makeText(getApplicationContext(), file.getPath() + "/n exists", Toast.LENGTH_SHORT).show();
displayFromUri(Uri.parse(file.getPath()));
} else {
beginDownload("https://www.heritagestatic.com/comics/d/history-of-comics.pdf",pdfFileName);
}
}
And this is how i define the path when i download the pdf, the downloader works as it should:
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.addRequestHeader("Accept", "application/pdf");
request.setDescription(file_name);
request.setTitle("Getting your doc");
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,"MyDocs/"+file_name+".pdf");
I did some research before posting the question and in some threads i found that is related to Android Q, but i can't find a real solution for it. Any help would be appreciated, thanks in advance!
The solution to my problem was how i was referring to file path and the method used for download. As #blackapps mentioned that if you use "setDestinationInExternalFilesDir" to save the file, the proper way to check if the file exist is with "getExternalFilesDir", in my case:
File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)+File.separator+"MyDocs"+File.separator+pdfFileName+".pdf");

How to cache audio for offline use in Android Studio

I am developing an Android application in which I need to get the specified audio file from my website when the user plays it, but I don't want to stream it or download it every time, just the first time. So I was thinking of caching it and play offline whenever the user is in need. So please suggest any method to do so. Or if exists any other method rather than caching like downloading the actual file to file storage and play whenever needed.
If you need to cache files, you should use createTempFile(). For example, the following method extracts the file name from a URL and creates a file with that name in your app's internal cache directory:
private File getTempFile(Context context, String url) {
File file;
try {
String fileName = Uri.parse(url).getLastPathSegment();
file = File.createTempFile(fileName, null,
context.getCacheDir());
} catch (IOException e) {
// Error while creating file
}
return file;
}
You can also see here for more about caching files.
https://developer.android.com/training/data-storage/files.html#WriteCacheFileInternal
Hope this will help.

How to use JaudioTagger to write data?

I am trying to use JaudioTagger 2.2.3 to edit tags of audio file but till now i have not achieved any success.
this is a test code to change the Artist tag of a mp3 file in Internal Storage
String path;
try
{
TagOptionSingleton.getInstance().setAndroid(true);
AudioFile f=AudioFileIO.read(new File(path));
Tag t=f.getTag();
t.setField(FieldKey.ARTIST,Str);
AudioFileIO.write(f);
}catch(CannotReadException e){}
catch(TagException e){}
catch(ReadOnlyException e){}
catch(InvalidAudioFrameException e){}
catch(CannotWriteException e){}
My Application is well elevated with android.permission.WRITE_EXTERNAL_STORAGE and android.permission.READ_EXTERNAL_STORAGE
I am testing in Android version Android 6.0
this code throws InvalidAudioFrameException with a message
No audio header found within example.mp3
Its not that the audio is corrupt as it shows similar error with other mp3s also
Also if any one has any other wat for audio tagging please do tell me and i have also used mp3agic which repeadedly shows:example.mp3:open failed :EROFS(Read only file system) on the line
Mp3File mp3file = new Mp3File(filePathStr+"example.mp3");
ID3v1 id3v1Tag;
if (mp3file.hasId3v1Tag()) {
id3v1Tag = mp3file.getId3v1Tag();
} else {
// mp3 does not have an ID3v1 tag, let's create one..
id3v1Tag = new ID3v1Tag();
mp3file.setId3v1Tag(id3v1Tag);
}
id3v1Tag.setTrack("5");
id3v1Tag.setArtist("An Artist");
id3v1Tag.setTitle("The Title");
id3v1Tag.setAlbum("The Album");
id3v1Tag.setYear("2001");
id3v1Tag.setGenre(12);
id3v1Tag.setComment("Some comment");
mp3file.save("example.mp3")//error showing in this line
My question
How to rectify Jaudiotagger?
Is there any way to use Mp3agic as an alternative to Jaudiotagger?
Or there is any other efficient way leaving these two?
I have also used JaudioTagger-android but same problem persists.
thanks in advance!
For the error when doing
mp3file.save("example.mp3")
i would recommend to not overwrite directly the old file. Try to create a new file, and then delete and rename to restore the original file setup.
song.save(location + "intermed");
File from = new File(location + "intermed");
File file = new File(location);
file.delete();
File to = new File(location);
from.renameTo(to);
Of course you need to add exception handling and what not, and also this will fail if you have no write permissions. This may be the case if you use a more recent Android version, i think above 4.4, and you try to access the SD card. Then, the write permissions need to be granted at runtime for specific folders, the manifest write permission is not sufficient. See Android's Storage Access Framework.

Receiving single file from external app is unreadable, but readable when multiple

I have a problem when receiving a file from an external app. I've been following the tutorial on https://developer.android.com/training/sharing/receive.html and it works fine until I want to handle the image in my code.
The problem I have is if I select and send only one file to my app, I am not able to read it after converting it from URI to a FILE object. However, if I send two or more images (the very same image selected before plus an additional one from the same directory), then I actually can read the files (all of them).
Why is that? Even setting the file to setReadable(true); I can not read it afterwards.
Target SDK is 23 and yes, I already implemented the request for permission in the code that is needed from API 23+. So this can't be the problem.
I need to be able to read the received files no matter if it was only one or a list of multiple.
On a side note: if I send any amount of images from the Google Photos app (one or multiple), I never can read the file. Images sent from the "ES File Explorer" app are readable in the code but not readable if I only send one single file to my app.
Here is my code snippet of the problematic part:
// THIS PART WORKS. RECEIVING MULTIPLE FILES ARE READABLE IN THE CODE BELOW.
void handleSendMultipleImages(Intent intent) {
ArrayList<Uri> imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
if (imageUris != null) {
addImagesToNewOrExistingContact(imageUris);
}
}
// THIS PART DOES NOT WORK. I CAN NOT READ THE FILE IN THE CODE BELOW.
private void addImageToNewOrExistingContactDialog(Uri imageUri) {
ArrayList imageUris = new ArrayList<>();
imageUris.add(imageUri);
addImagesToNewOrExistingContact(imageUris);
}
private void addImagesToNewOrExistingContact(final ArrayList<Uri> imageUris) {
for (Uri uri : imageUris) {
File f = new File(uri.getPath());
f.setReadable(true);
f.setWritable(true);
boolean readd = f.canRead(); // FALSE, but why?
boolean exec = f.canExecute(); // FALSE, but why?
}
}
Files I tested this with:
Selected two files from "ES File Explorer" and sent them to my app:
file:///storage/emulated/0/Pictures/Adobe%C2%AE%20Photoshop%C2%AE%20Touch/1452348875289.jpg
file:///storage/emulated/0/Pictures/Adobe%C2%AE%20Photoshop%C2%AE%20Touch/1455733673513.jpg
Both canRead() = TRUE
Selected one file from "ES File Explorer" and sent it to my app:
content://media/external/images/media/33675
canRead() = FALSE
Actually the files content://media/external/images/media/33675 and file:///storage/emulated/0/Pictures/Adobe%C2%AE%20Photoshop%C2%AE%20Touch/1455733673513.jpg are the exact same files.
Selected two files from "Google Photos" and send them to my app:
content://com.google.android.apps.photos.contentprovider/0/1/shared%3A%2Flocal%253A4541959b-3222-4ee0-b838-67049141b864%2FV2xDV01jNWhWVDRCQXRMY202YTh3NFNES1N4M01R/REQUIRE_ORIGINAL/NONE/1290260075
content://com.google.android.apps.photos.contentprovider/0/1/shared%3A%2Flocal%253A20e65034-795f-4300-9472-64a598afc4c1%2FV2xDV01jNWhWVDRCQXRMY202YTh3NFNES1N4M01R/REQUIRE_ORIGINAL/NONE/1096770166
Both canRead() = FALSE
Thanks for any help in advance.
Use openInputStream(uri) on getContentResolver(). No need for a File class.

How to pick file from external storage using file picker in Android

I am having a problem with selecting image file from external storage using file picker in Android. This question is the consequence of this question - No such file or diectory error in image file upload using Retrofit in Android. What my problem is opening and reading file from external storage on activity result. I want to convert result URI into File.
I read a pdf file from download folder on activity result
Uri bookUri = data.getData();
if(bookUri!=null)
{
String filePath = bookUri.toString();//bookUri.toString()
String mime = app.getMimeType(filePath);
if(mime!=null && !mime.isEmpty() && (mime.toLowerCase()=="application/pdf" || mime.toLowerCase()=="application/txt" || mime.toLowerCase()=="application/text"))
{
bookFile = new File(bookUri.getPath());
ivBookFile.setImageResource(R.drawable.book_selected);
}
else{
Toast.makeText(getBaseContext(),"Unable to process file you have chosen.",Toast.LENGTH_SHORT).show();
}
}
As you can see I used new File(bookUri.getPath()); to convert into File. The above code works well. It is working. The problem is now I am trying to open an image file in DCIM/Camera folder on activity result.
This is the code I used
Uri selectedImageUri = data.getData();
if(selectedImageUri!=null)
{
try{
bmpCoverImage = MediaStore.Images.Media.getBitmap(getContentResolver(), selectedImageUri);
imageFile = new File(selectedImageUri.getPath());
if(bmpCoverImage!=null)
{
ivCoverImage.setImageBitmap(bmpCoverImage);
}
}
catch (IOException e)
{
Toast.makeText(getBaseContext(),"An error occurred with the file selected",Toast.LENGTH_SHORT).show();
}
}
As you can see I used new File(selectedImageUri.getPath()); like I did in reading pdf file. This time the code is not working. When I do operation with the file like in previous question, it gives me error.
I used this way also
imageFile = new File(Environment.getExternalStorageDirectory(),selectedImageUri.getPath());
I got the same error. How can I open the image file correctly from external storage? How can I convert the chosen file URI from external storage into File?
I am having a problem with selecting image file from external storage using file picker in Android
If you are referring to the code that you are using in this question, you are not "using file picker". You are using ACTION_GET_CONTENT, which has never been a "file picker", nor will it ever be a "file picker".
I want to convert result URI into File.
Usually, that is not necessary. But, if that is what you want to do:
use ContentResolver and openInputStream() to get an InputStream on the content represented by the Uri
create a FileOutputStream on your desired file
use Java I/O to copy the bytes from the InputStream into the FileOutputStream
The above code works well. It is working.
It works for the small number of devices that you tested, for the specific activities that the user chose to handle the ACTION_GET_CONTENT request. It will not work on most Android devices, and it will not work in most circumstances. The only time that code will work is if the Uri has a file scheme. Most of the time, it will not. Instead, it will have a content scheme, representing content supplied by a ContentProvider.
Please how can I open the image file correctly from external storage?
If you wish to continue using ACTION_GET_CONTENT, please understand that this has nothing to do with external storage specifically. You are not getting a file, on external storage or elsewhere. You are getting a Uri. This is akin to a URL, such as the URL for this Web page. Just as a URL does not necessarily point to a file on your hard drive, a Uri does not necessarily point to a file on the filesystem. Use a ContentResolver and DocumentFile to work with the Uri and the content that it identifies.
If you want to always get files on external storage (and nowhere else), then use an actual file picker library.

Categories

Resources