I have read all of the similar posts in regards to sending an attachment from internal memory using the GMAIL app. I implemented the content provider suggestion and still cannot get the attachment to actually send using GMAIL.
When passing the intent, everything seems like it is working, the file just gets removed when sent and the recipient sees no attachments. This code works fine on the native Android Email application.
Any suggestions or comments are greatly appreciated.
Android Manifest:
<provider
android:authorities="com.myapp.fileprovider"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
file_paths.xml:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="/data/user/0/com.myapp/files" path="."/>
</paths>
java:
ShareButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
File fileToSend = new File("");
File dir = getFilesDir();
File[] subFiles = dir.listFiles();
if (subFiles != null) {
for (File file : subFiles) {
if (file.getName().equals(curveChosen)) {
fileToSend = file;
}
}
}
File Path = new File(view.getContext().getFilesDir(),"");
File newFile = new File(Path,fileToSend.getName());
Uri contentUri = FileProvider.getUriForFile(view.getContext(),"com.myapp.fileprovider", newFile);
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
sendIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
sendIntent.setType("text/plain");
sendIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, "Email Subject");
sendIntent.putExtra(Intent.EXTRA_TEXT,"Email Text");
startActivity(Intent.createChooser(sendIntent,"Select Email Application"));
}
});
Related
I try to share a pdf file from android/data/mypackage/files/file.pdf
I generate these pdfs also in this app, and when I try to share it, the pdf doesn't appear in on attached files from email, or google drive says something like: "No data to share".
Here is my code for sharing pdf:
val aName = intent.getStringExtra("iName")
val file = File(this.getExternalFilesDir(null)?.absolutePath.toString(), "$aName")
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.putExtra(Intent.EXTRA_STREAM, file)
shareIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
shareIntent.type = "application/pdf"
startActivity(Intent.createChooser(shareIntent, "share.."))
Toast.makeText(this,"$file",Toast.LENGTH_SHORT).show()
The pdf path looks correct when I toast it:
The problem is that you are not using a URI, just sending a path, you need several things.
Provider paths
You have to create provider_paths.xml under xml folder in res :
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path
name="files_root"
path="/" />
</paths>
Set the provider in the Manifest under Aplication:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
Get the URI
fun uriFromFile(context:Context, file:File):Uri {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
{
return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file)
}
else
{
return Uri.fromFile(file)
}
}
Your final code:
val aName = intent.getStringExtra("iName")
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.putExtra(Intent.EXTRA_STREAM, uriFromFile(context,File(this.getExternalFilesDir(null)?.absolutePath.toString(), "$aName")))
shareIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
shareIntent.type = "application/pdf"
startActivity(Intent.createChooser(shareIntent, "share.."))
I didn't test the code, write it from "memory", let me know if it works for you.
Using Android FileProvider, when I try to share a file using gmail it fails, I get this gmail toast message: "Couldn't attach file".
It also puts a text string showing the file name and path in the 'To' area of the gmail.
When I try to share a file using Google drive it fails, I get the message:
Upload was unsuccessful
Unable to schedule 1 file for upload.
My question:
Did I miss something in my code? Please provide code with your answer.
XML code:
ANDROIDMANIFEST.XML
<application
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.audiorecorder.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
</application>
res/xml/file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_audio" path="AudioRecorder/"/>
</paths>
Java code:
case R.id.context_menu_share:
/** ***********************************************
* Share Recording feature, code with FileProvider
* ***********************************************
*/
Intent i = new Intent(Intent.ACTION_SEND);
final String rowName2 = (itemNameArray.get(info.position));
File filePath = new File(this.getFilesDir(), "/AudioRecorder/");
File newFile = new File(filePath, rowName2);
Toast.makeText(getApplicationContext(), "newFile = " + newFile, Toast.LENGTH_LONG).show();
Uri uri = FileProvider.getUriForFile(this, "com.mydomain.audiorecorder.fileprovider", newFile);
Toast.makeText(getApplicationContext(), "uri = " + uri, Toast.LENGTH_LONG).show();
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
i.putExtra(Intent.EXTRA_EMAIL, new String[]{"add#email-address.com"});
i.putExtra(Intent.EXTRA_SUBJECT,"Test");
i.setDataAndType(uri, "audio/wav");
i.putExtra(Intent.EXTRA_STREAM, uri);
this.startActivity(i);
try {
startActivity(Intent.createChooser(i, "Share..."));
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(getApplicationContext(), "There are no email clients installed.", Toast.LENGTH_SHORT).show();
}
return true;
I'm trying to attach an image using different applications with the following code:
val sendIntent = Intent(Intent.ACTION_SEND)
sendIntent.putExtra(Intent.EXTRA_TEXT, "Test example")
sendIntent.type = "image/png"
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(logo.absolutePath))
startActivity(sendIntent)
The image that is attached is generated with this code:
// Generate file for application logo
val path = Environment.getExternalStorageDirectory().absolutePath
val logo = File(path, "logo.png")
// If logo doesn't exist
if (!logo.exists())
{
// Create new file
logo.createNewFile()
// Save application logo to new file
val fOut = FileOutputStream(logo)
val image = BitmapFactory.decodeResource(applicationContext.resources, R.mipmap.ic_launcher_round)
image.compress(Bitmap.CompressFormat.PNG, 100, fOut)
fOut.flush()
fOut.close()
}
But when I try to open GMAIL with this intent, only text shows app with an error: Couldn't attach file.
What am I missing?
EDIT
Here is another solution: android.os.FileUriExposedException: file.jpg exposed beyond app through ClipData.Item.getUri()
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
From Android N you have to use FileProvider to Obtain Uri.
Please see below example for file sharing.
ArrayList<Uri> files = new ArrayList<Uri>();
File file = new File(<Your File Path>);
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(DetailActivity.this, BuildConfig.APPLICATION_ID + ".provider", file);
} else {
uri = Uri.fromFile(file);
}
files.add(uri);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putExtra(Intent.EXTRA_SUBJECT, "Product Sharing");
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_TEXT, "ANY TEXT MESSAGE");
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, files);
startActivity(intent);
Place below code in AndroidManifest.xml in Application tag
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
and place filepath.xml file in xml resource directory
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>
You cannot send file without file provider. Gmail, for example, doesn't request READ/WRITE_EXTERNAL_STORAGE permissions, so it cannot access your file. You must use file provider with GRANT_READ_URI_PERMISSION. You can read more here
https://developer.android.com/reference/android/support/v4/content/FileProvider
https://developer.android.com/training/secure-file-sharing/setup-sharing
https://developer.android.com/training/secure-file-sharing/share-file
Hi It would help me greatly If anyone could please help me out. I have been trying to find a solution to Share my Audio File with a Text using Intent. I am just trying to share it on Whatsapp alone. It would be greatly appreciated if any of you could spare time out to help me out of this problem. When I run my code only the sound is shared. No text.
This is my code:
public void buttonClick(View v) {
try {
String a = copyFiletoExternalStorage(R.raw.accio, "accio.mp3");
String shareBody = "Here is the share content body";
Intent shareMedia = new Intent(Intent.ACTION_SEND);
//set WhatsApp application.
shareMedia.setPackage("com.whatsapp");
shareMedia.setType("*/*");
//set path of media file in ExternalStorage.
shareMedia.putExtra(Intent.EXTRA_STREAM, Uri.parse(a));
shareMedia.putExtra(android.content.Intent.EXTRA_SUBJECT, "Subject Here");
shareMedia.putExtra(android.content.Intent.EXTRA_TEXT, shareBody);
startActivity(Intent.createChooser(shareMedia, "Compartiendo archivo."));
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Whatsapp no se encuentra instalado", Toast.LENGTH_LONG).show();
}
}
I want the user to share the sound and the text in just one intent.
first you need to add provider_paths.xml
see this video to add file provider
my file provider
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
then add this line to AndroidManifest.xml
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
then use this code to share your voice and text
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "some text ... ");
sendIntent.setType("text/plain");
if (hasReadExternalStoragePermission()) {
Uri uriImage = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "voice.wav"));
sendIntent.putExtra(Intent.EXTRA_STREAM, uriImage);
sendIntent.setType("audio/*");
}
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(sendIntent, "share"));
I hope it has been helpful
Try to use Intent.ACTION_SEND_MULTIPLE instead of Intent.ACTION_SEND
Intent shareMedia = new Intent(Intent.ACTION_SEND_MULTIPLE);
//set WhatsApp application.
shareMedia.setPackage("com.whatsapp");
shareMedia.setType("*/*");
String[] extraMimeTypes = {"audio/*", "image/*"};
shareIntent.putExtra(Intent.EXTRA_MIME_TYPES, extraMimeTypes);
shareIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
shareMedia.putExtra(Intent.EXTRA_STREAM, Uri.parse(a));
shareMedia.putExtra(Intent.EXTRA_SUBJECT, "Subject Here");
shareMedia.putExtra(Intent.EXTRA_TEXT, shareBody);
startActivity(Intent.createChooser(shareMedia, "Compartiendo archivo."));
I want to open an image from internal folder with the android default image viewer, on the Nexus 7 tablet.
I use the following code,but for some reason the image is not displayed. What I'm doing wrong? The path to the file is :
file:///data/data/com.example.denandroidapp/files/Attachments/photoTemp/photo.jpg
(this is what Uri.parse("file://" + file) returns).
ArticlePhoto photo = new ArticlePhoto(soapObject);
File f = new File(context.getFilesDir() + "/Attachments/photoTemp");
if(!f.exists())
f.mkdirs();
if (photo.ArtPhoto != null) {
Bitmap articlePhoto = BitmapFactory.decodeByteArray(photo.ArtPhoto, 0, photo.ArtPhoto.length);
ByteArrayOutputStream bytesFile = new ByteArrayOutputStream();
articlePhoto.compress(Bitmap.CompressFormat.JPEG, 100, bytesFile);
File file = new File(f + "/photo.jpeg");
try {
if(!file.exists())
file.createNewFile();
FileOutputStream outStream = new FileOutputStream(file);
outStream.write(bytesFile.toByteArray());
outStream.close();
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + file),"image/jpeg");
startActivity(intent);
} catch(Exception ex) {
AlertDialog alert = new AlertDialog.Builder(context).create();
alert.setTitle("Warning!");
alert.setMessage(ex.getMessage());
alert.show();
}
}
Try with this :
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.parse("file://" + file.getAbsolutePath());
intent.setDataAndType(uri,"image/*");
startActivity(intent);
Thanks.
The problem is that the image is internal to your application! So an external application (Image Viewer) has no access to the data that is internal to your application.
What you might have to do is create a Content Provider .
http://web.archive.org/web/20111020204554/http://www.marcofaion.it/?p=7
Android Manifest.xml
<provider android:authorities="com.example.denandroidapp" android:enabled="true" android:exported="true" android:name=<fully classified name of provider class>>
</provider>
Creating Intent
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.parse("content://com.example.denandroidapp/" + filename);
intent.setDataAndType(uri, "image/jpeg");
If a file is associated with your app (stored on the internal storage of your app space ), other apps can not access your file directly provided a valid file path. Instead, you have to create a file provider and generate a content uri.
First, add the file provider in your AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
Then you need to create an a file named file_paths in xml/file_paths.xml (the directory xml is not created by default, so create it).
file_paths.xml looks like
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="myFiles" path="./"/>
</paths>
add as much as paths you want your provider to access in .
atlast you need to create your intent
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
File imagePath = new File(context.getFilesDir(), "fileName");
Uri contentUri = FileProvider.getUriForFile(context, "com.mydomain.fileprovider", imagePath);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(contentUri,"image/*");
context.startActivity(intent);
Note: make sure the file path sepecefied in file_paths.xml and new File(context.getFilesDir(),"fileName"), matches. getFilesDir() will give you the root directory of your app.
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(outputFileName)),"image/jpeg");
startActivity(intent);
You can use FileProvider which extends ContentProvider
Check the link -
https://developer.android.com/reference/android/support/v4/content/FileProvider
To specify the FileProvider component itself, add a "provider" element to your app manifest.
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
You must specify a child element of "paths" for each directory that contains files for which you want content URIs. For example, these XML elements specify two directories
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_images" path="images/"/>
<files-path name="my_docs" path="docs/"/>
</paths>
After this you need to generate content URI for the file and then call the intent, refer the below link
https://developer.android.com/reference/android/support/v4/content/FileProvider#GetUri
Check this: https://stackoverflow.com/a/11088980/1038442;
File file = new File(filePath);
MimeTypeMap map = MimeTypeMap.getSingleton();
String ext = MimeTypeMap.getFileExtensionFromUrl(file.getName());
String type = map.getMimeTypeFromExtension(ext);
if (type == null)
type = "*/*";
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.fromFile(file);
intent.setDataAndType(data, type);
startActivity(intent);
PS: if your are trying to open .jpg files, try to
Replace String ext = MimeTypeMap.getFileExtensionFromUrl(file.getName());
With String ext = MimeTypeMap.getFileExtensionFromUrl(".jpg");
Good luck.
In my case, The gallery launched but did not show any images and went straight to the home page. My situation is quite different from what OP faced but I think it's worth mentioning here since the question is about images not being shown through implicit intent.
My problem came from the code below.
val intent = context.packageManager.getLaunchIntentForPackage(packageName ?: "")
The code above tells PackageManager to launch the entry point of the application, instead of the activity that shows the images.
If you look at the Logcat above, you can find that the intent launched with cat=[android.intent.category.Launcher] will go to SplashActivity. This happened because I created the intent with getLaunchIntentForPackage()
Alternative is to use Intent with setPackage() like the code in below
val intent = Intent()
val uri = Uri.fromFile(file) // You should probably replace with ContentProvider's uri
intent.apply {
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
action = Intent.ACTION_VIEW
setPackage(packageName)
setDataAndType(uri, "image/*")
}
context.startActivity(intent)