1 package abi47_0_0.expo.modules.intentlauncher 2 3 import abi47_0_0.expo.modules.core.Promise 4 import abi47_0_0.expo.modules.core.ExportedModule 5 import abi47_0_0.expo.modules.core.ModuleRegistry 6 import abi47_0_0.expo.modules.core.interfaces.ExpoMethod 7 import abi47_0_0.expo.modules.core.ModuleRegistryDelegate 8 import abi47_0_0.expo.modules.core.arguments.ReadableArguments 9 import abi47_0_0.expo.modules.core.interfaces.ActivityProvider 10 import abi47_0_0.expo.modules.core.interfaces.services.UIManager 11 import abi47_0_0.expo.modules.core.interfaces.ActivityEventListener 12 import abi47_0_0.expo.modules.core.errors.CurrentActivityNotFoundException 13 import abi47_0_0.expo.modules.intentlauncher.exceptions.ActivityAlreadyStartedException 14 15 import android.net.Uri 16 import android.os.Bundle 17 import android.app.Activity 18 import android.content.Intent 19 import android.content.ComponentName 20 import android.content.ActivityNotFoundException 21 import android.content.Context 22 23 private const val NAME = "ExpoIntentLauncher" 24 25 private const val REQUEST_CODE = 12 26 private const val ATTR_ACTION = "action" 27 private const val ATTR_TYPE = "type" 28 private const val ATTR_CATEGORY = "category" 29 private const val ATTR_EXTRA = "extra" 30 private const val ATTR_DATA = "data" 31 private const val ATTR_FLAGS = "flags" 32 private const val ATTR_PACKAGE_NAME = "packageName" 33 private const val ATTR_CLASS_NAME = "className" 34 35 class IntentLauncherModule( 36 context: Context, 37 private val moduleRegistryDelegate: ModuleRegistryDelegate = ModuleRegistryDelegate() 38 ) : ExportedModule(context), ActivityEventListener { 39 private var pendingPromise: Promise? = null 40 private val uiManager: UIManager by moduleRegistry() 41 private val activityProvider: ActivityProvider by moduleRegistry() 42 moduleRegistrynull43 private inline fun <reified T> moduleRegistry() = moduleRegistryDelegate.getFromModuleRegistry<T>() 44 45 override fun getName() = NAME 46 47 override fun onCreate(moduleRegistry: ModuleRegistry) { 48 moduleRegistryDelegate.onCreate(moduleRegistry) 49 } 50 51 @ExpoMethod startActivitynull52 fun startActivity(activityAction: String, params: ReadableArguments, promise: Promise) { 53 if (pendingPromise != null) { 54 promise.reject(ActivityAlreadyStartedException()) 55 return 56 } 57 58 val activity = activityProvider.currentActivity 59 if (activity == null) { 60 promise.reject(CurrentActivityNotFoundException()) 61 return 62 } 63 64 val intent = Intent(activityAction) 65 66 if (params.containsKey(ATTR_CLASS_NAME)) { 67 intent.component = 68 if (params.containsKey(ATTR_PACKAGE_NAME)) ComponentName(params.getString(ATTR_PACKAGE_NAME), params.getString(ATTR_CLASS_NAME)) 69 else ComponentName(context, params.getString(ATTR_CLASS_NAME)) 70 } 71 72 // `setData` and `setType` are exclusive, so we need to use `setDateAndType` in that case. 73 if (params.containsKey(ATTR_DATA) && params.containsKey(ATTR_TYPE)) { 74 intent.setDataAndType(Uri.parse(params.getString(ATTR_DATA)), params.getString(ATTR_TYPE)) 75 } else { 76 if (params.containsKey(ATTR_DATA)) { 77 intent.data = Uri.parse(params.getString(ATTR_DATA)) 78 } else if (params.containsKey(ATTR_TYPE)) { 79 intent.type = params.getString(ATTR_TYPE) 80 } 81 } 82 83 params.getArguments(ATTR_EXTRA)?.let { intent.putExtras(it.toBundle()) } 84 params.getInt(ATTR_FLAGS)?.let { intent.addFlags(it) } 85 params.getString(ATTR_CATEGORY)?.let { intent.addCategory(it) } 86 87 uiManager.registerActivityEventListener(this) 88 pendingPromise = promise 89 90 try { 91 activity.startActivityForResult(intent, REQUEST_CODE) 92 } catch (e: ActivityNotFoundException) { 93 promise.reject(e) 94 pendingPromise = null 95 } 96 } 97 98 //region ActivityEventListener 99 onActivityResultnull100 override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, intent: Intent?) { 101 if (requestCode != REQUEST_CODE) return 102 103 val response = Bundle().apply { 104 putInt("resultCode", resultCode) 105 if (intent != null) { 106 intent.data?.let { putString(ATTR_DATA, it.toString()) } 107 intent.extras?.let { putBundle(ATTR_EXTRA, it) } 108 } 109 } 110 111 pendingPromise?.resolve(response) 112 pendingPromise = null 113 114 uiManager.unregisterActivityEventListener(this) 115 } 116 onNewIntentnull117 override fun onNewIntent(intent: Intent) = Unit 118 119 //endregion 120 } 121