0

I want open and email app with already generated text, subject, recipient and attached file, it works with android sdk version 29 (android 10) and lower. However starting Android 11 there are restriction to writing file in external or internal storages, and there is also another restriction that is not allowed to attach file automatically from app file directory. Previously I was copying from app storage to internal or external storage to attach file, any solutions?

done android:requestLegacyExternalStorage="true"

public static void sendMail(Context context) throws IOException {
        Context appContext = context.getApplicationContext();

        File logFile = FileUtils.createFile(context.getFilesDir().getAbsolutePath(), "testFile.txt", "Test");

        File logsDirectory = new File(FileUtils.getStorageDirectory(appContext), "files");
        logsDirectory.mkdirs();

        File destFile = new File(logsDirectory, "log.txt");

        InputStream in = new FileInputStream(logFile);
        boolean copied = FileUtils.copyToFile(in, destFile);

        Uri logPath = Uri.fromFile(destFile);

        Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
        emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        emailIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // set the type to 'email'
        emailIntent.setData(Uri.parse("mailto:"));
        String[] to = {"support@test.com"};
        String subject = "Test log";
        String body =
                "Hello";
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
        emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
        emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, body);
        // the attachment
        emailIntent.putExtra(Intent.EXTRA_STREAM, logPath);

        context.startActivity(Intent.createChooser(emailIntent, "Send email..."));
    } 
public class FileUtils {
    
        public static String getExtensionFromFileName(String fileName) {
        if (fileName == null) return null;

        String extension = null;
        int i = fileName.lastIndexOf('.');
        if (i > 0) {
            extension = fileName.substring(i + 1);
        }
        return extension;
    }

    /**
     * Copy data from a source stream to destFile. Return true if succeed, return false if failed.
     */
    public static boolean copyToFile(InputStream inputStream, File destFile) {
        if (inputStream == null || destFile == null) return false;
        try {
            try (OutputStream out = new FileOutputStream(destFile)) {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) >= 0) {
                    out.write(buffer, 0, bytesRead);
                }
            }
            return true;
        } catch (IOException e) {
            Log.e("[File Utils]", "copyToFile exception: " + e);

        }
        return false;
    }


    public static String getStorageDirectory(Context mContext) {
        String storageDir =
                Environment.getExternalStorageDirectory().getAbsolutePath()
                        + "/"
                        + mContext.getString(R.string.app_name);
        File file = new File(storageDir);
        mContext.getExternalMediaDirs();

        if (!file.isDirectory() || !file.exists()) {


        }
        return storageDir;
    }

    public static File createFile(String directory ,String fileName, String textToAttach)
    {
        File logFile = new File(directory  + "/" + fileName);
        if (!logFile.exists())
        {
            try
            {
                logFile.createNewFile();
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        try
        {
            //BufferedWriter for performance, true to set append to file flag
            BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
            buf.append(textToAttach);
            buf.newLine();
            buf.close();
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return logFile;
    }
}
Paruyr
  • 37
  • 1
  • 8
  • 1
    `Uri.fromFile(destFile)` has been banned for five years -- you should be [getting a `FileUriExposedException`](https://stackoverflow.com/q/38200282/115145). Use `FileProvider` to share content with other apps. – CommonsWare Apr 08 '21 at 14:59
  • @CommonsWare there is only this exception in android 11: E/[File Utils]: copyToFile exception: java.io.FileNotFoundException: /storage/emulated/0/MyApplication/files/log.txt: open failed: ENOENT (No such file or directory) – Paruyr Apr 08 '21 at 15:09
  • 1
    That's because you disabled the check for `FileUriExposedException` in `StrictMode`. Use `FileProvider` to share content with other apps. – CommonsWare Apr 08 '21 at 15:23
  • did you solve problem? – AlexS Jun 01 '21 at 12:57
  • @AlexS yes i used FileProvider as suggested in comment and add selector – Paruyr Jun 02 '21 at 13:32

1 Answers1

0

I have done using FileProvider and selector, this is for multiple files

public static void sendMail(Context context) {
        Context appContext = context.getApplicationContext();
        final String authority = appContext.getPackageName() + ".FileProvider";
        String[] to = {"test@test.com"};
        String subject = "subject";
        String body = "body";
        
        ArrayList<File> logFiles = getLogFile(context);

        if (logFiles.size() == 0) {
            Toast.makeText(
                            context,
                            context.getString(R.string.toast_send_failed_no_file_found),
                            Toast.LENGTH_LONG)
                    .show();
            return;
        }
        // has to be an ArrayList

        ArrayList<Uri> logPaths = new ArrayList<>();
        for (File file : logFiles) {
            if (file.exists()) {
                logPaths.add(FileProvider.getUriForFile(appContext, authority, file));
            }
        }

        Intent emailSelectorIntent = new Intent(Intent.ACTION_SENDTO);
        emailSelectorIntent.setDataAndType(Uri.parse("mailto:"), "plain/text");

        final Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
        // emailIntent.setType("plain/text");
        emailIntent.addFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

        emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
        emailIntent.putExtra(Intent.EXTRA_TEXT, body);
        emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, logPaths);
        emailIntent.setSelector(emailSelectorIntent);

        context.startActivity(Intent.createChooser(emailIntent, "Send Logs"));
    }
Paruyr
  • 37
  • 1
  • 8