package leesiongchan.reactnativeescpos; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule; import io.github.escposjava.print.NetworkPrinter; import io.github.escposjava.print.Printer; import io.github.escposjava.print.exceptions.BarcodeSizeError; import io.github.escposjava.print.exceptions.QRCodeException; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Map; import org.json.JSONObject; import static io.github.escposjava.print.Commands.*; public class EscPosModule extends ReactContextBaseJavaModule { public static final String PRINTING_SIZE_58_MM = "PRINTING_SIZE_58_MM"; public static final String PRINTING_SIZE_80_MM = "PRINTING_SIZE_80_MM"; public static final String BLUETOOTH_CONNECTED = "BLUETOOTH_CONNECTED"; public static final String BLUETOOTH_DISCONNECTED = "BLUETOOTH_DISCONNECTED"; public static final String BLUETOOTH_DEVICE_FOUND = "BLUETOOTH_DEVICE_FOUND"; private final ReactApplicationContext reactContext; private PrinterService printerService; private ReadableMap config; private ScanManager scanManager; enum BluetoothEvent { CONNECTED, DISCONNECTED, DEVICE_FOUND, NONE } public EscPosModule(ReactApplicationContext reactContext) { super(reactContext); this.reactContext = reactContext; scanManager = new ScanManager(reactContext, BluetoothAdapter.getDefaultAdapter()); } @Override public Map<String, Object> getConstants() { final Map<String, Object> constants = new HashMap<>(); constants.put(PRINTING_SIZE_58_MM, PRINTING_SIZE_58_MM); constants.put(PRINTING_SIZE_80_MM, PRINTING_SIZE_80_MM); constants.put(BLUETOOTH_CONNECTED, BluetoothEvent.CONNECTED.name()); constants.put(BLUETOOTH_DISCONNECTED, BluetoothEvent.DISCONNECTED.name()); constants.put(BLUETOOTH_DEVICE_FOUND, BluetoothEvent.DEVICE_FOUND.name()); return constants; } @Override public String getName() { return "EscPos"; } @ReactMethod public void cutPart(Promise promise) { printerService.cutPart(); promise.resolve(true); } @ReactMethod public void cutFull(Promise promise) { printerService.cutFull(); promise.resolve(true); } @ReactMethod public void lineBreak(Promise promise) { printerService.lineBreak(); promise.resolve(true); } @ReactMethod public void print(String text, Promise promise) { try { printerService.print(text); promise.resolve(true); } catch (UnsupportedEncodingException e) { promise.reject(e); } } @ReactMethod public void printLn(String text, Promise promise) { try { printerService.printLn(text); promise.resolve(true); } catch (UnsupportedEncodingException e) { promise.reject(e); } } @ReactMethod public void printBarcode(String code, String bc, int width, int height, String pos, String font, Promise promise) { try { printerService.printBarcode(code, bc, width, height, pos, font); promise.resolve(true); } catch (BarcodeSizeError e) { promise.reject(e); } } @ReactMethod public void printDesign(String text, Promise promise) { try { printerService.printDesign(text); promise.resolve(true); } catch (IOException e) { promise.reject(e); } } @ReactMethod public void printImage(String filePath, Promise promise) { try { printerService.printImage(filePath); promise.resolve(true); } catch (IOException e) { promise.reject(e); } } @ReactMethod public void printQRCode(String value, int size, Promise promise) { try { printerService.printQRCode(value, size); promise.resolve(true); } catch (QRCodeException e) { promise.reject(e); } } @ReactMethod public void printSample(Promise promise) { try { printerService.printSample(); promise.resolve(true); } catch (IOException e) { promise.reject(e); } } @ReactMethod public void write(byte[] command, Promise promise) { printerService.write(command); promise.resolve(true); } @ReactMethod public void setCharCode(String code) { printerService.setCharCode(code); } @ReactMethod public void setTextDensity(int density) { printerService.setTextDensity(density); } @ReactMethod public void setPrintingSize(String printingSize) { int charsOnLine; int printingWidth; switch (printingSize) { case PRINTING_SIZE_80_MM: charsOnLine = LayoutBuilder.CHARS_ON_LINE_80_MM; printingWidth = PrinterService.PRINTING_WIDTH_80_MM; break; case PRINTING_SIZE_58_MM: default: charsOnLine = LayoutBuilder.CHARS_ON_LINE_58_MM; printingWidth = PrinterService.PRINTING_WIDTH_58_MM; } printerService.setCharsOnLine(charsOnLine); printerService.setPrintingWidth(printingWidth); } @ReactMethod public void beep(Promise promise) { printerService.beep(); promise.resolve(true); } @ReactMethod public void setConfig(ReadableMap config) { this.config = config; } @ReactMethod public void kickCashDrawerPin2(Promise promise) { printerService.kickCashDrawerPin2(); promise.resolve(true); } @ReactMethod public void kickCashDrawerPin5(Promise promise) { printerService.kickCashDrawerPin5(); promise.resolve(true); } @ReactMethod public void connectBluetoothPrinter(String address, Promise promise) { try { if (!"bluetooth".equals(config.getString("type"))) { promise.reject("config.type is not a bluetooth type"); } Printer printer = new BluetoothPrinter(address); printerService = new PrinterService(printer); promise.resolve(true); } catch (IOException e) { promise.reject(e); } } @ReactMethod public void connectNetworkPrinter(String address, int port, Promise promise) { try { if (!"network".equals(config.getString("type"))) { promise.reject("config.type is not a network type"); } Printer printer = new NetworkPrinter(address, port); printerService = new PrinterService(printer); promise.resolve(true); } catch (IOException e) { promise.reject(e); } } @ReactMethod public void disconnect(Promise promise) { try { printerService.close(); promise.resolve(true); } catch (IOException e) { promise.reject(e); } } @ReactMethod public void scanDevices() { scanManager.registerCallback(new ScanManager.OnBluetoothScanListener() { @Override public void deviceFound(BluetoothDevice bluetoothDevice) { WritableMap deviceInfoParams = Arguments.createMap(); deviceInfoParams.putString("name", bluetoothDevice.getName()); deviceInfoParams.putString("macAddress", bluetoothDevice.getAddress()); // put deviceInfoParams into callbackParams WritableMap callbackParams = Arguments.createMap(); callbackParams.putMap("deviceInfo", deviceInfoParams); callbackParams.putString("state", BluetoothEvent.DEVICE_FOUND.name()); // emit callback to RN code reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("bluetoothDeviceFound", callbackParams); } }); scanManager.startScan(); } @ReactMethod public void stopScan() { scanManager.stopScan(); } @ReactMethod public void initBluetoothConnectionListener() { // Add listener when bluetooth conencted reactContext.registerReceiver(bluetoothConnectionEventListener, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)); // Add listener when bluetooth disconnected reactContext.registerReceiver(bluetoothConnectionEventListener, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED)); } /** * Bluetooth Connection Event Listener */ private BroadcastReceiver bluetoothConnectionEventListener = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String callbackAction = intent.getAction(); BluetoothDevice bluetoothDevice = (BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // if action or bluetooth data is null if (callbackAction == null || bluetoothDevice == null) { // do not proceed return; } // hold value for bluetooth event BluetoothEvent bluetoothEvent; switch (callbackAction) { case BluetoothDevice.ACTION_ACL_CONNECTED: bluetoothEvent = BluetoothEvent.CONNECTED; break; case BluetoothDevice.ACTION_ACL_DISCONNECTED: bluetoothEvent = BluetoothEvent.DISCONNECTED; break; default: bluetoothEvent = BluetoothEvent.NONE; } // bluetooth event must not be null if (bluetoothEvent != BluetoothEvent.NONE) { // extract bluetooth device info and put in deviceInfoParams WritableMap deviceInfoParams = Arguments.createMap(); deviceInfoParams.putString("name", bluetoothDevice.getName()); deviceInfoParams.putString("macAddress", bluetoothDevice.getAddress()); // put deviceInfoParams into callbackParams WritableMap callbackParams = Arguments.createMap(); callbackParams.putMap("deviceInfo", deviceInfoParams); callbackParams.putString("state", bluetoothEvent.name()); // emit callback to RN code reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("bluetoothStateChanged", callbackParams); } } }; }