Unable to attach text file to Gmail in Android - android

I am writing some texts to a file in cache memory. i want to sent email with that file as attachment. Tried below code but i am getting toast message says 'Unable to attach file'.
File creation and code to write data
String fileName="cachelog.txt";
File cacheFile = new File(context.getCacheDir(), fileName);
if (!cacheFile.exists())
{
cacheFile.createNewFile();
}
}
if(cacheFile.exists())
{
FileOutputStream fos = null;
fos = new FileOutputStream(cacheFile,true);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
BufferedWriter buf = new BufferedWriter(new OutputStreamWriter(fos));
buf.append(logData);
buf.flush();
buf.close();
}
Email code
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("plain/text");
String[] to = {"testing#gmail.com"};
intent.putExtra(Intent.EXTRA_EMAIL, to);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
File file = new File(context.getCacheDir(), fileName);
Uri uri = FileProvider.getUriForFile(context,
context.getApplicationContext().getPackageName() + ".helper.ProviderClass", file);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
startActivity(intent)
Manifest file
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.test.medapp.helper.ProviderClass"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/cachefile" />
</provider>
<cache-path
name="cache"
path="." />

Create File
String fileName="cachelog.txt";
File file = null;
if(Build.VERSION.SDK_INT >= 30){ //Build.VERSION_CODES.R
file = new File(context.getFilesDir() + "/" + fileName);
}else {
file = new File(Environment.getExternalStorageDirectory() + "/" + fileName);
}
if (!file.exists())
file.mkdirs();
if(file.exists())
{
FileOutputStream fos = null;
fos = new FileOutputStream(file,true);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
BufferedWriter buf = new BufferedWriter(new OutputStreamWriter(fos));
buf.append(logData);
buf.flush();
buf.close();
}
Send File
String filePath = "/cachelog/cachelog.txt";
File file = null;
if(Build.VERSION.SDK_INT >= 30){ //Build.VERSION_CODES.R
file = new File(getActivity().getFilesDir() + "/" + filePath);
}else {
file = new File(Environment.getExternalStorageDirectory() + "/" + filePath);
}
String mimetype = getMimeType(file.getAbsoluteFile());
Uri uri = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".provider_paths", file);
Intent intentaaa = ShareCompat.IntentBuilder.from((Activity) getActivity())
.setStream(uri) // uri from FileProvider
.getIntent()
.setAction(Intent.ACTION_SEND) //Change if needed
.setDataAndType(uri, mimetype)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
getActivity().startActivity(intentaaa);
public static String getMimeType(File file) {
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString());
// Let's check the official map first. Webkit has a nice extension-to-MIME map.
// Be sure to remove the first character from the extension, which is the "." character.
if (extension.length() > 0) {
//String webkitMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.substring(1));
String webkitMimeType = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (webkitMimeType != null)
return webkitMimeType;
}
return "*/*";
}
create provider_paths.xml
<files-path
name="share"
path="external_files" />
<external-path
path="Android/data/"
name="files_root" />
<external-path
name="pictures"
path="Pictures/" />
<external-path
name="storage/emulated"
path="." />
<root-path
name="root"
path="." />
Add provider_paths in AndroidManifest
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider_paths"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_provider_paths"
tools:replace="android:resource" />
</provider>

Related

Failed to find configured root that contains /data/data/my_package/cache/share_video_1610748162883.mp4

I want to share my video in WhatsApp. Video contain in URL where we have hosted. When user click on WhatsApp icon video should send to user from URL.
I have tried many thing but unable to succeed. I don't know why this giving me this Exception. what I'm doing wrong.
This is my Java code
#SuppressLint("StaticFieldLeak")
private class AsyncTaskExample extends AsyncTask<String, String, Uri> {
#Override
protected Uri doInBackground(String[] fileURL) {
Uri videoUri = null;
String s = Arrays.toString(fileURL);
String videoUrl = s.replaceAll("\\[", "").replaceAll("\\]", "");
try {
File rootFile = new File(getCacheDir(), "share_video_" + System.currentTimeMillis() + ".mp4");
URL url = new URL(videoUrl);
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.connect();
FileOutputStream f = new FileOutputStream(rootFile);
InputStream in = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = in.read(buffer)) > 0) {
f.write(buffer, 0, len1);
}
videoUri = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".fileprovider", rootFile);
f.close();
} catch (IOException e) {
Log.d("Error....", e.toString());
}
return videoUri; // returns the file path to the video from storage
}
#Override
protected void onPostExecute(Uri videoUri) {
super.onPostExecute(videoUri);
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("*/*");
i.setPackage("com.whatsapp.w4b");
i.putExtra(Intent.EXTRA_STREAM, videoUri); //to share video
startActivity(i);
}
}
Mainfest File
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="studio.pepup.app.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
file_xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="." />
</paths>
Your file is in getCacheDir(). This means you need to replace:
<external-path name="external_files" path="." />
with:
<cache-path name="external_files" path="." />
See the documentation for more.

Save file to internal storage and show in gallery

I should save an image (byte []) inside the internal memory and make it visible inside the gallery, but the following code does not work, what's wrong? the file is not saved and shown in the gallery but no error is generated
private void saveImageToDisk(final byte[] bytes) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd-hh:mm");
String todayDate = dateFormat.format(new Date());
Log.d("Foto data: ",todayDate);
File file = new File(context.getFilesDir(), "image.jpg");
try (final OutputStream output = new FileOutputStream(file)) {
output.write(bytes);
output.close();
} catch (final IOException e) {
Log.e("TAG", "Exception occurred while saving picture to storage ", e);
}
Log.d("Foto","File salvato"+ file.getAbsolutePath());
addPicToGallery(file.getPath());
}
private void addPicToGallery(String photoPath) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File file = new File(photoPath);
Uri contentUri = Uri.fromFile(file);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
To save an image to internal storage you can use the function below:
String saveImage(Context context, Bitmap image) {
String savedImagePath = null;
// Create the new file in the external storage
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
Locale.getDefault()).format(new Date());
String imageFileName = "JPEG_" + timeStamp + ".jpg";
File storageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
+ "/YourAppName");
boolean success = true;
if (!storageDir.exists()) {
success = storageDir.mkdirs();
}
// Save the new Bitmap
if (success) {
File imageFile = new File(storageDir, imageFileName);
savedImagePath = imageFile.getAbsolutePath();
try {
OutputStream fOut = new FileOutputStream(imageFile);
image.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
// Add the image to the system gallery
galleryAddPic(context, savedImagePath);
// Show a Toast with the save location
String savedMessage = context.getString(R.string.saved_message, savedImagePath);
Toast.makeText(context, savedMessage, Toast.LENGTH_SHORT).show();
}
return savedImagePath;
}
This function takes context and Bitmap image as the parameters and returns the path of the file stored.
And to make the image visible to default gallery:
static void galleryAddPic(Context context, String imagePath) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(imagePath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
context.sendBroadcast(mediaScanIntent);
}
You need to pass the context and path of the image stored to this function. This second function is called inside the first function.
And I am not sure if you would need to actually make a FileProvider for these purposes, but if you do.
In you AndroidManifest.xml inside of the <application> tag , use following:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="<YOUR.PACKAGE.NAME>.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
And create a new Resource directory. Right click 'res'>>New Android Resource Directory. Choose 'xml' from the dropdown. Then right click the xml folder and create a file called file_paths wherein put:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-cache-path name="my_cache" path="." />
<external-path name="my_images" path="Pictures/" />
</paths>
Save file to internal storage and show in gallery
That is not possible, sorry.
but the following code does not work, what's wrong?
Third-party apps, including the MediaStore and galleries, have no rights to access your files on internal storage.

java.lang.IllegalArgumentException: Failed to find configured root that contains /uploads/b056441c611b4e0a9a35.jpg

I got this error when trying to share image in gmail using FileProvider.
Androidmanifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="staging.mytours.co"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_provider_paths" />
</provider>
file_provider_paths.xml file:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="uploads" path="." />
</paths>
Java class code:
imageUri = FileProvider.getUriForFile(getApplicationContext(),"staging.mytours.co",new File(Uri.parse(http://staging.mytours.co/uploads/ + tour.getImageCover()).getPath()));
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "TOUR:" + tour.getTitle());
shareIntent.putExtra(Intent.EXTRA_TEXT, "My Tour");
shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
shareIntent.setType("image/*");
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(shareIntent, "Share via"));
Have already gone through other solutions from this site but nothing worked in my case.
Update:
I have added following function to save image to /data/co.mytours folder in storage.
public File DownloadFileFromURL()
{
String urlimage = http://staging.mytours.co/uploads/ + tour.getImageCover();
int count;
try {
URL url = new URL(urlimage);
URLConnection conection = url.openConnection();
conection.connect();
// download the file
InputStream input = new BufferedInputStream(url.openStream(),
8192);
// Output stream
File storagePath = Environment.getExternalStorageDirectory();
OutputStream output = new FileOutputStream(storagePath
+ "/data/co.mytours");
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// writing data to file
output.write(data, 0, count);
}
// flushing output
output.flush();
// closing streams
output.close();
input.close();
return storagePath;
} catch (Exception e) {
Log.e("Error: ", "Exceptio Occured");
return null;
}
}
And call this,
File imagepath = DownloadFileFromURL();
Uri imageUrishare = FileProvider.getUriForFile(getApplicationContext(), "co.mytours", new File(imagepath.getPath()));
But still get a error Attempt to invoke virtual method java.lang.String java.io.File.getPath() on a null object reference.
You have an HTTP URL. That is not a local file on the filesystem. You cannot create a File object from an HTTP URL.
The simplest thing is to embed the URL as part of your EXTRA_TEXT value.
If you really want to attach the image, you will need to:
Download that image to a file
Save that file someplace that is configured for your FileProvider
Use the File object for your getUriForFile() call for use with EXTRA_STREAM
Use the correct MIME type, not image/*

Android share app's apk using FileProvider

I've tried to share the app's apk file through intent.The provider in my manifest file:
`<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="package name"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/mypaths" />
and the mypaths file is:
<paths>
<external-path name="apk_folder"/>
</paths>
I set intent and the File path as below:
String packageName = getContext().getPackageName();
PackageManager pm = getContext().getPackageManager();
String apk = null;
try {
ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
apk = ai.publicSourceDir;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
File apkFile = new File(apk);
Uri uri = FileProvider.getUriForFile(getContext(), "package name", apkFile);
Intent intent = ShareCompat.IntentBuilder.from(getActivity())
.setType("*/*")
.setStream(uri)
.setChooserTitle("Share via")
.createChooserIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
I get IllegalArgumentException :
Failed to find configured root that contains /data/app/package name.edu-1/base.apk
Please help me to find out my mistakes.
change the "package name" in your code to activity.getPackageName() and cahnge path to root-path
or try This codes:
in Manifest
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
in res/xml/file_paths.xml
<paths>
<root-path
name="app"
path="/"/>
</paths>
Code :
public static void sendApkFile(Activity activity) {
try {
PackageManager pm = activity.getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo(activity.getPackageName(), 0);
File srcFile = new File(ai.publicSourceDir);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("*/*");
Uri uri = FileProvider.getUriForFile(context, activity.getPackageName(), srcFile);
intent.putExtra(Intent.EXTRA_STREAM, uri);
activity.grantUriPermission(activity.getPackageManager().toString(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
And IF you Want to APK File have any other name , not just base.APK , try this
public static void sendApplication(Activity activity) {
ApplicationInfo app = activity.getApplicationContext().getApplicationInfo();
String filePath = app.sourceDir;
Intent intent = new Intent(Intent.ACTION_SEND);
// MIME of .apk is "application/vnd.android.package-archive".
// but Bluetooth does not accept this. Let's use "*/*" instead.
intent.setType("*/*");
// Append file and send Intent
File originalApk = new File(filePath);
try {
//Make new directory in new location
File tempFile = new File(activity.getExternalCacheDir() + "/ExtractedApk");
//If directory doesn't exists create new
if (!tempFile.isDirectory()) {
if (!tempFile.mkdirs()) {
return;
}
}
//Get application's name and convert to lowercase
tempFile = new File(tempFile.getPath() + "/" + activity.getString(app.labelRes).replace(" ", "").toLowerCase() + ".apk");
//If file doesn't exists create new
if (!tempFile.exists()) {
if (!tempFile.createNewFile()) {
return;
}
}
//Copy file to new location
InputStream in = new FileInputStream(originalApk);
OutputStream out = new FileOutputStream(tempFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
System.out.println("File copied.");
//Open share dialog
Uri uri = FileProvider.getUriForFile(context, activity.getPackageName(), tempFile);
intent.putExtra(Intent.EXTRA_STREAM, uri);
activity.grantUriPermission(activity.getPackageManager().toString(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
i can solve exact this problem, only use:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<root-path path="data/app/" name="external_files"/>
</resources>
There is no available root in FileProvider that will handle your designated location. You would need to create your own ContentProvider for this.

Android 6.0 Permissions Issues

I am having one heck of a time with this new permission request in Android 6. My app worked fine, and then in the last two days it is force closing all the time. If I change the target SDK level to 22, it works fine, but of course Play Store wont let you downgrade the SDK.
I need these permissions.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.android.vending.BILLING" />
After this I am not sure how to work the requesting, or new way of implementing the permissions part so the errors will stop. I have been working on this for hours and have googled and search endlessly. While alot of examples out there all tell me to do the same thing, I just cannot seem to get it write in Android Studio. Any help would be greatly appreciated.
Here is part of the code that was giving me issues.
public void exportSkin(View arg0) throws IOException {
if (type.equals("popular")) {
AssetManager assetManager = getAssets();
InputStream is = assetManager.open("skins/" + skinname + ".png");
// create a File object for the parent directory
File wallpaperDirectory = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath() + "/SkinYourself/");
// have the object build the directory structure, if needed.
//noinspection ResultOfMethodCallIgnored
wallpaperDirectory.mkdirs();
// create a File object for the output file
File out = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/SkinYourself/", "" + PopChar.character_name + ".png");
byte[] buffer = new byte[1024];
FileOutputStream fos = new FileOutputStream(out);
int read;
while ((read = is.read(buffer, 0, 1024)) >= 0) {
fos.write(buffer, 0, read);
}
fos.flush();
fos.close();
is.close();
}
if (type.equals("create")) {
String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
File myDir = new File(root + "/SkinYourself");
myDir.mkdirs();
String fname = "SkinYourself" + System.currentTimeMillis() / 1000 + ".png";
File file = new File(myDir, fname);
if (file.exists()) file.delete();
try {
FileOutputStream out = new FileOutputStream(file);
b.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*sendBroadcast(new Intent(
Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory())));
*/
Toast.makeText(MainActivity.this,
"Your skin has been saved to the SkinYourself folder check the info button on how to use it", Toast.LENGTH_LONG)
.show();
displayInterstitial();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File("file://" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
} else {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES))));
}
}

Categories

Resources