diff --git a/pom.xml b/pom.xml index 608b6b13..ce68f93b 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ default-compile - 6 + 8 false module-info.java diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPort.java b/src/main/java/com/fazecast/jSerialComm/SerialPort.java index 1daf5f0e..60e0a150 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPort.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPort.java @@ -123,7 +123,14 @@ public class SerialPort cleanUpDirectory(new File(userHomeDirectory, "..")); // Determine Operating System and architecture - if (System.getProperty("java.vm.vendor", "").toLowerCase().contains("android")) + // Check multiple Java system properties for Android detection to handle OEM builds where + // java.vm.vendor does not contain "android" (e.g. some MediaTek/Qualcomm Android POS devices). + // java.vm.name is "Dalvik" on all standard Android runtimes regardless of OEM customization. + final boolean isAndroidRuntime = + System.getProperty("java.vm.vendor", "").toLowerCase().contains("android") || + System.getProperty("java.vm.name", "").toLowerCase().contains("dalvik") || + System.getProperty("java.vendor", "").toLowerCase().contains("android"); + if (isAndroidRuntime) { isAndroidDelete = true; libraryPath = "Android"; @@ -185,8 +192,15 @@ else if (arch.contains("86") || arch.contains("amd")) System.exit(-1); } - // Load platform-specific binaries for non-Android systems - if (!isAndroid) + // Load platform-specific binaries for non-Android systems. + // When running inside an Android app that manages USB Host access itself, the host + // sets jSerialComm.android.override=true before this class is loaded so that native + // library loading (which would fail on Android due to path and version constraints) + // is skipped entirely. The host app then calls setAndroidContext() and sets + // isAndroid=true via reflection to activate the USB Host API path. + final boolean androidOverride = isAndroidRuntime && + System.getProperty("jSerialComm.android.override", "false").equalsIgnoreCase("true"); + if (!isAndroid && !androidOverride) { // Attempt to load from a manually-specified user location boolean libraryLoaded = false; @@ -608,7 +622,8 @@ public final boolean openPort(int safetySleepTime, int deviceSendQueueSize, int try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); } // If this is an Android root application, we must explicitly allow serial port access to the library - File portFile = isAndroidDelete ? new File(comPort) : null; + // Skip su/chmod when androidPort is already set (USB serial path handles open itself) + File portFile = (isAndroidDelete && androidPort == null) ? new File(comPort) : null; if (portFile != null && (!portFile.canRead() || !portFile.canWrite())) { Process process = null; @@ -1130,6 +1145,10 @@ public final boolean setDTRandRTS(boolean dtr, boolean rts) // SerialPort Constructors private SerialPort() {} + private SerialPort(String port, String friendly, String description, String location, String serial, String manufacture, int vid, int pid) + { + this(port, friendly, description, location, serial, manufacture, "", vid, pid); + } private SerialPort(String port, String friendly, String description, String location, String serial, String manufacture, String driver, int vid, int pid) { comPort = port; diff --git a/src/main/java/com/fazecast/jSerialComm/android/AndroidPort.java b/src/main/java/com/fazecast/jSerialComm/android/AndroidPort.java index 93ab4d2b..4cf2f96e 100644 --- a/src/main/java/com/fazecast/jSerialComm/android/AndroidPort.java +++ b/src/main/java/com/fazecast/jSerialComm/android/AndroidPort.java @@ -147,15 +147,17 @@ public static SerialPort[] getCommPortsNative() AndroidPort androidPort = null; Constructor serialPortConstructor = - SerialPort.class.getDeclaredConstructor(String.class, String.class, String.class, String.class, String.class, int.class, int.class); + SerialPort.class.getDeclaredConstructor(String.class, String.class, String.class, String.class, String.class, String.class, String.class, int.class, int.class); serialPortConstructor.setAccessible(true); SerialPort serialPort = serialPortConstructor.newInstance( "COM" + (ports.size() + 1), - device.getDeviceName(), device.getProductName(), + device.getProductName(), + device.getDeviceName(), device.getSerialNumber(), - device.getSerialNumber(), + device.getManufacturerName(), + "", device.getVendorId(), device.getProductId() );