1 // Copyright 2015-present 650 Industries. All rights reserved. 2 package host.exp.exponent.modules 3 4 import com.facebook.react.bridge.* 5 import com.facebook.react.modules.core.DeviceEventManagerModule 6 import host.exp.exponent.Constants 7 import host.exp.exponent.analytics.EXL 8 import host.exp.exponent.di.NativeModuleDepsProvider 9 import host.exp.exponent.experience.ErrorActivity 10 import host.exp.exponent.kernel.DevMenuManager 11 import host.exp.exponent.kernel.ExponentKernelModuleInterface 12 import host.exp.exponent.kernel.ExponentKernelModuleProvider 13 import host.exp.exponent.kernel.ExponentKernelModuleProvider.KernelEvent 14 import host.exp.exponent.kernel.ExponentKernelModuleProvider.KernelEventCallback 15 import host.exp.exponent.kernel.Kernel 16 import host.exp.exponent.storage.ExponentSharedPreferences 17 import host.exp.exponent.utils.BundleJSONConverter 18 import org.json.JSONObject 19 import java.util.* 20 import javax.inject.Inject 21 22 class ExponentKernelModule(reactContext: ReactApplicationContext?) : 23 ReactContextBaseJavaModule(reactContext), ExponentKernelModuleInterface { 24 25 @Inject 26 lateinit var kernel: Kernel 27 28 @Inject 29 lateinit var exponentSharedPreferences: ExponentSharedPreferences 30 31 @Inject 32 lateinit var devMenuManager: DevMenuManager 33 34 override fun getConstants(): Map<String, Any> { 35 return mapOf( 36 "sdkVersions" to Constants.SDK_VERSIONS 37 ) 38 } 39 40 override fun getName(): String { 41 return "ExponentKernel" 42 } 43 44 override fun consumeEventQueue() { 45 if (ExponentKernelModuleProvider.eventQueue.size == 0) { 46 return 47 } 48 49 val (name, data, callback) = ExponentKernelModuleProvider.eventQueue.remove() 50 51 val eventId = UUID.randomUUID().toString() 52 data.putString("eventId", eventId) 53 54 kernelEventCallbacks[eventId] = callback 55 56 try { 57 reactApplicationContext 58 .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) 59 .emit(name, data) 60 } catch (e: Exception) { 61 onEventFailure(eventId, e.message) 62 } 63 64 consumeEventQueue() 65 } 66 67 //region Exported methods 68 @ReactMethod 69 fun getSessionAsync(promise: Promise) { 70 val sessionString = exponentSharedPreferences.getString(ExponentSharedPreferences.ExponentSharedPreferencesKey.EXPO_AUTH_SESSION) 71 if (sessionString == null) { 72 promise.resolve(null) 73 return 74 } 75 76 try { 77 val sessionJsonObject = JSONObject(sessionString) 78 val session = Arguments.fromBundle(BundleJSONConverter.convertToBundle(sessionJsonObject)) 79 promise.resolve(session) 80 } catch (e: Exception) { 81 promise.resolve(null) 82 EXL.e(TAG, e) 83 } 84 } 85 86 @ReactMethod 87 fun setSessionAsync(session: ReadableMap, promise: Promise) { 88 try { 89 val sessionJsonObject = JSONObject(session.toHashMap()) 90 exponentSharedPreferences.updateSession(sessionJsonObject) 91 promise.resolve(null) 92 } catch (e: Exception) { 93 promise.reject("ERR_SESSION_NOT_SAVED", "Could not save session secret", e) 94 EXL.e(TAG, e) 95 } 96 } 97 98 @ReactMethod 99 fun removeSessionAsync(promise: Promise) { 100 try { 101 exponentSharedPreferences.removeSession() 102 promise.resolve(null) 103 } catch (e: Exception) { 104 promise.reject("ERR_SESSION_NOT_REMOVED", "Could not remove session secret", e) 105 EXL.e(TAG, e) 106 } 107 } 108 109 @ReactMethod 110 fun goToHomeFromErrorScreen() { 111 if (ErrorActivity.visibleActivity == null) { 112 // shouldn't ever get here 113 EXL.e(TAG, "visibleActivity was null in goToHomeFromErrorScreen") 114 return 115 } 116 ErrorActivity.visibleActivity!!.onClickHome() 117 } 118 119 @ReactMethod 120 fun reloadFromErrorScreen() { 121 if (ErrorActivity.visibleActivity == null) { 122 // shouldn't ever get here 123 EXL.e(TAG, "visibleActivity was null in reloadFromErrorScreen") 124 return 125 } 126 ErrorActivity.visibleActivity!!.onClickReload() 127 } 128 129 @ReactMethod 130 fun onEventSuccess(eventId: String, result: ReadableMap) { 131 kernelEventCallbacks.remove(eventId)?.onEventSuccess(result) 132 } 133 134 @ReactMethod 135 fun onEventFailure(eventId: String, errorMessage: String?) { 136 kernelEventCallbacks.remove(eventId)?.onEventFailure(errorMessage) 137 } 138 139 //region DevMenu 140 @ReactMethod 141 fun doesCurrentTaskEnableDevtoolsAsync(promise: Promise) { 142 promise.resolve(devMenuManager.isDevSupportEnabledByCurrentActivity()) 143 } 144 145 @ReactMethod 146 fun getIsOnboardingFinishedAsync(promise: Promise) { 147 promise.resolve(devMenuManager.isOnboardingFinished()) 148 } 149 150 @ReactMethod 151 fun setIsOnboardingFinishedAsync(isOnboardingFinished: Boolean, promise: Promise) { 152 devMenuManager.setIsOnboardingFinished(isOnboardingFinished) 153 promise.resolve(null) 154 } 155 156 @ReactMethod 157 fun closeDevMenuAsync(promise: Promise) { 158 devMenuManager.hideInCurrentActivity() 159 promise.resolve(true) 160 } 161 162 @ReactMethod 163 fun getDevMenuItemsToShowAsync(promise: Promise) { 164 val devMenuItems = devMenuManager.getMenuItems() 165 promise.resolve(devMenuItems) 166 } 167 168 @ReactMethod 169 fun selectDevMenuItemWithKeyAsync(itemKey: String?, promise: Promise) { 170 devMenuManager.selectItemWithKey(itemKey!!) 171 devMenuManager.requestToClose() 172 promise.resolve(true) 173 } 174 175 @ReactMethod 176 fun reloadAppAsync(promise: Promise) { 177 devMenuManager.reloadApp() 178 devMenuManager.requestToClose() 179 promise.resolve(true) 180 } 181 182 @ReactMethod 183 fun goToHomeAsync(promise: Promise) { 184 kernel.openHomeActivity() 185 devMenuManager.requestToClose() 186 promise.resolve(true) 187 } //endregion DevMenu 188 189 //endregion Exported methods 190 companion object { 191 private val TAG = ExponentKernelModule::class.java.simpleName 192 193 private var instance: ExponentKernelModule? = null 194 195 private val kernelEventCallbacks = mutableMapOf<String, KernelEventCallback>() 196 197 fun queueEvent(name: String, data: WritableMap, callback: KernelEventCallback) { 198 queueEvent(KernelEvent(name, data, callback)) 199 } 200 201 fun queueEvent(event: KernelEvent) { 202 ExponentKernelModuleProvider.eventQueue.add(event) 203 instance?.consumeEventQueue() 204 } 205 } 206 207 init { 208 NativeModuleDepsProvider.instance.inject(ExponentKernelModule::class.java, this) 209 instance = this 210 } 211 } 212