Anant Anand Gupta
Anant Anand Gupta

Reputation: 738

Android Share Intent Chooser EMail Client Only

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.

ShareDialogFragment

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.

Activity Chooser

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:

only email clients

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:

enter image description here

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.

Upvotes: 5

Views: 2323

Answers (3)

Kishankumar Vasoya
Kishankumar Vasoya

Reputation: 936

try this snippet.

Intent testIntent = new Intent(Intent.ACTION_VIEW);
                    Uri data = Uri.parse("mailto:?subject=" + "Feedback" + "&body=" + "Write Feedback here....." + "&to=" + "[email protected]");
                    testIntent.setData(data);
                    startActivity(testIntent);

Upvotes: 0

Anant Anand Gupta
Anant Anand Gupta

Reputation: 738

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.

Upvotes: 0

Mohammed Rampurawala
Mohammed Rampurawala

Reputation: 3112

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) {
            }
        }
    }

}

Upvotes: 1

Related Questions