左晓为主开发手持机充值管理机
8个文件已添加
1 文件已重命名
2个文件已删除
36个文件已修改
2146 ■■■■ 已修改文件
app/CMakeLists.txt 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/build.gradle 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/libs/oaid_sdk_1.0.25.aar 补丁 | 查看 | 原始文档 | blame | 历史
app/libs/ocr-library.aar 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/cpp/native-lib.cpp 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/MyApplication.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/BaseNfcActivity.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/LoginActivity.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/MyActivity.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/NFCWreatActivity.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/NewCardActivity.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/NewCardListActivity.java 110 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/PassWordActivity.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/ReadCardAcitivy.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/RechargeActivity.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/RechargeListActivity.java 98 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/ReplacementActivity.java 103 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/adapter/BaseRecyclerAdapter.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/adapter/NewCardAdapter.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/adapter/RechargeAdapter.java 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/adapter/ReplacementAdapter.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/dao/BaseDaoSingleton.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/dao/RechargeDao.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/dao/UserCardDao.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/net/SocketNet.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/tools/BaseNFCHelper.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/tools/NFCWriteHelper.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/tools/NfcReadHelper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/tools/WriteCardUtils.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/utils/ExcelUtil.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_newcard_list.xml 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_recharge_list.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_replacement.xml 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_new_card.xml 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_no_more.xml 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_recharge.xml 87 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_replacement.xml 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/mipmap-xhdpi/ic_no_more.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/values/colors.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
dycz.jks 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/connect/SuperConnection.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/iowork/EasyReader.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/connection/iowork/EasyWriter.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easysocket/src/main/java/com/easysocket/utils/HexUtil.java 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gradlew 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gradlew.bat 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
local.properties 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/CMakeLists.txt
New file
@@ -0,0 +1,44 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
             native-lib
             # Sets the library as a shared library.
             SHARED
             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
              log-lib
              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
                       native-lib
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )
app/build.gradle
@@ -1,6 +1,14 @@
apply plugin: 'com.android.application'
android {
    signingConfigs {
        debug {
            storeFile file('../dycz.jks')
            storePassword 'dycz@2023'
            keyAlias 'dayu'
            keyPassword 'dycz@2023'
        }
    }
    namespace 'com.dayu.recharge'
    compileSdk 33
@@ -16,6 +24,7 @@
        ndk{
            abiFilters 'armeabi-v7a'
        }
        signingConfig signingConfigs.debug
    }
@@ -29,6 +38,9 @@
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    dataBinding {
        enabled = true;
    }
    viewBinding {
        enabled = true;
    }
@@ -37,6 +49,11 @@
//            dirs 'libs'
//        }
//    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}
//ps:dycz@2023
//alias:dayu
@@ -70,4 +87,11 @@
    }
    //滚动选择框
    implementation 'com.contrarywind:Android-PickerView:4.1.9'
    //列表
    implementation 'io.github.scwang90:refresh-layout-kernel:2.0.5'
    implementation 'io.github.scwang90:refresh-header-classics:2.0.5'
    implementation 'androidx.recyclerview:recyclerview:1.2.0'//经典刷新头
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
}
app/libs/oaid_sdk_1.0.25.aar
Binary files differ
app/libs/ocr-library.aar
Binary files differ
app/src/main/cpp/native-lib.cpp
New file
@@ -0,0 +1,70 @@
#include <jni.h>
#include <string>
#include <android/log.h>
#include <string.h>
#include <jni.h>
static jclass contextClass;
static jclass signatureClass;
static jclass packageNameClass;
static jclass packageInfoClass;
const char* RELEASE_SIGN = "308202b8308201a0020101300d06092a864886f70d01010b05003022310f300d06035504030c06e5a4a7e7a6b9310f300d06035504070c06e5a4a9e6b4a5301e170d3233313132303035333131325a170d3438313131333035333131325a3022310f300d06035504030c06e5a4a7e7a6b9310f300d06035504070c06e5a4a9e6b4a530820122300d06092a864886f70d01010105000382010f003082010a0282010100a0924f3d618e4a622def691e16e54ce5bdfd035bd73e7cb947d2bf3bd0c00afa26e52963e0299fc06d76d153be696c5285d630577e1dcb2b740a72b6d904482217de308fb91c8435441ed05e844ced1e5c3446d82cb8f38751049df26a42adcfc33f1f12c2ce03f676e5d148aad800ace89670b87835e2c02a8570a0b6740d9c0669d4cb3c597d0b2dd49fc0904e885773b6d3a87d9f1e73eb526e0d1a9e9e3c48d986938286cd824151b5a6214faf89d3e699524511b23c86d3b110a7f0bb56a6d2436f69816538a62a38cb1fee6eb685d267cc200df8af51b936bd280beaa2023f75678d77a11ac6de734b30af63d394c8b63bccf2115a47ea15c9212c740d0203010001300d06092a864886f70d01010b05000382010100307cafa9b14be91ba6424cfcc6aed75b069a1c4d6eb646eab0de93f372f236f5f0a6097499df99391075d6ced18d419a2b15adb041890e2b56a3bfbd6be40efee99c5c713ba8ea1d45da09b67916106116e96eb735271c4d53e0739f753145cbc42e149ad3d9507d422ec1c6f1a7f792a4542f9a64f0de3d4f4af69f0fb3390ef3577dcf8844cf744426d173b0934d879148062c5ca64022dc99af370dbfeaf2b5d4a279b20c54a361bca12c25bf185c2885519bbbc36e46ddb083080f0cc5b1f2eafe964ebce5071b0ae7d92a34a9193861b996d2c0299b1993f41063a27038199365a6e3cb27a02ffa9facdc48a63713eb5fbf90e9fd73056aba16b28e5fee";
const char *AUTH_KEY = "8b989c546f9ae3eb48ae977b4d4f11c99ae43217436200a0f6d0c4517150e0e6";
//extern "C" JNIEXPORT jstring
//
//JNICALL
//Java_com_yglx_testjni_MainActivity_getKey(
//        JNIEnv *env,
//        jobject /* this */) {
//    return env->NewStringUTF(AUTH_KEY);
//}
JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM* vm,void* reserved){
    JNIEnv* env = NULL;
    jint result=-1;
    if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK)
        return result;
    contextClass = (jclass)env->NewGlobalRef((env)->FindClass("android/content/Context"));
    signatureClass = (jclass)env->NewGlobalRef((env)->FindClass("android/content/pm/Signature"));
    packageNameClass = (jclass)env->NewGlobalRef((env)->FindClass("android/content/pm/PackageManager"));
    packageInfoClass = (jclass)env->NewGlobalRef((env)->FindClass("android/content/pm/PackageInfo"));
    __android_log_print(ANDROID_LOG_DEBUG, "jw", "sss");
    return JNI_VERSION_1_4;
}
extern "C"
JNIEXPORT jstring
Java_com_dayu_recharge_tools_BaseNFCHelper_getSafeKey(JNIEnv *env, jobject instance,jobject contextObject) {
    jmethodID getPackageManagerId = (env)->GetMethodID(contextClass, "getPackageManager","()Landroid/content/pm/PackageManager;");
    jmethodID getPackageNameId = (env)->GetMethodID(contextClass, "getPackageName","()Ljava/lang/String;");
    jmethodID signToStringId = (env)->GetMethodID(signatureClass, "toCharsString","()Ljava/lang/String;");
    jmethodID getPackageInfoId = (env)->GetMethodID(packageNameClass, "getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    jobject packageManagerObject =  (env)->CallObjectMethod(contextObject, getPackageManagerId);
    jstring packNameString =  (jstring)(env)->CallObjectMethod(contextObject, getPackageNameId);
    jobject packageInfoObject = (env)->CallObjectMethod(packageManagerObject, getPackageInfoId,packNameString, 64);
    jfieldID signaturefieldID =(env)->GetFieldID(packageInfoClass,"signatures", "[Landroid/content/pm/Signature;");
    jobjectArray signatureArray = (jobjectArray)(env)->GetObjectField(packageInfoObject, signaturefieldID);
    jobject signatureObject =  (env)->GetObjectArrayElement(signatureArray,0);
    const char* signStrng =  (env)->GetStringUTFChars((jstring)(env)->CallObjectMethod(signatureObject, signToStringId),0);
    __android_log_print(ANDROID_LOG_DEBUG, "jw_sign","%s",signStrng);
    __android_log_print(ANDROID_LOG_DEBUG, "jw_sign2","%s",signStrng+1023);
    __android_log_print(ANDROID_LOG_DEBUG,"jw_rels","%s",RELEASE_SIGN);
    __android_log_print(ANDROID_LOG_DEBUG,"jw_","sdf:%zd,sfs:%zd",strlen(signStrng),strlen(RELEASE_SIGN));
    if(strcmp(signStrng,RELEASE_SIGN)==0)//签名一致  返回合法的 api key,否则返回错误
    {
        return (env)->NewStringUTF(AUTH_KEY);
    }else
    {
        return (env)->NewStringUTF("error");
    }
}
app/src/main/java/com/dayu/recharge/MyApplication.java
@@ -1,21 +1,13 @@
package com.dayu.recharge;
import android.app.Application;
import android.nfc.Tag;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import com.dayu.recharge.dao.BaseDaoSingleton;
import com.dayu.recharge.dbBean.DeviceNumber;
import com.dayu.recharge.dbBean.IpBean;
import com.dayu.recharge.utils.DeviceNumberUtils;
import com.dayu.recharge.utils.ToastUtil;
import com.easysocket.EasySocket;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.entity.SocketAddress;
import com.tencent.bugly.crashreport.CrashReport;
import com.dayu.recharge.net.ScoketMessageProtocol;
import com.dayu.recharge.net.SocketCallBack;
import com.dayu.recharge.net.SocketData;
@@ -27,14 +19,17 @@
import com.dayu.recharge.tools.HexUtil;
import com.dayu.recharge.utils.AidlUtil;
import com.dayu.recharge.utils.CRC8;
import com.dayu.recharge.utils.DeviceNumberUtils;
import com.dayu.recharge.utils.SocketUtil;
import com.dayu.recharge.utils.TipUtil;
import com.dayu.recharge.utils.ToastUtil;
import com.easysocket.EasySocket;
import com.easysocket.config.EasySocketOptions;
import com.easysocket.entity.SocketAddress;
import com.tencent.bugly.crashreport.CrashReport;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
public class MyApplication extends Application {
    public static String TAG = "MyApplication";
@@ -237,6 +232,7 @@
                .setMaxWriteBytes(150)
                .setMaxReadBytes(150)
                .setRequestTimeout(5 * 1000)
                .setBackupAddress(new SocketAddress(backUpIp, backUpPort))
                .build();
app/src/main/java/com/dayu/recharge/activity/BaseNfcActivity.java
@@ -7,25 +7,14 @@
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.nfc.Tag;
import android.nfc.cardemulation.CardEmulation;
import android.os.Handler;
import android.os.Message;
import com.dayu.recharge.card.UserCard;
import com.dayu.recharge.tools.LoyaltyCardReader;
import com.dayu.recharge.tools.NfcReadHelper;
import com.dayu.recharge.utils.LogUtil;
import com.dayu.recharge.utils.TipUtil;
import com.tencent.bugly.crashreport.CrashReport;
import java.util.List;
import java.util.Map;
/**
 * Author:Created by Ricky on 2017/8/25.
@@ -65,6 +54,8 @@
     * 启动Activity,界面可见时.
     */
    public static int READER_FLAGS =
            NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK;
app/src/main/java/com/dayu/recharge/activity/LoginActivity.java
@@ -3,6 +3,7 @@
import android.Manifest;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Toast;
@@ -13,6 +14,7 @@
import com.dayu.recharge.dao.BaseDaoSingleton;
import com.dayu.recharge.databinding.ActivityLoginBinding;
import com.dayu.recharge.dbBean.PassWordBean;
import com.dayu.recharge.utils.TipUtil;
import com.dayu.recharge.utils.WSMD5;
import com.permissionx.guolindev.PermissionX;
@@ -43,7 +45,13 @@
        binding.loginBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if ((passWordBean != null && (passWordBean.getPassWord().equals(binding.loginPw.getText().toString()) || WSMD5.getMD5Str(binding.loginPw.getText().toString()).equals("8af357996269a1b52b182a839150097d"))) || (passWordBean == null && binding.loginPw.getText().toString().equals("123456")) || WSMD5.getMD5Str(binding.loginPw.getText().toString()).equalsIgnoreCase("00A93D54CF982B18A05ADB4520D58FC8")) {
                String psStr = binding.loginPw.getText().toString();
                if (TextUtils.isEmpty(psStr)) {
                    TipUtil.show("请输入密码");
                    return;
                }
                if ((passWordBean == null && psStr.equals("123456"))
                        || passWordBean != null && passWordBean.getPassWord().equals(psStr)) {
                    startActivity(new Intent(LoginActivity.this, HomeActivity.class));
                    LoginActivity.this.finish();
                } else {
app/src/main/java/com/dayu/recharge/activity/MyActivity.java
@@ -162,7 +162,7 @@
                            if (isRechargeList) {
                                listData = asynchBaseDao.rechargeDao().ansyFindByTime(beginTime, endTime);
                            } else {
                                listData = baseDao.userCardDao().findByTime(beginTime, endTime);
                                listData = asynchBaseDao.userCardDao().findByTime(beginTime, endTime);
                            }
                            if (listData == null || listData.size() == 0) {
                                handler.sendEmptyMessage(2);
@@ -178,7 +178,7 @@
                            return;
                        }
                        if (isRechargeList) {
                            title = new String[]{"设备序列号", "用户名", "身份证号", "充值日期", "充值金额(元)", "剩余金额(元)"};
                            title = new String[]{"设备序列号", "用户名", "订单号", "充值日期", "充值金额(元)", "剩余金额(元)"};
                            fileName = file.toString() + "/" + ExcelUtil.outRechargePathName;
                        } else {
                            title = new String[]{"设备序列号", "用户名", "身份证号", "注册日期", "电话"};
app/src/main/java/com/dayu/recharge/activity/NFCWreatActivity.java
@@ -2,15 +2,12 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.widget.Toast;
import com.dayu.recharge.MyApplication;
import com.dayu.recharge.R;
import com.dayu.recharge.card.CleanCard;
import com.dayu.recharge.card.CleanUserCard;
@@ -32,7 +29,6 @@
import com.dayu.recharge.socketBean.BalanceSelecteRequestBean;
import com.dayu.recharge.socketBean.RechargeRequestBean;
import com.dayu.recharge.tools.BcdUtil;
import com.dayu.recharge.tools.HexUtil;
import com.dayu.recharge.tools.NFCWriteHelper;
import com.dayu.recharge.tools.NfcReadHelper;
import com.dayu.recharge.tools.WriteCardUtils;
@@ -192,7 +188,7 @@
     */
    private void checkHasUser() {
        String cardType = NfcReadHelper.getInstence(intent).getCradType();
        String cardType = NfcReadHelper.getInstence(intent, this).getCradType();
        Log.i("NFCWreatActivity", "cardType=" + cardType);
        if (cardType.equals(MyCommon.USER_CARD_TYPE_1) ||
                cardType.equals(MyCommon.USER_CARD_TYPE_2) ||
@@ -221,7 +217,7 @@
                    || configurationPowerCard != null) {
                if (userCard != null && TextUtils.isEmpty(morny)) {
                    userFlag = WriteCardUtils.setUser(intent, userCard);
                    userFlag = WriteCardUtils.setUser(intent, userCard, this);
                }
                if (cleanCard != null) {
                    setClean(intent, cleanCard);
@@ -253,19 +249,9 @@
                            //用户卡
                            startDetailActivity(userCardBean.getUserName(), "启用");
                        } else if (!TextUtils.isEmpty(morny)) {
                            TipUtil.show(NFCWreatActivity.this, "充值成功", new TipUtil.TipListener() {
                                @Override
                                public void onCancle() {
                                    NFCWreatActivity.this.finish();
                                }
                            });
                            TipUtil.show(NFCWreatActivity.this, "充值成功", () -> NFCWreatActivity.this.finish());
                        } else {
                            TipUtil.show(NFCWreatActivity.this, "写卡成功", new TipUtil.TipListener() {
                                @Override
                                public void onCancle() {
                                    NFCWreatActivity.this.finish();
                                }
                            });
                            TipUtil.show(NFCWreatActivity.this, "写卡成功", () -> NFCWreatActivity.this.finish());
                        }
                    } catch (Exception e) {
@@ -407,7 +393,7 @@
                            userCard.setRechargeTimes(userCard.getRechargeTimes() + 1);
                        } else if ("01".equalsIgnoreCase(state)) {
                            userCard.setState("01");
                            userFlag = WriteCardUtils.setUser(intent, userCard);
                            userFlag = WriteCardUtils.setUser(intent, userCard, NFCWreatActivity.this);
                            NFCWreatActivity.this.finish();
                            TipUtil.show("充值报文错误-禁用");
                        } else if ("02".equalsIgnoreCase(state)) {
@@ -443,12 +429,12 @@
    //往卡内写充值后的数据
    private void rechargeWrratCard() {
        UserCard userCardold = NfcReadHelper.getInstence(intent).getUserCardData();
        UserCard userCardold = NfcReadHelper.getInstence(intent, this).getUserCardData();
        if (userCardold != null) {
            //判断是否充值的是一个卡
            if (userCard.getInitPeasantCode().equals(userCardold.getInitPeasantCode())) {
                userCard.setState("00");
                userFlag = WriteCardUtils.setUser(intent, userCard);
                userFlag = WriteCardUtils.setUser(intent, userCard, this);
                //   打印相关
                if (userFlag) {
                    setPrinterData(rechargeBean);
@@ -465,7 +451,7 @@
    }
    private void setmanageCard(Intent intent, final ManageCard manageCard) {
        manageCardFlag = NFCWriteHelper.getInstence(intent).writeData(manageCard.toZeroByte(), 1, 0);
        manageCardFlag = NFCWriteHelper.getInstence(intent, this).writeData(manageCard.toZeroByte(), 1, 0);
    }
    /**
@@ -475,7 +461,7 @@
     * @param clearOrInitCard
     */
    private void setClean(Intent intent, final CleanCard clearOrInitCard) {
        cleanFlag = NFCWriteHelper.getInstence(intent).writeData(clearOrInitCard.toByte(), 1, 0);
        cleanFlag = NFCWriteHelper.getInstence(intent, this).writeData(clearOrInitCard.toByte(), 1, 0);
    }
@@ -486,7 +472,7 @@
     * @param registeredCard
     */
    private void setRegisteredCard(Intent intent, RegisteredCard registeredCard) {
        registeredFlag = NFCWriteHelper.getInstence(intent).writeData(registeredCard.toByte(), 1, 0);
        registeredFlag = NFCWriteHelper.getInstence(intent, this).writeData(registeredCard.toByte(), 1, 0);
    }
    /**
@@ -496,7 +482,7 @@
     * @param cleanUserCard
     */
    private void setCleanUserCard(Intent intent, CleanUserCard cleanUserCard) {
        cleanUserCardFlag = NFCWriteHelper.getInstence(intent).writeData(cleanUserCard.toByte(), 1, 0);
        cleanUserCardFlag = NFCWriteHelper.getInstence(intent, this).writeData(cleanUserCard.toByte(), 1, 0);
    }
    /**
@@ -507,15 +493,15 @@
     */
    private void setDomainCard(Intent intent, DomainCard domainCard) {
        try {
            domainCrdFlag = NFCWriteHelper.getInstence(intent).writeData(domainCard.getZeroByte(), 1, 0);
            domainCrdFlag = NFCWriteHelper.getInstence(intent, this).writeData(domainCard.getZeroByte(), 1, 0);
            if (!domainCrdFlag) {
                return;
            }
            domainCrdFlag = NFCWriteHelper.getInstence(intent).writeData(domainCard.getOneByte(), 1, 1);
            domainCrdFlag = NFCWriteHelper.getInstence(intent, this).writeData(domainCard.getOneByte(), 1, 1);
            if (!domainCrdFlag) {
                return;
            }
            domainCrdFlag = NFCWriteHelper.getInstence(intent).writeData(domainCard.getTwoByte(), 1, 2);
            domainCrdFlag = NFCWriteHelper.getInstence(intent, this).writeData(domainCard.getTwoByte(), 1, 2);
        } catch (Exception e) {
            domainCrdFlag = false;
            throw new RuntimeException(e);
@@ -523,17 +509,17 @@
    }
    private void setTestCard(Intent intent, TestCard testCard) {
        testCardFlag = NFCWriteHelper.getInstence(intent).writeData(testCard.toByte(), 1, 0);
        testCardFlag = NFCWriteHelper.getInstence(intent, this).writeData(testCard.toByte(), 1, 0);
    }
    private void setConfigDeviceRegiest(Intent intent, ConfigureDeviceRegistrationCrad configureDeviceRegistrationCrad) {
        configDeviceRegiestFlag = NFCWriteHelper.getInstence(intent).writeData(configureDeviceRegistrationCrad.toByte(), 1, 0);
        configDeviceRegiestFlag = NFCWriteHelper.getInstence(intent, this).writeData(configureDeviceRegistrationCrad.toByte(), 1, 0);
    }
    private void setConfigurationPower(Intent intent, ConfigurationPowerCard configurationPowerCard) {
        try {
            configPowerFlag = NFCWriteHelper.getInstence(intent).writeData(configurationPowerCard.toByte(), 1, 0);
            configPowerFlag = NFCWriteHelper.getInstence(intent, this).writeData(configurationPowerCard.toByte(), 1, 0);
        } catch (Exception e) {
            configPowerFlag = false;
            throw new RuntimeException(e);
@@ -610,7 +596,7 @@
                                userCard.setBalance(balance);
                                userCard.setState("00");
                                //补卡逻辑
                                userFlag = WriteCardUtils.setUser(intent, userCard);
                                userFlag = WriteCardUtils.setUser(intent, userCard, NFCWreatActivity.this);
                                if (userFlag) {
                                    TipUtil.show(NFCWreatActivity.this, "补卡成功", new TipUtil.TipListener() {
                                        @Override
@@ -624,7 +610,7 @@
                                stateText.append("禁用");
                                userCard.setState("01");
                                userCard.setBalance(balance);
                                userFlag = WriteCardUtils.setUser(intent, userCard);
                                userFlag = WriteCardUtils.setUser(intent, userCard, NFCWreatActivity.this);
                                startDetailActivity(name, stateText.toString());
                            } else if ("02".equals(state)) {
@@ -659,8 +645,9 @@
        }
    }
    protected void onDestroy() {
        super.onDestroy();
        nfcWreatActivity=null;
        nfcWreatActivity = null;
    }
}
app/src/main/java/com/dayu/recharge/activity/NewCardActivity.java
@@ -12,7 +12,7 @@
import com.dayu.recharge.utils.DeviceNumberUtils;
import com.dayu.recharge.view.ProgressDialog;
import com.msd.ocr.idcard.LibraryInitOCR;
import com.dayu.recharge.MyApplication;
import com.dayu.recharge.card.UserCard;
import com.dayu.recharge.databinding.ActivityNewCardBinding;
@@ -36,6 +36,8 @@
import org.json.JSONObject;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * Copyright (C), 2023,
@@ -77,44 +79,80 @@
            }
        });
        newCardBinding.newCardRegistBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
        newCardBinding.newCardRegistBtn.setOnClickListener(v -> {
                String userName = newCardBinding.newCardName.getText().toString();
                long date = System.currentTimeMillis();
                String phone = newCardBinding.newCardPhone.getText().toString();
                String userID = newCardBinding.newCardId.getText().toString().toUpperCase();
            String userName = newCardBinding.newCardName.getText().toString();
            long date = System.currentTimeMillis();
            String phone = newCardBinding.newCardPhone.getText().toString();
            String userID = newCardBinding.newCardId.getText().toString().toUpperCase();
                if (!TextUtils.isEmpty(userName)
                        && !TextUtils.isEmpty(phone) && !TextUtils.isEmpty(userID)
                ) {
                    if (userName.length() <= 1 || !validateName(userName)) {
                        TipUtil.show(NewCardActivity.this, "请输入正确姓名");
                        return;
                    } else if (phone.length() < 11) {
                        TipUtil.show(NewCardActivity.this, "请输入正确手机号");
                        return;
                    } else if (!Utils.check(userID)) {
                        TipUtil.show(NewCardActivity.this, "请输入正确身份证号");
                        return;
                    } else {
                        userCardBean = new UserCardBean();
                        userCardBean.setUserName(userName);
                        userCardBean.setDate(date);
                        userCardBean.setSerial(adminData.getSerial());
                        userCardBean.setPhone(phone);
                        userCardBean.setUserID(userID);
                        initCard();
                    }
            if (!TextUtils.isEmpty(userName)
                    && !TextUtils.isEmpty(phone) && !TextUtils.isEmpty(userID)
            ) {
                if (userName.length() <= 1 || !validateName(userName)) {
                    TipUtil.show(NewCardActivity.this, "请输入正确姓名");
                    return;
                } else if (phone.length() < 11 || !isValidPhoneNumber(phone)) {
                    TipUtil.show(NewCardActivity.this, "请输入正确手机号");
                    return;
                } else if (!Utils.check(userID)) {
                    TipUtil.show(NewCardActivity.this, "请输入正确身份证号");
                    return;
                } else {
                    TipUtil.show(NewCardActivity.this, "请输入完整内容");
                    userCardBean = new UserCardBean();
                    userCardBean.setUserName(userName);
                    userCardBean.setDate(date);
                    userCardBean.setSerial(adminData.getSerial());
                    userCardBean.setPhone(phone);
                    userCardBean.setUserID(userID);
                    initCard();
                }
            } else {
                TipUtil.show(NewCardActivity.this, "请输入完整内容");
            }
        });
    }
    private boolean isValidPhoneNumber(String phoneNumber) {
        // 定义手机号的正则表达式,确保数字部分没有连续6位相同的数字
        String phoneRegex = "^1[0-9]{10}$";
        // 创建 Pattern 对象
        Pattern pattern = Pattern.compile(phoneRegex);
        // 创建 matcher 对象
        Matcher matcher = pattern.matcher(phoneNumber);
        // 判断手机号是否匹配正则表达式
        return matcher.matches() && !hasSixConsecutiveSameDigits(phoneNumber);
    }
    /**
     * 判断是否有6个相同的连续数字
     *
     * @param input
     * @return
     */
    public static boolean hasSixConsecutiveSameDigits(String input) {
        char[] digits = input.toCharArray();
        for (int i = 0; i <= digits.length - 6; i++) {
            boolean consecutiveSame = true;
            for (int j = 1; j < 6; j++) {
                if (digits[i + j] != digits[i + j - 1]) {
                    consecutiveSame = false;
                    break;
                }
            }
            if (consecutiveSame) {
                return true;
            }
        }
        return false;
    }
    private void rxPermission() {
        PermissionX.init(NewCardActivity.this).permissions(Manifest.permission.CAMERA)
@@ -124,7 +162,7 @@
                })
                .request((allGranted, grantedList, deniedList) -> {
                    if (allGranted) {//所有申请的权限都已通过
                        startCamera();
//                        startCamera();
                    } else {//您拒绝了如下权限:$deniedList
@@ -133,14 +171,6 @@
    }
    private void startCamera() {
        Bundle bundle = new Bundle();
        bundle.putBoolean("saveImage", false);
        bundle.putInt("requestCode", SCAN_IDCARD_REQUEST);
        bundle.putInt("type", 0); //0身份证, 1驾驶证
        LibraryInitOCR.startScan(NewCardActivity.this, bundle);
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
@@ -320,10 +350,11 @@
            return (c >= 0x4e00 && c <= 0x9fa5);
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        newCardActivity=null;
        newCardActivity = null;
    }
}
app/src/main/java/com/dayu/recharge/activity/NewCardListActivity.java
@@ -3,8 +3,13 @@
import static com.dayu.recharge.view.TitleBar.ClickType_RIGHT_TEXT;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.dayu.recharge.adapter.NewCardAdapter;
import com.dayu.recharge.databinding.ActivityNewcardListBinding;
@@ -12,8 +17,19 @@
import com.dayu.recharge.utils.TipUtil;
import com.dayu.recharge.view.datepicker.CustomDatePicker;
import com.dayu.recharge.view.datepicker.DateFormatUtils;
import com.scwang.smart.refresh.footer.ClassicsFooter;
import com.scwang.smart.refresh.header.ClassicsHeader;
import com.scwang.smart.refresh.layout.api.RefreshLayout;
import com.scwang.smart.refresh.layout.listener.OnLoadMoreListener;
import com.scwang.smart.refresh.layout.listener.OnRefreshListener;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Scheduler;
import io.reactivex.rxjava3.schedulers.Schedulers;
/**
 * Copyright (C), 2023,
@@ -26,12 +42,18 @@
    ActivityNewcardListBinding newcardListBinding;
    List<UserCardBean> userCardBeanList;
    List<UserCardBean> userCardBeanList = new ArrayList<>();
    NewCardAdapter adapter;
    private CustomDatePicker beginDatePicker;
    private CustomDatePicker endDatePicker;
    long beginTime;
    long endTime;
    int page = 0;
    //每页数据条数
    int limit = 30;
    RefreshLayout myRefreshLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
@@ -39,20 +61,67 @@
        newcardListBinding = ActivityNewcardListBinding.inflate(LayoutInflater.from(this));
        setContentView(newcardListBinding.getRoot());
        setRightButton();
        setData();
        initDatePicker();
        initList();
        getList();
    }
    private void setData() {
        try {
            userCardBeanList = baseDao.userCardDao().findAll();
        } catch (Exception e) {
            e.printStackTrace();
        }
    private void initList() {
        myRefreshLayout = (RefreshLayout) newcardListBinding.refreshLayout;
        myRefreshLayout.setEnableRefresh(false);
        myRefreshLayout.setRefreshFooter(new ClassicsFooter(this));
        myRefreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore(RefreshLayout refreshlayout) {
                page = page + 1;
                getList();
            }
        });
        adapter = new NewCardAdapter(this, userCardBeanList);
        newcardListBinding.newCardListView.setAdapter(adapter);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        newcardListBinding.recyclerView.setLayoutManager(layoutManager);
        newcardListBinding.recyclerView.setAdapter(adapter);
        int totale = baseDao.userCardDao().getUserTotale();
        newcardListBinding.userTotal.setText("开户数:" + totale + "");
    }
    private void getList() {
        // 创建一个 Observable
        Observable<List<UserCardBean>> observable = Observable.create(emitter -> {
            // 在这里执行异步操作
            List<UserCardBean> beanList;
            if (beginTime == 0 && endTime == 0) {
                beanList = asynchBaseDao.userCardDao().findAll(page * limit, limit);
            } else {
                beanList = asynchBaseDao.userCardDao().findByTime(beginTime, endTime);
            }
            // 将结果发送给观察者
            emitter.onNext(beanList);
            emitter.onComplete();
        });
        // 订阅观察者
        observable.subscribeOn(Schedulers.io()) // 指定在 IO 线程执行
                .observeOn(AndroidSchedulers.mainThread()) // 指定在单一线程观察结果
                .subscribe(
                        result -> {
                            // 在这里处理结果,这里是在主线程中
//                            System.out.println("Result: " + result);
                            if (result.size() < limit) {
                                myRefreshLayout.finishLoadMoreWithNoMoreData();
                            }
                            if (result != null && result.size() > 0) {
                                userCardBeanList.addAll(result);
                            }
                            adapter.notifyDataSetChanged();
                        },
                        error -> {
                            // 处理错误
                            System.err.println("Error: " + error.getMessage());
                        }
                );
    }
    private void setRightButton() {
        titleBar.setOnItemclickListner(ClickType_RIGHT_TEXT, new View.OnClickListener() {
@@ -91,15 +160,18 @@
                if ((endTime < beginTime) && endTime != beginTime) {
                    TipUtil.show(NewCardListActivity.this, "结束时间不能晚于开始时间");
                } else {
                    try {
                        endTime = endTime + (1000 * 60 * 60 * 24) - 1;
                        List<UserCardBean> userList = baseDao.userCardDao().findByTime(beginTime, endTime);
                        userCardBeanList.clear();
                        userCardBeanList.addAll(userList);
                        adapter.notifyDataSetChanged();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
//                    try {
//                        endTime = endTime + (1000 * 60 * 60 * 24) - 1;
//                        List<UserCardBean> userList = baseDao.userCardDao().findByTime(beginTime, endTime);
//                        userCardBeanList.clear();
//                        userCardBeanList.addAll(userList);
//                        adapter.notifyDataSetChanged();
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
                    endTime = endTime + (1000 * 60 * 60 * 24) - 1;
                    userCardBeanList.clear();
                    getList();
                }
            }
        }, beginTimestamp, endTimestamp);
app/src/main/java/com/dayu/recharge/activity/PassWordActivity.java
@@ -44,8 +44,10 @@
                            if (pswBinding.pswNew.getText().toString().equals(pswBinding.pswNewAgin.getText().toString())) {
                                passWordBean.setPassWord(pswBinding.pswNewAgin.getText().toString());
                                baseDao.loginPsDao().insert(passWordBean);
                                TipUtil.show(PassWordActivity.this, "密码修改完成");
                                PassWordActivity.this.finish();
                                TipUtil.show(PassWordActivity.this, "密码修改完成", () -> {
                                    PassWordActivity.this.finish();
                                });
                            } else {
                                TipUtil.show(PassWordActivity.this, "两次输入的密码不一致");
                            }
app/src/main/java/com/dayu/recharge/activity/ReadCardAcitivy.java
@@ -3,7 +3,6 @@
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
@@ -30,7 +29,6 @@
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
/**
 * Copyright (C), 2023,
@@ -73,7 +71,7 @@
        redCardBinding.redRemainderBlance.setText("剩余金额:" + MornyUtil.changeF2Y(blance) + "元");
        redCardBinding.redStatu.setText("卡状态:" + statu);
        if (userCard != null) {
            redCardBinding.redInitCode.setText( userCard.getInitPeasantCode());
            redCardBinding.redInitCode.setText(userCard.getInitPeasantCode());
            Calendar calendar = userCard.getRechargeDate();
            if (calendar != null) {
                int year = calendar.get(Calendar.YEAR);
@@ -107,7 +105,7 @@
     */
    public void readAllData(Intent intent) {
        NfcReadHelper.getInstence(intent)
        NfcReadHelper.getInstence(intent, this)
                .getOneSectorData(new NfcReadHelper.NFCCallListback() {
                    @Override
                    public void callBack(List<byte[]> data) {
@@ -252,12 +250,12 @@
                            userCard.setBalance(balance);
                            userCard.setState("00");
                            WriteCardUtils.setUser(intent, userCard);
                            WriteCardUtils.setUser(intent, userCard, ReadCardAcitivy.this);
                            stateText.append("启用");
                        } else if ("01".equals(state)) {
                            userCard.setBalance(balance);
                            userCard.setState("01");
                            WriteCardUtils.setUser(intent, userCard);
                            WriteCardUtils.setUser(intent, userCard, ReadCardAcitivy.this);
                            stateText.append("禁用");
                        } else if ("02".equals(state)) {
                            stateText.append("隶属信息不符");
app/src/main/java/com/dayu/recharge/activity/RechargeActivity.java
@@ -65,7 +65,7 @@
        try {
            this.intent = intent;
            userCard = NfcReadHelper.getInstence(intent).getUserCardData();
            userCard = NfcReadHelper.getInstence(intent, this).getUserCardData();
            if (userCard != null) {
                ProgressDialog.show(this);
                selectBalance(userCard.getInitPeasantCode());
@@ -88,24 +88,21 @@
            e.printStackTrace();
            CrashReport.postCatchedException(e);
        }
        binding.rechargeRegistBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String morny = binding.rechargeWater.getText().toString();
                if (!TextUtils.isEmpty(morny)) {
                    String initCode = DeviceNumberUtils.getDeviceNumber();
                    if (TextUtils.isEmpty(initCode)) {
                        TipUtil.show(RechargeActivity.this, "设备注册号为空,请先设置IP和管理员地址");
                        return;
                    }
                    Intent intent = new Intent(RechargeActivity.this, NFCWreatActivity.class);
                    intent.putExtra("morny", morny);
                    intent.putExtra("userName", userName);
                    intent.putExtra("userCard", userCard);
                    startActivity(intent);
                } else {
                    TipUtil.show(RechargeActivity.this, "请输入充值金额(元)");
        binding.rechargeRegistBtn.setOnClickListener(v -> {
            String morny = binding.rechargeWater.getText().toString();
            if (!TextUtils.isEmpty(morny)) {
                String initCode = DeviceNumberUtils.getDeviceNumber();
                if (TextUtils.isEmpty(initCode)) {
                    TipUtil.show(RechargeActivity.this, "设备注册号为空,请先设置IP和管理员地址");
                    return;
                }
                Intent intent = new Intent(RechargeActivity.this, NFCWreatActivity.class);
                intent.putExtra("morny", morny);
                intent.putExtra("userName", userName);
                intent.putExtra("userCard", userCard);
                startActivity(intent);
            } else {
                TipUtil.show(RechargeActivity.this, "请输入充值金额(元)");
            }
        });
    }
@@ -136,7 +133,6 @@
                    if (!s.toString().substring(1, 2).equals(".")) {
                        editText.setText(s.subSequence(0, 1));
                        editText.setSelection(1);
                        return;
                    }
                }
            }
@@ -176,7 +172,7 @@
                public void onSocketResponse(SocketData readData) {
                    ProgressDialog.dismiss();
                    if (CRC8.isCRC8(readData.getOriginDataBytes())) {
                        StringBuffer stateText = null;
                        StringBuffer stateText ;
                        try {
                            stateText = new StringBuffer();
                            String state = BcdUtil.bcdToStr(readData.getBodyBytes()[2]);  //BCD码00启用 01禁用 02隶属信息不符 03无此卡信息 04其它s
@@ -213,7 +209,7 @@
                                stateText.append("该卡已被禁用");
                                userCard.setState("01");
                                userCard.setBalance(balance);
                                userFlag = WriteCardUtils.setUser(intent, userCard);
                                userFlag = WriteCardUtils.setUser(intent, userCard, RechargeActivity.this);
                            } else if ("02".equals(state)) {
                                stateText.append("隶属信息不符");
                            } else if ("03".equals(state)) {
app/src/main/java/com/dayu/recharge/activity/RechargeListActivity.java
@@ -6,17 +6,28 @@
import android.view.LayoutInflater;
import android.view.View;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.dayu.recharge.adapter.NewCardAdapter;
import com.dayu.recharge.adapter.RechargeAdapter;
import com.dayu.recharge.databinding.ActivityRechargeListBinding;
import com.dayu.recharge.dbBean.RechargeBean;
import com.dayu.recharge.dbBean.UserCardBean;
import com.dayu.recharge.model.RechargeListModel;
import com.dayu.recharge.utils.ArithUtil;
import com.dayu.recharge.utils.TipUtil;
import com.dayu.recharge.view.datepicker.CustomDatePicker;
import com.dayu.recharge.view.datepicker.DateFormatUtils;
import com.scwang.smart.refresh.footer.ClassicsFooter;
import com.scwang.smart.refresh.layout.api.RefreshLayout;
import com.scwang.smart.refresh.layout.listener.OnLoadMoreListener;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;
/**
 * Copyright (C), 2023,
@@ -35,7 +46,11 @@
    long beginTime;
    long endTime;
    RechargeListModel rechargeListModel;
    int page = 0;
    //每页数据条数
    int limit = 30;
    RefreshLayout myRefreshLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
@@ -43,22 +58,26 @@
        rechargeListBinding = ActivityRechargeListBinding.inflate(LayoutInflater.from(this));
        setContentView(rechargeListBinding.getRoot());
        setRightButton();
        setData();
        initDatePicker();
        getTotal();
        initList();
        getList();
    }
    private void setData() {
        rechargeListModel = new RechargeListModel(this);
        rechargeListModel.getAllRechargeList().observe(this, myList -> {
            rechargeList.clear();
            rechargeList.addAll(myList);
            adapter.notifyDataSetChanged();
            getTotal();
    private void initList() {
        myRefreshLayout = (RefreshLayout) rechargeListBinding.refreshLayout;
        myRefreshLayout.setEnableRefresh(false);
        myRefreshLayout.setRefreshFooter(new ClassicsFooter(this));
        myRefreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore(RefreshLayout refreshlayout) {
                page = page + 1;
                getList();
            }
        });
        adapter = new RechargeAdapter(this, rechargeList);
        rechargeListBinding.rechargeList.setAdapter(adapter);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        rechargeListBinding.recyclerView.setLayoutManager(layoutManager);
        rechargeListBinding.recyclerView.setAdapter(adapter);
    }
    private void getTotal() {
@@ -68,9 +87,46 @@
                double b = Double.parseDouble(rechargeList.get(i).getMorny());
                total = ArithUtil.add(total, b);
            }
            rechargeListBinding.rechargeTotal.setText("累计充值:" + String.valueOf(total) + "元");
            rechargeListBinding.rechargeTotal.setText("已加载数据累计充值:" + String.valueOf(total) + "元");
        }
    }
    private void getList() {
        // 创建一个 Observable
        Observable<List<RechargeBean>> observable = Observable.create(emitter -> {
            // 在这里执行异步操作
            List<RechargeBean> beanList;
            if (beginTime == 0 && endTime == 0) {
                beanList = asynchBaseDao.rechargeDao().findAll(page * limit, limit);
            } else {
                beanList = asynchBaseDao.rechargeDao().ansyFindByTime(beginTime, endTime);
            }
            // 将结果发送给观察者
            emitter.onNext(beanList);
            emitter.onComplete();
        });
        // 订阅观察者
        observable.subscribeOn(Schedulers.io()) // 指定在 IO 线程执行
                .observeOn(AndroidSchedulers.mainThread()) // 指定在单一线程观察结果
                .subscribe(
                        result -> {
                            // 在这里处理结果,这里是在主线程中
//                            System.out.println("Result: " + result);
                            if (result.size() < limit) {
                                myRefreshLayout.finishLoadMoreWithNoMoreData();
                            }
                            if (result != null && result.size() > 0) {
                                rechargeList.addAll(result);
                            }
                            adapter.notifyDataSetChanged();
                            getTotal();
                        },
                        error -> {
                            // 处理错误
                            System.err.println("Error: " + error.getMessage());
                        }
                );
    }
@@ -112,20 +168,8 @@
                    TipUtil.show(RechargeListActivity.this, "结束时间不能晚于开始时间");
                } else {
                    endTime = endTime + (1000 * 60 * 60 * 24) - 1;
                    rechargeListModel.getRechargeList(beginTime, endTime).observe(RechargeListActivity.this, list -> {
                        if (rechargeList != null) {
                            rechargeList.clear();
                            rechargeList.addAll(list);
                            adapter.notifyDataSetChanged();
                            getTotal();
                        } else {
                            TipUtil.show(RechargeListActivity.this, "未查询到数据!");
                        }
                    });
                    rechargeList.clear();
                    getList();
                }
            }
        }, beginTimestamp, endTimestamp);
app/src/main/java/com/dayu/recharge/activity/ReplacementActivity.java
@@ -8,13 +8,24 @@
import android.view.View;
import android.widget.AdapterView;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.dayu.recharge.adapter.NewCardAdapter;
import com.dayu.recharge.adapter.ReplacementAdapter;
import com.dayu.recharge.databinding.ActivityReplacementBinding;
import com.dayu.recharge.dbBean.UserCardBean;
import com.dayu.recharge.utils.TipUtil;
import com.dayu.recharge.view.EdtDialog;
import com.scwang.smart.refresh.footer.ClassicsFooter;
import com.scwang.smart.refresh.layout.api.RefreshLayout;
import com.scwang.smart.refresh.layout.listener.OnLoadMoreListener;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;
/**
 * Created by Android Studio.
@@ -24,42 +35,90 @@
 * 备注: 补卡界面
 */
public class ReplacementActivity extends BaseActivity {
    ActivityReplacementBinding binding;
    List<UserCardBean> userCardBeanList;
    NewCardAdapter adapter;
    ActivityReplacementBinding newcardListBinding;
    List<UserCardBean> userCardBeanList = new ArrayList<>();
    ReplacementAdapter adapter;
    long beginTime;
    long endTime;
    int page = 0;
    //每页数据条数
    int limit = 30;
    RefreshLayout myRefreshLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityReplacementBinding.inflate(LayoutInflater.from(this));
        setContentView(binding.getRoot());
        newcardListBinding = ActivityReplacementBinding.inflate(LayoutInflater.from(this));
        setContentView(newcardListBinding.getRoot());
        setRightButton();
        setData();
        initView();
        initList();
        getList();
    }
    private void initView() {
        binding.newCardListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    public void itemClick(View view) {
        UserCardBean userCardBean = userCardBeanList.get((int) view.getTag());
        Intent intent = new Intent(ReplacementActivity.this, NFCWreatActivity.class);
        intent.putExtra("dbUserCard", userCardBean);
        startActivity(intent);
    }
    private void initList() {
        myRefreshLayout = (RefreshLayout) newcardListBinding.refreshLayout;
        myRefreshLayout.setEnableRefresh(false);
        myRefreshLayout.setRefreshFooter(new ClassicsFooter(this));
        myRefreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                UserCardBean userCardBean = userCardBeanList.get(position);
                Intent intent = new Intent(ReplacementActivity.this, NFCWreatActivity.class);
                intent.putExtra("dbUserCard", userCardBean);
                startActivity(intent);
            public void onLoadMore(RefreshLayout refreshlayout) {
                page = page + 1;
                getList();
            }
        });
        adapter = new ReplacementAdapter(this, userCardBeanList);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        newcardListBinding.recyclerView.setLayoutManager(layoutManager);
        newcardListBinding.recyclerView.setAdapter(adapter);
    }
    private void setData() {
        try {
            userCardBeanList = baseDao.userCardDao().findAll();
        } catch (Exception e) {
            e.printStackTrace();
        }
        adapter = new NewCardAdapter(this, userCardBeanList);
        binding.newCardListView.setAdapter(adapter);
    private void getList() {
        // 创建一个 Observable
        Observable<List<UserCardBean>> observable = Observable.create(emitter -> {
            // 在这里执行异步操作
            List<UserCardBean> beanList;
            if (beginTime == 0 && endTime == 0) {
                beanList = asynchBaseDao.userCardDao().findAll(page * limit, limit);
            } else {
                beanList = asynchBaseDao.userCardDao().findByTime(beginTime, endTime);
            }
            // 将结果发送给观察者
            emitter.onNext(beanList);
            emitter.onComplete();
        });
        // 订阅观察者
        observable.subscribeOn(Schedulers.io()) // 指定在 IO 线程执行
                .observeOn(AndroidSchedulers.mainThread()) // 指定在单一线程观察结果
                .subscribe(
                        result -> {
                            // 在这里处理结果,这里是在主线程中
//                            System.out.println("Result: " + result);
                            if (result.size() < limit) {
                                myRefreshLayout.finishLoadMoreWithNoMoreData();
                            }
                            if (result != null && result.size() > 0) {
                                userCardBeanList.addAll(result);
                            }
                            adapter.notifyDataSetChanged();
                        },
                        error -> {
                            // 处理错误
                            System.err.println("Error: " + error.getMessage());
                        }
                );
    }
    EdtDialog edtDialog;
    private void setRightButton() {
app/src/main/java/com/dayu/recharge/adapter/BaseRecyclerAdapter.java
New file
@@ -0,0 +1,64 @@
package com.dayu.recharge.adapter;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.dayu.recharge.databinding.ItemNoMoreBinding;
/**
 * Copyright (C), 2023,
 * Author: zuo
 * Date: 2023-04-20 8:48
 * Description:
 */
public class BaseRecyclerAdapter<T extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<T> {
    /**
     * viewType--分别为item以及空view
     */
    public static final int VIEW_TYPE_ITEM = 1;
    public static final int VIEW_TYPE_EMPTY = 0;
    public int myiewType;
    @NonNull
    @Override
    public T onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return null;
    }
    @Override
    public void onBindViewHolder(@NonNull T holder, int position) {
    }
    @Override
    public int getItemCount() {
        return 0;
    }
    static class ViewHolderEmpty extends RecyclerView.ViewHolder {
        ItemNoMoreBinding mBinding;
        public ItemNoMoreBinding getBinding() {
            return mBinding;
        }
        public void setBinding(ItemNoMoreBinding binding) {
            this.mBinding = binding;
        }
        public ViewHolderEmpty(ItemNoMoreBinding itemView) {
            super(itemView.getRoot());
            this.mBinding = itemView;
        }
    }
}
app/src/main/java/com/dayu/recharge/adapter/NewCardAdapter.java
@@ -1,12 +1,20 @@
package com.dayu.recharge.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import androidx.recyclerview.widget.RecyclerView;
import com.dayu.recharge.R;
import com.dayu.recharge.databinding.ItemNewCardBinding;
import com.dayu.recharge.databinding.ItemNoMoreBinding;
import com.dayu.recharge.dbBean.UserCardBean;
import com.dayu.recharge.utils.DateUtil;
@@ -16,7 +24,7 @@
 * Created by zuoxiao on 2018/12/24.
 */
public class NewCardAdapter extends BaseAdapter {
public class NewCardAdapter extends BaseRecyclerAdapter<RecyclerView.ViewHolder> {
    List<UserCardBean> rechargeList;
    Context mContext;
@@ -26,51 +34,69 @@
        this.rechargeList = rechargeList;
    }
    @NonNull
    @Override
    public int getCount() {
        if (rechargeList == null) {
            return 0;
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType == VIEW_TYPE_EMPTY) {
            ItemNoMoreBinding emptyView = DataBindingUtil.inflate((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE), R.layout.item_no_more, parent, false);
            return new ViewHolderEmpty(emptyView);
        } else {
            ItemNewCardBinding binding = DataBindingUtil.inflate((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE), R.layout.item_new_card, parent, false);
            return new ViewHolder(binding);
        }
    }
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof ViewHolder) {
            if (rechargeList.size() > 0) {
                ((ViewHolder) holder).getBinding().userName.setText("用户名:" + rechargeList.get(position).getUserName());
                ((ViewHolder) holder).getBinding().userNo.setText("身份证号:" + rechargeList.get(position).getUserID());
                ((ViewHolder) holder).getBinding().water.setText("电话:" + rechargeList.get(position).getPhone());
                ((ViewHolder) holder).getBinding().date.setText("日期:" + DateUtil.dateToStamp(rechargeList.get(position).getDate(), DateUtil.type1));
            }
        }
    }
    @Override
    public int getItemCount() {
        //同时这里也需要添加判断,如果mData.size()为0的话,只引入一个布局,就是emptyView
        // 那么,这个recyclerView的itemCount为1
        if (rechargeList.size() == 0) {
            return 1;
        }
        return rechargeList.size();
    }
    @Override
    public Object getItem(int position) {
        return position;
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        NewCardAdapter.ViewHolder holder = null;
        if (convertView == null) {
            holder = new NewCardAdapter.ViewHolder();
            convertView = View.inflate(mContext, R.layout.item_new_card, null);
            holder.userName = (TextView) convertView.findViewById(R.id.userName);
            holder.userNo = (TextView) convertView.findViewById(R.id.userNo);
            holder.water = (TextView) convertView.findViewById(R.id.water);
            holder.date = (TextView) convertView.findViewById(R.id.date);
            convertView.setTag(holder);
    public int getItemViewType(int position) {
        if (rechargeList.size() == 0) {
            return VIEW_TYPE_EMPTY;
        } else {
            holder = (NewCardAdapter.ViewHolder) convertView.getTag();
            return VIEW_TYPE_ITEM;
        }
        holder.userName.setText("用户名:" + rechargeList.get(position).getUserName());
        holder.userNo.setText("身份证号:" + rechargeList.get(position).getUserID());
        holder.water.setText("电话:" + rechargeList.get(position).getPhone());
        holder.date.setText("日期:" + DateUtil.dateToStamp(rechargeList.get(position).getDate(), DateUtil.type1));
        return convertView;
    }
    class ViewHolder {
        TextView userName;
        TextView userNo;
        TextView water;
        TextView date;
    static class ViewHolder extends RecyclerView.ViewHolder {
        ItemNewCardBinding mBinding;
        public ItemNewCardBinding getBinding() {
            return mBinding;
        }
        public void setBinding(ItemNewCardBinding binding) {
            this.mBinding = binding;
        }
        public ViewHolder(ItemNewCardBinding itemView) {
            super(itemView.getRoot());
            this.mBinding = itemView;
        }
    }
}
app/src/main/java/com/dayu/recharge/adapter/RechargeAdapter.java
@@ -1,6 +1,7 @@
package com.dayu.recharge.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
@@ -8,8 +9,16 @@
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.dayu.recharge.R;
import com.dayu.recharge.databinding.ItemRechargeBinding;
import com.dayu.recharge.databinding.ItemNoMoreBinding;
import com.dayu.recharge.databinding.ItemRechargeBinding;
import com.dayu.recharge.dbBean.RechargeBean;
import com.dayu.recharge.dbBean.UserCardBean;
import com.dayu.recharge.utils.DateUtil;
import java.util.List;
@@ -18,7 +27,7 @@
 * Created by zuoxiao on 2018/12/24.
 */
public class RechargeAdapter extends BaseAdapter {
public class RechargeAdapter extends BaseRecyclerAdapter<RecyclerView.ViewHolder> {
    List<RechargeBean> rechargeList;
    Context mContext;
@@ -28,51 +37,69 @@
        this.rechargeList = rechargeList;
    }
    @NonNull
    @Override
    public int getCount() {
        if (rechargeList == null) {
            return 0;
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType == VIEW_TYPE_EMPTY) {
            ItemNoMoreBinding emptyView = DataBindingUtil.inflate((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE), R.layout.item_no_more, parent, false);
            return new ViewHolderEmpty(emptyView);
        } else {
            ItemRechargeBinding binding = DataBindingUtil.inflate((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE), R.layout.item_recharge, parent, false);
            return new ViewHolder(binding);
        }
    }
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof ViewHolder) {
            if (rechargeList.size() > 0) {
                ((ViewHolder) holder).getBinding().userName.setText("用户名:" + rechargeList.get(position).getUserName());
                ((ViewHolder) holder).getBinding().userNo.setText("用户编号:" + rechargeList.get(position).getInitPeasantCode());
                ((ViewHolder) holder).getBinding().morny.setText("充值金额:" + rechargeList.get(position).getMorny());
                ((ViewHolder) holder).getBinding().date.setText("日期:" + DateUtil.dateToStamp(rechargeList.get(position).getDate(), DateUtil.type1));
            }
        }
    }
    @Override
    public int getItemCount() {
        //同时这里也需要添加判断,如果mData.size()为0的话,只引入一个布局,就是emptyView
        // 那么,这个recyclerView的itemCount为1
        if (rechargeList.size() == 0) {
            return 1;
        }
        return rechargeList.size();
    }
    @Override
    public Object getItem(int position) {
        return position;
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = View.inflate(mContext, R.layout.item_recharge, null);
            holder.userName = (TextView) convertView.findViewById(R.id.userName);
            holder.userNo = (TextView) convertView.findViewById(R.id.userNo);
            holder.morny = (TextView) convertView.findViewById(R.id.morny);
            holder.date = (TextView) convertView.findViewById(R.id.date);
            convertView.setTag(holder);
    public int getItemViewType(int position) {
        if (rechargeList.size() == 0) {
            return VIEW_TYPE_EMPTY;
        } else {
            holder = (ViewHolder) convertView.getTag();
            return VIEW_TYPE_ITEM;
        }
        holder.userName.setText("用户名:" + rechargeList.get(position).getUserName());
        holder.userNo.setText("用户编号:" + rechargeList.get(position).getInitPeasantCode());
        holder.morny.setText("充值金额:" + rechargeList.get(position).getMorny());
        holder.date.setText("日期:" + DateUtil.dateToStamp(rechargeList.get(position).getDate(), DateUtil.type1));
        return convertView;
    }
    class ViewHolder {
        TextView userName;
        TextView userNo;
        TextView morny;
        TextView date;
    static class ViewHolder extends RecyclerView.ViewHolder {
        ItemRechargeBinding mBinding;
        public ItemRechargeBinding getBinding() {
            return mBinding;
        }
        public void setBinding(ItemRechargeBinding binding) {
            this.mBinding = binding;
        }
        public ViewHolder(ItemRechargeBinding itemView) {
            super(itemView.getRoot());
            this.mBinding = itemView;
        }
    }
}
app/src/main/java/com/dayu/recharge/adapter/ReplacementAdapter.java
New file
@@ -0,0 +1,97 @@
package com.dayu.recharge.adapter;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.dayu.recharge.R;
import com.dayu.recharge.activity.ReplacementActivity;
import com.dayu.recharge.databinding.ItemNewCardBinding;
import com.dayu.recharge.databinding.ItemNoMoreBinding;
import com.dayu.recharge.databinding.ItemReplacementBinding;
import com.dayu.recharge.dbBean.UserCardBean;
import com.dayu.recharge.utils.DateUtil;
import java.util.List;
public class ReplacementAdapter extends BaseRecyclerAdapter<RecyclerView.ViewHolder> {
    List<UserCardBean> rechargeList;
    ReplacementActivity mContext;
    public ReplacementAdapter(ReplacementActivity context, List<UserCardBean> rechargeList) {
        mContext = context;
        this.rechargeList = rechargeList;
    }
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType == VIEW_TYPE_EMPTY) {
            ItemNoMoreBinding emptyView = DataBindingUtil.inflate((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE), R.layout.item_no_more, parent, false);
            return new ViewHolderEmpty(emptyView);
        } else {
            ItemReplacementBinding binding = DataBindingUtil.inflate((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE), R.layout.item_replacement, parent, false);
            return new ViewHolder(binding);
        }
    }
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof ViewHolder) {
            if (rechargeList.size() > 0) {
                ((ViewHolder) holder).getBinding().userName.setText("用户名:" + rechargeList.get(position).getUserName());
                ((ViewHolder) holder).getBinding().userNo.setText("身份证号:" + rechargeList.get(position).getUserID());
                ((ViewHolder) holder).getBinding().water.setText("电话:" + rechargeList.get(position).getPhone());
                ((ViewHolder) holder).getBinding().date.setText("日期:" + DateUtil.dateToStamp(rechargeList.get(position).getDate(), DateUtil.type1));
                ((ViewHolder) holder).getBinding().item.setTag(position);
                ((ViewHolder) holder).getBinding().setActivity(mContext);
            }
        }
    }
    @Override
    public int getItemCount() {
        //同时这里也需要添加判断,如果mData.size()为0的话,只引入一个布局,就是emptyView
        // 那么,这个recyclerView的itemCount为1
        if (rechargeList.size() == 0) {
            return 1;
        }
        return rechargeList.size();
    }
    @Override
    public int getItemViewType(int position) {
        if (rechargeList.size() == 0) {
            return VIEW_TYPE_EMPTY;
        } else {
            return VIEW_TYPE_ITEM;
        }
    }
    static class ViewHolder extends RecyclerView.ViewHolder {
        ItemReplacementBinding mBinding;
        public ItemReplacementBinding getBinding() {
            return mBinding;
        }
        public void setBinding(ItemReplacementBinding binding) {
            this.mBinding = binding;
        }
        public ViewHolder(ItemReplacementBinding itemView) {
            super(itemView.getRoot());
            this.mBinding = itemView;
        }
    }
}
app/src/main/java/com/dayu/recharge/dao/BaseDaoSingleton.java
@@ -39,7 +39,7 @@
            AsynchBaseDao = Room.databaseBuilder(
                    context,
                    AppDatabase.class,
                    "ConfigurationData"
                    SqlitePath + "ConfigurationData"
            ).build();
        }
        return AsynchBaseDao;
app/src/main/java/com/dayu/recharge/dao/RechargeDao.java
@@ -39,4 +39,7 @@
    @Query("select  * from RechargeBean where date>=:beginTime and date<=:endTime")
    List<RechargeBean> ansyFindByTime(long beginTime, long endTime);
    @Query("select  * from RechargeBean order by date desc LIMIT :limit OFFSET :offset")
    List<RechargeBean> findAll(int offset,int limit);
}
app/src/main/java/com/dayu/recharge/dao/UserCardDao.java
@@ -35,4 +35,9 @@
    List<UserCardBean> findByTime(long beginTime, long endTime);
    @Query("select  * from UserCardBean where userName like :data or userID like :data or  phone like :data")
    List<UserCardBean> findByData(String data);
    @Query("select  * from UserCardBean order by date desc LIMIT :limit OFFSET :offset")
    List<UserCardBean> findAll(int offset,int limit);
    @Query("select COUNT(*) from UserCardBean")
    int getUserTotale();
}
app/src/main/java/com/dayu/recharge/net/SocketNet.java
@@ -11,11 +11,13 @@
import com.dayu.recharge.dbBean.DeviceNumber;
import com.dayu.recharge.dbBean.IpBean;
import com.easysocket.EasySocket;
import com.easysocket.connection.action.SocketStatus;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.conn.ISocketActionListener;
import com.easysocket.interfaces.conn.SocketActionListener;
import com.dayu.recharge.MyApplication;
import com.easysocket.utils.HexUtil;
/**
@@ -53,7 +55,12 @@
        if (EasySocket.getInstance().getDefconnection() != null) {
//            EasySocket.getInstance().disconnect(false);
//            EasySocket.getInstance().connect();
//            if (EasySocket.getInstance().getDefconnection().getConnectionStatus()== SocketStatus.SOCKET_CONNECTED){
            EasySocket.getInstance().upMessage(dataMessage);
//            }else {
//
//            }
//            this.dataMessage = dataMessage;
        } else {
            MyApplication.myApplication.initEasySocket(false, null);
@@ -144,21 +151,17 @@
            rushState();
        }
        /**
         * socket接收的数据
         * @param socketAddress
         * @param readData
         * @param originReadData
         */
        @Override
        public void onSocketResponse(SocketAddress socketAddress, String readData) {
            Log.i("SocketActionListener", "SocketActionListener收到数据-->" + readData);
        }
        @Override
        public void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData) {
            super.onSocketResponse(socketAddress, originReadData);
            Log.i("SocketActionListener", "SocketActionListener收到数据-->" + originReadData.getBodyString());
            Log.i("SocketActionListener", "SocketActionListener收到数据-->" + HexUtil.bytesToHex(originReadData.getBodyBytes()));
            SocketData socketData = new SocketData();
            socketData.setBodyData(originReadData.getBodyBytes());
            socketData.setHeaderData(originReadData.getHeaderData());
app/src/main/java/com/dayu/recharge/tools/BaseNFCHelper.java
@@ -1,5 +1,6 @@
package com.dayu.recharge.tools;
import android.app.Activity;
import android.util.Base64;
import java.nio.charset.StandardCharsets;
@@ -34,13 +35,21 @@
    String companyKeyB;
    public BaseNFCHelper() {
    static {
        System.loadLibrary("native-lib");
    }
    public native String getSafeKey(Object object);
    public BaseNFCHelper(Activity activity) {
        // 解密字符串
        try {
            //初始密码
            byte[] encryptedBytes = Base64.decode("orDiGzvueQqPpU+VQ3NEzQ==", Base64.DEFAULT);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            byte[] encodedKey = {-117, -104, -100, 84, 111, -102, -29, -21, 72, -82, -105, 123, 77, 79, 17, -55, -102, -28, 50, 23, 67, 98, 0, -96, -10, -48, -60, 81, 113, 80, -32, -26};
            String data = getSafeKey(activity);
            byte[] encodedKey = HexUtil.hexToByteArray(data);
//            byte[] encodedKey = {-117, -104, -100, 84, 111, -102, -29, -21, 72, -82, -105, 123, 77, 79, 17, -55, -102, -28, 50, 23, 67, 98, 0, -96, -10, -48, -60, 81, 113, 80, -32, -26};
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(encodedKey, "AES"));
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);
@@ -55,19 +64,13 @@
            //修改后的密码
            byte[] encryptedBytes3 = Base64.decode("n+SSZFb4DHsreVav/Z5ftg==", Base64.DEFAULT);
            byte[] decryptedBytes3 = cipher.doFinal(encryptedBytes3);
            companyKeyB = new String(decryptedBytes3, StandardCharsets.UTF_8);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (NoSuchPaddingException e) {
            throw new RuntimeException(e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        } catch (BadPaddingException e) {
            throw new RuntimeException(e);
        } catch (IllegalBlockSizeException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
                 BadPaddingException | IllegalBlockSizeException e) {
            e.printStackTrace();
        }
    }
}
app/src/main/java/com/dayu/recharge/tools/NFCWriteHelper.java
@@ -1,23 +1,13 @@
package com.dayu.recharge.tools;
import android.app.Activity;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.MifareClassic;
import android.util.Base64;
import android.util.Log;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
 * @author zx
@@ -32,7 +22,8 @@
    private static NFCWriteHelper helper;
    private static int PASSWORD_LENTH = 12;
    public NFCWriteHelper(Intent intent) {
    public NFCWriteHelper(Intent intent, Activity activity) {
        super(activity);
        this.tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    }
@@ -42,9 +33,9 @@
     * @param intent
     * @return
     */
    public static NFCWriteHelper getInstence(Intent intent) {
    public static NFCWriteHelper getInstence(Intent intent, Activity activity) {
        if (helper == null) {
            helper = new NFCWriteHelper(intent);
            helper = new NFCWriteHelper(intent, activity);
        }
        return helper;
    }
@@ -130,8 +121,8 @@
    /**
     * 修改密码
     *
     * @param a        书写的扇区
     *                 //     * @param callback 返回监听
     * @param a 书写的扇区
     *          //     * @param callback 返回监听
     */
    public boolean changePasword(int a) {
        MifareClassic mfc = MifareClassic.get(tag);
app/src/main/java/com/dayu/recharge/tools/NfcReadHelper.java
@@ -1,5 +1,6 @@
package com.dayu.recharge.tools;
import android.app.Activity;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
@@ -11,7 +12,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -29,7 +29,8 @@
    private static NfcReadHelper helper;
    public NfcReadHelper(Intent intent) {
    public NfcReadHelper(Intent intent, Activity activity) {
        super(activity);
        this.tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    }
@@ -40,9 +41,9 @@
     * @param intent
     * @return
     */
    public static NfcReadHelper getInstence(Intent intent) {
    public static NfcReadHelper getInstence(Intent intent, Activity activity) {
        if (helper == null) {
            helper = new NfcReadHelper(intent);
            helper = new NfcReadHelper(intent, activity);
        }
        return helper;
    }
app/src/main/java/com/dayu/recharge/tools/WriteCardUtils.java
@@ -1,5 +1,6 @@
package com.dayu.recharge.tools;
import android.app.Activity;
import android.content.Intent;
import com.dayu.recharge.card.UserCard;
@@ -15,16 +16,16 @@
    static boolean userFlag = false;
    //向卡写入用户信息
    public static boolean setUser(Intent intent, UserCard userCard) {
        userFlag = NFCWriteHelper.getInstence(intent).writeData(userCard.getZeroBytes(), 1, 0);
    public static boolean setUser(Intent intent, UserCard userCard, Activity activity) {
        userFlag = NFCWriteHelper.getInstence(intent,activity).writeData(userCard.getZeroBytes(), 1, 0);
        if (!userFlag) {
            return false;
        }
        userFlag = NFCWriteHelper.getInstence(intent).writeData(userCard.getOneBytes(), 1, 1);
        userFlag = NFCWriteHelper.getInstence(intent,activity).writeData(userCard.getOneBytes(), 1, 1);
        if (!userFlag) {
            return false;
        }
        userFlag = NFCWriteHelper.getInstence(intent).writeData(userCard.getTwoBytes(), 1, 2);
        userFlag = NFCWriteHelper.getInstence(intent,activity).writeData(userCard.getTwoBytes(), 1, 2);
        return userFlag;
    }
}
app/src/main/java/com/dayu/recharge/utils/ExcelUtil.java
@@ -29,32 +29,30 @@
 */
public class ExcelUtil {
    private static WritableFont arial14font = null;
    private static WritableCellFormat arial14format = null;
    private static WritableFont arial10font = null;
    private static WritableCellFormat arial10format = null;
    private static WritableFont arial12font = null;
    private static WritableCellFormat arial12format = null;
    private final static String UTF8_ENCODING = "UTF-8";
    public static String outPath = MyFileUtil.getSDPath() + "/" + "农业水价记录";
    public static String outRechargePathName = "水价充值记录.xls";
    public static String outUserPathName = "水价开户记录.xls";
    public static String outPath = MyFileUtil.getSDPath() + "/" + "大禹节水充值机记录";
    public static String outRechargePathName = "充值记录.xls";
    public static String outUserPathName = "开户记录.xls";
    /**
     * 单元格的格式设置 字体大小 颜色 对齐方式、背景颜色等...
     */
    private static void format() {
        try {
            arial14font = new WritableFont(WritableFont.ARIAL, 14, WritableFont.BOLD);
            WritableFont arial14font = new WritableFont(WritableFont.ARIAL, 14, WritableFont.BOLD);
            arial14font.setColour(jxl.format.Colour.LIGHT_BLUE);
            arial14format = new WritableCellFormat(arial14font);
            arial14format.setAlignment(jxl.format.Alignment.CENTRE);
            arial14format.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN);
            arial14format.setBackground(jxl.format.Colour.VERY_LIGHT_YELLOW);
            arial10font = new WritableFont(WritableFont.ARIAL, 10, WritableFont.BOLD);
            WritableFont arial10font = new WritableFont(WritableFont.ARIAL, 10, WritableFont.BOLD);
            arial10format = new WritableCellFormat(arial10font);
            arial10format.setAlignment(jxl.format.Alignment.CENTRE);
            arial10format.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN);
@@ -131,11 +129,7 @@
                        RechargeBean projectBean = (RechargeBean) objList.get(j);
                        list.add(projectBean.getSerial());
                        list.add(projectBean.getUserName());
                        if (projectBean.getUserId() != null) {
                            list.add(projectBean.getUserId());
                        } else {
                            list.add("");
                        }
                        list.add(projectBean.getOrderID());
                        list.add(DateUtil.dateToStamp(projectBean.getDate(), DateUtil.type2));
                        list.add(projectBean.getMorny());
                        list.add(projectBean.getBalance());
app/src/main/res/layout/activity_newcard_list.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
@@ -10,17 +10,40 @@
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimen_title_height"
        android:background="@drawable/title_bar_bg"
        app:centerText="注册记录"
        app:centerText="开户记录"
        app:leftImage="@mipmap/icon_back"
        app:rightText="筛选" />
    <ListView
        android:id="@+id/newCard_listView"
    <com.scwang.smart.refresh.layout.SmartRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:cacheColorHint="#ffffff"
        android:divider="@null"
        android:dividerHeight="0dp" />
        android:layout_above="@id/user_total"
        android:layout_below="@+id/titleBar">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ffffff"
            android:overScrollMode="never"
            android:padding="10dp" />
        <com.scwang.smart.refresh.footer.ClassicsFooter
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.scwang.smart.refresh.layout.SmartRefreshLayout>
</LinearLayout>
    <TextView
        android:id="@+id/user_total"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:background="@color/title_bg"
        android:gravity="center"
        android:text="已创建用户:"
        android:textSize="@dimen/text_size" />
</RelativeLayout>
app/src/main/res/layout/activity_recharge_list.xml
@@ -14,15 +14,25 @@
        app:leftImage="@mipmap/icon_back"
        app:rightText="筛选" />
    <ListView
        android:id="@+id/recharge_list"
    <com.scwang.smart.refresh.layout.SmartRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/recharge_total"
        android:layout_below="@+id/titleBar"
        android:cacheColorHint="#ffffff"
        android:divider="@null"
        android:dividerHeight="0dp" />
        android:layout_above="@id/recharge_total"
        android:layout_below="@+id/titleBar">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ffffff"
            android:overScrollMode="never"
            android:padding="10dp" />
        <com.scwang.smart.refresh.footer.ClassicsFooter
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.scwang.smart.refresh.layout.SmartRefreshLayout>
    <TextView
        android:id="@+id/recharge_total"
@@ -31,7 +41,7 @@
        android:layout_alignParentBottom="true"
        android:background="@color/title_bg"
        android:gravity="center"
        android:text="累计充值:"
        android:text="已加载数据累计充值:"
        android:textSize="@dimen/text_size" />
</RelativeLayout>
app/src/main/res/layout/activity_replacement.xml
@@ -14,13 +14,24 @@
        app:leftImage="@mipmap/icon_back"
        app:rightText="筛选" />
    <ListView
        android:id="@+id/newCard_listView"
    <com.scwang.smart.refresh.layout.SmartRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:cacheColorHint="#ffffff"
        android:divider="@null"
        android:dividerHeight="0dp" />
        android:layout_above="@id/user_total"
        android:layout_below="@+id/titleBar">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#fff"
            android:overScrollMode="never"
            android:padding="10dp" />
        <com.scwang.smart.refresh.footer.ClassicsFooter
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.scwang.smart.refresh.layout.SmartRefreshLayout>
</LinearLayout>
app/src/main/res/layout/item_new_card.xml
@@ -1,57 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="10dp"
        android:layout_marginRight="15dp"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <TextView
            android:id="@+id/userName"
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="用户名"
            android:textSize="14sp" />
            android:layout_marginLeft="15dp"
            android:layout_marginTop="10dp"
        <TextView
            android:id="@+id/userNo"
            android:layout_marginRight="15dp"
            android:orientation="vertical">
            <TextView
                android:id="@+id/userName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="用户名"
                android:textSize="14sp" />
            <TextView
                android:id="@+id/userNo"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="户号:123123"
                android:textSize="14sp" />
            <TextView
                android:id="@+id/water"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="水量:123123"
                android:textSize="14sp" />
            <TextView
                android:id="@+id/date"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="日期"
                android:textSize="14sp" />
        </LinearLayout>
        <View
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="户号:123123"
            android:textSize="14sp" />
        <TextView
            android:id="@+id/water"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="水量:123123"
            android:textSize="14sp" />
        <TextView
            android:id="@+id/date"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="日期"
            android:textSize="14sp" />
            android:layout_height="1px"
            android:layout_marginTop="15dp"
            android:background="#000000" />
    </LinearLayout>
    <View
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:layout_marginTop="15dp"
        android:background="#000000" />
</layout>
</LinearLayout>
app/src/main/res/layout/item_no_more.xml
New file
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:gravity="center"
        android:orientation="vertical">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="50dp"
            android:layout_marginRight="50dp"
            android:src="@mipmap/ic_no_more" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="没有数据"
            android:textColor="@color/choose_grey" />
    </LinearLayout>
</layout>
app/src/main/res/layout/item_recharge.xml
@@ -1,55 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="10dp"
        android:orientation="vertical">
        <TextView
            android:id="@+id/userName"
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="用户名"
            android:textSize="14sp" />
            android:layout_marginLeft="15dp"
            android:layout_marginTop="10dp"
            android:layout_marginRight="15dp"
            android:orientation="vertical">
        <TextView
            android:id="@+id/userNo"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="用户编号"
            android:textSize="14sp" />
            <TextView
                android:id="@+id/userName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="用户名"
                android:textSize="14sp" />
        <TextView
            android:id="@+id/morny"
            <TextView
                android:id="@+id/userNo"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="用户编号"
                android:textSize="14sp" />
            <TextView
                android:id="@+id/morny"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="金额:"
                android:textSize="14sp" />
            <TextView
                android:id="@+id/date"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="日期"
                android:textSize="14sp" />
        </LinearLayout>
        <View
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="金额:"
            android:textSize="14sp" />
        <TextView
            android:id="@+id/date"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="日期"
            android:textSize="14sp" />
            android:layout_height="1px"
            android:layout_marginTop="15dp"
            android:background="#000000" />
    </LinearLayout>
</layout>
    <View
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:layout_marginTop="15dp"
        android:background="#000000" />
</LinearLayout>
app/src/main/res/layout/item_replacement.xml
New file
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="activity"
            type="com.dayu.recharge.activity.ReplacementActivity" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <LinearLayout
            android:id="@+id/item"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:layout_marginTop="10dp"
            android:layout_marginRight="15dp"
            android:onClick="@{ activity.itemClick}"
            android:orientation="vertical">
            <TextView
                android:id="@+id/userName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="用户名"
                android:textSize="14sp" />
            <TextView
                android:id="@+id/userNo"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="户号:123123"
                android:textSize="14sp" />
            <TextView
                android:id="@+id/water"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="水量:123123"
                android:textSize="14sp" />
            <TextView
                android:id="@+id/date"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="日期"
                android:textSize="14sp" />
        </LinearLayout>
        <View
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:layout_marginTop="15dp"
            android:background="#000000" />
    </LinearLayout>
</layout>
app/src/main/res/mipmap-xhdpi/ic_no_more.png
app/src/main/res/values/colors.xml
@@ -20,6 +20,7 @@
    <color name="date_picker_text_dark">#333333</color>
    <color name="ws_pay_alpha">#00000000</color>
    <color name="red">#ff0000</color>
    <color name="white">#FFFFFFFF</color>
    <color name="text_wite">#ffffff</color>
    <color name="choose_grey">#cdcdcd</color>
</resources>
dycz.jks
Binary files differ
easysocket/src/main/java/com/easysocket/connection/connect/SuperConnection.java
@@ -321,6 +321,7 @@
     */
    private IConnectionManager sendBytes(byte[] bytes) {
        if (ioManager == null || connectionStatus.get() != SocketStatus.SOCKET_CONNECTED) {
            LogUtil.w("sendBytes错误-----ioManager为null或者connectionStatus状态不为已连接");
            return this;
        }
        ioManager.sendBytes(bytes);
easysocket/src/main/java/com/easysocket/connection/iowork/EasyReader.java
@@ -10,6 +10,7 @@
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.io.IReader;
import com.easysocket.utils.HexUtil;
import com.easysocket.utils.LogUtil;
import java.io.IOException;
@@ -138,7 +139,7 @@
                    // 保存body
                    originalData.setBodyData(bodyBuf.array());
                    LogUtil.d("Socket收到数据-->" + originalData.getBodyString());
                    LogUtil.d("Socket收到数据-->" +HexUtil.bytesToHex(originalData.getBodyBytes()) );
                    // 分发数据
                    actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, originalData);
@@ -171,7 +172,7 @@
            throw new ReadUnrecoverableException("数据body的长度不能小于0");
        }
        LogUtil.d("Socket收到数据-->" + originalData.getBodyString());
        LogUtil.d("Socket收到数据-->" + HexUtil.bytesToHex(originalData.getBodyBytes()));
        // 分发
        actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, originalData);
@@ -236,7 +237,7 @@
        byte[] data = new byte[len];
        originBuf.get(data, 0, len);
        readData.setBodyData(data);
        LogUtil.d("Socket收到数据-->" + readData.getBodyString());
        LogUtil.d("Socket收到数据-->" + HexUtil.bytesToHex(readData.getBodyBytes()));
        // 分发数据
        actionDispatch.dispatchAction(IOAction.ACTION_READ_COMPLETE, readData);
        // 相当于把指针重新指向positon=0
easysocket/src/main/java/com/easysocket/connection/iowork/EasyWriter.java
@@ -4,6 +4,7 @@
import com.easysocket.interfaces.conn.IConnectionManager;
import com.easysocket.interfaces.conn.ISocketActionDispatch;
import com.easysocket.interfaces.io.IWriter;
import com.easysocket.utils.HexUtil;
import com.easysocket.utils.LogUtil;
import java.io.IOException;
@@ -92,8 +93,8 @@
    @Override
    public void write(byte[] sendBytes) throws IOException {
        if (sendBytes != null) {
            LogUtil.d("Socket发送数据String-->" + new String(sendBytes, Charset.forName("utf-8")));
            LogUtil.d("Socket发送数据byte[]-->" + Arrays.toString(sendBytes));
            LogUtil.d("EasyWriter--Socket发送数据String-->" + HexUtil.bytesToHex(sendBytes));
            LogUtil.d("EasyWriter--Socket发送数据byte[]-->" + Arrays.toString(sendBytes));
            int packageSize = socketOptions.getMaxWriteBytes(); // 每次可以发送的最大数据
            int remainingCount = sendBytes.length;
            ByteBuffer writeBuf = ByteBuffer.allocate(packageSize);
easysocket/src/main/java/com/easysocket/utils/HexUtil.java
New file
@@ -0,0 +1,275 @@
package com.easysocket.utils;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
 * Copyright (C), 2022,
 * Author: zuo
 * Date: 2022/3/9 14:55
 * Description:
 */
public class HexUtil {
    /**
     * hex字符串转byte数组
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte数组结果
     */
    public static byte[] hexToByteArray(String inHex) {
        int hexlen = inHex.length();
        byte[] result;
        if (hexlen % 2 == 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++;
        }
        return result;
    }
    /**
     * Hex字符串转byte
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte
     */
    public static byte hexToByte(String inHex) {
        return (byte) Integer.parseInt(inHex, 16);
    }
    /**
     * 字节转十六进制
     *
     * @param b 需要进行转换的byte字节
     * @return 转换后的Hex字符串
     */
    public static String byteToHex(byte b) {
        String hex = Integer.toHexString(b & 0xFF);
        if (hex.length() < 2) {
            hex = "0" + hex;
        }
        return hex.toUpperCase();
    }
    /**
     * 字节数组转16进制
     *
     * @param bytes 需要转换的byte数组
     * @return 转换后的Hex字符串
     */
    public static String bytesToHex(byte[] bytes) {
        try {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(bytes[i] & 0xFF);
                if (hex.length() < 2) {
                    sb.append(0);
                }
                sb.append(hex);
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
    public static String byteArrayToHexString(byte[] byteArray) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : byteArray) {
            // 将字节转换为无符号整数
            int unsignedInt = b & 0xff;
            // 将无符号整数转换为16进制字符串
            String hex = Integer.toHexString(unsignedInt);
            // 如果字符串长度小于2,在前面补0
            if (hex.length() < 2) {
                hex = "0" + hex;
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
    /**
     * 字节数组转16进制 不在末尾添加0
     *
     * @param bytes 需要转换的byte数组
     * @return 转换后的Hex字符串
     */
    public static String bytesToHexNoAddZero(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            sb.append(hex);
        }
        return sb.toString();
    }
    /**
     * 将 4字节的16进制字符串,转换为32位带符号的十进制浮点型
     *
     * @param str 4字节 16进制字符
     * @return
     */
    public static float hexToFloat(String str) {
        return Float.intBitsToFloat(new BigInteger(str, 16).intValue());
    }
    /**
     * 将带符号的32位浮点数装换为16进制
     *
     * @param value
     * @return
     */
    public static String folatToHexString(Float value) {
        return Integer.toHexString(Float.floatToIntBits(value));
    }
    /**
     * 十进制转16进制
     *
     * @param number
     * @return
     */
    public static String get10to16(int number) {
        return Integer.toHexString(number);
    }
    /**
     * 十进制转16进制 补齐偶数 高位在前低位在后
     *
     * @param number
     * @return
     */
    public static String get10to16CompleteHex(int number) {
        String hex = Integer.toHexString(number);
        if (hex.length() % 2 == 0) {
            return hex;
        } else {
            return "0" + hex;
        }
    }
    /**
     * 十进制转16进制低位在前高位在后
     *
     * @param number 十进制数
     * @param length 补足多少位
     * @return
     */
    public static String get10to16LowHigh(int number, int length) {
        String str = "";
        try {
            str = Integer.toHexString(number);
            str = getHexToLenght(str, length);
            str = spaceHex(str);
            str = HighLowHex(str);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }
    /**
     * 16进制转10进制高低位转换
     *
     * @param hex
     * @return
     */
    public static int get16to10LowHigh(String hex) {
        try {
            String str = "";
            str = spaceHex(hex);
            str = HighLowHex(str);
            return Integer.parseInt(str, 16);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return 0;
    }
    /**
     * 返回特定长度的16进制字符串
     *
     * @param data
     * @param length
     * @return
     */
    public static String getHexToLenght(String data, int length) {
        StringBuffer stringBuilder = new StringBuffer(data);
        for (int i = 0; i < length - data.length(); i++) {
            stringBuilder.insert(0, "0");
        }
        return stringBuilder.toString();
    }
    /**
     * 十六进制数隔空位
     *
     * @param str
     * @return
     */
    public static String spaceHex(String str) {
        char[] array = str.toCharArray();
        if (str.length() <= 2) return str;
        StringBuffer bufferHex = new StringBuffer();
        for (int i = 0; i < array.length; i++) {
            int start = i + 1;
            if (start % 2 == 0) {
                bufferHex.append(array[i]).append(" ");
            } else {
                bufferHex.append(array[i]);
            }
        }
        return bufferHex.toString();
    }
    /**
     * 高位16进制转低位
     *
     * @param str
     * @return
     */
    private static String HighLowHex(String str) {
        if (str.trim().length() <= 2) return str;
        List<String> list = Arrays.asList(str.split(" "));
        Collections.reverse(list);
        StringBuffer stringBuffer = new StringBuffer();
        for (String string : list) {
            stringBuffer.append(string);
        }
        return stringBuffer.toString();
    }
    /**
     * @param hex
     * @return
     */
    public static int get16to10(String hex) {
        int x = 0;
        try {
            x = Integer.parseInt(hex, 16);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return x;
    }
}
gradlew
@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
#
##############################################################################
##
##  Gradle start up script for UN*X
##
#
#   Gradle start up script for POSIX generated by Gradle.
#
#   Important for running:
#
#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
#       noncompliant, but you have some other compliant shell such as ksh or
#       bash, then to run this script, type that shell name before the whole
#       command line, like:
#
#           ksh Gradle
#
#       Busybox and similar reduced shells will NOT work, because this script
#       requires all of these POSIX shell features:
#         * functions;
#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
#         * compound commands having a testable exit status, especially «case»;
#         * various built-in commands including «command», «set», and «ulimit».
#
#   Important for patching:
#
#   (2) This script targets any POSIX shell, so it avoids extensions provided
#       by Bash, Ksh, etc; in particular arrays are avoided.
#
#       The "traditional" practice of packing multiple parameters into a
#       space-separated string is a well documented source of bugs and security
#       problems, so this is (mostly) avoided, by progressively accumulating
#       options in "$@", and eventually passing that to Java.
#
#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
#       see the in-line comments for details.
#
#       There are tweaks for specific operating systems such as AIX, CygWin,
#       Darwin, MinGW, and NonStop.
#
#   (3) This script is generated from the Groovy template
#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
#       within the Gradle project.
#
#       You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
app_path=$0
# Need this for daisy-chained symlinks.
while
    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
    [ -h "$app_path" ]
do
    ls=$( ls -ld "$app_path" )
    link=${ls#*' -> '}
    case $link in             #(
      /*)   app_path=$link ;; #(
      *)    app_path=$APP_HOME$link ;;
    esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
    echo "$*"
}
} >&2
die () {
    echo
    echo "$*"
    echo
    exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
  NONSTOP* )
    nonstop=true
    ;;
case "$( uname )" in                #(
  CYGWIN* )         cygwin=true  ;; #(
  Darwin* )         darwin=true  ;; #(
  MSYS* | MINGW* )  msys=true    ;; #(
  NONSTOP* )        nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
        JAVACMD=$JAVA_HOME/jre/sh/java
    else
        JAVACMD="$JAVA_HOME/bin/java"
        JAVACMD=$JAVA_HOME/bin/java
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@
location of your Java installation."
    fi
else
    JAVACMD="java"
    JAVACMD=java
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,101 @@
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`
    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=`expr $i + 1`
    done
    case $i in
        0) set -- ;;
        1) set -- "$args0" ;;
        2) set -- "$args0" "$args1" ;;
        3) set -- "$args0" "$args1" "$args2" ;;
        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
    case $MAX_FD in #(
      max*)
        MAX_FD=$( ulimit -H -n ) ||
            warn "Could not query maximum file descriptor limit"
    esac
    case $MAX_FD in  #(
      '' | soft) :;; #(
      *)
        ulimit -n "$MAX_FD" ||
            warn "Could not set maximum file descriptor limit to $MAX_FD"
    esac
fi
# Escape application args
save () {
    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
    echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
#   * args from the command line
#   * the main class name
#   * -classpath
#   * -D...appname settings
#   * --module-path (only if needed)
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
    JAVACMD=$( cygpath --unix "$JAVACMD" )
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    for arg do
        if
            case $arg in                                #(
              -*)   false ;;                            # don't mess with options #(
              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
                    [ -e "$t" ] ;;                      #(
              *)    false ;;
            esac
        then
            arg=$( cygpath --path --ignore --mixed "$arg" )
        fi
        # Roll the args list around exactly as many times as the number of
        # args, so each arg winds up back in the position where it started, but
        # possibly modified.
        #
        # NB: a `for` loop captures its iteration list before it begins, so
        # changing the positional parameters here affects neither the number of
        # iterations, nor the values presented in `arg`.
        shift                   # remove old arg
        set -- "$@" "$arg"      # push replacement arg
    done
fi
# Collect all arguments for the java command;
#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
#     shell script including quotes and variable substitutions, so put them in
#     double quotes to make sure that they get re-expanded; and
#   * put everything else in single quotes, so that it's not re-expanded.
set -- \
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
        -classpath "$CLASSPATH" \
        org.gradle.wrapper.GradleWrapperMain \
        "$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
    die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
#   set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
        xargs -n1 |
        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
        tr '\n' ' '
    )" '"$@"'
exec "$JAVACMD" "$@"
gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +40,7 @@
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +75,15 @@
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
local.properties
@@ -4,5 +4,6 @@
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Thu Dec 14 09:58:29 CST 2023
sdk.dir=D\:\\AndroidStudio\\sdk
#Tue Dec 19 11:21:25 CST 2023
sdk.dir=D\:\\android\\sdk
ndk.dir=D\:\\android\\sdk\\ndk\\android-ndk-r21