I am trying to create a option for the user to send the file from my application via email only. The file is internal to the application and is accessible via the FileProvider.
This is the contentURI looks like content://packagename.files/files/somefile.ext
Here as you can see that I am giving the user to share the file to PicsArt, Google Drive, OneDrive and EMail.
I am able to share the content to the first three clients successfully as they very specific applications. But when it comes to Email, I need to user to pick the client from the applications he has installed in his mobile.
Here are 2 set of codes I have created:
Code Option 1:
Intent EMail = ShareCompat.IntentBuilder.from(this)
.setType("message/rfc822")
.setSubject("Emailing: File Attached")
.setText("Hello")
.setStream(contentUri)
.setChooserTitle("Send via EMail").getIntent();
startActivity(Intent.createChooser(EMail, "Send via EMail"));
Above code shows me a chooser where there are many applications which can handle the files as shown in the image below.
This one works fine if I select any email client application or any other application.
But the problem with this is that there is an option for the user to select any application, which is not the desired behavior of the application. So, I modified the code as below:
final Intent _Intent = new Intent(Intent.ACTION_SENDTO);
_Intent.setType("text/html");
_Intent.setData(Uri.parse("mailto:"));
_Intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
_Intent.putExtra(Intent.EXTRA_STREAM, contentUri);
_Intent.putExtra(android.content.Intent.EXTRA_SUBJECT,
"Emailing: File Attached");
_Intent.putExtra(android.content.Intent.EXTRA_TEXT,
"Hello");
startActivity(Intent.createChooser(_Intent, "Send via EMail"));
Here is the outcome of the code:
But, now the problem here is that I am not able to send the file from the content provider (FileProvider). The email client shows the message as below after selecting:
It is simply not attaching the file to the email in any client in the above list.
I will be greatfull, if anyone can help me out here. I think that, I have tried all the possible scenarios here, by changing the mime-type, setting content in different manner setting data setting stream etc, but not able to get the desired outcome.
Please let me know in case you need any other details on this.
Thanks again in advance.
You need to write the ContentProvider which will provide the InputStream to the client to which you have passed the ContentUri or may be you can directly provide the file path if its present in the SdCard or the Internal storage because you will need to handle the uri's and pass the InputStream . Note: ExtraStream is best for files that are not in device that is which is to be accessed from internet.
public class SampleContentProvider extends ContentProvider implements ContentProvider.PipeDataWriter<InputStream> {
static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//Uri matcher for different
}
/**
* Database specific constant declarations
*/
private SQLiteDatabase db;
#Override
public boolean onCreate() {
return true;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
throw new SQLException("Insert operation not supported for " + uri);
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
//condition just for files. You can try something else
if (uri.toString().contains("files")) {
//you get the file name
String lastSegment = uri.getLastPathSegment();
if (projection == null) {
projection = new String[]{OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
}
File file = //Code to read the file as u have the directory, just get the file from the file name obtained from the uri
if (null == file) {
throw new IllegalArgumentException("Unknown File for Uri " + uri);
}
String[] cols = new String[projection.length];
Object[] values = new Object[projection.length];
int i = 0;
for (String col : projection) {
if (OpenableColumns.DISPLAY_NAME.equals(col)) {
cols[i] = OpenableColumns.DISPLAY_NAME;
values[i++] = //file name;
} else if (OpenableColumns.SIZE.equals(col)) {
cols[i] = OpenableColumns.SIZE;
values[i++] = //file size;
}
}
cols = copyOf(cols, i);
values = copyOf(values, i);
final MatrixCursor cursor = new MatrixCursor(cols, 1);
cursor.addRow(values);
return cursor;
}
return super.query(uri, projection, selection, selectionArgs, sortOrder);
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return super.delete(uri, selection, selectionArgs);
}
private static String[] copyOf(String[] original, int newLength) {
final String[] result = new String[newLength];
System.arraycopy(original, 0, result, 0, newLength);
return result;
}
private static Object[] copyOf(Object[] original, int newLength) {
final Object[] result = new Object[newLength];
System.arraycopy(original, 0, result, 0, newLength);
return result;
}
#Nullable
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File file = //read the file
if (file != null) {
try {
StrictMode.ThreadPolicy tp = StrictMode.ThreadPolicy.LAX;
StrictMode.setThreadPolicy(tp);
InputStream in = //Code to get the inputstream;
// Start a new thread that pipes the stream data back to the caller.
return openPipeHelper(uri, null, null, in, this);
} catch (IOException e) {
FileNotFoundException fnf = new FileNotFoundException("Unable to open " + uri);
throw fnf;
}
}
throw new IllegalArgumentException("Unknown URI " + uri);
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return super.update(uri, values, selection, selectionArgs);
}
#Override
public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType,
Bundle opts, InputStream args) {
// Transfer data from the asset to the pipe the client is reading.
byte[] buffer = new byte[8192];
int n;
FileOutputStream fout = new FileOutputStream(output.getFileDescriptor());
try {
while ((n = args.read(buffer)) >= 0) {
fout.write(buffer, 0, n);
}
} catch (IOException e) {
} finally {
try {
args.close();
} catch (IOException e) {
}
try {
fout.close();
} catch (IOException e) {
}
}
}
}
I have decided to copy the file from internal app storage to external app storage (not external public storage) and sharing the file from there. I am bit surprised though as the FileProvider is capable of sharing the files from the internal file storage with anything and every thing in the system but fails to do so when I want to filter the Intents which are email clients only.
It was kind of difficult for me to implement a custom provider at beginner's level.
try this snippet.
Intent testIntent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.parse("mailto:?subject=" + "Feedback" + "&body=" + "Write Feedback here....." + "&to=" + "someone#example.com");
testIntent.setData(data);
startActivity(testIntent);
Related
I have an application for API26+
With Android 10 and above (API29+) should be used MediaStore to access files, instead of Environment.getExternalStoragePublicDirectory
normally making of new approach would be maked in creation of if-block
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
// deprecated code
} else {
// new approach
}
But:
MediaStorage use Uri to request a file. API28 and below works with File or String as path to file
With MediaStore manually creation of a folder is not needed. API 28 and below should create a folder if not exists.
Deleting of Files requires User interaction with MediaStore.
CRUD:
Create: To write data in File for any API is OutputStream required. That could be reached with if else
Read: How to create general approach to read a File, where API 29+ needs Uri, and API28- needs File|String to access a file?
Update: first Read to check if exists, then Create to get OutputStream
Delete: How to create a batch confirmation with MediaStore?
Is it possible to work with MediaStorage with API26+?
If yes, how? Many properties are added first in API29
After some own research and testing i have found the way to work with MediaStore and on old devices in same time.
First of all some helper classes needed:
With FileType we can support different file types in application at same time.
public enum FileType {
File(Environment.DIRECTORY_DOCUMENTS, Constants.VERSION_29_ABOVE ? MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) : null, "text/plain"),
Download(Environment.DIRECTORY_DOWNLOADS, Constants.VERSION_29_ABOVE ? MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL) : null, "text/plain"),
Image(Environment.DIRECTORY_PICTURES, Constants.VERSION_29_ABOVE ? MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) : null, "image/jpeg"),
Audio(Environment.DIRECTORY_MUSIC, Constants.VERSION_29_ABOVE ? MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) : null, "audio/mpeg"),
Video(Environment.DIRECTORY_MOVIES, Constants.VERSION_29_ABOVE ? MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) : null, "video/mpeg");
private final String directory;
private final Uri contentUri;
private String mimeType;
FileType(String directory, Uri contentUri, String mimeType) {
this.directory = directory;
this.contentUri = contentUri;
this.mimeType = mimeType;
}
public String getDirectory() {
return directory;
}
public Uri getContentUri() {
return contentUri;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
}
with setMimeType we can change current file extension and still use other settings
And we need simple callback class to get different results
public interface ObjectCallback<T> {
void result(T object);
}
When we want write some data in a file, we need an OutputStream
With internal storage, the way to get a file has not changed
/**
* opens OutputStream to write data to file
*
* #param context activity context
* #param fileName relative file name
* #param fileType file type to get folder specific values for access
* #param fileStream callback with file output stream to requested file
* #return true if output stream successful opened, false otherwise
*/
public boolean openOutputStream(Context context, String fileName, FileType fileType, ObjectCallback<OutputStream> fileStream) {
File internalFolder = context.getExternalFilesDir(fileType.getDirectory());
File absFileName = new File(internalFolder, fileName);
try {
FileOutputStream fOut = new FileOutputStream(absFileName);
fileStream.result(fOut);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
By external storage, the way to access a file on API 28- and API 29+ is completely different.
On API 28- we could just use a file for it.
On API 29+ we shoould first check, if file already exists. If it (say text.txt) exists and we would make ContentResolver.insert, it would create text-1.txt and in worst case (endless loop) in could quick fill whole smartphone storage.
/**
* #param context application context
* #param fileName relative file name
* #return uri to file or null if file not exist
*/
public Uri getFileUri(Context context, String fileName) {
// remove folders from file name
fileName = fileName.contains("/") ? fileName.substring(fileName.lastIndexOf("/") + 1) : fileName;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
// Deprecated in API 29
File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), Constants.PUBLIC_STORAGE_FOLDER);
File file = new File(storageDir, fileName);
return file.exists() ? Uri.fromFile(file) : null;
} else {
String folderName = Environment.DIRECTORY_PICTURES + File.separator + Constants.PUBLIC_STORAGE_FOLDER + File.separator;
// get content resolver that can interact with public storage
ContentResolver resolver = context.getContentResolver();
String selection = MediaStore.MediaColumns.RELATIVE_PATH + "=?";
String[] selectionArgs = new String[]{folderName};
Cursor cursor = resolver.query(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL), null, selection, selectionArgs, null);
Uri uri = null;
if (cursor.getCount() > 0) {
while (cursor.moveToNext()) {
String itemFileName = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME));
if (itemFileName.equals(fileName)) {
long id = cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
uri = ContentUris.withAppendedId(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL), id);
break;
}
}
}
cursor.close();
return uri;
}
}
/**
* opens OutputStream to write data to file
*
* #param context activity context
* #param fileName relative file name
* #param fileType file type to get folder specific values for access
* #param fileStream callback with file output stream to requested file
* #return true if output stream successful opened, false otherwise
*/
public boolean openOutputStream(Context context, String fileName, FileType fileType, ObjectCallback<OutputStream> fileStream) {
// remove folders from file name
fileName = fileName.contains("/") ? fileName.substring(fileName.lastIndexOf("/") + 1) : fileName;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), Constants.PUBLIC_STORAGE_FOLDER);
if (!storageDir.exists() && !storageDir.mkdir()) {
// directory for file not exists and not created. return false
return false;
}
File file = new File(storageDir, fileName);
try {
FileOutputStream fOut = new FileOutputStream(file);
fileStream.result(fOut);
} catch (Exception e) {
e.printStackTrace();
return false;
}
} else {
// get content resolver that can interact with public storage
ContentResolver resolver = context.getContentResolver();
// always check first if file already exist
Uri existFile = getFileUri(context, fileName);
if (existFile == null) {
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.MIME_TYPE, fileType.getMimeType());
// absolute folder name
values.put(MediaStore.MediaColumns.RELATIVE_PATH, fileType.getDirectory() + File.separator + Constants.PUBLIC_STORAGE_FOLDER);
// file name
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
// create uri to the file. If folder not exists, it would be created automatically
Uri uri = resolver.insert(fileType.getContentUri(), values);
// open stream from uri and write data to file
try (OutputStream outputStream = resolver.openOutputStream(uri)) {
fileStream.result(outputStream);
// end changing of file
// when this point reached, no exception was thrown and file write was successful
values.put(MediaStore.MediaColumns.IS_PENDING, false);
resolver.update(uri, values, null, null);
} catch (Exception e) {
e.printStackTrace();
if (uri != null) {
// Don't leave an orphan entry in the MediaStore
resolver.delete(uri, null, null);
}
return false;
}
} else {
// open stream from uri and write data to file
try (OutputStream outputStream = resolver.openOutputStream(existFile)) {
fileStream.result(outputStream);
} catch (Exception e) {
e.printStackTrace();
// Don't leave an orphan entry in the MediaStore
resolver.delete(existFile, null, null);
return false;
}
}
}
return true;
}
In same way could be opened InputStream on all devices and different storage.
To delete file:
internal could be still deleted with file.delete on every API
external storage with API29+ requires user interaction to delete some file
FileProvider
To use Intent for showing some picture, crop picture or whatever, where we use setDataAndType
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(photoUri, "image/*");
// allow to read the file
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
we need in some cases the FileProvider. Specially:
To show external file created with the app, the photoUri would look this way
Uri photoUri = Constants.VERSION_29_ABOVE ? uriToFile :
FileProvider.getUriForFile(context,
context.getApplicationContext().getPackageName() + ".provider",
new File(uriToFile.getPath()));
I have a function below that I got from a post on here, where I am trying to read the music files from the device.
public List<AudioModel> getAllAudioFromDevice(final Context context) {
final List<AudioModel> tempAudioList = new ArrayList<>();
Cursor c = getAllTracks(this);
if (c != null) {
Log.d("Count :", String.valueOf(c.getCount()));
while (c.moveToNext()) {
AudioModel audioModel = new AudioModel();
String path = c.getString(0);
String name = c.getString(1);
String album = c.getString(4);
audioModel.setaAlbum(album);
audioModel.setaArtist(artist);
Log.e("Name :" + name, " Album :" + album);
Log.e("Path :" + path, " Artist :" + artist);
tempAudioList.add(audioModel);
}
c.close();
} else {
Log.d("Name :", "No Music");
}
return tempAudioList;
}
public Cursor getAllTracks(Context context) {
// gets all tracks
if (context != null) {
ContentResolver cr = context.getContentResolver();
final String[] columns = {track_id, track_no, artist, track_name,
album, duration, path, year, composer};
return cr.query(uri, columns, null, null, null);
} else {
return null;
}
}
When I run the app, it doesn't list any of the MP3 files, but it picks up oog files. The mp3 files I have uploaded to the emulator look as below:
I have tried the EXTERNAL_CONTENT_URI as well, but that doesn't display them.
This is from the "Playlist Manager" app as suggested by Theo:
Sorry, I am very new to Android Studio and am probably missing something very obvious. Can someone help please?
Your issue is
Uri uri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
change this to
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
and also remove the .DATA bit from
Cursor c = context.getContentResolver().query(uri, projection, MediaStore.Audio.Media.DATA, null, null)
as you put criteria there. Look up the syntax for query. Set it to null and it will work
For what it's worth - I had the exact same problem. I added my audio files to the emulator using the Device File Explorer and the code didn't seem to work.
It turns out that I had to simply reboot my emulator after adding the files in order for the uploaded files to appear in the MediaStore data base.
I don't know if this is a bug or a feature in Android Studio and/or the emulator, but in my case it fixed the issue. I tested it on two different emulator sessions (one with SDK31 and the other SDK29).
This is my approach, note the syntax of
return cr.query(uri, columns, null, null, null)
whereas you have
Cursor c = context.getContentResolver().query(uri, projection, MediaStore.Audio.Media.DATA, null, null);
private final String track_id = MediaStore.Audio.Media._ID;
private final String track_no = MediaStore.Audio.Media.TRACK;
private final String track_name = MediaStore.Audio.Media.TITLE;
private final String artist = MediaStore.Audio.Media.ARTIST;
private final String artist_id = MediaStore.Audio.Media.ARTIST_ID;
private final String duration = MediaStore.Audio.Media.DURATION;
private final String album = MediaStore.Audio.Media.ALBUM;
private final String composer = MediaStore.Audio.Media.COMPOSER;
private final String year = MediaStore.Audio.Media.YEAR;
private final String path = MediaStore.Audio.Media.DATA;
private final String date_added = MediaStore.Audio.Media.DATE_ADDED;
private final Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
public Cursor getAllTracks(Context context) {
// gets all tracks
if (context != null) {
ContentResolver cr = context.getContentResolver();
final String[] columns = {track_id, track_no, artist, track_name,
album, duration, path, year, composer};
return cr.query(uri, columns, null, null, null);
} else {
return null;
}
}
I've now tried since a long time to make a cross app sharing intent from assets folder for different types of files, but there is always a problem working. I went on a lot of different types of solutions such as:
Try to use a custom content provider (here, or here, ..)
Try to save the file on local storage (example here)
and others but as it didn't worked I don't have links anymore..
Right now, here is my working solution for sharing an audio file to whatsapp and messenger only, all other app are failing).
My function to create a new file on app storage:
public String getNewPathFromSbElem(SbElem sbElem, String fileName) {
AssetManager assetManager = getAssets();
String path = sbElem.soundPath;
String newName = fileName;
String newPath = getExternalFilesDir(null).getAbsolutePath() + File.separator + newName;
InputStream in = null;
OutputStream out = null;
File outFile;
File deleteFile = new File(newPath);
if(deleteFile.exists()) {
deleteFile.delete();
}
try {
in = assetManager.open(path);
outFile = new File(getExternalFilesDir(null), newName);
out = new FileOutputStream(outFile);
copyFile(in, out);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
return newPath;
}
My 2 functions to share on whatsapp or messenger:
public void shareOnWhatsApp(SbElem sbElem) {
final String newPath = getNewPathFromSbElem(sbElem, "_share_temp_file.mp3");
Intent whatsappIntent = new Intent(Intent.ACTION_SEND);
whatsappIntent.setPackage("com.whatsapp");
whatsappIntent.setType("audio/mp3");
whatsappIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(newPath));
whatsappIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
startActivity(whatsappIntent);
} catch (android.content.ActivityNotFoundException ex) {
Log.d("error", "WhatsApp not installed");
}
}
public void shareOnMessenger (SbElem sbElem) {
final String newPath = getNewPathFromSbElem(sbElem, "_share_temp_file.mp3");
final File newFile = new File(newPath);
final Uri newUri = FileProvider.getUriForFile(this, getString(R.string.file_provider_authority), newFile);
final Integer SHARE_TO_MESSENGER_REQUEST_CODE = 1;
String mimeType = "audio/*";
ShareToMessengerParams shareToMessengerParams = ShareToMessengerParams.newBuilder(newUri, mimeType).build();
MessengerUtils.shareToMessenger(this, SHARE_TO_MESSENGER_REQUEST_CODE, shareToMessengerParams);
}
The thing is, I would like to be able to share from my asset folder a .mp3, a .jpg, a .png, to gmail, to whatsapp, to slack, or any type of app that supports this extension...
So as almost all the 1000 questions / articles online regarding sharing assets are answered by using a custom content provider, I tried the following sharing function:
public void shareBasic () {
// I added the test.jpg in the root of my asset folder
// Tried with content / file / 2 or 3 '/', with package name and with assets / ...
Uri theUri = Uri.parse("content:///com.MY_PACKAGE_NAME/test.jpg");
//Uri theUri = Uri.parse("content:///assets/test.jpg");
//Uri theUri = Uri.parse("file:///com.MY_PACKAGE_NAME/test.jpg");
//Uri theUri = Uri.parse("file:///asset.jpg");
Intent theIntent = new Intent(Intent.ACTION_SEND);
// Tried with jpeg / png / jpg ...
theIntent.setType("image/*");
theIntent.putExtra(Intent.EXTRA_STREAM, theUri);
theIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(theIntent);
}
And here is my Android manifest:
<provider
android:name="MY_PACKAGE_NAME.MyContentProvider"
android:authorities="MY_PACKAGE_NAME"
android:grantUriPermissions="true"
android:exported="true" />
And the file provider (almost the same on every tutorial)
public class MyContentProvider extends ContentProvider {
#Override
public boolean onCreate() {
return true;
}
#Override
public Cursor query(#NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}
#Override
public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal )
{
// TODO: Implement this method
return super.query( uri, projection, selection, selectionArgs, sortOrder, cancellationSignal );
}
#Nullable
#Override
public String getType(#NonNull Uri uri) {
return null;
}
#Nullable
#Override
public Uri insert(#NonNull Uri uri, ContentValues values) {
return null;
}
#Override
public int delete(#NonNull Uri uri, String selection, String[] selectionArgs) {
return 0;
}
#Override
public int update(#NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
#Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
AssetManager am = getContext().getAssets();
String fileName = uri.getLastPathSegment();
if(fileName == null)
throw new FileNotFoundException();
AssetFileDescriptor fileDescriptor = null;
try {
fileDescriptor = am.openFd(fileName);
} catch (IOException e) {
e.printStackTrace();
}
return fileDescriptor;
}
}
I guess I'm doing huge mistakes as sharing an file from asset folder shouldn't be such a struggle, any ideas ?
For your ContentProvider solution:
You need to have your query() function support the OpenableColumns
You need to have your getType() function return the actual MIME type
Your Intent needs to use a concrete MIME type, not a wildcard
See this old sample project for a demonstration.
So what i want is to delete file using URI
Do not flag is duplicate
I tried many answer but nothing worked here is the question i tried
How to delete file that is created using Uri?
Delete file using Uri
How to delete file that is created using Uri?
I write code to get images from gallery and then copy it to directory called ".blackhat" and delete original one (Kind of Move File Function)..But it's not working. even it is not generation Log so i can check the error.
this code working proper for copying file but not deleting after copying....
if(requestCode == 2 && data.getData() !=null){
if(cd == null){
path.add(data.getData());
Random rn = new Random();
if(copyFileFromUri(this,data.getData(),String.valueOf(rn.nextInt(500)))){
File fdelete = new File(data.getData().getPath());
if (fdelete.exists()) {
if (fdelete.delete()) {
Log.d("delete","deleted");
} else {
Log.d("delete","not deleted");
}
}
Toast.makeText(this, "Done", Toast.LENGTH_SHORT).show();
}
}else{
for(int i=0;i<data.getClipData().getItemCount();i++){
path.add(data.getClipData().getItemAt(i).getUri());
Log.d("RjList",path.get(i).toString());
Random rn=new Random();
if(copyFileFromUri(this,data.getClipData().getItemAt(i).getUri(),String.valueOf(rn.nextInt(500)))){
File fdelete = new File(data.getClipData().getItemAt(i).getUri().getPath());
if (fdelete.exists()) {
if (fdelete.delete()) {
Log.d("delete","deleted");
} else {
Log.d("delete","not deleted");
}
}
Toast.makeText(this, "Done", Toast.LENGTH_SHORT).show();
}
}
}
}
Where am i doing wrong ????
Thank in advance...
public static boolean delete(final Context context, final File file) {
final String pathone = MediaStore.MediaColumns.DATA + "=?";
final String[] selectedArgs = new String[] {
file.getAbsolutePath()
};
final ContentResolver contentResolver = context.getContentResolver();
final Uri fileUri = MediaStore.Files.getContentUri("external");
contentResolver.delete(fileUri, pathone, selectedArgs );
if (file.exists()) {
contentResolver.delete(fileUri, pathone, selectedArgs );
}
return !file.exists();
}
File fdelete = new File(data.getData().getPath(),"here you should pass the file name");
if (fdelete.exists()) {
if (fdelete.delete()) {
Log.d("delete","deleted");
} else {
Log.d("delete","not deleted");
}
}
This question already has an answer here:
Android send mail with PDF file
(1 answer)
Closed 7 years ago.
I need send a PDF file attach on a message, I have a button that calls a function that open a Intent with message, email address and subject filled, but I need that the PDF file has been attached too.
This is my code and I can not find my error, someone can help me please?
public void initializeWebView() {
// Initialize the webview
webView.setResourceClient(new XWalkResourceClient(webView) {
#Override
public boolean shouldOverrideUrlLoading(XWalkView view, String stringUrl) {
if(stringUrl.equals(baseUrl)) {
return false;
}
// mailto links will be handled by the OS.
if (stringUrl.startsWith("mailto:")) {
Uri uri = Uri.parse(stringUrl);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
String fileName = "bouhnik.pdf";
String filePath = (Configuration.getMagazineAssetPath()).toString()+ File.separator + fileName;
Context c = getActivity().getApplicationContext();
File file = null;
FileOutputStream fos = null;
try {
InputStream is = c.getAssets().open(filePath);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
fos = new FileOutputStream(file);
fos.write(buffer);
fos.close();
} catch (IOException e) {
Log.i("Ferrou",e.toString());
e.printStackTrace();
}
if (!file.exists() || !file.canRead()) {
return false;
}
intent.putExtra(intent.EXTRA_STREAM, file.getPath());
intent.setClassName("com.android.email", "com.android.mail.compose.ComposeActivity");
intent .putExtra(Intent.EXTRA_SUBJECT, "Subject");
WebViewFragment.this.startActivity(Intent.createChooser(intent, "Send email..."));
} else {
try {
URL url = new URL(stringUrl);
// We try to remove the referrer string to avoid passing it to the server in case the URL is an external link.
String referrer = "";
if (url.getQuery() != null) {
Map<String, String> variables = Configuration.splitUrlQueryString(url);
String finalQueryString = "";
for (Map.Entry<String, String> entry : variables.entrySet()) {
if (entry.getKey().equals("referrer")) {
referrer = entry.getValue();
} else {
finalQueryString += entry.getKey() + "=" + entry.getValue() + "&";
}
}
if (!finalQueryString.isEmpty()) {
finalQueryString = "?" + finalQueryString.substring(0, finalQueryString.length() - 1);
}
stringUrl = stringUrl.replace("?" + url.getQuery(), finalQueryString);
}
// Remove referrer from query string
if (!url.getProtocol().equals("file")) {
if (referrer.equals(WebViewFragment.this.getActivity().getString(R.string.url_external_referrer))) {
Uri uri = Uri.parse(stringUrl);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
WebViewFragment.this.startActivity(intent);
} else if (referrer.toLowerCase().equals(WebViewFragment.this.getActivity().getString(R.string.url_baker_referrer))) {
((IssueActivity) WebViewFragment.this.getActivity()).openLinkInModal(stringUrl);
return true;
} else {
return false;
}
} else {
stringUrl = url.getPath().substring(url.getPath().lastIndexOf("/") + 1);
int index = ((IssueActivity) WebViewFragment.this.getActivity()).getJsonBook().getContents().indexOf(stringUrl);
if (index != -1) {
Log.d(this.getClass().toString(), "Index to load: " + index + ", page: " + stringUrl);
((IssueActivity) WebViewFragment.this.getActivity()).getViewPager().setCurrentItem(index);
view.setVisibility(View.GONE);
} else {
// If the file DOES NOT exist, we won't load it.
File htmlFile = new File(url.getPath());
if (htmlFile.exists()) {
return false;
}
}
}
} catch (MalformedURLException | UnsupportedEncodingException ex) {
Log.d(">>>URL_DATA", ex.getMessage());
}
}
return true;
}
});
// Set UI Client (Start stop animations)
webView.setUIClient(new XWalkUIClient(webView) {
#Override
public void onPageLoadStopped(XWalkView view, String url, LoadStatus status) {
if(!url.isEmpty() && status == LoadStatus.FINISHED) {
if(isUserVisible) {
webView.resumeTimers();
}else{
webView.pauseTimers();
}
}
}
});
webView.load(baseUrl, null);
}
Thank's so much for everyone!!
I solve my problem change the type of Intent to:
Intent emailIntent = new Intent(Intent.ACTION_SEND);
Because this is better to email commands, and I define a emailUri where:
emailUri = Uri.fromFile(file.getAbsoluteFile());
because this get a absolute path with a file inside, and when the email client open, it open this file, not a path.
I add a type at my intent but I select the type of my attachment, so I define:
emailIntent.setType("application/pdf");
And finally:
emailIntent.putExtra(Intent.EXTRA_STREAM, uriMail);
startActivity(emailIntent);
It's works now!! Thanks :D
It looks like something is might be going wrong with your file path. Double check it. Then
1 - You need to add the package name of your application with context.getPackageName()
private String path = Environment.getExternalStorageDirectory().getPath() + context.getPackageName() + "books/"+fileName;
2 - Declare the permission inside your AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />