Android sharing Files, by sending them via email or other apps - java

I have a list of files in my android app and I want to be able to get the selected items and send them via email or any other sharing app. Here is my code.
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_EMAIL, getListView().getCheckedItemIds());
sendIntent.setType("text/plain");
startActivity(sendIntent);

this is the code for sharing file in android
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
File fileWithinMyDir = new File(myFilePath);
if(fileWithinMyDir.exists()) {
intentShareFile.setType("application/pdf");
intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://"+myFilePath));
intentShareFile.putExtra(Intent.EXTRA_SUBJECT,
"Sharing File...");
intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File...");
startActivity(Intent.createChooser(intentShareFile, "Share File"));
}
Below is another method to share PDF file if you have put file provider in manifest
Uri pdfUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
pdfUri = FileProvider.getUriForFile(PDFViewerActivity.this, fileprovider, pdfFile);
} else {
pdfUri = Uri.fromFile(pdfFile);
}
Intent share = new Intent();
share.setAction(Intent.ACTION_SEND);
share.setType("application/pdf");
share.putExtra(Intent.EXTRA_STREAM, pdfUri);
startActivity(Intent.createChooser(share, "Share file"));

sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(exportPath));
also you can make zip file of all file and attach zip file for send multiple file in android

For those who trying in Kotlin here is the way:
Start the intent like below:
fun startFileShareIntent(filePath: String) { // pass the file path where the actual file is located.
val shareIntent = Intent(Intent.ACTION_SEND).apply {
type = FILE_TYPE // "*/*" will accepts all types of files, if you want specific then change it on your need.
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
putExtra(
Intent.EXTRA_SUBJECT,
"Sharing file from the AppName"
)
putExtra(
Intent.EXTRA_TEXT,
"Sharing file from the AppName with some description"
)
val fileURI = FileProvider.getUriForFile(
context!!, context!!.packageName + ".provider",
File(filePath)
)
putExtra(Intent.EXTRA_STREAM, fileURI)
}
startActivity(shareIntent)
}
In Manifest inside the application tag:
<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>
Under res-->xml--> provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path name="files" path="." />
<external-path name="external_files" path="."/>
</paths>

This is work for every single file!
private void shareFile(File file) {
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
intentShareFile.setType(URLConnection.guessContentTypeFromName(file.getName()));
intentShareFile.putExtra(Intent.EXTRA_STREAM,
Uri.parse("file://"+file.getAbsolutePath()));
//if you need
//intentShareFile.putExtra(Intent.EXTRA_SUBJECT,"Sharing File Subject);
//intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File Description");
startActivity(Intent.createChooser(intentShareFile, "Share File"));
}
Thanks Tushar-Mate!

First you should define File Provider, see https://medium.com/#ali.dev/open-a-file-in-another-app-with-android-fileprovider-for-android-7-42c9abb198c1.
The code checks that a device contains applications which can receive the file, see How to check if an intent can be handled from some activity?.
fun sharePdf(file: File, context: Context) {
val uri = getUriFromFile(file, context)
if (uri != null) {
val intent = Intent().apply {
action = Intent.ACTION_SEND
type = "application/pdf" // For PDF files.
putExtra(Intent.EXTRA_STREAM, uri)
putExtra(Intent.EXTRA_SUBJECT, file.name)
putExtra(Intent.EXTRA_TEXT, file.name)
// Grant temporary read permission to the content URI.
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
// Validate that the device can open your File.
val activityInfo = intent.resolveActivityInfo(context.packageManager, intent.flags)
if (activityInfo?.exported == true) {
context.startActivity(Intent.createChooser(intent,
"Share PDF file")
}
}
}
fun getUriFromFile(file: File, context: Context): Uri? =
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
Uri.fromFile(file)
} else {
try {
FileProvider.getUriForFile(context, context.packageName + ".provider", file)
} catch (e: Exception) {
throw if (e.message?.contains("ProviderInfo.loadXmlMetaData") == true) {
Error("FileProvider is not set or doesn't have needed permissions")
} else {
e
}
}
}

Use ACTION_SEND_MULTIPLE for delivering multiple data to someone
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, arrayUri);
intent.setType("text/plain");
startActivity(intent);
The arrayUri is the Array List of Uri of files to Send.

Here is an example to share or save a text file:
private void shareFile(String filePath) {
File f = new File(filePath);
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
File fileWithinMyDir = new File(filePath);
if (fileWithinMyDir.exists()) {
intentShareFile.setType("text/*");
intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + filePath));
intentShareFile.putExtra(Intent.EXTRA_SUBJECT, "MyApp File Share: " + f.getName());
intentShareFile.putExtra(Intent.EXTRA_TEXT, "MyApp File Share: " + f.getName());
this.startActivity(Intent.createChooser(intentShareFile, f.getName()));
}
}

File directory = new File(Environment.getExternalStorageDirectory() + File.separator + BuildConfig.APPLICATION_ID + File.separator + DIRECTORY_VIDEO);
String fileName = mediaModel.getContentPath().substring(mediaModel.getContentPath().lastIndexOf('/') + 1, mediaModel.getContentPath().length());
File fileWithinMyDir = new File(directory, fileName);
if (fileWithinMyDir.exists()) {
Uri fileUri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", fileWithinMyDir);
Intent intent = ShareCompat.IntentBuilder.from(this)
.setStream(fileUri) // uri from FileProvider
.setType("text/html")
.getIntent()
.setAction(Intent.ACTION_SEND) //Change if needed
.setDataAndType(fileUri, "video/*")
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);

val uriArrayList: ArrayList<Uri> = ArrayList()
GlobalScope.launch(Dispatchers.IO) {
runCatching {
itemsList!!.forEach {
uriArrayList.add(
FileProvider.getUriForFile(
mContext,
APPLICATION_ID + ".provider",
File(it.path)
)
)
}
}.onSuccess {
requireActivity().runOnUiThread {
if (uriArrayList.size > 0) {
val intent = Intent()
intent.action = Intent.ACTION_SEND_MULTIPLE
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uriArrayList)
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
intent.type = "image/*|application/pdf/*"
startActivity(Intent.createChooser(intent, resources.getString(R.string.share)))
}
}
}
.onFailure {
Log.e("SHARING_FAILED", it)
}
}
First of all you have to write provider code in app manifest file for sharing on android 7.0 and above
<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>
here provider_paths are:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="/storage/emulated/0" path="."/>
<root-path name="root" path="." />
<files-path name="files" path="."/>
</paths>

Read this article about Sending Content to Other Apps
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_to)));

Related

Android: How to create a temporary text file and send it by email?

UPDATE
Everything is working now! I'm a little slow but thanks to the incredible patience of #blackapps I've gotten it to work. First here is how the file is created:
try {
File outputFile = new File(getFilesDir(), "myFile.txt");
FileWriter fileWriter = new FileWriter(outputFile, false);
//use fileWriter.write to write strings to the file
fileWriter.close();
sendEmail(outputFile);
} catch (ClassNotFoundException e) {
Log.e(TAG, e.getMessage());
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
And then here's the method to send the text file by email.
private void sendEmail(File outputFile) {
Intent emailSelectorIntent = new Intent(Intent.ACTION_SENDTO);
emailSelectorIntent.setData(Uri.parse("mailto:"));
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"goodweathercorp#gmail.com"});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Logcat");
Uri uri = FileProvider.getUriForFile(this, getPackageName() + ".fileProvider", outputFile);
emailIntent.putExtra(android.content.Intent.EXTRA_STREAM, uri);
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailIntent.setSelector(emailSelectorIntent);
if (emailIntent.resolveActivity(getPackageManager()) != null) {
startActivity(Intent.createChooser(emailIntent, "Choose email client"));
} else {
Toast.makeText(this, "No email apps detected", Toast.LENGTH_LONG).show();
}
}
Also you must add this to manifest:
</application>
....
<provider
android:enabled="true"
android:name="androidx.core.content.FileProvider"
android:authorities="com.braapproductions.braaaaap.fileProvider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/paths" />
</provider>
</application>
And finally in values>xml> create a file called paths.xml:
<paths>
<files-path name="files" path="/"/>
</paths>

Download a PDF and open with Acrobat Reader

I just try to play with the PRDownloader class to get a PDF from the Internet.
This works good in the VDI (I see the file in the Device File Explorer).
But now I want to test this on a real Android phone and let the Acrobat Reader open the PDF.
I use "getFilesDir()" as path to save the document, this seems to work (file.exist()).
But when I start an Intent to open this file with a PDF Viewer, the Acrobar Reader opens very short and reports (as a Toast) "Cannot access this file".
I use "file.setReadable(true,false)" to set the rights, and I see (also on the read device) the rights "-rw-r--r--" to the file.
How/where to set the rights for other applications to read this file/folder?
Thanks
Steffen
--
I use this code in "MainActivity::onDownloadComplete" ('String fname' is the complete filename)
String fname = getContext().getFilesDir().getPath() + File.separator + "download.pdf";
....
File file = new File(fname);
String ext = file.getName().substring(file.getName().lastIndexOf(".") + 1);
MimeTypeMap mime = MimeTypeMap.getSingleton();
String type = mime.getMimeTypeFromExtension(ext);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(fname), type);
file.setReadable(true, false);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
I also tried to save to file to download folder, but this (also) failed (no file was written):
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()
--[2021-03-02 07:20]--
I extracted and merge all the code to another button onClick:
public void onClick(View v) {
String url = "https://www.antennahouse.com/hubfs/xsl-fo-sample/pdf/basic-link-1.pdf";
String dir = getContext().getFilesDir().getPath();
String bname = "download.pdf";
int downloadId = PRDownloader.download(url, dir, bname)
.build()
.start(new OnDownloadListener() {
#Override
public void onDownloadComplete() {
try {
File file = new File(dir + File.separator + bname);
String ext = file.getName().substring(file.getName().lastIndexOf(".") + 1);
MimeTypeMap mime = MimeTypeMap.getSingleton();
String type = mime.getMimeTypeFromExtension(ext);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), type);
file.setReadable(true, false);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
catch (FileUriExposedException e) {
Log.e("Download", e.toString());
}
}
#Override
public void onError(Error error) {
}
});
}
----[2021-03-04]----
file "res\xml\filepath.xml"
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="external_files" path="."/>
</paths>
AndroidManifest.xml
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.test.downloadfile.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepath" />
</provider>
</application>
MainActivity:
String dir = getContext().getFilesDir().getPath();
String bname = "download.pdf";
....
....
File downloadPath = new File(dir);
File downloadFile = new File(downloadPath, bname);
String ext = downloadFile.getName().substring(downloadFile.getName().lastIndexOf(".") + 1);
MimeTypeMap mime = MimeTypeMap.getSingleton();
String type = mime.getMimeTypeFromExtension(ext);
Context context = MainActivity.this;
final Uri data = FileProvider.getUriForFile(context, "com.test.downloadfile.fileprovider", downloadFile);
context.grantUriPermission(context.getPackageName(), data, Intent.FLAG_GRANT_READ_URI_PERMISSION);
final Intent intent = new Intent(Intent.ACTION_VIEW)
.setDataAndType(data, type)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);

Install app automatically in android 7 or higher

I want to install app in my projects.
But my code don't work in api 24 or higher.
What is its solution?
My code is:
String timestamp = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date());
String dir = Environment.getExternalStorageDirectory() + "/" + context.getResources().getString(R.string.cache_path);
String appName = appModel.getAppUrl().substring(appModel.getAppUrl().lastIndexOf('/') + 1, appModel.getAppUrl().length());
appName = timestamp + "_" + appName;
private void appInstaller(String dir, String appName) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
File file = new File(dir, appName);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);
} else {
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/" + dir + "/" + appName)), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
Manifest:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
This question is like my question. But does not work its solution for me!
Thanks about to help me!
I resolved this problem and this way is true for me:
First:
private static final String APP_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyAppFolderInStorage/";
private void install() {
File file = new File(APP_DIR + fileName);
if (file.exists()) {
Intent intent = new Intent(Intent.ACTION_VIEW);
String type = "application/vnd.android.package-archive";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri downloadedApk = FileProvider.getUriForFile(getContext(), "ir.greencode", file);
intent.setDataAndType(downloadedApk, type);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
intent.setDataAndType(Uri.fromFile(file), type);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
getContext().startActivity(intent);
} else {
Toast.makeText(getContext(), "ّFile not found!", Toast.LENGTH_SHORT).show();
}
}
Second: For android 7 and above you should define a provider in manifest like below!
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="ir.greencode"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/paths" />
</provider>
Third: Define path.xml in res/xml folder like below! I'm using this path for internal storage if you want to change it to something else there is a few way! You can go to this FileProvider
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="your_folder_name" path="MyAppFolderInStorage/"/>
</paths>
Forth: You should add this permission in manifest:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

I can not share video to whatsapp from my app

I have an Android Studio project with the option to share videos by whatsapp.
This is my code:
private void shareFile(File file){
String titulo = file.getName();
String path = file.getAbsolutePath();
Uri uri = Uri.parse(path);
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.setType("video/*");
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, title);
shareIntent.putExtra(android.content.Intent.EXTRA_TITLE, title);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(shareIntent);
}
But when I share it I receive the message from Whatsapp: this file format is not compatible.
I do not understand what happens, before it worked.
ANDROIDMANIFEST.XML
<provider
android:name="android.support.v4.content.FileProvider"
android:grantUriPermissions="true"
android:exported="false"
android:authorities="${applicationId}">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_provider_paths"/>
</provider>
FILE_PROVIDER_PATHS.XML in res/xml
<paths>
<cache-path name="cache" path="/" />
<files-path name=”files” path=”/” />
</paths>
USE YOUR FILEPROVIDER
// create new Intent
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, "video/*");
// validate that the device can open your File!
PackageManager pm = getActivity().getPackageManager();
if (intent.resolveActivity(pm) != null) {
startActivity(intent);
}

FileProvider not working

What I am trying to do is to get a file that is in the private area to be opened by another program. In this example, a image viewer app.
AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.myapp"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/path" />
</provider>
/res/xml/path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="cache" path="cache/"/>
</paths>
Java code (file location)
File file = new File(context.getApplicationInfo().dataDir + File.separator + "cache" + File.separator + filename);
Java code (open file)
if(file != null && file.isFile() && file.canRead() && file.length() > 0){
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
List<ResolveInfo> resInfoList = this.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
Uri uri = Uri.parse(file.toURI().toString());
for (int i = 0; i < resInfoList.size(); i++) {
try{
ResolveInfo resolveInfo = resInfoList.get(i);
String packageName = resolveInfo.activityInfo.packageName;
grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}catch(Exception e){
}catch(Error e){
}
}
MimeTypeMap myMime = MimeTypeMap.getSingleton();
Intent newIntent = new Intent(Intent.ACTION_VIEW);
String mimeType = myMime.getMimeTypeFromExtension(".jpg");
newIntent.setDataAndType(Uri.fromFile(file), mimeType);
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(newIntent);
return true;
} catch (Exception e) {
}
}
This always results in a toast message "Unable to find item". What am I doing wrong and how to resolve this?
What am I doing wrong
File file = new File(context.getApplicationInfo().dataDir + File.separator + "cache" + File.separator + filename);
Use getCacheDir() to get the cache directory, as your approach is not going to be reliable for secondary accounts on Android 4.2+ tablets and Android 5.0+ phones. So, this should be:
File file = new File(context.getCacheDir(), filename);
Then, you need to replace Uri.fromFile(file) with a call to getUriForFile() on FileProvider, as is covered in the documentation. What you presently have is a Uri pointing to a file, not pointing to a ContentProvider, let alone your FileProvider implementation.
Finally, you will need to call addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) on the Intent before you use it with startActivity(), as otherwise the app that responds to the startActivity() request will not have access to the content.
This sample app demonstrates a working implementation of a FileProvider.

Categories