Browse Source

feat 增加串口相关的打印和扫描器基础代码

robin 4 years ago
parent
commit
af1947a972
35 changed files with 1917 additions and 1 deletions
  1. 7 0
      .idea/dictionaries/Robin.xml
  2. 1 0
      .idea/gradle.xml
  3. 36 0
      .idea/inspectionProfiles/Project_Default.xml
  4. 1 0
      app/build.gradle
  5. 544 0
      app/src/main/java/com/doverfuelingsolutions/issp/api/bean/PayResultHs.java
  6. 223 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/printer/ComPrintManager.java
  7. 10 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/printer/PrintManager.java
  8. 22 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/printer/PrintStatusContants.java
  9. 9 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/printer/PrintStatusListen.java
  10. 131 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/scan/ComScanKeyManager.java
  11. 164 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/scan/NormalScanKeyManager.java
  12. 14 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/scan/ScanManager.java
  13. 5 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/scan/ScanValueListener.java
  14. 22 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/serialPort/ComBean.java
  15. 12 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/serialPort/DataReceivedListener.java
  16. 38 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/serialPort/SerialControl.java
  17. 266 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/serialPort/SerialHelper.java
  18. 211 0
      app/src/main/java/com/doverfuelingsolutions/issp/driver/usb/UsbTools.java
  19. 1 1
      app/src/main/java/com/doverfuelingsolutions/issp/utils/ValidateUtil.kt
  20. 2 0
      app/src/main/java/com/doverfuelingsolutions/issp/view/MainActivity.kt
  21. 1 0
      libserial/.gitignore
  22. 44 0
      libserial/build.gradle
  23. 0 0
      libserial/consumer-rules.pro
  24. BIN
      libserial/libs/PrintUtils1114.jar
  25. BIN
      libserial/libs/armeabi-v7a/libserial_port.so
  26. BIN
      libserial/libs/armeabi/libserial_port.so
  27. BIN
      libserial/libs/core-3.2.1.jar
  28. BIN
      libserial/libs/printsdk1015-v2.2.jar
  29. BIN
      libserial/libs/x86/libserial_port.so
  30. 21 0
      libserial/proguard-rules.pro
  31. 24 0
      libserial/src/androidTest/java/com/doverfuelingsolutions/libserial/ExampleInstrumentedTest.kt
  32. 5 0
      libserial/src/main/AndroidManifest.xml
  33. 85 0
      libserial/src/main/java/android_serialport_api/SerialPort.java
  34. 17 0
      libserial/src/test/java/com/doverfuelingsolutions/libserial/ExampleUnitTest.kt
  35. 1 0
      settings.gradle

+ 7 - 0
.idea/dictionaries/Robin.xml

@@ -0,0 +1,7 @@
+<component name="ProjectDictionaryState">
+  <dictionary name="Robin">
+    <words>
+      <w>libserial</w>
+    </words>
+  </dictionary>
+</component>

+ 1 - 0
.idea/gradle.xml

@@ -12,6 +12,7 @@
           <set>
             <option value="$PROJECT_DIR$" />
             <option value="$PROJECT_DIR$/app" />
+            <option value="$PROJECT_DIR$/libserial" />
             <option value="$PROJECT_DIR$/waynelib_" />
           </set>
         </option>

+ 36 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,36 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="TOP_LEVEL_CLASS_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="" />
+        </value>
+      </option>
+      <option name="INNER_CLASS_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="" />
+        </value>
+      </option>
+      <option name="METHOD_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
+        </value>
+      </option>
+      <option name="FIELD_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="" />
+        </value>
+      </option>
+      <option name="IGNORE_DEPRECATED" value="false" />
+      <option name="IGNORE_JAVADOC_PERIOD" value="true" />
+      <option name="IGNORE_DUPLICATED_THROWS" value="false" />
+      <option name="IGNORE_POINT_TO_ITSELF" value="false" />
+      <option name="myAdditionalJavadocTags" value="desc" />
+    </inspection_tool>
+  </profile>
+</component>

+ 1 - 0
app/build.gradle

@@ -52,6 +52,7 @@ dependencies {
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
 
     implementation project(':waynelib_')
+    implementation project(':libserial')
 
     def retrofitVersion = '2.9.0'
     implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"

+ 544 - 0
app/src/main/java/com/doverfuelingsolutions/issp/api/bean/PayResultHs.java

@@ -0,0 +1,544 @@
+package com.doverfuelingsolutions.issp.api.bean;
+
+import com.wayne.www.waynelib.webservice.entity.PosTrxItem;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * @desc
+ * @info Created by LzPeng on 2020/3/20
+ */
+public class PayResultHs {
+
+
+    /**
+     * Id : 31519ce0-0473-4c31-aa49-709152419fd2
+     * LineNum : 0
+     * Paid : 0.01
+     * AuthCode : 135329938250208451
+     * ResultCode : 0
+     * ResultMessage : OK
+     * ErrorDetail :
+     * BillNumber : 2020032016564336400000000020
+     * PayBack : 0.0
+     * PosTrx : {"Id":"9aa8e955-7156-4c47-a51e-98414df730ec","Items":[{"Id":"06a9680f-2465-43bc-99b3-242bdc66ee49","LineNum":0,"PosItemId":"d2cb7584-c6eb-4cba-8bdb-d0eaebbe3c1e","Item":{"Id":"d2cb7584-c6eb-4cba-8bdb-d0eaebbe3c1e","ItemId":"1","BarCode":"1","ItemName":"0#","UnitId":0,"Price":6.99,"DateToActivate":"2019-08-13 09:53:23.000","DateToDeactivate":"2020-08-15 23:59:59.000","CreatedDateTime":"2020-03-10 09:40:58.909","IsFuelItem":true,"IsMarkedAsDeletion":false,"TargetBusinessUnitId":"aaa3bf03-1da6-4f31-9f56-c86b487beeee"},"Qty":0.08,"Voided":false,"PosTrxId":"9aa8e955-7156-4c47-a51e-98414df730ec","NetAmount":0.01,"GrossAmount":0.01,"FuelItemSoldOnPumpId":3,"FuelItemSoldOnPumpNozzleId":2,"FuelItemOriginalGrossAmount":0.01,"FuelItemFdcTransactionSeqNo":"57170349","FuelItemFdcReleaseTokenAttribute":11}],"Payments":[],"TransactionSource":0,"TransactionType":0,"ReceiptId":"I0320165640","ShiftId":30,"TransactionInitTimeInPos":"2020-03-20 16:56:55.581","TransactionArrivedAtServerTime":"2020-03-20 16:56:40.965","NetAmount":0.01,"GrossAmount":0.01,"Discount":0,"TransactionStatus":1,"ServiceIdentityUserId":"3c3c4bf7-7f6b-4f90-b052-973cac8a4e6a","BusinessUnitId":"aaa3bf03-1da6-4f31-9f56-c86b487beeee","SiteDeviceId":"503f3e99-fe56-4261-afce-38d28aeed3f1","AccountId":""}
+     * PosTrxId : 9aa8e955-7156-4c47-a51e-98414df730ec
+     * Mop : {"Id":"b936e87e-5bc2-4155-9529-8b282c8eea0c","PaymentId":3,"CreatedDateTime":"2019-07-10 15:34:44.492","TargetBusinessUnitId":"aaa3bf03-1da6-4f31-9f56-c86b487beeee","Status":0}
+     * PosMopId : b936e87e-5bc2-4155-9529-8b282c8eea0c
+     */
+
+    private String Id;
+    private int LineNum;
+    private double Paid;
+    private String AuthCode;
+    private String ResultCode;
+    private String ResultMessage;
+    private String ErrorDetail;
+    private String BillNumber;
+    private double PayBack;
+    private PosTrxBean PosTrx;
+    private String PosTrxId;
+    private MopBean Mop;
+    private String PosMopId;
+
+    public String getId() {
+        return Id;
+    }
+
+    public void setId(String Id) {
+        this.Id = Id;
+    }
+
+    public int getLineNum() {
+        return LineNum;
+    }
+
+    public void setLineNum(int LineNum) {
+        this.LineNum = LineNum;
+    }
+
+    public double getPaid() {
+        return Paid;
+    }
+
+    public void setPaid(double Paid) {
+        this.Paid = Paid;
+    }
+
+    public String getAuthCode() {
+        return AuthCode;
+    }
+
+    public void setAuthCode(String AuthCode) {
+        this.AuthCode = AuthCode;
+    }
+
+    public String getResultCode() {
+        return ResultCode;
+    }
+
+    public void setResultCode(String ResultCode) {
+        this.ResultCode = ResultCode;
+    }
+
+    public String getResultMessage() {
+        return ResultMessage;
+    }
+
+    public void setResultMessage(String ResultMessage) {
+        this.ResultMessage = ResultMessage;
+    }
+
+    public String getErrorDetail() {
+        return ErrorDetail;
+    }
+
+    public void setErrorDetail(String ErrorDetail) {
+        this.ErrorDetail = ErrorDetail;
+    }
+
+    public String getBillNumber() {
+        return BillNumber;
+    }
+
+    public void setBillNumber(String BillNumber) {
+        this.BillNumber = BillNumber;
+    }
+
+    public double getPayBack() {
+        return PayBack;
+    }
+
+    public void setPayBack(double PayBack) {
+        this.PayBack = PayBack;
+    }
+
+    public PosTrxBean getPosTrx() {
+        return PosTrx;
+    }
+
+    public void setPosTrx(PosTrxBean PosTrx) {
+        this.PosTrx = PosTrx;
+    }
+
+    public String getPosTrxId() {
+        return PosTrxId;
+    }
+
+    public void setPosTrxId(String PosTrxId) {
+        this.PosTrxId = PosTrxId;
+    }
+
+    public MopBean getMop() {
+        return Mop;
+    }
+
+    public void setMop(MopBean Mop) {
+        this.Mop = Mop;
+    }
+
+    public String getPosMopId() {
+        return PosMopId;
+    }
+
+    public void setPosMopId(String PosMopId) {
+        this.PosMopId = PosMopId;
+    }
+
+    public static class PosTrxBean implements Serializable {
+        /**
+         * Id : 9aa8e955-7156-4c47-a51e-98414df730ec
+         * Items : [{"Id":"06a9680f-2465-43bc-99b3-242bdc66ee49","LineNum":0,"PosItemId":"d2cb7584-c6eb-4cba-8bdb-d0eaebbe3c1e","Item":{"Id":"d2cb7584-c6eb-4cba-8bdb-d0eaebbe3c1e","ItemId":"1","BarCode":"1","ItemName":"0#","UnitId":0,"Price":6.99,"DateToActivate":"2019-08-13 09:53:23.000","DateToDeactivate":"2020-08-15 23:59:59.000","CreatedDateTime":"2020-03-10 09:40:58.909","IsFuelItem":true,"IsMarkedAsDeletion":false,"TargetBusinessUnitId":"aaa3bf03-1da6-4f31-9f56-c86b487beeee"},"Qty":0.08,"Voided":false,"PosTrxId":"9aa8e955-7156-4c47-a51e-98414df730ec","NetAmount":0.01,"GrossAmount":0.01,"FuelItemSoldOnPumpId":3,"FuelItemSoldOnPumpNozzleId":2,"FuelItemOriginalGrossAmount":0.01,"FuelItemFdcTransactionSeqNo":"57170349","FuelItemFdcReleaseTokenAttribute":11}]
+         * Payments : []
+         * TransactionSource : 0
+         * TransactionType : 0
+         * ReceiptId : I0320165640
+         * ShiftId : 30
+         * TransactionInitTimeInPos : 2020-03-20 16:56:55.581
+         * TransactionArrivedAtServerTime : 2020-03-20 16:56:40.965
+         * NetAmount : 0.01
+         * GrossAmount : 0.01
+         * Discount : 0.0
+         * TransactionStatus : 1
+         * ServiceIdentityUserId : 3c3c4bf7-7f6b-4f90-b052-973cac8a4e6a
+         * BusinessUnitId : aaa3bf03-1da6-4f31-9f56-c86b487beeee
+         * SiteDeviceId : 503f3e99-fe56-4261-afce-38d28aeed3f1
+         * AccountId :
+         */
+
+        private String Id;
+        private int TransactionSource;
+        private int TransactionType;
+        private String ReceiptId;
+        private int ShiftId;
+        private String TransactionInitTimeInPos;
+        private String TransactionArrivedAtServerTime;
+        private BigDecimal NetAmount;
+        private BigDecimal GrossAmount;
+        private BigDecimal Discount;
+        private int TransactionStatus;
+        private String ServiceIdentityUserId;
+        private String BusinessUnitId;
+        private String SiteDeviceId;
+        private String AccountId;
+        private List<PosTrxItem> Items;
+        private List<?> Payments;
+
+        public String getId() {
+            if (Id == null) return "null";
+            return Id;
+        }
+
+        public void setId(String Id) {
+            this.Id = Id;
+        }
+
+        public int getTransactionSource() {
+            return TransactionSource;
+        }
+
+        public void setTransactionSource(int TransactionSource) {
+            this.TransactionSource = TransactionSource;
+        }
+
+        public int getTransactionType() {
+            return TransactionType;
+        }
+
+        public void setTransactionType(int TransactionType) {
+            this.TransactionType = TransactionType;
+        }
+
+        public String getReceiptId() {
+            return ReceiptId;
+        }
+
+        public void setReceiptId(String ReceiptId) {
+            this.ReceiptId = ReceiptId;
+        }
+
+        public int getShiftId() {
+            return ShiftId;
+        }
+
+        public void setShiftId(int ShiftId) {
+            this.ShiftId = ShiftId;
+        }
+
+        public String getTransactionInitTimeInPos() {
+            return TransactionInitTimeInPos;
+        }
+
+        public void setTransactionInitTimeInPos(String TransactionInitTimeInPos) {
+            this.TransactionInitTimeInPos = TransactionInitTimeInPos;
+        }
+
+        public String getTransactionArrivedAtServerTime() {
+            return TransactionArrivedAtServerTime;
+        }
+
+        public void setTransactionArrivedAtServerTime(String TransactionArrivedAtServerTime) {
+            this.TransactionArrivedAtServerTime = TransactionArrivedAtServerTime;
+        }
+
+        public BigDecimal getNetAmount() {
+            return NetAmount;
+        }
+
+        public void setNetAmount(BigDecimal NetAmount) {
+            this.NetAmount = NetAmount;
+        }
+
+        public BigDecimal getGrossAmount() {
+            return GrossAmount;
+        }
+
+        public void setGrossAmount(BigDecimal GrossAmount) {
+            this.GrossAmount = GrossAmount;
+        }
+
+        public BigDecimal getDiscount() {
+            return Discount;
+        }
+
+        public void setDiscount(BigDecimal Discount) {
+            this.Discount = Discount;
+        }
+
+        public int getTransactionStatus() {
+            return TransactionStatus;
+        }
+
+        public void setTransactionStatus(int TransactionStatus) {
+            this.TransactionStatus = TransactionStatus;
+        }
+
+        public String getServiceIdentityUserId() {
+            return ServiceIdentityUserId;
+        }
+
+        public void setServiceIdentityUserId(String ServiceIdentityUserId) {
+            this.ServiceIdentityUserId = ServiceIdentityUserId;
+        }
+
+        public String getBusinessUnitId() {
+            return BusinessUnitId;
+        }
+
+        public void setBusinessUnitId(String BusinessUnitId) {
+            this.BusinessUnitId = BusinessUnitId;
+        }
+
+        public String getSiteDeviceId() {
+            return SiteDeviceId;
+        }
+
+        public void setSiteDeviceId(String SiteDeviceId) {
+            this.SiteDeviceId = SiteDeviceId;
+        }
+
+        public String getAccountId() {
+            return AccountId;
+        }
+
+        public void setAccountId(String AccountId) {
+            this.AccountId = AccountId;
+        }
+
+        public List<PosTrxItem> getItems() {
+            return Items;
+        }
+
+        public void setItems(List<PosTrxItem> Items) {
+            this.Items = Items;
+        }
+
+        public List<?> getPayments() {
+            return Payments;
+        }
+
+        public void setPayments(List<?> Payments) {
+            this.Payments = Payments;
+        }
+
+//        public static class ItemsBean implements Serializable {
+//            /**
+//             * Id : 06a9680f-2465-43bc-99b3-242bdc66ee49
+//             * LineNum : 0
+//             * PosItemId : d2cb7584-c6eb-4cba-8bdb-d0eaebbe3c1e
+//             * Item : {"Id":"d2cb7584-c6eb-4cba-8bdb-d0eaebbe3c1e","ItemId":"1","BarCode":"1","ItemName":"0#","UnitId":0,"Price":6.99,"DateToActivate":"2019-08-13 09:53:23.000","DateToDeactivate":"2020-08-15 23:59:59.000","CreatedDateTime":"2020-03-10 09:40:58.909","IsFuelItem":true,"IsMarkedAsDeletion":false,"TargetBusinessUnitId":"aaa3bf03-1da6-4f31-9f56-c86b487beeee"}
+//             * Qty : 0.08
+//             * Voided : false
+//             * PosTrxId : 9aa8e955-7156-4c47-a51e-98414df730ec
+//             * NetAmount : 0.01
+//             * GrossAmount : 0.01
+//             * FuelItemSoldOnPumpId : 3
+//             * FuelItemSoldOnPumpNozzleId : 2
+//             * FuelItemOriginalGrossAmount : 0.01
+//             * FuelItemFdcTransactionSeqNo : 57170349
+//             * FuelItemFdcReleaseTokenAttribute : 11
+//             */
+//
+//            private String Id;
+//            private int LineNum;
+//            private String PosItemId;
+//            private PosItem Item;
+//            private double Qty;
+//            private boolean Voided;
+//            private String PosTrxId;
+//            private double NetAmount;
+//            private double GrossAmount;
+//            private int FuelItemSoldOnPumpId;
+//            private int FuelItemSoldOnPumpNozzleId;
+//            private double FuelItemOriginalGrossAmount;
+//            private String FuelItemFdcTransactionSeqNo;
+//            private int FuelItemFdcReleaseTokenAttribute;
+//
+//            public String getId() {
+//                return Id;
+//            }
+//
+//            public void setId(String Id) {
+//                this.Id = Id;
+//            }
+//
+//            public int getLineNum() {
+//                return LineNum;
+//            }
+//
+//            public void setLineNum(int LineNum) {
+//                this.LineNum = LineNum;
+//            }
+//
+//            public String getPosItemId() {
+//                return PosItemId;
+//            }
+//
+//            public void setPosItemId(String PosItemId) {
+//                this.PosItemId = PosItemId;
+//            }
+//
+//            public PosItem getItem() {
+//                return Item;
+//            }
+//
+//            public double getQty() {
+//                return Qty;
+//            }
+//
+//            public void setQty(double Qty) {
+//                this.Qty = Qty;
+//            }
+//
+//            public boolean isVoided() {
+//                return Voided;
+//            }
+//
+//            public void setVoided(boolean Voided) {
+//                this.Voided = Voided;
+//            }
+//
+//            public String getPosTrxId() {
+//                return PosTrxId;
+//            }
+//
+//            public void setPosTrxId(String PosTrxId) {
+//                this.PosTrxId = PosTrxId;
+//            }
+//
+//            public double getNetAmount() {
+//                return NetAmount;
+//            }
+//
+//            public void setNetAmount(double NetAmount) {
+//                this.NetAmount = NetAmount;
+//            }
+//
+//            public double getGrossAmount() {
+//                return GrossAmount;
+//            }
+//
+//            public void setGrossAmount(double GrossAmount) {
+//                this.GrossAmount = GrossAmount;
+//            }
+//
+//            public int getFuelItemSoldOnPumpId() {
+//                return FuelItemSoldOnPumpId;
+//            }
+//
+//            public void setFuelItemSoldOnPumpId(int FuelItemSoldOnPumpId) {
+//                this.FuelItemSoldOnPumpId = FuelItemSoldOnPumpId;
+//            }
+//
+//            public int getFuelItemSoldOnPumpNozzleId() {
+//                return FuelItemSoldOnPumpNozzleId;
+//            }
+//
+//            public void setFuelItemSoldOnPumpNozzleId(int FuelItemSoldOnPumpNozzleId) {
+//                this.FuelItemSoldOnPumpNozzleId = FuelItemSoldOnPumpNozzleId;
+//            }
+//
+//            public double getFuelItemOriginalGrossAmount() {
+//                return FuelItemOriginalGrossAmount;
+//            }
+//
+//            public void setFuelItemOriginalGrossAmount(double FuelItemOriginalGrossAmount) {
+//                this.FuelItemOriginalGrossAmount = FuelItemOriginalGrossAmount;
+//            }
+//
+//            public String getFuelItemFdcTransactionSeqNo() {
+//                return FuelItemFdcTransactionSeqNo;
+//            }
+//
+//            public void setFuelItemFdcTransactionSeqNo(String FuelItemFdcTransactionSeqNo) {
+//                this.FuelItemFdcTransactionSeqNo = FuelItemFdcTransactionSeqNo;
+//            }
+//
+//            public int getFuelItemFdcReleaseTokenAttribute() {
+//                return FuelItemFdcReleaseTokenAttribute;
+//            }
+//
+//            public void setFuelItemFdcReleaseTokenAttribute(int FuelItemFdcReleaseTokenAttribute) {
+//                this.FuelItemFdcReleaseTokenAttribute = FuelItemFdcReleaseTokenAttribute;
+//            }
+//
+//        }
+
+        public String getMyGrossAmount() {
+            if (GrossAmount == null) return "0.00";
+            // FIXME 是否需要保留两位小数点
+            return GrossAmount.toString();
+        }
+
+        public String getMyDiscount() {
+            if (Discount == null) return "0.00";
+            // FIXME 是否需要保留两位小数点
+            return Discount.toString();
+        }
+
+        public String getMyNetAmount() {
+            if (NetAmount == null) return "0.00";
+            // FIXME 是否需要保留两位小数点
+            return NetAmount.toString();
+        }
+    }
+
+    public static class MopBean {
+        /**
+         * Id : b936e87e-5bc2-4155-9529-8b282c8eea0c
+         * PaymentId : 3
+         * CreatedDateTime : 2019-07-10 15:34:44.492
+         * TargetBusinessUnitId : aaa3bf03-1da6-4f31-9f56-c86b487beeee
+         * Status : 0
+         */
+
+        private String Id;
+        private int PaymentId;
+        private String CreatedDateTime;
+        private String TargetBusinessUnitId;
+        private int Status;
+
+        public String getId() {
+            return Id;
+        }
+
+        public void setId(String Id) {
+            this.Id = Id;
+        }
+
+        public int getPaymentId() {
+            return PaymentId;
+        }
+
+        public void setPaymentId(int PaymentId) {
+            this.PaymentId = PaymentId;
+        }
+
+        public String getCreatedDateTime() {
+            return CreatedDateTime;
+        }
+
+        public void setCreatedDateTime(String CreatedDateTime) {
+            this.CreatedDateTime = CreatedDateTime;
+        }
+
+        public String getTargetBusinessUnitId() {
+            return TargetBusinessUnitId;
+        }
+
+        public void setTargetBusinessUnitId(String TargetBusinessUnitId) {
+            this.TargetBusinessUnitId = TargetBusinessUnitId;
+        }
+
+        public int getStatus() {
+            return Status;
+        }
+
+        public void setStatus(int Status) {
+            this.Status = Status;
+        }
+    }
+
+
+}

+ 223 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/printer/ComPrintManager.java

@@ -0,0 +1,223 @@
+package com.doverfuelingsolutions.issp.driver.printer;
+
+
+import android.text.TextUtils;
+
+import com.doverfuelingsolutions.issp.api.bean.PayResultHs;
+import com.doverfuelingsolutions.issp.data.GlobalData;
+import com.doverfuelingsolutions.issp.utils.log.DFSLog;
+import com.printsdk.cmd.PrintCmd;
+import com.doverfuelingsolutions.issp.driver.scan.ScanValueListener;
+import com.doverfuelingsolutions.issp.driver.serialPort.DataReceivedListener;
+import com.doverfuelingsolutions.issp.driver.serialPort.SerialControl;
+import com.doverfuelingsolutions.issp.driver.serialPort.SerialHelper;
+import com.wayne.www.waynelib.fdc.message.DeviceClass;
+import com.wayne.www.waynelib.webservice.entity.PosTrxItem;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class ComPrintManager implements PrintManager, DataReceivedListener {
+
+    SerialControl serialControl;
+    private int getStatus_flag; // 检查状态1或者状态2
+    private boolean isReceived = false;
+    private int status_1 = 0;
+    private int status_2 = 0;
+
+    private PrintStatusListen printStatusListen;
+
+    public ComPrintManager(String port, int rate, PrintStatusListen psl) throws Exception {
+        // serialControl = new SerialControl("/dev/ttyS3", 115200); // 串口号和波特率
+        serialControl = new SerialControl(port, rate, this, psl); // 串口号和波特率
+        serialControl.setbLoopData(PrintCmd.GetStatus4());
+        OpenComPort(serialControl); // 打开串口
+    }
+
+    /**
+     * 打印最后部分
+     */
+    private void printEnd() throws Exception {
+        if (serialControl == null) return;
+        serialControl.send(PrintCmd.PrintChargeRow());
+        serialControl.send(PrintCmd.PrintString("感谢您使用,请妥善保管交易凭条", 0));
+        serialControl.send(PrintCmd.PrintString("欢迎下次光临", 0));
+        serialControl.send(PrintCmd.PrintFeedline(3));
+        serialControl.send(PrintCmd.PrintFeedline(3));
+        serialControl.send(PrintCmd.PrintCutpaper(1)); // 半切纸
+    }
+
+    /**
+     * 支付成功后的小票打印
+     * TODO LZP备注:新的数据应该拿 payResult 的
+     */
+    public void printOrderOkBillHs(DeviceClass dc, PayResultHs.PosTrxBean ptb) throws Exception {
+        if (serialControl == null) return;
+        if (ptb == null || dc == null) return;
+
+        getStatus1();
+        serialControl.send(PrintCmd.SetAlignment(1));
+        serialControl.send(PrintCmd.PrintString("自助机加油支付小票", 0));
+        serialControl.send(PrintCmd.PrintFeedline(2));
+        serialControl.send(PrintCmd.SetAlignment(0));
+        if (!TextUtils.isEmpty(GlobalData.INSTANCE.getBusinessName().get()))
+            serialControl.send(PrintCmd.PrintString("加油站名称:" + GlobalData.INSTANCE.getBusinessName().get(), 0));
+        serialControl.send(PrintCmd.SetBold(1));
+        // confirm 确认 dc.getLogicNo 是否可以取到物理枪号
+        serialControl.send(PrintCmd.PrintString("油枪号:" + dc.getLogicNo() + "号枪", 0));
+        if (null != ptb.getGrossAmount())
+            serialControl.send(PrintCmd.PrintString("加油金额:" + ptb.getMyGrossAmount() + "元", 0));
+        serialControl.send(PrintCmd.SetBold(0));
+        if (null != ptb.getDiscount())
+            serialControl.send(PrintCmd.PrintString("优惠金额:" + ptb.getMyDiscount() + "元", 0));
+        if (null != ptb.getNetAmount())
+            serialControl.send(PrintCmd.PrintString("支付金额:" + ptb.getMyNetAmount() + "元", 0));
+        serialControl.send(PrintCmd.PrintString("加油升数:" + dc.getVolume() + "升", 0));
+        serialControl.send(PrintCmd.PrintString("油品名称:" + dc.getMyProductName(), 0));
+        if (ptb.getItems() != null && !ptb.getItems().isEmpty()) {
+            PosTrxItem ib = ptb.getItems().get(0);
+            if (null != ib.getPosItem()) {
+                serialControl.send(PrintCmd.PrintString("油品单价:" + ib.getPosItem().getPrice() + "/升", 0));
+            }
+            if (ib.isHaveTagId())
+                serialControl.send(PrintCmd.PrintString("员工卡号:" + ib.getCardNo(), 0));
+        }
+//        serialControl.send(PrintCmd.PrintString("加油时间:" + ib.getItem().getCreatedDateTime(), 0));
+        serialControl.send(PrintCmd.PrintFeedline(1));
+//        serialControl.send(PrintCmd.PrintString("支付方式:" + payResult.getMyPayType(), 0));
+//        serialControl.send(PrintCmd.PrintString("订单号:" + ptb.getId(), 0));
+//        serialControl.send(PrintCmd.PrintString("支付ID:" + o.getMyId(), 0));
+        serialControl.send(PrintCmd.PrintString("支付时间:" + ptb.getTransactionInitTimeInPos(), 0));
+        serialControl.send(PrintCmd.PrintFeedline(1));
+        serialControl.send(PrintCmd.SetAlignment(1));
+        serialControl.send(PrintCmd.PrintString("感谢您使用,请妥善保管交易凭条", 0));
+        serialControl.send(PrintCmd.PrintString("欢迎下次光临", 0));
+        serialControl.send(PrintCmd.PrintFeedline(3));
+        serialControl.send(PrintCmd.PrintFeedline(3));
+        serialControl.send(PrintCmd.PrintCutpaper(1)); // 半切纸
+        getStatus2Latter(2500);
+    }
+
+    @Override
+    public void getStatus2() throws Exception {
+        status_2 = 0;
+        getStatus_flag = PrintStatusContants.GETSTATUS_2;
+        isReceived = false;
+        if (null != PrintCmd.GetStatus2() && null != serialControl)
+            serialControl.send(PrintCmd.GetStatus2());// 获取状态2
+//        LogHelper.i(TAG, "getStatus2");
+    }
+
+    public void getStatus2Latter(int waittime) {
+        Executors.newSingleThreadScheduledExecutor().schedule(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    getStatus2();
+                    checkReceived();
+                } catch (Exception e) {
+//                    Utils.postException(e);
+                    e.printStackTrace();
+                }
+            }
+        }, waittime, TimeUnit.MILLISECONDS);
+    }
+
+    public void checkReceived() {
+        try {
+            Thread.sleep(500);
+            if (getStatus_flag == 2 && !isReceived) {
+                if (printStatusListen != null) {
+                    printStatusListen.receivePrintStatus(PrintStatusContants.ERROR_CONNECT_FAIL);
+                }
+            }
+        } catch (Exception e) {
+            DFSLog.Companion.e(e);
+        }
+    }
+
+    @Override
+    public void getStatus1() throws Exception {
+        status_1 = 0;
+        getStatus_flag = PrintStatusContants.GETSTATUS_1;
+        serialControl.send(PrintCmd.GetStatus1()); // 获取状态1
+    }
+
+    private void OpenComPort(SerialHelper ComPort) throws Exception {
+        try {
+            ComPort.open();
+        } catch (Exception e) {
+            DFSLog.Companion.e(e);
+            e.printStackTrace();
+//            LogHelper.i(TAG, "failed to open com port");
+            throw e;
+        }
+    }
+
+
+    @Override
+    public void onDataReceived(byte[] data, PrintStatusListen printStatusListen) {
+        if (data == null) return;
+        if (this.printStatusListen == null)
+            this.printStatusListen = printStatusListen;
+        switch (getStatus_flag) {
+            case PrintStatusContants.GETSTATUS_2:
+                isReceived = true;
+                if ((data[0] & 0x20) == 0x20) {
+                    status_2 = PrintStatusContants.ERROR_STATE2_PRINTINGPAPER_USEDUP; //打印纸用完,停止打
+                    if (null != printStatusListen) {
+                        printStatusListen.receivePrintStatus(status_2);
+                        return;
+                    }
+                }
+                if ((data[0] & 0x40) == 0x40) {
+                    status_2 = PrintStatusContants.ERROR_STATE2;//发生错误
+                    if (null != printStatusListen) {
+                        printStatusListen.receivePrintStatus(status_2);
+                        return;
+                    }
+                }
+                if (null != printStatusListen) {
+                    //先判断 status_1状态  再判断status_2状态
+                    if (status_1 != PrintStatusContants.DEFAULT) {
+                        printStatusListen.receivePrintStatus(status_1);
+                    } else if (status_2 != PrintStatusContants.DEFAULT) {
+                        printStatusListen.receivePrintStatus(status_2);
+                    } else {
+                        printStatusListen.receivePrintStatus(PrintStatusContants.DEFAULT);
+                    }
+                }
+                break;
+            case PrintStatusContants.GETSTATUS_1:
+                if ((data[0] & 0x8) == 0x8) {
+                    status_1 = PrintStatusContants.ERROR_STATE1_OFFLINE; //脱机
+                    if (null != printStatusListen)
+                        printStatusListen.receivePrintStatus(status_1);
+                }
+                break;
+        }
+
+    }
+
+    /**
+     * @desc 摧毁界面后
+     * @info Created by LzPeng on 2020/3/11 9:52
+     */
+    public void destroy() {
+        if (null != printStatusListen) printStatusListen = null;
+        if (null != serialControl) {
+            serialControl.close();
+            serialControl = null;
+        }
+    }
+
+
+    @Override
+    public void onDataReceived(byte[] data) {
+
+    }
+
+    @Override
+    public void onDataReceived(byte[] data, ScanValueListener scanValueListener) {
+
+    }
+}

+ 10 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/printer/PrintManager.java

@@ -0,0 +1,10 @@
+package com.doverfuelingsolutions.issp.driver.printer;
+
+public interface PrintManager {
+
+    void getStatus2()throws Exception;
+
+    void getStatus1()throws Exception;
+
+
+}

+ 22 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/printer/PrintStatusContants.java

@@ -0,0 +1,22 @@
+package com.doverfuelingsolutions.issp.driver.printer;
+
+/**
+ * @desc xxx
+ * @info Created by Steven on 2020/1/6 17:34.
+ */
+public class PrintStatusContants {
+    public static final int DEFAULT = 0; //默认状态 正常状态
+    public static final int ERROR_CONNECT_FAIL = -1; //与打印机通讯失败
+
+    public static final int GETSTATUS_1 = 1; //检查打印机状态1的标记
+    public static final int ERROR_STATE1_OFFLINE = -13; //脱机
+
+    public static final int GETSTATUS_2 = 2;//检查打印机状态2的标记
+    public static final int ERROR_STATE2_PRINTINGPAPER_USEDUP = -25; //打印纸用完
+    public static final int ERROR_STATE2 = -26; //发送错误
+
+    public static final int GETSTATUS_4 = 4;//检查打印机状态4的标记
+    public static final int ERROR_STATE4_PRINTINGPAPER_WANETOTHECLOSE = -43; //纸将尽检测器检测到纸张接近末端
+    public static final int ERROR_STATE4_PRINTINGPAPER_USEDUP = -46;//纸尽传感器检测到卷纸末端
+
+}

+ 9 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/printer/PrintStatusListen.java

@@ -0,0 +1,9 @@
+package com.doverfuelingsolutions.issp.driver.printer;
+
+/**
+ * @desc xxx
+ * @info Created by Steven on 2020/1/5 17:03.
+ */
+public interface PrintStatusListen {
+    void receivePrintStatus(int value);
+}

+ 131 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/scan/ComScanKeyManager.java

@@ -0,0 +1,131 @@
+package com.doverfuelingsolutions.issp.driver.scan;
+
+
+import com.doverfuelingsolutions.issp.driver.printer.PrintStatusListen;
+import com.doverfuelingsolutions.issp.driver.serialPort.DataReceivedListener;
+import com.doverfuelingsolutions.issp.driver.serialPort.SerialControl;
+import com.doverfuelingsolutions.issp.driver.serialPort.SerialHelper;
+import com.doverfuelingsolutions.issp.utils.ValidateUtil;
+import com.doverfuelingsolutions.issp.utils.log.DFSLog;
+
+public class ComScanKeyManager implements ScanManager, DataReceivedListener {
+    private final static String TAG = "ComScanKeyManager";
+    SerialControl serialControl;//串口
+    ScanValueListener scanValueListener;
+
+    public ComScanKeyManager(String port, int rate, ScanValueListener scanValueListener) throws Exception {
+        serialControl = new SerialControl(port, rate, this, scanValueListener); //串口号和波特率
+//         serialControl.setbLoopData(PrintCmd.GetStatus4());
+        OpenComPort(serialControl);     //打开串口
+    }
+
+
+    @Override
+    public void onDataReceived(byte[] data, ScanValueListener scanValueListener) {
+        if (data == null || data.length <= 2) return;
+//        try {
+//            String s = new String(data, 0, data.length - 2, StandardCharsets.ISO_8859_1);//不知这里为何要减2,暂时先这样,后面研究下
+//            if (s.length() != 18 || !RegexUtils.isNumeric(s)) {
+//                BaseLogUtils.i(MyLogTag.SCAN_COM, "other");
+//
+//                return;//纯数字且18位才可能是收款码
+//            }
+//            if (null != scanValueListener) {
+//                this.scanValueListener = scanValueListener;
+//                stop();
+//                BaseLogUtils.i(MyLogTag.SCAN_COM, Thread.currentThread().toString());
+//                scanValueListener.onScanValue(s);
+//            } else {
+//                BaseLogUtils.i(MyLogTag.SCAN_COM, "scanValueListener is null");
+//            }
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//            BaseLogUtils.i(MyLogTag.SCAN_COM, e.toString());
+//        }
+        try {
+            boolean isGo = data[data.length - 1] == 10 && data[data.length - 2] == 13;//旧的扫描器判断
+            String code = null;
+            if (isGo) {
+                code = new String(data, 0, data.length - 2);//旧的扫描器
+            }
+            if (data[data.length - 1] == 13) {
+                code = new String(data, 0, data.length - 1);//新的扫描器
+            }
+            if (code == null) return;
+            if (null != scanValueListener) {
+                this.scanValueListener = scanValueListener;
+                stop();
+
+                if (code.length() != 18 || !ValidateUtil.Companion.isPositiveInt(code)) {
+                    scanValueListener.onScanValue(null);//非正确付款码时
+                    return;//纯数字且18位才可能是收款码
+                }
+                scanValueListener.onScanValue(code);
+            } else {
+                DFSLog.Companion.e("scanValueListener is null");
+            }
+        } catch (Exception e) {
+            DFSLog.Companion.e(e);
+        }
+
+
+    }
+
+
+    private void OpenComPort(SerialHelper ComPort) throws Exception {
+        try {
+            ComPort.open();
+        } catch (Exception e) {
+            DFSLog.Companion.e(e);
+            throw e;
+        }
+    }
+
+
+    public void start() {
+        if (serialControl == null) {
+            DFSLog.Companion.e("ComScanKeyManager.start", "serialControl is null");
+            return;
+        }
+        try {
+            serialControl.sendHex("07C60408008800FE9F");
+            serialControl.sendHex("04E40400FF14");
+        } catch (Exception e) {
+            DFSLog.Companion.e(e);
+        }
+    }
+
+    public void stop() {
+        if (serialControl == null) {
+            DFSLog.Companion.e("ComScanKeyManager.start", "serialControl is null");
+            return;
+        }
+        try {
+            serialControl.sendHex("04E50400FF13");
+        } catch (Exception e) {
+            DFSLog.Companion.e(e);
+        }
+    }
+
+    /**
+     * 摧毁界面后
+     */
+    public void destroy() {
+        if (null != scanValueListener) scanValueListener = null;
+        if (null != serialControl) {
+            serialControl.close();
+            serialControl = null;
+        }
+    }
+
+    @Override
+    public void onDataReceived(byte[] data, PrintStatusListen printStatusListen) {
+
+    }
+
+    @Override
+    public void onDataReceived(byte[] data) {
+
+    }
+
+}

+ 164 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/scan/NormalScanKeyManager.java

@@ -0,0 +1,164 @@
+package com.doverfuelingsolutions.issp.driver.scan;
+
+import android.content.Context;
+import android.view.KeyEvent;
+
+import com.doverfuelingsolutions.issp.driver.printer.PrintStatusListen;
+import com.doverfuelingsolutions.issp.driver.serialPort.DataReceivedListener;
+
+
+public class NormalScanKeyManager implements ScanManager, DataReceivedListener {
+    private final static String TAG = "NormalScanKeyManager";
+    private StringBuilder mResult;
+    private ScanValueListener mListener;
+    private boolean mCaps;
+    protected Context context;
+
+    public NormalScanKeyManager(Context context) {
+        this.mResult = new StringBuilder();
+        this.context = context;
+    }
+
+//    @Override
+//    public void setListener(ScanValueListener listener) {
+//        mListener = listener;
+//    }
+//
+//    @Override
+//    public ScanValueListener getListener() {
+//        return mListener;
+//    }
+
+    @Override
+    public void onDataReceived(byte[] data, ScanValueListener scanValueListener) {
+    }
+
+    @Override
+    public void onDataReceived(byte[] data, PrintStatusListen printStatusListen) {
+
+    }
+
+    @Override
+    public void onDataReceived(byte[] data) {
+
+    }
+
+
+    /**
+     * 扫码设备事件解析
+     */
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (mListener == null) {
+            return false;
+        }
+        int keyCode = event.getKeyCode();
+        checkLetterStatus(event);
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            char aChar = getInputCode(mCaps, event.getKeyCode());
+            if (aChar != 0) {
+                mResult.append(aChar);
+            }
+            if (keyCode == KeyEvent.KEYCODE_ENTER) {
+                if (mListener != null) {
+                    mListener.onScanValue(mResult.toString());
+                }
+                mResult.delete(0, mResult.length());
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 判断大小写
+     */
+    private void checkLetterStatus(KeyEvent event) {
+        int keyCode = event.getKeyCode();
+        if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT || keyCode == KeyEvent.KEYCODE_SHIFT_LEFT) {
+            mCaps = event.getAction() == KeyEvent.ACTION_DOWN;
+        }
+    }
+
+    /**
+     * 将keyCode转为char
+     *
+     * @param caps    是不是大写
+     * @param keyCode 按键
+     * @return 按键对应的char
+     */
+    private char getInputCode(boolean caps, int keyCode) {
+        if (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) {
+            return (char) ((caps ? 'A' : 'a') + keyCode - KeyEvent.KEYCODE_A);
+        } else {
+            return keyValue(caps, keyCode);
+        }
+    }
+
+    /**
+     * 按键对应的char
+     */
+    private char keyValue(boolean caps, int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_0:
+                return caps ? ')' : '0';
+            case KeyEvent.KEYCODE_1:
+                return caps ? '!' : '1';
+            case KeyEvent.KEYCODE_2:
+                return caps ? '@' : '2';
+            case KeyEvent.KEYCODE_3:
+                return caps ? '#' : '3';
+            case KeyEvent.KEYCODE_4:
+                return caps ? '$' : '4';
+            case KeyEvent.KEYCODE_5:
+                return caps ? '%' : '5';
+            case KeyEvent.KEYCODE_6:
+                return caps ? '^' : '6';
+            case KeyEvent.KEYCODE_7:
+                return caps ? '&' : '7';
+            case KeyEvent.KEYCODE_8:
+                return caps ? '*' : '8';
+            case KeyEvent.KEYCODE_9:
+                return caps ? '(' : '9';
+            case KeyEvent.KEYCODE_NUMPAD_SUBTRACT:
+                return '-';
+            case KeyEvent.KEYCODE_MINUS:
+                return '_';
+            case KeyEvent.KEYCODE_EQUALS:
+                return '=';
+            case KeyEvent.KEYCODE_NUMPAD_ADD:
+                return '+';
+            case KeyEvent.KEYCODE_GRAVE:
+                return caps ? '~' : '`';
+            case KeyEvent.KEYCODE_BACKSLASH:
+                return caps ? '|' : '\\';
+            case KeyEvent.KEYCODE_LEFT_BRACKET:
+                return caps ? '{' : '[';
+            case KeyEvent.KEYCODE_RIGHT_BRACKET:
+                return caps ? '}' : ']';
+            case KeyEvent.KEYCODE_SEMICOLON:
+                return caps ? ':' : ';';
+            case KeyEvent.KEYCODE_APOSTROPHE:
+                return caps ? '"' : '\'';
+            case KeyEvent.KEYCODE_COMMA:
+                return caps ? '<' : ',';
+            case KeyEvent.KEYCODE_PERIOD:
+                return caps ? '>' : '.';
+            case KeyEvent.KEYCODE_SLASH:
+                return caps ? '?' : '/';
+            default:
+                return 0;
+        }
+    }
+
+    @Override
+    public void start() throws Exception {
+    }
+
+    @Override
+    public void stop() throws Exception {
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}

+ 14 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/scan/ScanManager.java

@@ -0,0 +1,14 @@
+package com.doverfuelingsolutions.issp.driver.scan;
+
+public interface ScanManager {
+    void start() throws Exception;
+
+    void stop() throws Exception;
+
+    void destroy();
+
+//    void setListener(ScanValueListener listener);
+
+
+//    ScanValueListener getListener();
+}

+ 5 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/scan/ScanValueListener.java

@@ -0,0 +1,5 @@
+package com.doverfuelingsolutions.issp.driver.scan;
+
+public interface ScanValueListener {
+    void onScanValue(String value);
+}

+ 22 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/serialPort/ComBean.java

@@ -0,0 +1,22 @@
+package com.doverfuelingsolutions.issp.driver.serialPort;
+
+import java.text.SimpleDateFormat;
+
+/**
+ *
+ */
+public class ComBean {
+    public byte[] bRec = null;
+    public String sRecTime = "";
+    public String sComPort = "";
+
+    public ComBean(String sPort, byte[] buffer, int size) {
+        sComPort = sPort;
+        bRec = new byte[size];
+        for (int i = 0; i < size; i++) {
+            bRec[i] = buffer[i];
+        }
+        SimpleDateFormat sDateFormat = new SimpleDateFormat("hh:mm:ss");
+        sRecTime = sDateFormat.format(new java.util.Date());
+    }
+}

+ 12 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/serialPort/DataReceivedListener.java

@@ -0,0 +1,12 @@
+package com.doverfuelingsolutions.issp.driver.serialPort;
+
+import com.doverfuelingsolutions.issp.driver.printer.PrintStatusListen;
+import com.doverfuelingsolutions.issp.driver.scan.ScanValueListener;
+
+public interface DataReceivedListener {
+    void onDataReceived(byte[] data, ScanValueListener scanValueListener);
+
+    void onDataReceived(byte[] data, PrintStatusListen printStatusListen);
+
+    void onDataReceived(byte[] data);
+}

+ 38 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/serialPort/SerialControl.java

@@ -0,0 +1,38 @@
+package com.doverfuelingsolutions.issp.driver.serialPort;
+
+import com.doverfuelingsolutions.issp.driver.printer.PrintStatusListen;
+import com.doverfuelingsolutions.issp.driver.scan.ScanValueListener;
+
+public class SerialControl extends SerialHelper {
+    private final static String TAG = "SerialControl";
+    DataReceivedListener listener;
+    ScanValueListener scanValueListener;//扫描器的监听
+    PrintStatusListen printStatusListen;//小票的监听
+
+    public SerialControl(String sPort, int iBaudRate, DataReceivedListener listener, ScanValueListener scanValueListener) {
+        super(sPort, iBaudRate);
+        this.listener = listener;
+        this.scanValueListener = scanValueListener;
+    }
+
+    public SerialControl(String sPort, int iBaudRate, DataReceivedListener listener, PrintStatusListen printStatusListen) {
+        super(sPort, iBaudRate);
+        this.listener = listener;
+        this.printStatusListen = printStatusListen;
+    }
+
+    @Override
+    protected void onDataReceived(final ComBean ComRecData) {
+        if (null != listener) {
+            if (null != scanValueListener) {
+                listener.onDataReceived(ComRecData.bRec, scanValueListener);
+                return;
+            }
+            if (null != printStatusListen) {
+                listener.onDataReceived(ComRecData.bRec, printStatusListen);
+                return;
+            }
+            listener.onDataReceived(ComRecData.bRec);
+        }
+    }
+}

+ 266 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/serialPort/SerialHelper.java

@@ -0,0 +1,266 @@
+package com.doverfuelingsolutions.issp.driver.serialPort;
+
+
+
+import com.doverfuelingsolutions.issp.utils.log.DFSLog;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidParameterException;
+
+import android_serialport_api.SerialPort;
+
+/**
+ * 串口辅助工具类
+ */
+public abstract class SerialHelper {
+    private SerialPort mSerialPort;
+    private OutputStream mOutputStream;
+    private InputStream mInputStream;
+    private ReadThread mReadThread;
+    private SendThread mSendThread;
+    private String sPort = "/dev/ttyS0";
+    private int iBaudRate = 115200;
+    private boolean _isOpen = false;
+    private byte[] _bLoopData = new byte[]{0x30};
+    private int iDelay = 500;
+
+    //----------------------------------------------------
+    public SerialHelper(String sPort, int iBaudRate) {
+        this.sPort = sPort;
+        this.iBaudRate = iBaudRate;
+    }
+
+    //----------------------------------------------------
+    public void open() throws SecurityException, IOException, InvalidParameterException {
+        mSerialPort = new SerialPort(new File(sPort), iBaudRate, 0);
+        mOutputStream = mSerialPort.getOutputStream();
+        mInputStream = mSerialPort.getInputStream();
+        mReadThread = new ReadThread();
+        mReadThread.start();
+        mSendThread = new SendThread();
+        mSendThread.setSuspendFlag();
+        mSendThread.start();
+        _isOpen = true;
+    }
+
+    //----------------------------------------------------
+    public void close() {
+        if (mReadThread != null)
+            mReadThread.interrupt();
+        if (mSendThread != null)
+            mSendThread.interrupt();
+        if (mSerialPort != null) {
+            mSerialPort.close();
+            mSerialPort = null;
+        }
+        _isOpen = false;
+    }
+
+    //----------------------------------------------------
+    public int send(byte[] bOutArray) throws Exception {
+        int iResult = 0;
+        try {
+            if (mOutputStream == null) {
+                throw new Exception("mOutputStream is null");
+            }
+            if (!_isOpen) {
+                throw new Exception("串口未打开");
+            }
+            mOutputStream.write(bOutArray);
+            iResult = bOutArray.length;
+        } catch (IOException e) {
+            DFSLog.Companion.e(e);
+            throw e;
+        }
+        return iResult;
+    }
+
+    //----------------------------------------------------
+    public void sendTxt(String sTxt) throws Exception {
+        byte[] bOutArray = sTxt.getBytes();
+        send(bOutArray);
+    }
+
+    static public int isOdd(int num) {
+        return num & 0x1;
+    }
+
+    static public byte HexToByte(String inHex)// Hex字符串转byte
+    {
+        return (byte) Integer.parseInt(inHex, 16);
+    }
+
+    public void sendHex(String inHex) throws Exception {
+        int hexlen = inHex.length();
+        byte[] result;
+        if (isOdd(hexlen) == 1) {// 奇数
+            hexlen++;
+            result = new byte[(hexlen / 2)];
+            inHex = "0" + inHex;
+        } else {// 偶数
+            result = new byte[(hexlen / 2)];
+        }
+        int j = 0;
+        for (int i = 0; i < hexlen; i += 2) {
+            result[j] = HexToByte(inHex.substring(i, i + 2));
+            j++;
+        }
+        send(result);
+    }
+
+    //----------------------------------------------------
+    private class ReadThread extends Thread {
+        @Override
+        public void run() {
+            super.run();
+            while (!isInterrupted()) {
+                try {
+                    if (mInputStream == null) return;
+                    byte[] buffer = new byte[512];
+                    int size = mInputStream.read(buffer);
+                    if (size > 0) {
+                        ComBean ComRecData = new ComBean(sPort, buffer, size);
+                        onDataReceived(ComRecData);
+                    }
+                    try {
+                        Thread.sleep(50);//延时50ms
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+//                        Utils.postException(e);
+                    }
+                } catch (Throwable e) {
+                    e.printStackTrace();
+//                    Utils.postException(e);
+                    return;
+                }
+            }
+        }
+    }
+
+    //----------------------------------------------------
+    private class SendThread extends Thread {
+        public boolean suspendFlag = true;// 控制线程的执行
+
+        @Override
+        public void run() {
+            super.run();
+            while (!isInterrupted()) {
+                synchronized (this) {
+                    while (suspendFlag) {
+                        try {
+                            wait();
+                        } catch (InterruptedException e) {
+//                            Utils.postException(e);
+                            e.printStackTrace();
+                        }
+                    }
+                }
+                try {
+                    send(getbLoopData());
+                } catch (Exception e) {
+                    DFSLog.Companion.e(e);
+                    e.printStackTrace();
+                }
+                try {
+                    Thread.sleep(iDelay);
+                } catch (InterruptedException e) {
+                    DFSLog.Companion.e(e);
+                }
+            }
+        }
+
+        //线程暂停
+        public void setSuspendFlag() {
+            this.suspendFlag = true;
+        }
+
+        //唤醒线程
+        public synchronized void setResume() {
+            this.suspendFlag = false;
+            notify();
+        }
+    }
+
+    //----------------------------------------------------
+    public int getBaudRate() {
+        return iBaudRate;
+    }
+
+    public boolean setBaudRate(int iBaud) {
+        if (_isOpen) {
+            return false;
+        } else {
+            iBaudRate = iBaud;
+            return true;
+        }
+    }
+
+    public boolean setBaudRate(String sBaud) {
+        int iBaud = Integer.parseInt(sBaud);
+        return setBaudRate(iBaud);
+    }
+
+    //----------------------------------------------------
+    public String getPort() {
+        return sPort;
+    }
+
+    public boolean setPort(String sPort) {
+        if (_isOpen) {
+            return false;
+        } else {
+            this.sPort = sPort;
+            return true;
+        }
+    }
+
+    //----------------------------------------------------
+    public boolean isOpen() {
+        return _isOpen;
+    }
+
+    //----------------------------------------------------
+    public byte[] getbLoopData() {
+        return _bLoopData;
+    }
+
+    //----------------------------------------------------
+    public void setbLoopData(byte[] bLoopData) {
+        this._bLoopData = bLoopData;
+    }
+
+    //----------------------------------------------------
+    public void setTxtLoopData(String sTxt) {
+        this._bLoopData = sTxt.getBytes();
+    }
+
+    //----------------------------------------------------
+    public int getiDelay() {
+        return iDelay;
+    }
+
+    //----------------------------------------------------
+    public void setiDelay(int iDelay) {
+        this.iDelay = iDelay;
+    }
+
+    //----------------------------------------------------
+    public void startSend() {
+        if (mSendThread != null) {
+            mSendThread.setResume();
+        }
+    }
+
+    //----------------------------------------------------
+    public void stopSend() {
+        if (mSendThread != null) {
+            mSendThread.setSuspendFlag();
+        }
+    }
+
+    //----------------------------------------------------
+    protected abstract void onDataReceived(ComBean ComRecData);
+}

+ 211 - 0
app/src/main/java/com/doverfuelingsolutions/issp/driver/usb/UsbTools.java

@@ -0,0 +1,211 @@
+package com.doverfuelingsolutions.issp.driver.usb;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.widget.Toast;
+
+import com.doverfuelingsolutions.issp.utils.log.DFSLog;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class UsbTools {
+    private static UsbTools INSTANCE;
+    private final static String TAG = "UsbTools";
+    private Context context;
+    private UsbManager usgManager;
+    private UsbReceiver usbReceiver;
+    private Set<UsbDevice> usbDeviceSet = new HashSet<UsbDevice>();
+
+    private UsbDevice openedDevice;
+    private UsbInterface openedUsbInterface;
+    private UsbDeviceConnection openedUsbConnection;
+    private UsbEndpoint usbReadEndpoint;
+    private UsbEndpoint usbWriteEndpoint;
+    private Integer vendorId;
+    private Set<Integer> productIds = new HashSet<Integer>();
+    private static final String ACTION_USB_PERMISSION = "com.usb.sample.USB_PERMISSION";
+
+    public static UsbTools getInstance(Context context) {
+        if (INSTANCE == null) {
+            INSTANCE = new UsbTools(context);
+        }
+        return INSTANCE;
+    }
+
+    private UsbTools(Context context) {
+        this.context = context;
+        this.usgManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+        this.usbReceiver = new UsbReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_USB_PERMISSION);
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
+        context.registerReceiver(this.usbReceiver, filter);
+    }
+
+    public void queryUsbDevice(int vendorId, int... productId) {
+        this.vendorId = vendorId;
+        for (int pid : productId) {
+            this.productIds.add(pid);
+        }
+        for (UsbDevice device : usgManager.getDeviceList().values()) {
+            if (device.getVendorId() == vendorId && this.productIds.contains(device.getProductId())) {
+                if (usgManager.hasPermission(device)) {
+                    usbDeviceSet.add(device);
+                } else {
+                    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
+                    usgManager.requestPermission(device, pendingIntent);
+                }
+            }
+        }
+    }
+
+    public Set<UsbDevice> getDeviceList() {
+        return usbDeviceSet;
+    }
+
+    public boolean openUsbDevice(UsbDevice device) {
+        if (openedDevice != null && openedDevice != device) {
+            closeOpenDevice();
+        }
+        int interfaceCount = device.getInterfaceCount();
+        DFSLog.Companion.i(TAG, " openUsbDevice getInterfaceCount():" + interfaceCount);
+        if (interfaceCount == 0) {
+            return false;
+        } else {
+            if (interfaceCount > 0) {
+                openedUsbInterface = device.getInterface(0);
+                if (openedUsbInterface == null) {
+                    closeOpenDevice();
+                    return false;
+                }
+                if (openedUsbInterface.getEndpointCount() > 0) {
+                    usbWriteEndpoint = openedUsbInterface.getEndpoint(0);
+                    if (openedUsbInterface.getEndpointCount() > 1) {
+                        usbReadEndpoint = openedUsbInterface.getEndpoint(1);
+                    }
+                } else {
+                    closeOpenDevice();
+                    return false;
+                }
+                this.openedUsbConnection = this.usgManager.openDevice(device);
+                if (this.openedUsbConnection == null) {
+                    closeOpenDevice();
+                    return false;
+                } else if (this.openedUsbConnection.claimInterface(openedUsbInterface, true)) {
+                    openedDevice = device;
+                    return true;
+                } else {
+                    closeOpenDevice();
+                    return false;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean closeOpenDevice() {
+        try {
+            if (this.openedUsbConnection != null && this.openedUsbInterface != null) {
+                this.openedUsbConnection.releaseInterface(this.openedUsbInterface);
+            }
+            if (openedUsbConnection != null) {
+                this.openedUsbConnection.close();
+            }
+            this.openedUsbInterface = null;
+            this.openedUsbConnection = null;
+            openedDevice = null;
+            usbWriteEndpoint = null;
+            usbReadEndpoint = null;
+        } catch (Exception var2) {
+            DFSLog.Companion.e(var2);
+        }
+        return true;
+    }
+
+    public boolean isConnected() {
+        return openedDevice != null && usbWriteEndpoint != null && usbReadEndpoint != null;
+    }
+
+    public int write(byte[] var1) {
+        return this.write(var1, var1.length);
+    }
+
+    public int write(byte[] var1, int var2) {
+        if (openedDevice == null || usbWriteEndpoint == null) {
+            return -1;
+        }
+        int var6 = 0;
+        int var4;
+        for (byte[] var5 = new byte[4096]; var6 < var2; var6 += var4) {
+            var4 = 4096;
+            if (var6 + 4096 > var2) {
+                var4 = var2 - var6;
+            }
+            System.arraycopy(var1, var6, var5, 0, var4);
+            var4 = this.openedUsbConnection.bulkTransfer(usbWriteEndpoint, var5, var4, 3000);
+            DFSLog.Companion.i(TAG, "write length:" + String.valueOf(var4));
+            if (var4 < 0) {
+                return -1;
+            }
+        }
+        return var6;
+    }
+
+    public int read(byte[] var1) {
+        if (openedDevice == null || usbWriteEndpoint == null) {
+            return -1;
+        }
+        int var4 = this.openedUsbConnection.bulkTransfer(usbReadEndpoint, var1, var1.length, 100);
+        DFSLog.Companion.i(TAG, "read length:" + var4);
+        return var4;
+    }
+
+    private void onUsbReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
+            UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            if (vendorId == null || (device.getVendorId() == vendorId && this.productIds.contains(device.getProductId()))) {
+                if (usgManager.hasPermission(device)) {
+                    usbDeviceSet.add(device);
+                } else {
+                    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
+                    usgManager.requestPermission(device, pendingIntent);
+                }
+            }
+        } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
+            UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+            usbDeviceSet.remove(device);
+            if (openedDevice == device) {
+                closeOpenDevice();
+            }
+        } else if (ACTION_USB_PERMISSION.equals(action)) {
+            synchronized (this) {
+                UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+                if (vendorId == null || (device.getVendorId() == vendorId && this.productIds.contains(device.getProductId()))) {
+                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+                        usbDeviceSet.add(device);
+                    } else {
+                        Toast.makeText(context, "permission denied for device", Toast.LENGTH_SHORT).show();
+                    }
+                }
+            }
+        }
+    }
+
+    private class UsbReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            INSTANCE.onUsbReceive(context, intent);
+        }
+    }
+}

+ 1 - 1
app/src/main/java/com/doverfuelingsolutions/issp/utils/ValidateUtil.kt

@@ -9,7 +9,7 @@ class ValidateUtil {
         private val regexUrl: Regex by lazyOf(Regex("^(https?|ftp|file)://([\\da-z.-]+)\\.([a-z.]{2,6})([/\\w .-]*)*/?\$"))
 
         fun isIP(ip: String): Boolean = regexIP.matches(ip)
-        private fun isPositiveInt(num: String): Boolean = regexPositiveInt.matches(num)
+        fun isPositiveInt(num: String): Boolean = regexPositiveInt.matches(num)
         fun isUrl(url: String): Boolean = regexUrl.matches(url)
         fun isPort(port: String): Boolean = isPositiveInt(port) && port.toInt() < 65535
     }

+ 2 - 0
app/src/main/java/com/doverfuelingsolutions/issp/view/MainActivity.kt

@@ -56,6 +56,8 @@ class MainActivity : AppCompatActivity(),
         binding.mainViewModel = mainViewModel
         initView()
         initFusion()
+
+
     }
 
     override fun onResume() {

+ 1 - 0
libserial/.gitignore

@@ -0,0 +1 @@
+/build

+ 44 - 0
libserial/build.gradle

@@ -0,0 +1,44 @@
+plugins {
+    id 'com.android.library'
+    id 'kotlin-android'
+}
+
+android {
+    compileSdkVersion 30
+    buildToolsVersion "30.0.2"
+
+    defaultConfig {
+        minSdkVersion 19
+        targetSdkVersion 30
+        versionCode 1
+        versionName "1.0"
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        consumerProguardFiles "consumer-rules.pro"
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+    kotlinOptions {
+        jvmTarget = '1.8'
+    }
+}
+
+dependencies {
+    api fileTree(include: ['*.jar'], dir: 'libs')
+    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+    implementation 'androidx.core:core-ktx:1.3.2'
+    implementation 'androidx.appcompat:appcompat:1.2.0'
+    implementation 'com.google.android.material:material:1.2.1'
+    testImplementation 'junit:junit:4.+'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+}

+ 0 - 0
libserial/consumer-rules.pro


BIN
libserial/libs/PrintUtils1114.jar


BIN
libserial/libs/armeabi-v7a/libserial_port.so


BIN
libserial/libs/armeabi/libserial_port.so


BIN
libserial/libs/core-3.2.1.jar


BIN
libserial/libs/printsdk1015-v2.2.jar


BIN
libserial/libs/x86/libserial_port.so


+ 21 - 0
libserial/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 24 - 0
libserial/src/androidTest/java/com/doverfuelingsolutions/libserial/ExampleInstrumentedTest.kt

@@ -0,0 +1,24 @@
+package com.doverfuelingsolutions.libserial
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+    @Test
+    fun useAppContext() {
+        // Context of the app under test.
+        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+        assertEquals("com.doverfuelingsolutions.libserial.test", appContext.packageName)
+    }
+}

+ 5 - 0
libserial/src/main/AndroidManifest.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.doverfuelingsolutions.libserial">
+
+</manifest>

+ 85 - 0
libserial/src/main/java/android_serialport_api/SerialPort.java

@@ -0,0 +1,85 @@
+/*
+ * Copyright 2009 Cedric Priscal
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android_serialport_api;
+
+import android.util.Log;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class SerialPort {
+
+    private static final String TAG = "SerialPort";
+
+    /*
+     * Do not remove or rename the field mFd: it is used by native method close();
+     */
+    private FileDescriptor mFd;
+    private FileInputStream mFileInputStream;
+    private FileOutputStream mFileOutputStream;
+
+    public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {
+
+        /* Check access permission */
+        if (!device.canRead() || !device.canWrite()) {
+            try {
+                /* Missing read/write permission, trying to chmod the file */
+                Process su;
+                su = Runtime.getRuntime().exec("/system/bin/su");
+                String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
+                        + "exit\n";
+                su.getOutputStream().write(cmd.getBytes());
+                if ((su.waitFor() != 0) || !device.canRead()
+                        || !device.canWrite()) {
+                    throw new SecurityException();
+                }
+            } catch (Exception e) {
+                Log.e("robin", Log.getStackTraceString(e));
+            }
+        }
+
+        mFd = open(device.getAbsolutePath(), baudrate, flags);
+        if (mFd == null) {
+            Log.e(TAG, "native open returns null");
+            throw new IOException();
+        }
+        mFileInputStream = new FileInputStream(mFd);
+        mFileOutputStream = new FileOutputStream(mFd);
+    }
+
+    // Getters and setters
+    public InputStream getInputStream() {
+        return mFileInputStream;
+    }
+
+    public OutputStream getOutputStream() {
+        return mFileOutputStream;
+    }
+
+    // JNI
+    private native static FileDescriptor open(String path, int baudrate, int flags);
+
+    public native void close();
+
+    static {
+        System.loadLibrary("serial_port");
+    }
+}

+ 17 - 0
libserial/src/test/java/com/doverfuelingsolutions/libserial/ExampleUnitTest.kt

@@ -0,0 +1,17 @@
+package com.doverfuelingsolutions.libserial
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+    @Test
+    fun addition_isCorrect() {
+        assertEquals(4, 2 + 2)
+    }
+}

+ 1 - 0
settings.gradle

@@ -1,2 +1,3 @@
+include ':libserial'
 include ':app', ':waynelib_'
 rootProject.name = "issp"