I am fetching a document Uri from the server which points out to where the document (pdf or word) was initially stored in the phone storage at the time of upload. In my app, I would want to check if the document still exists in the user's phone storage (by checking if this uri is still valid) before downloading the document. How can I do this?I've tried multiple ways to no success. Please help.
This is what I've already tried.
Uri uri = Uri.parse("content://com.android.providers.downloads.documments/document/748");
final File f = new File(uri.getPath());
if (f.exists()){
Log.d("File existence", "Yes, file exists");
}else {
Log.d("File does not exist", "so sorry");
}
I also tried implementing this using ContentResolver as pointed out in this similar question but the method threw a security exception: querying the cursor requires manage documents permission which when added to the manifest also brought an error, that the permission is only used by system apps.
Please help. I'm running the app in android 6.0.1
Thanks in advance
Try this out :
getContext().getContentResolver().getPersistedUriPermissions().forEach( {element -> element.uri == yourUri});
Related
private void share(Uri uri){
Intent waIntent = new Intent(Intent.ACTION_SEND);
waIntent.setType("audio/*");
waIntent.putExtra("jid", get_DATA.getSelectedPhonewdcountrycode() + "#s.whatsapp.net"); //phone number without "+" prefix
waIntent.setPackage("com.whatsapp");
waIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(waIntent, "Share with"));
}
I have tried many solution but every solutio takes me to whatsapp contact list to chose a contact, i want the file to be send directly to users inbox
BTW it does take me to the targeted contact after a few second delay but it toast a message File is not supported
There is no foreseeable way to upload it directly from a file to a user (unlike on laptops), unless you extend the file path to reach a particular contact e.g
com.whatsapp.jeremy
This however might still not help as WhatsApp chats are end to end encrypted, not direct, so you might have to go through some of the database files like db.crypt to find the right path to each individual.
Try seeing how these pan out for you
I'm trying to upload a file by copying it from mobile app to server app running on windows.
I used a file chooser to let the user select the file:
public void openFile(View view) {
Intent intent = new Intent();
intent.setType("*/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select file"), LEARN_TREE);
}
Then i got the uri from the intent of onActivityResult.
First question here is why it displays a file named "servo.dat" as numbers (in this case it shows "5889")?
After that I put the uri as an extra into another intent and use that intent to start another activity.
In the second activity I retrieve the uri.
Now I'd like to use FileInputStream to read bytes from my file in order to write them to the ObjectOutputStream created from Socket.getOutputStream().
Here is where it doesn't work. Basically the path provided here
FileInputStream fis = new FileInputStream(uri.getPath());
is incorrect. If I check on my device the file location is Download/servo.dat, the Uri in the app shows Download/5889 and the absolute path that I tried retrieving using a UriUtils library found online shows storage/emulated/0/Download/servo.dat but this one doesn't actually exist on my phone.
I think it's not so hard but I'm getting confused since I'm new to both Android app development and Android itself, please help!
I'm open to any good solution, I saw online there is the ContentResolver class that should be helpful but I didn't manage to understand how to use it :|
First question here is why it displays a file named "servo.dat" as numbers (in this case it shows "5889")?
Because it is not a file. It is a piece of content, and you are attempting to treat the path portion of a Uri as a filesystem path, which is is not.
If you want a display name for the content:
Call DocumentFile.fromSingleUri(), passing in your Uri, to create a DocumentFile
Call getDisplayName on the DocumentFile
Basically the path provided here is incorrect
That is because you are trying to treat the path portion of a Uri as a filesystem path, which it is not.
To get an InputStream, call openInputStream() on a ContentResolver, passing in your Uri. See the documentation. So, for example, from a method in an Activity, you would use InputStream inputStream = getContentResolver().openInputStream(uri);.
I'm getting confused since I'm new to both Android app development and Android itself
You may wish to consider reading a book on Android app development or taking a course in Android app development.
I'm trying to copy a file that is located in the External storage directory into a directory that is in my SD Card. However, when I check to see if the file has successfully been copied, the file is not even created in the SD Card.
Am I missing something? Here is the code I have:
String sourcePath = Environment.getExternalStorageDirectory().getPath() + newFileName;
File source = new File(Environment.getExternalStorageDirectory().getPath(), newFileName);
String destinationPath = "/storage/external_SD";
File destination = new File(destinationPath, newFileName);
try {
if(!destination.exists()){
destination.mkdir();
}
FileUtils.copyFile(source, destination);
} catch (IOException e) {
e.printStackTrace();
}
The copyFile method is from an Apache library. Here is the link for it: https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/FileUtils.html
However, when I check to see if the file has successfully been copied, the file is not even created in the sd Card.
You do not have arbitrary filesystem-level access to removable storage on Android 4.4+.
Is there a work around for this?
That depends on what your objective is.
If you insist that you must be able to write to that specific path on arbitrary user devices... then, no, there is no supported workaround. After all, there is no /storage/external_SD on the vast majority of Android devices. Where and how device manufacturers choose to mount removable media is up to them and is an implementation detail that will vary.
If you relax that restriction, but insist that you must be able to write a file to the root directory of removable storage on arbitrary user devices... then, no, there is no supported workaround today. The N Developer Preview has a "Scoped Directory Access" feature that should allow this, but it will be several years before you can assume that an arbitrary user device will be running that version of Android or higher. Also, you do not get actual filesystem access, but rather a Uri (see the Storage Access Framework option, below).
Now, if you are more flexible about the precise location, you have other options:
You can use getExternalFilesDirs(), getExternalCacheDirs(), and getExternalMediaDirs(), all methods on Context. Note the plural form. If those return 2+ entries, the second and subsequent ones are locations on removable storage that you can read from and write to, no permissions required. However, you do not get to choose the exact path. And if the device has 2+ removable storage volumes, I'm not quite certain how you would help the user tell them apart.
You can use the Storage Access Framework and let the user choose where to put the file. The user is welcome to choose removable storage... or not. You get a Uri back, which you can use with ContentResolver and openOutputStream() to write your content. You can also take persistable Uri permissions so you can work with that file again in the future, assuming the user doesn't move or delete it behind your back.
If you want to copy to external storage then you need
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
The destinationPath you mentioned may not be accessible as it may belong to the private system folders or some other application folders. You can however use public folders like Pictures,Music, Videos,Downloads,etc. or create sub folders inside them -
String sourcePath = Environment.getExternalStorageDirectory().getPath() + newFileName;
File source = new File(Environment.getExternalStorageDirectory().getPath(), newFileName);
File destinationPath = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS, "/external_SD");
try {
if(!destinationPath.exists()){
destinationPath.mkdir();
}
File destination = new File(destinationPath, newFileName);
FileUtils.copyFile(source, destination);
} catch (IOException e) {
e.printStackTrace();
}
I have just written a function in an android app that deletes a file using the standard 'File' class in Java. i.e:
String fileName= "/mnt/Gallery/Img001.jpg";
File file = new File(fileName);
file.delete();
While the above procedure is simple enough, I have been wondering if there is any advantage to doing the same via a 'ContentResolver'. Any advice would be appreciated.
------------------------------------------ EDIT ----------------------------------------
Here's an example of deleting a file via the Content Resolver. This example assumes the file being deleted is an image and that its 'id' is known.
long mediaId = 155; // NOTE: You would normally obtain this from the content provider!
Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Uri itemUri = ContentUris.withAppendedId(contentUri, mediaId);
int rows = getContentResolver().delete(itemUri, null, null);
String path = itemUri.getEncodedPath();
if(rows == 0)
{
Log.e("Example Code:","Could not delete "+path+" :(");
}
else
{
Log.d("Example Code:","Deleted "+path+ " ^_^");
}
Android's content provider framework has certain added advantages when compared to directly manipulating data.
You can think on the lines of 'Where does the file reside and who may be deleting it'.
Scenario 1
File resides on SD card (a path accessible by your app) and you app is deleting it.
Solution : Since the path is accessible to you, the java approach will work with a file Uri like:
file://mnt/sdcard/downloads/image.jpeg
Scenario 2
File resides in another app (say dropbox) and your app needs to delete the file.
Solution : This means that the file actually resides in the private storage of another app. A file: Uri will the above approach will give you access denied. So, your app will need to fetch a content Uri from the app containing the file and call into its content provider to delete.
fileUri = Uri.parse ("content : // " + packageContainingTheFile " + fileId); // replace this with Uri obtained from the app.
getContext().getContentResolver().delete (fileUri, null, null);
Scenario 3
File resides in your app's package directory i.e, under data/data/com.yourpackage/yourfolder/yourfile.xxx and your app is the only one deleting it.
Solution : Here, either of the above approaches will work since you have the access to delete the file.
Uri will look like:
file://data/data/yourpackage/folder/file.ext
The prime advantage of using content provider here is that you automatically gain the observer model. Content provider callbacks are a well defined entry point from where data is modified. Hence, its a desired place to notify others of changes using:
getContext().getContentResolver().notify(uri, null)
Assume you have views that show a listing of such file items. As soon as the delete is done, your can be notified.
Scenario 4
File resides in your app's package directory i.e, under data/data/com.yourpackage/yourfolder/yourfile.xxx and you want to expose the delete functionality to other apps.
Solution : This is similar to Scenario 1, just the other way round. Other apps cannot delete the file in your private storage with a Uri like
file://data/data/yourpackage/folder/file.ext // works just for your app
They will need to call in your content provider to do this with a Uri like.
content://providerAuthority/delete/id
which your content provider will need to map to file.ext absolute path.
Summary
To conclude, the use of content provider is necessary is some scenarios while optional in others. It largely depends on your app requirements. If you have views, CursorLoaders in place and want to be informed about updates or wish to expose deletion of your app data to other apps, content provider is the cleanest approach.
I am trying to read a pdf file from internal memory of the device my code is here:
File pdfFile;
pdfFile=new File("data/data/com.myapp.main/app_c"+md+"/c"+md+".pdf");
if(pdfFile.exists())
{
try{
FileOutputStream fileOutput = openFileOutput(pdfFile.toString(), Context.MODE_WORLD_READABLE);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
Uri path = Uri.fromFile(pdfFile);
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(ChTable.this, "No Application available to view pdf", Toast.LENGTH_LONG).show();
}
But the Pdf reader shows an Error -File not supported-Or File Not found .But I have checked that file is there at this location.I have also changed the permission to the file ,but still the same result. Would Someone help me detect and solve my problem ?
you can use PDFBox library to read data from pdf -
http://pdfbox.apache.org/
data/data/com.myapp.main/app_c"+md+"/c"+md+".pdf"
Is this path correct?
I am guessing the path should be like below.
data/data/com/myapp/main/app_c"+md+"/c"+md+".pdf"
You should be using one of the apis to get the application's files directory rather than assuming what the path will be.
Your actual problem however is most likely that any file you create there is probably private to the owning application, so the PDF reader app lacks permission to access it.
Solutions to that would be to change the file mode to world readable, or more commonly to put the file on the external storage (ie, "sdcard") rather than the internal memory, as that does not (to date) have a concept of permissions. Though it's worth remembering that a device isn't guaranteed to have an external storage, or for it to be accessible at any given point in time even if it exists.