1 package expo.modules.mailcomposer 2 3 import android.content.Context 4 import android.content.Intent 5 import android.content.pm.LabeledIntent 6 import android.net.Uri 7 import android.os.Bundle 8 import expo.modules.core.ExportedModule 9 import expo.modules.core.ModuleRegistry 10 import expo.modules.core.ModuleRegistryDelegate 11 import expo.modules.core.Promise 12 import expo.modules.core.arguments.ReadableArguments 13 import expo.modules.core.interfaces.ActivityProvider 14 import expo.modules.core.interfaces.ExpoMethod 15 import expo.modules.core.interfaces.LifecycleEventListener 16 17 class MailComposerModule( 18 context: Context, 19 private val moduleRegistryDelegate: ModuleRegistryDelegate = ModuleRegistryDelegate() 20 ) : ExportedModule(context), LifecycleEventListener { 21 private var composerOpened = false 22 private var pendingPromise: Promise? = null 23 override fun getName() = "ExpoMailComposer" 24 private val activityProvider: ActivityProvider by moduleRegistry() 25 26 private inline fun <reified T> moduleRegistry() = moduleRegistryDelegate.getFromModuleRegistry<T>() 27 28 override fun onCreate(moduleRegistry: ModuleRegistry) { 29 moduleRegistryDelegate.onCreate(moduleRegistry) 30 } 31 32 @ExpoMethod 33 fun isAvailableAsync(promise: Promise) { 34 promise.resolve(true) 35 } 36 37 @ExpoMethod 38 fun composeAsync(options: ReadableArguments, promise: Promise) { 39 val intent = Intent(Intent.ACTION_SENDTO).apply { data = Uri.parse("mailto:") } 40 val application = activityProvider.currentActivity.application 41 val resolveInfo = context.packageManager.queryIntentActivities(intent, 0) 42 val mailIntents = resolveInfo.map { info -> 43 val isHtml = options.containsKey("isHtml") && options.getBoolean("isHtml") 44 val mailIntentBuilder = MailIntentBuilder(options) 45 .setComponentName(info.activityInfo.packageName, info.activityInfo.name) 46 .putExtraIfKeyExists("recipients", Intent.EXTRA_EMAIL) 47 .putExtraIfKeyExists("ccRecipients", Intent.EXTRA_CC) 48 .putExtraIfKeyExists("bccRecipients", Intent.EXTRA_BCC) 49 .putExtraIfKeyExists("subject", Intent.EXTRA_SUBJECT) 50 .putExtraIfKeyExists("body", Intent.EXTRA_TEXT, isHtml) 51 .putParcelableArrayListExtraIfKeyExists( 52 "attachments", 53 Intent.EXTRA_STREAM, 54 application 55 ) 56 LabeledIntent( 57 mailIntentBuilder.build(), 58 info.activityInfo.packageName, 59 info.loadLabel(context.packageManager), 60 info.icon 61 ) 62 }.toMutableList() 63 val chooser = Intent.createChooser( 64 mailIntents.removeAt(mailIntents.size - 1), 65 null 66 ).apply { 67 putExtra(Intent.EXTRA_INITIAL_INTENTS, mailIntents.toTypedArray()) 68 addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 69 addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 70 } 71 pendingPromise = promise 72 context.startActivity(chooser) 73 composerOpened = true 74 } 75 76 override fun onHostResume() { 77 val promise = pendingPromise ?: return 78 if (composerOpened) { 79 composerOpened = false 80 promise.resolve(Bundle().apply { putString("status", "sent") }) 81 } 82 } 83 84 override fun onHostPause() = Unit 85 86 override fun onHostDestroy() { 87 // do nothing 88 } 89 } 90