1 package expo.modules.taskManager; 2 3 import android.content.Context; 4 import android.os.Bundle; 5 6 import java.lang.ref.WeakReference; 7 import java.util.ArrayList; 8 import java.util.Arrays; 9 import java.util.List; 10 import java.util.Map; 11 12 import org.unimodules.core.ModuleRegistry; 13 import org.unimodules.core.interfaces.InternalModule; 14 import org.unimodules.core.interfaces.LifecycleEventListener; 15 import org.unimodules.core.interfaces.ModuleRegistryConsumer; 16 import org.unimodules.core.interfaces.services.EventEmitter; 17 import org.unimodules.core.interfaces.services.UIManager; 18 import org.unimodules.interfaces.constants.ConstantsInterface; 19 import org.unimodules.interfaces.taskManager.TaskConsumerInterface; 20 import org.unimodules.interfaces.taskManager.TaskServiceInterface; 21 import org.unimodules.interfaces.taskManager.TaskManagerInterface; 22 23 public class TaskManagerInternalModule implements InternalModule, ModuleRegistryConsumer, TaskManagerInterface, LifecycleEventListener { 24 private UIManager mUIManager; 25 private EventEmitter mEventEmitter; 26 private ConstantsInterface mConstants; 27 private TaskServiceInterface mTaskService; 28 private WeakReference<Context> mContextRef; 29 private List<Bundle> mEventsQueue = new ArrayList<>(); 30 31 public TaskManagerInternalModule(Context context) { 32 mContextRef = new WeakReference<>(context); 33 } 34 35 //region InternalModule 36 37 @Override 38 public List<Class> getExportedInterfaces() { 39 return Arrays.<Class>asList(TaskManagerInterface.class); 40 } 41 42 //endregion 43 //region ModuleRegistryConsumer 44 45 @Override 46 public void setModuleRegistry(ModuleRegistry moduleRegistry) { 47 if (mUIManager != null) { 48 mUIManager.unregisterLifecycleEventListener(this); 49 } 50 51 mUIManager = moduleRegistry.getModule(UIManager.class); 52 mEventEmitter = moduleRegistry.getModule(EventEmitter.class); 53 mConstants = moduleRegistry.getModule(ConstantsInterface.class); 54 mTaskService = moduleRegistry.getSingletonModule("TaskService", TaskServiceInterface.class); 55 56 // Register in TaskService. 57 mTaskService.setTaskManager(this, getAppId(), getAppUrl()); 58 59 if (mUIManager != null) { 60 mUIManager.registerLifecycleEventListener(this); 61 } 62 } 63 64 //endregion 65 //region TaskManagerInterface 66 67 @Override 68 public void registerTask(String taskName, Class consumerClass, Map<String, Object> options) throws Exception { 69 checkTaskService(); 70 mTaskService.registerTask(taskName, getAppId(), getAppUrl(), consumerClass, options); 71 } 72 73 @Override 74 public void unregisterTask(String taskName, Class consumerClass) throws Exception { 75 checkTaskService(); 76 mTaskService.unregisterTask(taskName, getAppId(), consumerClass); 77 } 78 79 @Override 80 public void executeTaskWithBody(Bundle body) { 81 if (mEventsQueue != null) { 82 // `startObserving` on TaskManagerModule wasn't called yet - add event body to the queue. 83 mEventsQueue.add(body); 84 } else { 85 // Manager is already being observed by JS app, so we can execute the event immediately. 86 mEventEmitter.emit(TaskManagerModule.EVENT_NAME, body); 87 } 88 } 89 90 @Override 91 public boolean taskHasConsumerOfClass(String taskName, Class consumerClass) { 92 if (mTaskService == null) { 93 return false; 94 } 95 return mTaskService.taskHasConsumerOfClass(taskName, getAppId(), consumerClass); 96 } 97 98 @Override 99 public void flushQueuedEvents() { 100 // Execute any events that came before this call. 101 if (mEventsQueue != null) { 102 for (Bundle body : mEventsQueue) { 103 mEventEmitter.emit(TaskManagerModule.EVENT_NAME, body); 104 } 105 mEventsQueue = null; 106 } 107 } 108 109 @Override 110 public String getAppId() { 111 if (mConstants != null) { 112 return mConstants.getAppId(); 113 } 114 return null; 115 } 116 117 @Override 118 public boolean isRunningInHeadlessMode() { 119 if (mConstants != null) { 120 return (boolean) mConstants.getConstants().get("isHeadless"); 121 } 122 return false; 123 } 124 125 //endregion 126 //region LifecycleEventListener 127 128 @Override 129 public void onHostResume() { 130 if (!isRunningInHeadlessMode()) { 131 List<TaskConsumerInterface> taskConsumers = mTaskService.getTaskConsumers(getAppId()); 132 for (TaskConsumerInterface taskConsumer : taskConsumers) { 133 if (taskConsumer instanceof LifecycleEventListener) { 134 ((LifecycleEventListener) taskConsumer).onHostResume(); 135 } 136 } 137 } 138 } 139 140 @Override 141 public void onHostPause() { 142 if (!isRunningInHeadlessMode()) { 143 List<TaskConsumerInterface> taskConsumers = mTaskService.getTaskConsumers(getAppId()); 144 for (TaskConsumerInterface taskConsumer : taskConsumers) { 145 if (taskConsumer instanceof LifecycleEventListener) { 146 ((LifecycleEventListener) taskConsumer).onHostPause(); 147 } 148 } 149 } 150 } 151 152 @Override 153 public void onHostDestroy() { 154 if (!isRunningInHeadlessMode()) { 155 List<TaskConsumerInterface> taskConsumers = mTaskService.getTaskConsumers(getAppId()); 156 for (TaskConsumerInterface taskConsumer : taskConsumers) { 157 if (taskConsumer instanceof LifecycleEventListener) { 158 ((LifecycleEventListener) taskConsumer).onHostDestroy(); 159 } 160 } 161 mTaskService.setTaskManager(null, getAppId(), getAppUrl()); 162 } 163 } 164 165 //endregion 166 //region helpers 167 168 private String getAppUrl() { 169 // If Constants module is available and experienceUrl is provided, just return it. 170 if (mConstants != null) { 171 String experienceUrl = (String) mConstants.getConstants().get("experienceUrl"); 172 if (experienceUrl != null) { 173 return experienceUrl; 174 } 175 } 176 177 // Fallback to package name? It should work well for RN apps with just one JS app inside. 178 Context context = mContextRef.get(); 179 if (context != null) { 180 return context.getPackageName(); 181 } 182 183 return null; 184 } 185 186 private void checkTaskService() throws IllegalStateException { 187 if (mTaskService == null) { 188 throw new IllegalStateException("Unable to find TaskService singleton module in module registry."); 189 } 190 } 191 192 //endregion 193 } 194