@munchi_oy/react-native-epson-printer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +223 -0
  2. package/android/build.gradle +34 -0
  3. package/android/consumer-rules.pro +0 -0
  4. package/android/libs/ePOS2.jar +0 -0
  5. package/android/src/main/AndroidManifest.xml +17 -0
  6. package/android/src/main/java/com/munchiepsonprinter/MunchiEpsonModule.java +1212 -0
  7. package/android/src/main/java/com/munchiepsonprinter/MunchiPrinterPackage.java +24 -0
  8. package/android/src/main/jniLibs/arm64-v8a/libepos2.so +0 -0
  9. package/android/src/main/jniLibs/armeabi-v7a/libepos2.so +0 -0
  10. package/android/src/main/jniLibs/x86/libepos2.so +0 -0
  11. package/android/src/main/jniLibs/x86_64/libepos2.so +0 -0
  12. package/dist/config.d.ts +14 -0
  13. package/dist/config.d.ts.map +1 -0
  14. package/dist/epson/constants.d.ts +124 -0
  15. package/dist/epson/constants.d.ts.map +1 -0
  16. package/dist/epson/discovery.d.ts +14 -0
  17. package/dist/epson/discovery.d.ts.map +1 -0
  18. package/dist/epson/driver.d.ts +26 -0
  19. package/dist/epson/driver.d.ts.map +1 -0
  20. package/dist/epson/errors.d.ts +8 -0
  21. package/dist/epson/errors.d.ts.map +1 -0
  22. package/dist/epson/eventRouter.d.ts +23 -0
  23. package/dist/epson/eventRouter.d.ts.map +1 -0
  24. package/dist/epson/mapper.d.ts +22 -0
  25. package/dist/epson/mapper.d.ts.map +1 -0
  26. package/dist/epson/modelUtils.d.ts +16 -0
  27. package/dist/epson/modelUtils.d.ts.map +1 -0
  28. package/dist/epson/native.d.ts +21 -0
  29. package/dist/epson/native.d.ts.map +1 -0
  30. package/dist/epson/payloadMapper.d.ts +7 -0
  31. package/dist/epson/payloadMapper.d.ts.map +1 -0
  32. package/dist/epson/queueController.d.ts +15 -0
  33. package/dist/epson/queueController.d.ts.map +1 -0
  34. package/dist/epson/recoveryController.d.ts +15 -0
  35. package/dist/epson/recoveryController.d.ts.map +1 -0
  36. package/dist/epson/sessionManager.d.ts +11 -0
  37. package/dist/epson/sessionManager.d.ts.map +1 -0
  38. package/dist/errorResolver.d.ts +15 -0
  39. package/dist/errorResolver.d.ts.map +1 -0
  40. package/dist/errors.d.ts +23 -0
  41. package/dist/errors.d.ts.map +1 -0
  42. package/dist/index.d.ts +15 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +11 -0
  45. package/dist/index.mjs +11 -0
  46. package/dist/react/PrinterProvider.d.ts +19 -0
  47. package/dist/react/PrinterProvider.d.ts.map +1 -0
  48. package/dist/react/usePrinterStatus.d.ts +12 -0
  49. package/dist/react/usePrinterStatus.d.ts.map +1 -0
  50. package/dist/types.d.ts +123 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/utils/errorUtils.d.ts +3 -0
  53. package/dist/utils/errorUtils.d.ts.map +1 -0
  54. package/dist/version.d.ts +2 -0
  55. package/dist/version.d.ts.map +1 -0
  56. package/ios/MunchiPrinter-Bridging-Header.h +4 -0
  57. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/Info.plist +48 -0
  58. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/_CodeSignature/CodeDirectory +0 -0
  59. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/_CodeSignature/CodeRequirements +0 -0
  60. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/_CodeSignature/CodeRequirements-1 +0 -0
  61. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/_CodeSignature/CodeResources +398 -0
  62. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/_CodeSignature/CodeSignature +0 -0
  63. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64/dSYMs/libepos2.framework.dSYM/Contents/Info.plist +20 -0
  64. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64/dSYMs/libepos2.framework.dSYM/Contents/Resources/DWARF/libepos2 +0 -0
  65. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64/dSYMs/libepos2.framework.dSYM/Contents/Resources/Relocations/aarch64/libepos2.yml +5177 -0
  66. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64/libepos2.framework/Headers/ePOS2.h +1809 -0
  67. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64/libepos2.framework/Headers/libepos2.h +13 -0
  68. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64/libepos2.framework/Info.plist +0 -0
  69. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64/libepos2.framework/Modules/module.modulemap +6 -0
  70. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64/libepos2.framework/PrivacyInfo.xcprivacy +31 -0
  71. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64/libepos2.framework/libepos2 +0 -0
  72. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/dSYMs/libepos2.framework.dSYM/Contents/Info.plist +20 -0
  73. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/dSYMs/libepos2.framework.dSYM/Contents/Resources/DWARF/libepos2 +0 -0
  74. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/dSYMs/libepos2.framework.dSYM/Contents/Resources/Relocations/aarch64/libepos2.yml +5177 -0
  75. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/dSYMs/libepos2.framework.dSYM/Contents/Resources/Relocations/x86_64/libepos2.yml +5062 -0
  76. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/libepos2.framework/Headers/ePOS2.h +1809 -0
  77. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/libepos2.framework/Headers/libepos2.h +13 -0
  78. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/libepos2.framework/Info.plist +0 -0
  79. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/libepos2.framework/Modules/module.modulemap +6 -0
  80. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/libepos2.framework/PrivacyInfo.xcprivacy +31 -0
  81. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/libepos2.framework/_CodeSignature/CodeResources +146 -0
  82. package/ios/Vendors/Epson/Frameworks/libepos2.xcframework/ios-arm64_x86_64-simulator/libepos2.framework/libepos2 +0 -0
  83. package/ios/Vendors/Epson/MunchiEpsonModule.m +35 -0
  84. package/ios/Vendors/Epson/MunchiEpsonModule.swift +455 -0
  85. package/munchi-printer.podspec +22 -0
  86. package/package.json +59 -0
  87. package/react-native.config.js +12 -0
@@ -0,0 +1,1212 @@
1
+ package com.munchiepsonprinter;
2
+
3
+ import android.Manifest;
4
+ import android.bluetooth.BluetoothAdapter;
5
+ import android.bluetooth.BluetoothManager;
6
+ import android.content.Context;
7
+ import android.content.pm.PackageManager;
8
+ import android.graphics.Bitmap;
9
+ import android.graphics.BitmapFactory;
10
+ import android.location.LocationManager;
11
+ import android.os.Build;
12
+ import android.os.Handler;
13
+ import android.os.Looper;
14
+ import android.util.Base64;
15
+
16
+ import androidx.annotation.NonNull;
17
+
18
+ import com.epson.epos2.ConnectionListener;
19
+ import com.epson.epos2.Epos2CallbackCode;
20
+ import com.epson.epos2.Epos2Exception;
21
+ import com.epson.epos2.discovery.DeviceInfo;
22
+ import com.epson.epos2.discovery.Discovery;
23
+ import com.epson.epos2.discovery.DiscoveryListener;
24
+ import com.epson.epos2.discovery.FilterOption;
25
+ import com.epson.epos2.printer.Printer;
26
+ import com.epson.epos2.printer.PrinterStatusInfo;
27
+ import com.epson.epos2.printer.ReceiveListener;
28
+ import com.epson.epos2.printer.StatusChangeListener;
29
+ import com.facebook.react.bridge.Arguments;
30
+ import com.facebook.react.bridge.Promise;
31
+ import com.facebook.react.bridge.ReactApplicationContext;
32
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
33
+ import com.facebook.react.bridge.ReactMethod;
34
+ import com.facebook.react.bridge.ReadableArray;
35
+ import com.facebook.react.bridge.ReadableMap;
36
+ import com.facebook.react.bridge.ReadableType;
37
+ import com.facebook.react.bridge.WritableArray;
38
+ import com.facebook.react.bridge.WritableMap;
39
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
40
+
41
+ import java.util.HashMap;
42
+ import java.util.HashSet;
43
+ import java.util.IdentityHashMap;
44
+ import java.util.Map;
45
+ import java.util.Set;
46
+ import java.util.UUID;
47
+
48
+ public class MunchiEpsonModule extends ReactContextBaseJavaModule implements ConnectionListener, StatusChangeListener, ReceiveListener, DiscoveryListener {
49
+ private static final String MODULE_NAME = "MunchiEpsonModule";
50
+ private static final String EVENT_PRINTER_STATUS_CHANGE = "onPrinterStatusChange";
51
+ private static final String EVENT_PRINTER_CONNECTION_CHANGE = "onPrinterConnectionChange";
52
+ private static final String EVENT_PRINTER_RECEIVE = "onPrinterReceive";
53
+
54
+ private static final int DEFAULT_DISCOVERY_TIMEOUT_MS = 5000;
55
+ private static final int PRINT_TIMEOUT_MS = 30000;
56
+ private static final int CONNECTION_CACHE_TTL_MS = 120000;
57
+
58
+ private final ReactApplicationContext reactContext;
59
+ private final Handler mainHandler = new Handler(Looper.getMainLooper());
60
+ private final Object lock = new Object();
61
+
62
+ private final Map<String, EpsonSession> sessions = new HashMap<>();
63
+ private final Map<Printer, String> printerToSessionId = new IdentityHashMap<>();
64
+ private final Map<String, String> targetToSessionId = new HashMap<>();
65
+ private final Map<String, CachedConnection> cachedConnections = new HashMap<>();
66
+
67
+ private Promise discoveryPromise;
68
+ private WritableArray discoveredPrinters;
69
+ private Set<String> discoveredTargets;
70
+ private Runnable discoveryTimeoutRunnable;
71
+
72
+ public MunchiEpsonModule(ReactApplicationContext reactContext) {
73
+ super(reactContext);
74
+ this.reactContext = reactContext;
75
+ }
76
+
77
+ @NonNull
78
+ @Override
79
+ public String getName() {
80
+ return MODULE_NAME;
81
+ }
82
+
83
+ @ReactMethod
84
+ public void addListener(String eventName) {
85
+ }
86
+
87
+ @ReactMethod
88
+ public void removeListeners(double count) {
89
+ }
90
+
91
+ @ReactMethod
92
+ public void initSession(Promise promise) {
93
+ String sessionId = UUID.randomUUID().toString();
94
+ synchronized (lock) {
95
+ sessions.put(sessionId, new EpsonSession(sessionId));
96
+ }
97
+ promise.resolve(sessionId);
98
+ }
99
+
100
+ @ReactMethod
101
+ public void disposeSession(String sessionId, Promise promise) {
102
+ EpsonSession session;
103
+ synchronized (lock) {
104
+ session = sessions.remove(sessionId);
105
+ }
106
+
107
+ if (session != null) {
108
+ teardownPrinter(session, true);
109
+ }
110
+
111
+ promise.resolve(null);
112
+ }
113
+
114
+ @ReactMethod
115
+ public void discover(ReadableMap params, Promise promise) {
116
+ if (!ensureDiscoverReadiness(promise)) {
117
+ return;
118
+ }
119
+
120
+ int timeout = DEFAULT_DISCOVERY_TIMEOUT_MS;
121
+ if (params != null && params.hasKey("timeout") && !params.isNull("timeout")) {
122
+ timeout = (int) params.getDouble("timeout");
123
+ }
124
+ if (timeout <= 0) {
125
+ timeout = DEFAULT_DISCOVERY_TIMEOUT_MS;
126
+ }
127
+
128
+ synchronized (lock) {
129
+ if (discoveryPromise != null) {
130
+ promise.reject("DISCOVERY_BUSY", "Discovery is already in progress");
131
+ return;
132
+ }
133
+ discoveryPromise = promise;
134
+ discoveredPrinters = Arguments.createArray();
135
+ discoveredTargets = new HashSet<>();
136
+ }
137
+
138
+ try {
139
+ stopDiscoveryQuietly();
140
+
141
+ FilterOption filter = new FilterOption();
142
+ filter.setPortType(Discovery.PORTTYPE_ALL);
143
+ filter.setDeviceType(Discovery.TYPE_PRINTER);
144
+ filter.setEpsonFilter(Discovery.FILTER_NAME);
145
+ filter.setUsbDeviceName(Discovery.TRUE);
146
+
147
+ Discovery.start(reactContext.getApplicationContext(), filter, this);
148
+
149
+ Runnable timeoutRunnable = this::stopDiscoveryAndResolve;
150
+ synchronized (lock) {
151
+ discoveryTimeoutRunnable = timeoutRunnable;
152
+ }
153
+ mainHandler.postDelayed(timeoutRunnable, timeout);
154
+ } catch (Exception error) {
155
+ Promise pending;
156
+ synchronized (lock) {
157
+ pending = discoveryPromise;
158
+ clearDiscoveryStateLocked();
159
+ }
160
+ if (pending != null) {
161
+ rejectWithEposError(pending, "DISCOVERY_ERROR", "Failed to start discovery", error);
162
+ }
163
+ }
164
+ }
165
+
166
+ @ReactMethod
167
+ public void connect(String sessionId, String target, double timeout, double model, double lang, Promise promise) {
168
+ int safeModel = normalizeModel((int) model);
169
+ int safeLang = normalizeLanguage((int) lang);
170
+
171
+ EpsonSession session;
172
+ CachedConnection cachedConnection;
173
+ synchronized (lock) {
174
+ session = sessions.get(sessionId);
175
+ if (session == null) {
176
+ promise.reject("SESSION_ERROR", "Session not found");
177
+ return;
178
+ }
179
+
180
+ String ownerSessionId = targetToSessionId.get(target);
181
+ if (ownerSessionId != null && !ownerSessionId.equals(sessionId)) {
182
+ promise.reject("TARGET_IN_USE", "Target is already connected by another session: " + target);
183
+ return;
184
+ }
185
+ }
186
+
187
+ if (!ensureBluetoothOperationReadiness(target, promise)) {
188
+ return;
189
+ }
190
+
191
+ synchronized (lock) {
192
+ CachedConnection existingCache = cachedConnections.remove(target);
193
+ if (existingCache != null) {
194
+ cancelCacheEvictionLocked(existingCache);
195
+ }
196
+ cachedConnection = existingCache;
197
+ }
198
+
199
+ teardownPrinter(session, true);
200
+
201
+ Printer printer = null;
202
+ if (cachedConnection != null) {
203
+ if (cachedConnection.model == safeModel
204
+ && cachedConnection.lang == safeLang
205
+ && isConnectionHealthy(cachedConnection.printer)) {
206
+ printer = cachedConnection.printer;
207
+ } else {
208
+ disconnectPrinterQuietly(cachedConnection.printer);
209
+ }
210
+ }
211
+
212
+ if (printer != null) {
213
+ synchronized (lock) {
214
+ EpsonSession latestSession = sessions.get(sessionId);
215
+ if (latestSession == null) {
216
+ disconnectPrinterQuietly(printer);
217
+ promise.reject("SESSION_ERROR", "Session disposed while connecting");
218
+ return;
219
+ }
220
+
221
+ latestSession.printer = printer;
222
+ latestSession.target = target;
223
+ latestSession.model = safeModel;
224
+ latestSession.lang = safeLang;
225
+ printerToSessionId.put(printer, sessionId);
226
+ targetToSessionId.put(target, sessionId);
227
+ }
228
+ promise.resolve(null);
229
+ return;
230
+ }
231
+
232
+ try {
233
+ printer = new Printer(safeModel, safeLang, reactContext.getApplicationContext());
234
+ printer.setConnectionEventListener(this);
235
+ printer.setStatusChangeEventListener(this);
236
+ printer.setReceiveEventListener(this);
237
+ printer.connect(target, (int) timeout);
238
+ } catch (Exception error) {
239
+ if (printer != null) {
240
+ try {
241
+ printer.setReceiveEventListener(null);
242
+ printer.setConnectionEventListener(null);
243
+ printer.setStatusChangeEventListener(null);
244
+ printer.disconnect();
245
+ } catch (Exception ignored) {
246
+ }
247
+ }
248
+ rejectWithEposError(promise, "CONNECT_ERROR", "Failed to connect", error);
249
+ return;
250
+ }
251
+
252
+ synchronized (lock) {
253
+ EpsonSession latestSession = sessions.get(sessionId);
254
+ if (latestSession == null) {
255
+ try {
256
+ printer.disconnect();
257
+ } catch (Exception ignored) {
258
+ }
259
+ promise.reject("SESSION_ERROR", "Session disposed while connecting");
260
+ return;
261
+ }
262
+
263
+ latestSession.printer = printer;
264
+ latestSession.target = target;
265
+ latestSession.model = safeModel;
266
+ latestSession.lang = safeLang;
267
+ printerToSessionId.put(printer, sessionId);
268
+ targetToSessionId.put(target, sessionId);
269
+ }
270
+
271
+ promise.resolve(null);
272
+ }
273
+
274
+ @ReactMethod
275
+ public void disconnect(String sessionId, Promise promise) {
276
+ EpsonSession session;
277
+ synchronized (lock) {
278
+ session = sessions.get(sessionId);
279
+ }
280
+
281
+ if (session == null) {
282
+ promise.resolve(true);
283
+ return;
284
+ }
285
+
286
+ teardownPrinter(session, true);
287
+ promise.resolve(true);
288
+ }
289
+
290
+ @ReactMethod
291
+ public void print(String sessionId, ReadableArray commands, Promise promise) {
292
+ EpsonSession session;
293
+ Printer printer;
294
+ synchronized (lock) {
295
+ session = sessions.get(sessionId);
296
+ if (session == null || session.printer == null) {
297
+ promise.reject("PRINT_ERROR", "Printer not connected");
298
+ return;
299
+ }
300
+ if (session.printPromise != null) {
301
+ promise.reject("PRINT_BUSY", "Another print job is in progress");
302
+ return;
303
+ }
304
+ printer = session.printer;
305
+ }
306
+
307
+ if (!ensureBluetoothOperationReadiness(session.target, promise)) {
308
+ return;
309
+ }
310
+
311
+ PrinterStatusInfo status;
312
+ try {
313
+ status = printer.getStatus();
314
+ } catch (Exception error) {
315
+ detachUnhealthyPrinter(sessionId, printer);
316
+ rejectWithEposError(promise, "PRINT_ERROR", "Printer is not reachable", error);
317
+ return;
318
+ }
319
+
320
+ if (!isStatusReady(status)) {
321
+ detachUnhealthyPrinter(sessionId, printer);
322
+ promise.reject("PRINTER_OFFLINE", "Printer is offline or unreachable");
323
+ return;
324
+ }
325
+
326
+ try {
327
+ printer.clearCommandBuffer();
328
+ applyCommands(printer, commands);
329
+ } catch (Exception error) {
330
+ rejectWithEposError(promise, "PRINT_ERROR", "Failed to build print data", error);
331
+ return;
332
+ }
333
+
334
+ synchronized (lock) {
335
+ session.printPromise = promise;
336
+ Runnable timeoutRunnable = () -> handlePrintTimeout(sessionId);
337
+ session.printTimeoutRunnable = timeoutRunnable;
338
+ mainHandler.postDelayed(timeoutRunnable, PRINT_TIMEOUT_MS);
339
+ }
340
+
341
+ try {
342
+ printer.sendData(Printer.PARAM_DEFAULT);
343
+ } catch (Exception error) {
344
+ detachUnhealthyPrinter(sessionId, printer);
345
+ Promise pending = null;
346
+ synchronized (lock) {
347
+ EpsonSession latestSession = sessions.get(sessionId);
348
+ if (latestSession != null) {
349
+ pending = latestSession.printPromise;
350
+ cancelPrintTimeoutLocked(latestSession);
351
+ latestSession.printPromise = null;
352
+ latestSession.printTimeoutRunnable = null;
353
+ }
354
+ }
355
+ if (pending != null) {
356
+ rejectWithEposError(pending, "PRINT_ERROR", "Failed to send data", error);
357
+ }
358
+ }
359
+ }
360
+
361
+ @ReactMethod
362
+ public void getStatus(String sessionId, Promise promise) {
363
+ EpsonSession session;
364
+ synchronized (lock) {
365
+ session = sessions.get(sessionId);
366
+ }
367
+
368
+ if (session == null || session.printer == null) {
369
+ promise.reject("STATUS_ERROR", "Printer not connected");
370
+ return;
371
+ }
372
+
373
+ if (!ensureBluetoothOperationReadiness(session.target, promise)) {
374
+ return;
375
+ }
376
+
377
+ try {
378
+ PrinterStatusInfo status = session.printer.getStatus();
379
+ if (status == null) {
380
+ promise.reject("STATUS_ERROR", "Failed to retrieve status");
381
+ return;
382
+ }
383
+
384
+ WritableMap statusMap = Arguments.createMap();
385
+ boolean paperEmpty = status.getPaper() == Printer.PAPER_EMPTY;
386
+ statusMap.putBoolean("online", isStatusReady(status));
387
+ statusMap.putBoolean("coverOpen", status.getCoverOpen() == Printer.TRUE);
388
+ statusMap.putBoolean("paperEmpty", paperEmpty);
389
+ statusMap.putString("paper", mapPaperStatus(status.getPaper()));
390
+ statusMap.putBoolean("drawerOpen", status.getDrawer() == Printer.DRAWER_HIGH);
391
+ statusMap.putString("errorStatus", mapErrorStatus(status.getErrorStatus()));
392
+
393
+ promise.resolve(statusMap);
394
+ } catch (Exception error) {
395
+ rejectWithEposError(promise, "STATUS_ERROR", "Failed to retrieve status", error);
396
+ }
397
+ }
398
+
399
+ @Override
400
+ public void onConnection(Object deviceObj, int eventType) {
401
+ if (!(deviceObj instanceof Printer)) {
402
+ return;
403
+ }
404
+
405
+ String sessionId;
406
+ EpsonSession session;
407
+ String target;
408
+ synchronized (lock) {
409
+ sessionId = printerToSessionId.get((Printer) deviceObj);
410
+ session = sessionId == null ? null : sessions.get(sessionId);
411
+ target = session != null ? session.target : null;
412
+ if (eventType == ConnectionListener.EVENT_DISCONNECT && session != null) {
413
+ printerToSessionId.remove((Printer) deviceObj);
414
+ if (target != null && session.sessionId.equals(targetToSessionId.get(target))) {
415
+ targetToSessionId.remove(target);
416
+ }
417
+ session.printer = null;
418
+ session.target = null;
419
+ session.model = -1;
420
+ session.lang = -1;
421
+ }
422
+ }
423
+
424
+ if (session == null) {
425
+ return;
426
+ }
427
+
428
+ WritableMap body = Arguments.createMap();
429
+ body.putString("sessionId", session.sessionId);
430
+ body.putString("status", mapConnectionEvent(eventType));
431
+ body.putString("target", target == null ? "" : target);
432
+ emitEvent(EVENT_PRINTER_CONNECTION_CHANGE, body);
433
+ }
434
+
435
+ @Override
436
+ public void onPtrStatusChange(Printer printer, int eventType) {
437
+ String sessionId;
438
+ EpsonSession session;
439
+ synchronized (lock) {
440
+ sessionId = printerToSessionId.get(printer);
441
+ session = sessionId == null ? null : sessions.get(sessionId);
442
+ }
443
+
444
+ if (session == null) {
445
+ return;
446
+ }
447
+
448
+ WritableMap body = Arguments.createMap();
449
+ body.putString("sessionId", session.sessionId);
450
+ body.putString("target", session.target == null ? "" : session.target);
451
+ body.putInt("eventType", eventType);
452
+ emitEvent(EVENT_PRINTER_STATUS_CHANGE, body);
453
+ }
454
+
455
+ @Override
456
+ public void onPtrReceive(Printer printer, int code, PrinterStatusInfo status, String printJobId) {
457
+ EpsonSession session;
458
+ Promise printPromise = null;
459
+ synchronized (lock) {
460
+ String sessionId = printerToSessionId.get(printer);
461
+ session = sessionId == null ? null : sessions.get(sessionId);
462
+ if (session != null) {
463
+ printPromise = session.printPromise;
464
+ cancelPrintTimeoutLocked(session);
465
+ session.printPromise = null;
466
+ session.printTimeoutRunnable = null;
467
+ }
468
+ }
469
+
470
+ if (session == null) {
471
+ return;
472
+ }
473
+
474
+ if (printPromise != null) {
475
+ if (code == Epos2CallbackCode.CODE_SUCCESS) {
476
+ printPromise.resolve(true);
477
+ } else {
478
+ printPromise.reject("PRINT_FAILURE", "Print finished with error code: " + code);
479
+ }
480
+ }
481
+
482
+ WritableMap body = Arguments.createMap();
483
+ body.putString("sessionId", session.sessionId);
484
+ body.putString("target", session.target == null ? "" : session.target);
485
+ body.putInt("code", code);
486
+ emitEvent(EVENT_PRINTER_RECEIVE, body);
487
+ }
488
+
489
+ @Override
490
+ public void onDiscovery(DeviceInfo deviceInfo) {
491
+ if (deviceInfo == null) {
492
+ return;
493
+ }
494
+
495
+ synchronized (lock) {
496
+ if (discoveryPromise == null || discoveredPrinters == null || discoveredTargets == null) {
497
+ return;
498
+ }
499
+
500
+ String target = valueOrEmpty(deviceInfo.getTarget());
501
+ if (discoveredTargets.contains(target)) {
502
+ return;
503
+ }
504
+ discoveredTargets.add(target);
505
+
506
+ WritableMap printer = Arguments.createMap();
507
+ printer.putString("target", target);
508
+ printer.putString("name", valueOrEmpty(deviceInfo.getDeviceName()));
509
+ printer.putString("macAddress", valueOrEmpty(deviceInfo.getMacAddress()));
510
+ printer.putString("ipAddress", valueOrEmpty(deviceInfo.getIpAddress()));
511
+ printer.putString("bdAddress", valueOrEmpty(deviceInfo.getBdAddress()));
512
+ printer.putString("type", "EPSON");
513
+
514
+ discoveredPrinters.pushMap(printer);
515
+ }
516
+ }
517
+
518
+ @Override
519
+ public void invalidate() {
520
+ stopDiscoveryQuietly();
521
+
522
+ synchronized (lock) {
523
+ for (EpsonSession session : sessions.values()) {
524
+ teardownPrinter(session, false);
525
+ }
526
+ sessions.clear();
527
+ printerToSessionId.clear();
528
+ targetToSessionId.clear();
529
+ clearCachedConnectionsLocked();
530
+ clearDiscoveryStateLocked();
531
+ }
532
+
533
+ super.invalidate();
534
+ }
535
+
536
+ private void stopDiscoveryAndResolve() {
537
+ Promise promise;
538
+ WritableArray results;
539
+ synchronized (lock) {
540
+ promise = discoveryPromise;
541
+ results = discoveredPrinters;
542
+ clearDiscoveryStateLocked();
543
+ }
544
+
545
+ stopDiscoveryQuietly();
546
+
547
+ if (promise != null) {
548
+ promise.resolve(results == null ? Arguments.createArray() : results);
549
+ }
550
+ }
551
+
552
+ private void stopDiscoveryQuietly() {
553
+ synchronized (lock) {
554
+ if (discoveryTimeoutRunnable != null) {
555
+ mainHandler.removeCallbacks(discoveryTimeoutRunnable);
556
+ discoveryTimeoutRunnable = null;
557
+ }
558
+ }
559
+
560
+ while (true) {
561
+ try {
562
+ Discovery.stop();
563
+ return;
564
+ } catch (Epos2Exception error) {
565
+ if (error.getErrorStatus() != Epos2Exception.ERR_PROCESSING) {
566
+ return;
567
+ }
568
+ } catch (Exception ignored) {
569
+ return;
570
+ }
571
+ }
572
+ }
573
+
574
+ private void clearDiscoveryStateLocked() {
575
+ discoveryPromise = null;
576
+ discoveredPrinters = null;
577
+ discoveredTargets = null;
578
+ discoveryTimeoutRunnable = null;
579
+ }
580
+
581
+ private void teardownPrinter(EpsonSession session, boolean disconnect) {
582
+ Promise pendingPromise = null;
583
+ Printer printer;
584
+ String target;
585
+ int model;
586
+ int lang;
587
+
588
+ synchronized (lock) {
589
+ if (session.printPromise != null) {
590
+ pendingPromise = session.printPromise;
591
+ }
592
+ cancelPrintTimeoutLocked(session);
593
+ session.printPromise = null;
594
+ session.printTimeoutRunnable = null;
595
+
596
+ if (session.target != null && session.sessionId.equals(targetToSessionId.get(session.target))) {
597
+ targetToSessionId.remove(session.target);
598
+ }
599
+
600
+ if (session.printer != null) {
601
+ printerToSessionId.remove(session.printer);
602
+ }
603
+
604
+ target = session.target;
605
+ model = session.model;
606
+ lang = session.lang;
607
+ printer = session.printer;
608
+ session.printer = null;
609
+ session.target = null;
610
+ session.model = -1;
611
+ session.lang = -1;
612
+ }
613
+
614
+ if (pendingPromise != null) {
615
+ pendingPromise.reject("PRINT_CANCELED", "Print canceled because printer session was torn down");
616
+ }
617
+
618
+ if (printer == null) {
619
+ return;
620
+ }
621
+
622
+ if (disconnect && target != null && model >= 0 && lang >= 0) {
623
+ synchronized (lock) {
624
+ if (!targetToSessionId.containsKey(target)) {
625
+ cacheConnectionLocked(target, model, lang, printer);
626
+ return;
627
+ }
628
+ }
629
+ }
630
+
631
+ disconnectPrinterQuietly(printer);
632
+ }
633
+
634
+ private void cacheConnectionLocked(String target, int model, int lang, Printer printer) {
635
+ CachedConnection existing = cachedConnections.remove(target);
636
+ if (existing != null) {
637
+ cancelCacheEvictionLocked(existing);
638
+ disconnectPrinterQuietly(existing.printer);
639
+ }
640
+
641
+ CachedConnection cached = new CachedConnection(target, model, lang, printer);
642
+ Runnable evictionRunnable = () -> evictCachedConnection(target);
643
+ cached.evictionRunnable = evictionRunnable;
644
+ cachedConnections.put(target, cached);
645
+ mainHandler.postDelayed(evictionRunnable, CONNECTION_CACHE_TTL_MS);
646
+ }
647
+
648
+ private void evictCachedConnection(String target) {
649
+ CachedConnection cached;
650
+ synchronized (lock) {
651
+ cached = cachedConnections.remove(target);
652
+ if (cached == null) {
653
+ return;
654
+ }
655
+ cancelCacheEvictionLocked(cached);
656
+ }
657
+ disconnectPrinterQuietly(cached.printer);
658
+ }
659
+
660
+ private void cancelCacheEvictionLocked(CachedConnection cached) {
661
+ if (cached.evictionRunnable != null) {
662
+ mainHandler.removeCallbacks(cached.evictionRunnable);
663
+ cached.evictionRunnable = null;
664
+ }
665
+ }
666
+
667
+ private void clearCachedConnectionsLocked() {
668
+ for (CachedConnection cached : cachedConnections.values()) {
669
+ cancelCacheEvictionLocked(cached);
670
+ disconnectPrinterQuietly(cached.printer);
671
+ }
672
+ cachedConnections.clear();
673
+ }
674
+
675
+ private boolean isConnectionHealthy(Printer printer) {
676
+ try {
677
+ PrinterStatusInfo status = printer.getStatus();
678
+ return isStatusReady(status);
679
+ } catch (Exception ignored) {
680
+ return false;
681
+ }
682
+ }
683
+
684
+ private boolean isStatusReady(PrinterStatusInfo status) {
685
+ return status != null
686
+ && status.getConnection() == Printer.TRUE
687
+ && status.getOnline() == Printer.TRUE;
688
+ }
689
+
690
+ private void detachUnhealthyPrinter(String sessionId, Printer printer) {
691
+ EpsonSession session;
692
+ synchronized (lock) {
693
+ session = sessions.get(sessionId);
694
+ if (session == null || session.printer != printer) {
695
+ return;
696
+ }
697
+ }
698
+ teardownPrinter(session, false);
699
+ }
700
+
701
+ private void disconnectPrinterQuietly(Printer printer) {
702
+ try {
703
+ printer.setReceiveEventListener(null);
704
+ printer.setConnectionEventListener(null);
705
+ printer.setStatusChangeEventListener(null);
706
+ printer.disconnect();
707
+ } catch (Exception ignored) {
708
+ }
709
+ }
710
+
711
+ private void cancelPrintTimeoutLocked(EpsonSession session) {
712
+ if (session.printTimeoutRunnable != null) {
713
+ mainHandler.removeCallbacks(session.printTimeoutRunnable);
714
+ }
715
+ }
716
+
717
+ private void handlePrintTimeout(String sessionId) {
718
+ Promise pendingPromise = null;
719
+ EpsonSession session;
720
+
721
+ synchronized (lock) {
722
+ session = sessions.get(sessionId);
723
+ if (session != null) {
724
+ pendingPromise = session.printPromise;
725
+ session.printPromise = null;
726
+ session.printTimeoutRunnable = null;
727
+ }
728
+ }
729
+
730
+ if (pendingPromise != null) {
731
+ pendingPromise.reject("PRINT_TIMEOUT", "Print timed out waiting for printer response");
732
+ }
733
+
734
+ if (session != null && session.printer != null) {
735
+ detachUnhealthyPrinter(sessionId, session.printer);
736
+ }
737
+ }
738
+
739
+ private void applyCommands(Printer printer, ReadableArray commands) throws Epos2Exception {
740
+ if (commands == null) {
741
+ return;
742
+ }
743
+
744
+ for (int i = 0; i < commands.size(); i++) {
745
+ if (commands.getType(i) != ReadableType.Map) {
746
+ continue;
747
+ }
748
+
749
+ ReadableMap command = commands.getMap(i);
750
+ if (command == null || !command.hasKey("cmd") || command.isNull("cmd")) {
751
+ continue;
752
+ }
753
+
754
+ String type = command.getString("cmd");
755
+ if (type == null) {
756
+ continue;
757
+ }
758
+
759
+ switch (type) {
760
+ case "addText":
761
+ applyTextCommand(printer, command);
762
+ break;
763
+ case "addTextAlign":
764
+ applyAlignCommand(printer, command);
765
+ break;
766
+ case "addTextStyle":
767
+ applyTextStyleCommand(printer, command);
768
+ break;
769
+ case "addTextSize":
770
+ applyTextSizeCommand(printer, command);
771
+ break;
772
+ case "addBarcode":
773
+ applyBarcodeCommand(printer, command);
774
+ break;
775
+ case "addSymbol":
776
+ applySymbolCommand(printer, command);
777
+ break;
778
+ case "addCut":
779
+ printer.addCut(Printer.CUT_FEED);
780
+ break;
781
+ case "addFeedLine":
782
+ printer.addFeedLine(optionalInt(command, "line", 1));
783
+ break;
784
+ case "addPulse":
785
+ printer.addPulse(Printer.DRAWER_2PIN, Printer.PULSE_100);
786
+ break;
787
+ case "addTextLang":
788
+ if (hasNumeric(command, "lang")) {
789
+ printer.addTextLang((int) command.getDouble("lang"));
790
+ }
791
+ break;
792
+ case "addTextFont":
793
+ if (hasNumeric(command, "font")) {
794
+ printer.addTextFont((int) command.getDouble("font"));
795
+ }
796
+ break;
797
+ case "addImage":
798
+ applyImageCommand(printer, command);
799
+ break;
800
+ default:
801
+ break;
802
+ }
803
+ }
804
+ }
805
+
806
+ private void applyTextCommand(Printer printer, ReadableMap command) throws Epos2Exception {
807
+ String data = optionalString(command, "data");
808
+ if (data == null) {
809
+ return;
810
+ }
811
+
812
+ if (command.hasKey("align") && !command.isNull("align")) {
813
+ applyAlignCommand(printer, command);
814
+ }
815
+
816
+ if (command.hasKey("bold") && !command.isNull("bold") && command.getType("bold") == ReadableType.Boolean) {
817
+ boolean bold = command.getBoolean("bold");
818
+ printer.addTextStyle(Printer.PARAM_DEFAULT, Printer.PARAM_DEFAULT, bold ? Printer.TRUE : Printer.FALSE, Printer.PARAM_DEFAULT);
819
+ }
820
+
821
+ printer.addText(data);
822
+ }
823
+
824
+ private void applyAlignCommand(Printer printer, ReadableMap command) throws Epos2Exception {
825
+ String align = optionalString(command, "align");
826
+ int alignValue = Printer.ALIGN_LEFT;
827
+ if ("center".equals(align)) {
828
+ alignValue = Printer.ALIGN_CENTER;
829
+ } else if ("right".equals(align)) {
830
+ alignValue = Printer.ALIGN_RIGHT;
831
+ }
832
+ printer.addTextAlign(alignValue);
833
+ }
834
+
835
+ private void applyTextStyleCommand(Printer printer, ReadableMap command) throws Epos2Exception {
836
+ if (command.hasKey("bold") && !command.isNull("bold") && command.getType("bold") == ReadableType.Boolean) {
837
+ boolean bold = command.getBoolean("bold");
838
+ printer.addTextStyle(Printer.PARAM_DEFAULT, Printer.PARAM_DEFAULT, bold ? Printer.TRUE : Printer.FALSE, Printer.PARAM_DEFAULT);
839
+ }
840
+ }
841
+
842
+ private void applyTextSizeCommand(Printer printer, ReadableMap command) throws Epos2Exception {
843
+ int width = optionalInt(command, "width", 1);
844
+ int height = optionalInt(command, "height", 1);
845
+ printer.addTextSize(width, height);
846
+ }
847
+
848
+ private void applyBarcodeCommand(Printer printer, ReadableMap command) throws Epos2Exception {
849
+ String data = optionalString(command, "data");
850
+ if (data == null) {
851
+ return;
852
+ }
853
+
854
+ String barcodeType = optionalString(command, "type");
855
+ int type = Printer.BARCODE_CODE39;
856
+ if ("UPC-A".equals(barcodeType)) {
857
+ type = Printer.BARCODE_UPC_A;
858
+ } else if ("UPC-E".equals(barcodeType)) {
859
+ type = Printer.BARCODE_UPC_E;
860
+ } else if ("EAN13".equals(barcodeType)) {
861
+ type = Printer.BARCODE_EAN13;
862
+ } else if ("EAN8".equals(barcodeType)) {
863
+ type = Printer.BARCODE_EAN8;
864
+ } else if ("ITF".equals(barcodeType)) {
865
+ type = Printer.BARCODE_ITF;
866
+ } else if ("CODABAR".equals(barcodeType)) {
867
+ type = Printer.BARCODE_CODABAR;
868
+ }
869
+
870
+ int width = optionalInt(command, "width", 2);
871
+ int height = optionalInt(command, "height", 100);
872
+ printer.addBarcode(data, type, Printer.HRI_BELOW, Printer.FONT_A, width, height);
873
+ }
874
+
875
+ private void applySymbolCommand(Printer printer, ReadableMap command) throws Epos2Exception {
876
+ String data = optionalString(command, "data");
877
+ if (data == null) {
878
+ return;
879
+ }
880
+
881
+ String levelText = optionalString(command, "level");
882
+ int level = Printer.LEVEL_M;
883
+ if ("L".equalsIgnoreCase(levelText)) {
884
+ level = Printer.LEVEL_L;
885
+ } else if ("Q".equalsIgnoreCase(levelText)) {
886
+ level = Printer.LEVEL_Q;
887
+ } else if ("H".equalsIgnoreCase(levelText)) {
888
+ level = Printer.LEVEL_H;
889
+ }
890
+
891
+ int width = optionalInt(command, "width", 3);
892
+ printer.addSymbol(data, Printer.SYMBOL_QRCODE_MODEL_2, level, width, width, 0);
893
+ }
894
+
895
+ private void applyImageCommand(Printer printer, ReadableMap command) throws Epos2Exception {
896
+ String base64 = optionalString(command, "data");
897
+ if (base64 == null) {
898
+ return;
899
+ }
900
+
901
+ byte[] imageBytes;
902
+ try {
903
+ imageBytes = Base64.decode(base64, Base64.DEFAULT);
904
+ } catch (Exception ignored) {
905
+ return;
906
+ }
907
+
908
+ Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
909
+ if (bitmap == null) {
910
+ return;
911
+ }
912
+
913
+ printer.addImage(
914
+ bitmap,
915
+ 0,
916
+ 0,
917
+ bitmap.getWidth(),
918
+ bitmap.getHeight(),
919
+ Printer.COLOR_1,
920
+ Printer.MODE_MONO,
921
+ Printer.HALFTONE_DITHER,
922
+ Printer.PARAM_DEFAULT,
923
+ Printer.COMPRESS_AUTO
924
+ );
925
+ }
926
+
927
+ private boolean hasNumeric(ReadableMap map, String key) {
928
+ return map.hasKey(key) && !map.isNull(key) && map.getType(key) == ReadableType.Number;
929
+ }
930
+
931
+ private int optionalInt(ReadableMap map, String key, int fallback) {
932
+ if (hasNumeric(map, key)) {
933
+ return (int) map.getDouble(key);
934
+ }
935
+ return fallback;
936
+ }
937
+
938
+ private String optionalString(ReadableMap map, String key) {
939
+ if (!map.hasKey(key) || map.isNull(key) || map.getType(key) != ReadableType.String) {
940
+ return null;
941
+ }
942
+ return map.getString(key);
943
+ }
944
+
945
+ private String valueOrEmpty(String value) {
946
+ return value == null ? "" : value;
947
+ }
948
+
949
+ private String mapConnectionEvent(int eventType) {
950
+ if (eventType == ConnectionListener.EVENT_RECONNECTING) {
951
+ return "RECONNECTING";
952
+ }
953
+ if (eventType == ConnectionListener.EVENT_RECONNECT) {
954
+ return "RECONNECTED";
955
+ }
956
+ if (eventType == ConnectionListener.EVENT_DISCONNECT) {
957
+ return "DISCONNECTED";
958
+ }
959
+ return "UNKNOWN";
960
+ }
961
+
962
+ private String mapPaperStatus(int paperStatus) {
963
+ if (paperStatus == Printer.PAPER_EMPTY) {
964
+ return "EMPTY";
965
+ }
966
+ if (paperStatus == Printer.PAPER_NEAR_END) {
967
+ return "NEAR_EMPTY";
968
+ }
969
+ return "OK";
970
+ }
971
+
972
+ private String mapErrorStatus(int errorStatus) {
973
+ if (errorStatus == Printer.MECHANICAL_ERR) {
974
+ return "MECHANICAL_ERR";
975
+ }
976
+ if (errorStatus == Printer.AUTOCUTTER_ERR) {
977
+ return "AUTOCUTTER_ERR";
978
+ }
979
+ return "NONE";
980
+ }
981
+
982
+ private boolean ensureDiscoverReadiness(Promise promise) {
983
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
984
+ if (!hasPermission(Manifest.permission.BLUETOOTH_SCAN)) {
985
+ promise.reject("PERMISSION_DENIED", "Missing Android permission: android.permission.BLUETOOTH_SCAN");
986
+ return false;
987
+ }
988
+ return true;
989
+ }
990
+
991
+ if (!hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
992
+ promise.reject("PERMISSION_DENIED", "Missing Android permission: android.permission.ACCESS_FINE_LOCATION");
993
+ return false;
994
+ }
995
+
996
+ if (!isLocationEnabled()) {
997
+ promise.reject("LOCATION_DISABLED", "Location services must be enabled for Bluetooth discovery");
998
+ return false;
999
+ }
1000
+
1001
+ return true;
1002
+ }
1003
+
1004
+ private boolean ensureBluetoothOperationReadiness(String target, Promise promise) {
1005
+ if (!isBluetoothTarget(target)) {
1006
+ return true;
1007
+ }
1008
+
1009
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
1010
+ if (!hasPermission(Manifest.permission.BLUETOOTH_CONNECT)) {
1011
+ promise.reject("PERMISSION_DENIED", "Missing Android permission: android.permission.BLUETOOTH_CONNECT");
1012
+ return false;
1013
+ }
1014
+ } else {
1015
+ if (!hasPermission(Manifest.permission.BLUETOOTH)) {
1016
+ promise.reject("PERMISSION_DENIED", "Missing Android permission: android.permission.BLUETOOTH");
1017
+ return false;
1018
+ }
1019
+ }
1020
+
1021
+ if (!isBluetoothEnabled()) {
1022
+ promise.reject("BLUETOOTH_DISABLED", "Bluetooth is disabled");
1023
+ return false;
1024
+ }
1025
+
1026
+ return true;
1027
+ }
1028
+
1029
+ private boolean hasPermission(String permission) {
1030
+ return reactContext.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
1031
+ }
1032
+
1033
+ private boolean isBluetoothTarget(String target) {
1034
+ return target != null && target.toUpperCase().startsWith("BT:");
1035
+ }
1036
+
1037
+ private boolean isBluetoothEnabled() {
1038
+ BluetoothManager bluetoothManager = (BluetoothManager) reactContext.getSystemService(Context.BLUETOOTH_SERVICE);
1039
+ if (bluetoothManager == null) {
1040
+ return false;
1041
+ }
1042
+ BluetoothAdapter adapter = bluetoothManager.getAdapter();
1043
+ return adapter != null && adapter.isEnabled();
1044
+ }
1045
+
1046
+ private boolean isLocationEnabled() {
1047
+ LocationManager locationManager = (LocationManager) reactContext.getSystemService(Context.LOCATION_SERVICE);
1048
+ if (locationManager == null) {
1049
+ return false;
1050
+ }
1051
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
1052
+ return locationManager.isLocationEnabled();
1053
+ }
1054
+ return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
1055
+ || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
1056
+ }
1057
+
1058
+ private int normalizeLanguage(int lang) {
1059
+ if (lang >= 0 && lang <= 7) {
1060
+ return lang;
1061
+ }
1062
+ return Printer.LANG_EN;
1063
+ }
1064
+
1065
+ private int normalizeModel(int model) {
1066
+ switch (model) {
1067
+ case 0:
1068
+ case 1:
1069
+ case 2:
1070
+ case 3:
1071
+ case 4:
1072
+ case 5:
1073
+ case 6:
1074
+ case 7:
1075
+ case 8:
1076
+ case 9:
1077
+ case 10:
1078
+ case 11:
1079
+ case 12:
1080
+ case 13:
1081
+ case 14:
1082
+ case 15:
1083
+ case 16:
1084
+ case 17:
1085
+ case 18:
1086
+ case 19:
1087
+ case 20:
1088
+ return model;
1089
+ case 21:
1090
+ return Printer.TM_M30II;
1091
+ case 22:
1092
+ return Printer.TS_100;
1093
+ case 23:
1094
+ return Printer.TM_M50;
1095
+ case 24:
1096
+ return Printer.TM_T88VII;
1097
+ case 25:
1098
+ return Printer.TM_L90LFC;
1099
+ case 26:
1100
+ return Printer.TM_L100;
1101
+ case 27:
1102
+ return Printer.TM_P20II;
1103
+ case 28:
1104
+ return Printer.TM_P80II;
1105
+ case 29:
1106
+ return Printer.TM_M30III;
1107
+ case 30:
1108
+ return Printer.TM_M50II;
1109
+ case 31:
1110
+ return Printer.TM_M55;
1111
+ case 32:
1112
+ return Printer.TM_U220II;
1113
+ case 33:
1114
+ return Printer.SB_H50;
1115
+ case 34:
1116
+ return Printer.SB_M30;
1117
+ default:
1118
+ return Printer.TM_M30III;
1119
+ }
1120
+ }
1121
+
1122
+ private void rejectWithEposError(Promise promise, String code, String message, Exception error) {
1123
+ if (error instanceof Epos2Exception) {
1124
+ Epos2Exception epos2Error = (Epos2Exception) error;
1125
+ int status = epos2Error.getErrorStatus();
1126
+ promise.reject(code, message + ": " + status + " (" + eposErrorStatusToString(status) + ")", error);
1127
+ return;
1128
+ }
1129
+
1130
+ String errorMessage = error.getMessage() == null ? message : message + ": " + error.getMessage();
1131
+ promise.reject(code, errorMessage, error);
1132
+ }
1133
+
1134
+ private String eposErrorStatusToString(int code) {
1135
+ switch (code) {
1136
+ case 0:
1137
+ return "SUCCESS";
1138
+ case Epos2Exception.ERR_PARAM:
1139
+ return "ERR_PARAM";
1140
+ case Epos2Exception.ERR_CONNECT:
1141
+ return "ERR_CONNECT";
1142
+ case Epos2Exception.ERR_TIMEOUT:
1143
+ return "ERR_TIMEOUT";
1144
+ case Epos2Exception.ERR_MEMORY:
1145
+ return "ERR_MEMORY";
1146
+ case Epos2Exception.ERR_ILLEGAL:
1147
+ return "ERR_ILLEGAL";
1148
+ case Epos2Exception.ERR_PROCESSING:
1149
+ return "ERR_PROCESSING";
1150
+ case Epos2Exception.ERR_NOT_FOUND:
1151
+ return "ERR_NOT_FOUND";
1152
+ case Epos2Exception.ERR_IN_USE:
1153
+ return "ERR_IN_USE";
1154
+ case Epos2Exception.ERR_TYPE_INVALID:
1155
+ return "ERR_TYPE_INVALID";
1156
+ case Epos2Exception.ERR_DISCONNECT:
1157
+ return "ERR_DISCONNECT";
1158
+ case Epos2Exception.ERR_ALREADY_OPENED:
1159
+ return "ERR_ALREADY_OPENED";
1160
+ case Epos2Exception.ERR_ALREADY_USED:
1161
+ return "ERR_ALREADY_USED";
1162
+ case Epos2Exception.ERR_BOX_COUNT_OVER:
1163
+ return "ERR_BOX_COUNT_OVER";
1164
+ case Epos2Exception.ERR_BOX_CLIENT_OVER:
1165
+ return "ERR_BOX_CLIENT_OVER";
1166
+ case Epos2Exception.ERR_UNSUPPORTED:
1167
+ return "ERR_UNSUPPORTED";
1168
+ case Epos2Exception.ERR_FAILURE:
1169
+ return "ERR_FAILURE";
1170
+ default:
1171
+ return "UNKNOWN_ERROR_" + code;
1172
+ }
1173
+ }
1174
+
1175
+ private void emitEvent(String eventName, WritableMap body) {
1176
+ if (!reactContext.hasActiveCatalystInstance()) {
1177
+ return;
1178
+ }
1179
+ reactContext
1180
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
1181
+ .emit(eventName, body);
1182
+ }
1183
+
1184
+ private static final class EpsonSession {
1185
+ final String sessionId;
1186
+ Printer printer;
1187
+ String target;
1188
+ int model = -1;
1189
+ int lang = -1;
1190
+ Promise printPromise;
1191
+ Runnable printTimeoutRunnable;
1192
+
1193
+ EpsonSession(String sessionId) {
1194
+ this.sessionId = sessionId;
1195
+ }
1196
+ }
1197
+
1198
+ private static final class CachedConnection {
1199
+ final String target;
1200
+ final int model;
1201
+ final int lang;
1202
+ final Printer printer;
1203
+ Runnable evictionRunnable;
1204
+
1205
+ CachedConnection(String target, int model, int lang, Printer printer) {
1206
+ this.target = target;
1207
+ this.model = model;
1208
+ this.lang = lang;
1209
+ this.printer = printer;
1210
+ }
1211
+ }
1212
+ }