1058d2dd0SWill Schurman // Copyright 2015-present 650 Industries. All rights reserved.
2058d2dd0SWill Schurman package host.exp.exponent.modules
3058d2dd0SWill Schurman 
4058d2dd0SWill Schurman import com.facebook.react.bridge.*
5058d2dd0SWill Schurman import com.facebook.react.modules.core.DeviceEventManagerModule
6058d2dd0SWill Schurman import host.exp.exponent.Constants
7058d2dd0SWill Schurman import host.exp.exponent.analytics.EXL
8058d2dd0SWill Schurman import host.exp.exponent.di.NativeModuleDepsProvider
9058d2dd0SWill Schurman import host.exp.exponent.experience.ErrorActivity
10058d2dd0SWill Schurman import host.exp.exponent.kernel.DevMenuManager
11058d2dd0SWill Schurman import host.exp.exponent.kernel.ExponentKernelModuleInterface
12058d2dd0SWill Schurman import host.exp.exponent.kernel.ExponentKernelModuleProvider
13058d2dd0SWill Schurman import host.exp.exponent.kernel.ExponentKernelModuleProvider.KernelEvent
14058d2dd0SWill Schurman import host.exp.exponent.kernel.ExponentKernelModuleProvider.KernelEventCallback
15058d2dd0SWill Schurman import host.exp.exponent.kernel.Kernel
16058d2dd0SWill Schurman import host.exp.exponent.storage.ExponentSharedPreferences
17*3ba32fe9SKudo Chien import host.exp.exponent.utils.BundleJSONConverter
18058d2dd0SWill Schurman import org.json.JSONObject
19058d2dd0SWill Schurman import java.util.*
20058d2dd0SWill Schurman import javax.inject.Inject
21058d2dd0SWill Schurman 
22058d2dd0SWill Schurman class ExponentKernelModule(reactContext: ReactApplicationContext?) :
23058d2dd0SWill Schurman   ReactContextBaseJavaModule(reactContext), ExponentKernelModuleInterface {
24058d2dd0SWill Schurman 
25058d2dd0SWill Schurman   @Inject
26058d2dd0SWill Schurman   lateinit var kernel: Kernel
27058d2dd0SWill Schurman 
28058d2dd0SWill Schurman   @Inject
29058d2dd0SWill Schurman   lateinit var exponentSharedPreferences: ExponentSharedPreferences
30058d2dd0SWill Schurman 
31058d2dd0SWill Schurman   @Inject
32058d2dd0SWill Schurman   lateinit var devMenuManager: DevMenuManager
33058d2dd0SWill Schurman 
getConstantsnull34058d2dd0SWill Schurman   override fun getConstants(): Map<String, Any> {
35058d2dd0SWill Schurman     return mapOf(
36058d2dd0SWill Schurman       "sdkVersions" to Constants.SDK_VERSIONS
37058d2dd0SWill Schurman     )
38058d2dd0SWill Schurman   }
39058d2dd0SWill Schurman 
getNamenull40058d2dd0SWill Schurman   override fun getName(): String {
41058d2dd0SWill Schurman     return "ExponentKernel"
42058d2dd0SWill Schurman   }
43058d2dd0SWill Schurman 
consumeEventQueuenull44058d2dd0SWill Schurman   override fun consumeEventQueue() {
45058d2dd0SWill Schurman     if (ExponentKernelModuleProvider.eventQueue.size == 0) {
46058d2dd0SWill Schurman       return
47058d2dd0SWill Schurman     }
48058d2dd0SWill Schurman 
49058d2dd0SWill Schurman     val (name, data, callback) = ExponentKernelModuleProvider.eventQueue.remove()
50058d2dd0SWill Schurman 
51058d2dd0SWill Schurman     val eventId = UUID.randomUUID().toString()
52058d2dd0SWill Schurman     data.putString("eventId", eventId)
53058d2dd0SWill Schurman 
54058d2dd0SWill Schurman     kernelEventCallbacks[eventId] = callback
55058d2dd0SWill Schurman 
56058d2dd0SWill Schurman     try {
57058d2dd0SWill Schurman       reactApplicationContext
58058d2dd0SWill Schurman         .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
59058d2dd0SWill Schurman         .emit(name, data)
60058d2dd0SWill Schurman     } catch (e: Exception) {
61058d2dd0SWill Schurman       onEventFailure(eventId, e.message)
62058d2dd0SWill Schurman     }
63058d2dd0SWill Schurman 
64058d2dd0SWill Schurman     consumeEventQueue()
65058d2dd0SWill Schurman   }
66058d2dd0SWill Schurman 
67058d2dd0SWill Schurman   //region Exported methods
68058d2dd0SWill Schurman   @ReactMethod
getSessionAsyncnull69058d2dd0SWill Schurman   fun getSessionAsync(promise: Promise) {
70058d2dd0SWill Schurman     val sessionString = exponentSharedPreferences.getString(ExponentSharedPreferences.ExponentSharedPreferencesKey.EXPO_AUTH_SESSION)
71058d2dd0SWill Schurman     if (sessionString == null) {
72058d2dd0SWill Schurman       promise.resolve(null)
73058d2dd0SWill Schurman       return
74058d2dd0SWill Schurman     }
75058d2dd0SWill Schurman 
76058d2dd0SWill Schurman     try {
77058d2dd0SWill Schurman       val sessionJsonObject = JSONObject(sessionString)
78058d2dd0SWill Schurman       val session = Arguments.fromBundle(BundleJSONConverter.convertToBundle(sessionJsonObject))
79058d2dd0SWill Schurman       promise.resolve(session)
80058d2dd0SWill Schurman     } catch (e: Exception) {
81058d2dd0SWill Schurman       promise.resolve(null)
82058d2dd0SWill Schurman       EXL.e(TAG, e)
83058d2dd0SWill Schurman     }
84058d2dd0SWill Schurman   }
85058d2dd0SWill Schurman 
86058d2dd0SWill Schurman   @ReactMethod
setSessionAsyncnull87058d2dd0SWill Schurman   fun setSessionAsync(session: ReadableMap, promise: Promise) {
88058d2dd0SWill Schurman     try {
89058d2dd0SWill Schurman       val sessionJsonObject = JSONObject(session.toHashMap())
90058d2dd0SWill Schurman       exponentSharedPreferences.updateSession(sessionJsonObject)
91058d2dd0SWill Schurman       promise.resolve(null)
92058d2dd0SWill Schurman     } catch (e: Exception) {
93058d2dd0SWill Schurman       promise.reject("ERR_SESSION_NOT_SAVED", "Could not save session secret", e)
94058d2dd0SWill Schurman       EXL.e(TAG, e)
95058d2dd0SWill Schurman     }
96058d2dd0SWill Schurman   }
97058d2dd0SWill Schurman 
98058d2dd0SWill Schurman   @ReactMethod
removeSessionAsyncnull99058d2dd0SWill Schurman   fun removeSessionAsync(promise: Promise) {
100058d2dd0SWill Schurman     try {
101058d2dd0SWill Schurman       exponentSharedPreferences.removeSession()
102058d2dd0SWill Schurman       promise.resolve(null)
103058d2dd0SWill Schurman     } catch (e: Exception) {
104058d2dd0SWill Schurman       promise.reject("ERR_SESSION_NOT_REMOVED", "Could not remove session secret", e)
105058d2dd0SWill Schurman       EXL.e(TAG, e)
106058d2dd0SWill Schurman     }
107058d2dd0SWill Schurman   }
108058d2dd0SWill Schurman 
109058d2dd0SWill Schurman   @ReactMethod
goToHomeFromErrorScreennull110058d2dd0SWill Schurman   fun goToHomeFromErrorScreen() {
111058d2dd0SWill Schurman     if (ErrorActivity.visibleActivity == null) {
112058d2dd0SWill Schurman       // shouldn't ever get here
113058d2dd0SWill Schurman       EXL.e(TAG, "visibleActivity was null in goToHomeFromErrorScreen")
114058d2dd0SWill Schurman       return
115058d2dd0SWill Schurman     }
116058d2dd0SWill Schurman     ErrorActivity.visibleActivity!!.onClickHome()
117058d2dd0SWill Schurman   }
118058d2dd0SWill Schurman 
119058d2dd0SWill Schurman   @ReactMethod
reloadFromErrorScreennull120058d2dd0SWill Schurman   fun reloadFromErrorScreen() {
121058d2dd0SWill Schurman     if (ErrorActivity.visibleActivity == null) {
122058d2dd0SWill Schurman       // shouldn't ever get here
123058d2dd0SWill Schurman       EXL.e(TAG, "visibleActivity was null in reloadFromErrorScreen")
124058d2dd0SWill Schurman       return
125058d2dd0SWill Schurman     }
126058d2dd0SWill Schurman     ErrorActivity.visibleActivity!!.onClickReload()
127058d2dd0SWill Schurman   }
128058d2dd0SWill Schurman 
129058d2dd0SWill Schurman   @ReactMethod
onEventSuccessnull130058d2dd0SWill Schurman   fun onEventSuccess(eventId: String, result: ReadableMap) {
131058d2dd0SWill Schurman     kernelEventCallbacks.remove(eventId)?.onEventSuccess(result)
132058d2dd0SWill Schurman   }
133058d2dd0SWill Schurman 
134058d2dd0SWill Schurman   @ReactMethod
onEventFailurenull135058d2dd0SWill Schurman   fun onEventFailure(eventId: String, errorMessage: String?) {
136058d2dd0SWill Schurman     kernelEventCallbacks.remove(eventId)?.onEventFailure(errorMessage)
137058d2dd0SWill Schurman   }
138058d2dd0SWill Schurman 
139058d2dd0SWill Schurman   //region DevMenu
140058d2dd0SWill Schurman   @ReactMethod
doesCurrentTaskEnableDevtoolsAsyncnull141058d2dd0SWill Schurman   fun doesCurrentTaskEnableDevtoolsAsync(promise: Promise) {
142058d2dd0SWill Schurman     promise.resolve(devMenuManager.isDevSupportEnabledByCurrentActivity())
143058d2dd0SWill Schurman   }
144058d2dd0SWill Schurman 
145058d2dd0SWill Schurman   @ReactMethod
getIsOnboardingFinishedAsyncnull146058d2dd0SWill Schurman   fun getIsOnboardingFinishedAsync(promise: Promise) {
147058d2dd0SWill Schurman     promise.resolve(devMenuManager.isOnboardingFinished())
148058d2dd0SWill Schurman   }
149058d2dd0SWill Schurman 
150058d2dd0SWill Schurman   @ReactMethod
setIsOnboardingFinishedAsyncnull151058d2dd0SWill Schurman   fun setIsOnboardingFinishedAsync(isOnboardingFinished: Boolean, promise: Promise) {
152058d2dd0SWill Schurman     devMenuManager.setIsOnboardingFinished(isOnboardingFinished)
153058d2dd0SWill Schurman     promise.resolve(null)
154058d2dd0SWill Schurman   }
155058d2dd0SWill Schurman 
156058d2dd0SWill Schurman   @ReactMethod
closeDevMenuAsyncnull157058d2dd0SWill Schurman   fun closeDevMenuAsync(promise: Promise) {
158058d2dd0SWill Schurman     devMenuManager.hideInCurrentActivity()
159058d2dd0SWill Schurman     promise.resolve(true)
160058d2dd0SWill Schurman   }
161058d2dd0SWill Schurman 
162058d2dd0SWill Schurman   @ReactMethod
getDevMenuItemsToShowAsyncnull163058d2dd0SWill Schurman   fun getDevMenuItemsToShowAsync(promise: Promise) {
164058d2dd0SWill Schurman     val devMenuItems = devMenuManager.getMenuItems()
165058d2dd0SWill Schurman     promise.resolve(devMenuItems)
166058d2dd0SWill Schurman   }
167058d2dd0SWill Schurman 
168058d2dd0SWill Schurman   @ReactMethod
selectDevMenuItemWithKeyAsyncnull169058d2dd0SWill Schurman   fun selectDevMenuItemWithKeyAsync(itemKey: String?, promise: Promise) {
170058d2dd0SWill Schurman     devMenuManager.selectItemWithKey(itemKey!!)
171058d2dd0SWill Schurman     devMenuManager.requestToClose()
172058d2dd0SWill Schurman     promise.resolve(true)
173058d2dd0SWill Schurman   }
174058d2dd0SWill Schurman 
175058d2dd0SWill Schurman   @ReactMethod
reloadAppAsyncnull176058d2dd0SWill Schurman   fun reloadAppAsync(promise: Promise) {
177058d2dd0SWill Schurman     devMenuManager.reloadApp()
178058d2dd0SWill Schurman     devMenuManager.requestToClose()
179058d2dd0SWill Schurman     promise.resolve(true)
180058d2dd0SWill Schurman   }
181058d2dd0SWill Schurman 
182058d2dd0SWill Schurman   @ReactMethod
goToHomeAsyncnull183058d2dd0SWill Schurman   fun goToHomeAsync(promise: Promise) {
184058d2dd0SWill Schurman     kernel.openHomeActivity()
185058d2dd0SWill Schurman     devMenuManager.requestToClose()
186058d2dd0SWill Schurman     promise.resolve(true)
187058d2dd0SWill Schurman   } //endregion DevMenu
188058d2dd0SWill Schurman 
189058d2dd0SWill Schurman   //endregion Exported methods
190058d2dd0SWill Schurman   companion object {
191058d2dd0SWill Schurman     private val TAG = ExponentKernelModule::class.java.simpleName
192058d2dd0SWill Schurman 
193058d2dd0SWill Schurman     private var instance: ExponentKernelModule? = null
194058d2dd0SWill Schurman 
195058d2dd0SWill Schurman     private val kernelEventCallbacks = mutableMapOf<String, KernelEventCallback>()
196058d2dd0SWill Schurman 
queueEventnull197058d2dd0SWill Schurman     fun queueEvent(name: String, data: WritableMap, callback: KernelEventCallback) {
198058d2dd0SWill Schurman       queueEvent(KernelEvent(name, data, callback))
199058d2dd0SWill Schurman     }
200058d2dd0SWill Schurman 
queueEventnull201058d2dd0SWill Schurman     fun queueEvent(event: KernelEvent) {
202058d2dd0SWill Schurman       ExponentKernelModuleProvider.eventQueue.add(event)
203058d2dd0SWill Schurman       instance?.consumeEventQueue()
204058d2dd0SWill Schurman     }
205058d2dd0SWill Schurman   }
206058d2dd0SWill Schurman 
207058d2dd0SWill Schurman   init {
208058d2dd0SWill Schurman     NativeModuleDepsProvider.instance.inject(ExponentKernelModule::class.java, this)
209058d2dd0SWill Schurman     instance = this
210058d2dd0SWill Schurman   }
211058d2dd0SWill Schurman }
212