I had a program that would always attach the same file to GMAIL (Compose > Attach File > Open From > "MyProgram"). It would always select the same file.
What it was doing was:
String path = Environment.getExternalStorageDirectory() + "/file.3gp";
File f = new File(path);
Uri data = Uri.fromFile(f);
Intent i = new Intent();
i.setData(data);
setResult(Activity.RESULT_OK, i);
finish();
This was working fine until Android 6.0.
Now, I receive the following error when trying to use it:
Can't attach empty file
Astro File Sharing is giving me the same error (can be an old build).
However, I installed ES File Explorer, and when I do the same routine, and select the file, I receive a Dialog which says:
Pick up file as
Normal Android Way (For MMS,Gmail,...)
File Way (Try this if above fails)
The "File Way" will fail as my program does. The "Normal Android Way" will work fine.
Does anyone have any idea on what it does, so I can replicate?
Thanks in advance!
OBS: Already tried the putExtra(STREAM, path) a lot of times, but without success.
Ok, got it to work now, after a lot of research and intercepting some Intents.
What I had to do was change the file:/// to content://.
I did this following this information from Android: https://developer.android.com/reference/android/support/v4/content/FileProvider.html
The only major change was that I used a hard-coded path to /sdcard/file.ext.
Also, the line
getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);
was changed to
Uri contentUri = FileProvider.getUriForFile(this, "com.mydomain.fileprovider", newFile);
Also had to include:
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
i.setData(contentUri);
I do not really understand why I had to change from File to Content, but after this, the file is now being attached again! See the link if you face this issue, and don't forget about the new .xml that needs to be created.
See the following question:
android-6-cannot-share-files-anymore
This behavior is with Android 6.0 and Gmail. Please see the following thread.
Issue 3141 - android-developer-preview
If you go to Settings->Apps->Gmail->Permissions and enable the
"Storage" permission manually, then the share works.
Gmail should ask for "Storage" permission in this scenario and it
would work as it did in all the past version of Android.
Other email apps should handle attachments correctly.
Here is how to fix it.
Go to Settings -> Apps -> Gmail -> Permissions
Turn on the permission for "Storage"
That work-around solved the issue for me.
I couldn't find a clear answer(sending an attachment on gmail without SD card) I tried to copy to another file name but no cigar. The way I got it to work was copy to the Downloads folder and go from there.
Get the path for Downloads with this
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
pulls the full path to downlaods folder copy the attachemnt to there and we are good. Files over 20M don't go
Share any file using INTENT provided given file path
//File file= shareable File Path
Uri uri = FileProvider.getUriForFile(this, "com.example.myapp.fileprovider", file);
//FileProvider authorities from Manifest
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("*/*");
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(sharingIntent);
Just match your authorities from the manifest in arguments of method getUriForFile.
In Manifest
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
Related
I create file on the internal storage as suggested by android docs. To be accurate the file is created under a specific directory in the internal storage. I do this using the mode world_readable mode. Then later on i try to attach the file using email program. I was able to get the file attached, however sending the email failed (does not seem to be to load the file) i am sure it is internal storage/permission thingy.
Anyone knows how to fix it or a working example? It will suck to have convert everything on external storage.
Thank you
Ps:I checked other threads and they don't seem to have solutions (old threads)
It is possible to share a file from your apps local storage to another application (such as email attachment) by granting temporary permissions to read that file as part of the share intent.
Step 1: Add a file provider to your AndroidManifest.xml:
<applicaton>
....
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.your.package.name.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
</application>
Step 2: Add a file res/xml/filepaths.xml with the path to the file in local app storage that you want to share:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="myFolder" path="Folder/"/>
</paths>
Step 3: In your java code create the file sharing intent:
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND_MULTIPLE);
shareIntent.setType("text/plain");
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Your subject");
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, "Your message");
ArrayList<Uri> uris = new ArrayList<Uri>();
String shareName = new String(pathToFile + filename);
File shareFile = new File(shareName);
Uri contentUri = FileProvider.getUriForFile(context, "com.your.package.name.fileprovider", shareFile);
uris.add(contentUri);
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
// Grant temporary read permission to the content URI
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
String msgStr = "Share...";
startActivity(Intent.createChooser(shareIntent, msgStr));
If you have any problems with it see the docs here
https://developer.android.com/training/secure-file-sharing/share-file.html for further details.
I'm assuming you are trying to send the file as an email attachment
using intents.
The reason why the file is empty is that the email app does not have
access to the file in /data/data/package_name/myfile_name, due to
Androids security model (the /data/data/package_name directory is
private to your app).
In order to add the file as an attachment, you need to write it to
public storage (such as the SD card) so the email app can access it.
I am trying to open a local file in Android (4.0) using intents. The following is the code to do the action. This works fine as long as the file has no special spaces (For example: if the file is /data/data/com.xxxx.yyyy/files/Downloads/Documents/ProductFeature.pptx, the it opens fine, but if the file name is /data/data/com.xxxx.yyyy/files/Downloads/Documents/Product Feature.pptx (note the space in name), then it fails. The Uri.fromFile encodes the space correctly, but the other apps cant seem to interpret them and seem fail opening.
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(new File( selectedEntry.get(Defs.PATH_KEY)));
System.out.println("openFileWith: File to open: " + uri);
intent.setDataAndType(uri,type);
startActivity(Intent.createChooser(intent, "Open With ..."));
I also tried to use "file://" + unencoded path without much help.
So how do you handle this condition? Any help is appreciated
You need to replace the spaces with "\ ". Note that if you are using String.replace() then you need to escape the slash as well ("\\ ").
The main problem for me turned out to be I was storing files in application directory of internal storage and the access to the files had to be given explicitly. I was giving permissions using chmod 755 command. But the files with spaces were not getting the permissions set correctly which prevented those files being opened.
I have since moved to use external (Activity.getExternalFilesDir()) and that folder allows access permission to every other application and that solved the issue for me.
My app writes data to text files (on sd card and internal memory).
Later the app emails the text files to a list of people.
I am having trouble getting gmail to attach a file that is pulled from the internal application files area. 'Native Android mail' can attach a file from either internal or SD card area with no problem. Gmail will attach a file if it's from SD card, but won't attach a file if its located in internal storage.
// this sends a file from SD - works for android mail and gmail
Intent jj=new Intent(android.content.Intent.ACTION_SEND);
String fileName = "file://" + Environment.getExternalStorageDirectory()+"/aFolder/externalfile.txt"
jj.putExtra(Intent.EXTRA_STREAM, Uri.parse(fileName));
jj.setType("text/plain");
Intent chooser = Intent.createChooser(jj , "Select Sender");
startActivity(chooser);
// this sends an internal file-works for android mail, but no attachment sent with gmail
Intent jj=new Intent(android.content.Intent.ACTION_SEND);
String fileName = "file://" + getFilesDir().toString() + "/internalfile.txt";
jj.putExtra(Intent.EXTRA_STREAM, Uri.parse(fileName));
jj.setType("text/plain");
Intent chooser = Intent.createChooser(jj , "Select Sender");
startActivity(chooser);
Any suggestions?
Do I need to give Gmail special permission somehow?
My attachments are all text files - written by the app.
Internal files were created with openFileOutput(myFile,32769)
Thanks
John D
the only way I found around this was to make my own content provider and pass in the uri to my content provider as the attachment.
Like Dhego, I used a content provider. Specifically, a FileProvider.
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
Using this only requires that you modify your Manifest and create an additional resource file. Also, you will need to obtain a validly formatted URI via a static method provided by FileProvider.
In your Manfiest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.authority.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
The "com.example.authority.fileprovider" is your application authority with "fileprovider" appended.
In the res/xml folder, create a file_paths.xml file that contains the paths to the files you want to expose. In my case, I was exposing them from the application cache directory, so my XML looks like:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="reports" path="reports/"/>
</paths>
In my case, "reports" is a folder within the application cache directory that I am writing files to.
The last thing to do is in your code:
Write files you want to expose to the folders and storage areas specified in file_paths.xml.
Generate a valid URI to set on the Intent you will invoke for sending an email (Intent.ACTION_SEND).
Here's some sample code:
emailIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(getActivity(), "com.example.authority.fileprovider", fileToAttach));
Invoke startActivity on your Intent and that should be it!
It appears that there is indeed an issue with gmail. Unfortunately however, at the time of the writing it seems it hasn't been fixed.
My app writes data to text files (on sd card and internal memory).
Later the app emails the text files to a list of people.
I am having trouble getting gmail to attach a file that is pulled from the internal application files area. 'Native Android mail' can attach a file from either internal or SD card area with no problem. Gmail will attach a file if it's from SD card, but won't attach a file if its located in internal storage.
// this sends a file from SD - works for android mail and gmail
Intent jj=new Intent(android.content.Intent.ACTION_SEND);
String fileName = "file://" + Environment.getExternalStorageDirectory()+"/aFolder/externalfile.txt"
jj.putExtra(Intent.EXTRA_STREAM, Uri.parse(fileName));
jj.setType("text/plain");
Intent chooser = Intent.createChooser(jj , "Select Sender");
startActivity(chooser);
// this sends an internal file-works for android mail, but no attachment sent with gmail
Intent jj=new Intent(android.content.Intent.ACTION_SEND);
String fileName = "file://" + getFilesDir().toString() + "/internalfile.txt";
jj.putExtra(Intent.EXTRA_STREAM, Uri.parse(fileName));
jj.setType("text/plain");
Intent chooser = Intent.createChooser(jj , "Select Sender");
startActivity(chooser);
Any suggestions?
Do I need to give Gmail special permission somehow?
My attachments are all text files - written by the app.
Internal files were created with openFileOutput(myFile,32769)
Thanks
John D
the only way I found around this was to make my own content provider and pass in the uri to my content provider as the attachment.
Like Dhego, I used a content provider. Specifically, a FileProvider.
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
Using this only requires that you modify your Manifest and create an additional resource file. Also, you will need to obtain a validly formatted URI via a static method provided by FileProvider.
In your Manfiest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.authority.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
The "com.example.authority.fileprovider" is your application authority with "fileprovider" appended.
In the res/xml folder, create a file_paths.xml file that contains the paths to the files you want to expose. In my case, I was exposing them from the application cache directory, so my XML looks like:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="reports" path="reports/"/>
</paths>
In my case, "reports" is a folder within the application cache directory that I am writing files to.
The last thing to do is in your code:
Write files you want to expose to the folders and storage areas specified in file_paths.xml.
Generate a valid URI to set on the Intent you will invoke for sending an email (Intent.ACTION_SEND).
Here's some sample code:
emailIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(getActivity(), "com.example.authority.fileprovider", fileToAttach));
Invoke startActivity on your Intent and that should be it!
It appears that there is indeed an issue with gmail. Unfortunately however, at the time of the writing it seems it hasn't been fixed.
This was my original question:
I want to be able to open a pdf file
in my app using the android's built in
pdf viewer app, but i dont know how to
start other apps. I'm sure i have to
call start activity, i just dont know
how to identify the app im opening and
how to pass the file to that specific
app.
Anyone have a clue?
I just learned that the pdf viewer i have on my phone is actually made by HTC and that Adobe just barely released their android pdf viewer (which is great). So the new question is this: how do i verify that the user has installed adobe's viewer, and then how do i open the file in that app from my app?
You can programmatically determine whether a suitable application exists on the user's device, without catching exceptions.
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("path-to-document"));
intent.setType("application/pdf");
PackageManager pm = getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
if (activities.size() > 0) {
startActivity(intent);
} else {
// Do something else here. Maybe pop up a Dialog or Toast
}
AFAIK, Adobe has not documented any public Intents it wants developers to use.
You can try an ACTION_VIEW Intent with a Uri pointing to the file (either on the SD card or MODE_WORLD_READABLE in your app-local file store) and a MIME type of "application/pdf".
FileFinalpath = SdCardpath + "/" + Filepath + Filename;
File file = new File(FileFinalpath);
if (file.exists()) {
Uri filepath = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(filepath, "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
startActivity(intent);
} catch (Exception e) {
alert.showAlertDialog(PDF_Activity.this, "File Not Started...","File Not Started From SdCard ", false);
Log.e("error", "" + e);
}
} else {
alert.showAlertDialog(PDF_Activity.this, "File Not Found...","File Not Found From SdCard ", false);
}
Although this is a pretty old topic, here is a solution for opening a PDF that is in the asset/ folder with an external PDF reader app. It uses a custom content provider: https://github.com/commonsguy/cwac-provider
Using this you can define any file to be provided from the assets/ or res/raw/ folder.
Try it! Best and easiest solution I found so far.
I was also faced same issue when was trying to display PDF on android device and finally end up with the solution (3rd party PDF library integration)
https://github.com/JoanZapata/android-pdfview
while I have tested multiple libraries for this listed below which are also working,
https://github.com/jblough/Android-Pdf-Viewer-Library
& mupdf which comes with the ndk flavour (https://code.google.com/p/mupdf/downloads/detail?name=mupdf-1.2-source.zip&can=2&q=) and need to extract with NDK and then use it in application as a jar or java etc. nice article to explain the use of this library # http://dixitpatel.com/integrating-pdf-in-android-application/
Android has a built in framework from Android 5.0 / Lollipop, it's called PDFRenderer. If you can make the assumption that your users have Android 5.0, it's probably the best solution.
There's an official example on Google's developer site:
http://developer.android.com/samples/PdfRendererBasic/index.html
It doesn't support annotation or other more advanced features; for those your really back to either using an Intent to open a full app, or embedding an SDK like mupdf.
(Disclaimer: I very occasionally do work on mupdf.)
In addition to the ones marked as answer you would need these permissions in the manifest.xml
**
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
**
Add FLAG_GRANT_READ_URI_PERMISSION
Intent intent = new Intent(Intent.ACTION_VIEW)
Uri outputFileUri = FileProvider.getUriForFile(getActivity(), BuildConfig.APPLICATION_ID + ".provider", file);
intent.setDataAndType(outputFileUri, "application/pdf");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Intent in = Intent.createChooser(intent, "Open File");
startActivity(in);
also add provider_paths.xml at res -> xml folder
and need to add below code at manifests
<application>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
tools:replace="android:resource"
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
</application>