左晓为主开发手持机充值管理机
feat(generallibrary): 新增主界面和相关功能模块
- 新增 MainActivity 作为主界面,包含三个底部导航栏选项卡- 新增 BSCardFragment、RechargeFragment 和 MyFragment 作为三个选项卡对应的页面
- 新增 NewCardActivity 用于新建卡片
- 新增 AreaCard 类用于处理区域表号卡数据
- 新增 BaseCard 类作为卡片数据的基础类
- 新增 TabAdapter 用于管理选项卡页面
- 更新 AndroidManifest.xml 设置主活动为 MainActivity
- 更新 build.gradle 添加 generallibrary 依赖
20个文件已修改
35个文件已添加
3901 ■■■■■ 已修改文件
app/build.gradle 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/AndroidManifest.xml 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNFCHelper.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcWriteHelper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NFCCallBack.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcWriteHelper.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcWriteAdapter.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/CMakeLists.txt 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/build.gradle 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/AndroidManifest.xml 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/cpp/general-native-lib.cpp 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/BSCardFragment.kt 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/BaseActivity.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/MainActivity.kt 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/MyFragment.kt 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/NewCardActivity.kt 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/RechargeFragment.kt 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/adapter/TabAdapter.kt 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/AreaCard.kt 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/BaseCard.kt 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/CardCommon.kt 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/CheckCard.kt 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/ClearCard.kt 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/DebugCard.kt 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/DomainSettingCard.kt 213 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/FetchDataCard.kt 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/GpsCard.kt 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/IpSettingCard.kt 219 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/UserCard.kt 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/ValveTimeCard.kt 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/db/CardData.kt 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/db/PassWordCardBean.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/dao/AppDataBase.kt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/dao/BaseDaoSingleton.kt 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/dao/CardDataDao.kt 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/tool/GeBaseHelper.kt 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/bottom_circle_bg.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/bottom_nav_background.xml 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/fab_background.xml 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/nav_item_color.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/ripple_effect.xml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/rounded_button_bg.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/shadow_gradient.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/shadow_gradient_strong.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/tab_indicator.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/tab_ripple_effect.xml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/activity_main.xml 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/activity_new_card_ge.xml 311 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/fragment_card.xml 341 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/fragment_my.xml 355 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/fragment_recharge.xml 400 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/values/colors.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/values/dimens.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
henanlibrary/src/main/java/com/dayu/henanlibrary/tools/NFCWriteHelper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/build.gradle
@@ -75,6 +75,7 @@
    implementation project(':baselibrary')
    implementation project(':qihealonelibrary')
    implementation project(':qiheonlinelibrary')
    implementation project(':generallibrary')
    implementation 'com.tencent.bugly:crashreport:4.1.9.3'
//    处理图片
app/src/main/AndroidManifest.xml
@@ -41,15 +41,22 @@
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
<!--        <activity-->
<!--            android:name="com.dayu.recharge.activity.LoginActivity"-->
<!--            android:exported="true">-->
<!--            <intent-filter>-->
<!--                <action android:name="android.intent.action.MAIN" />-->
<!--                <category android:name="android.intent.category.LAUNCHER" />-->
<!--            </intent-filter>-->
<!--        </activity>-->
        <activity
            android:name="com.dayu.recharge.activity.LoginActivity"
            android:name="com.dayu.general.activity.MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data
            android:name="BUGLY_APP_VERSION"
            android:value="7.1" />
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNFCHelper.java
@@ -22,10 +22,14 @@
    public static byte[] companyKey;
    /**
     * 密码集合
     * 扇区都为统一密码时集合
     */
    public static List<byte[]> listKeyA = new ArrayList<>();
    /**
     * 每个扇区密码不同时集合
     */
    public static List<byte[]> listA_PS=new ArrayList<>();
    //密码a区
    public static String companyKeyA;
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcWriteHelper.java
@@ -30,6 +30,8 @@
    public abstract boolean writeData(byte[] str, int a, int b);
    public abstract boolean writeData(byte[] str, int a, int b,NFCCallBack callBack);
    /**
     * 修改密码
     *
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NFCCallBack.java
New file
@@ -0,0 +1,17 @@
package com.dayu.baselibrary.tools.nfc;
/**
 * NFCCallBack -
 *
 * @author zuoxiao
 * @version 1.0
 * @since 2025-03-03
 */
public interface NFCCallBack {
    /**
     * 返回是否成功
     *
     * @param msg
     */
    void isSusses(boolean flag,String msg);
}
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java
@@ -53,6 +53,7 @@
     *
     * @return
     */
    @Override
    public BaseUserCardCard getUserCardData(BaseUserCardCard userCardCard) {
        if (userCardCard!=null){
            BaseUserCardCard userCard = null;
@@ -117,6 +118,7 @@
        return null;
    }
    @Override
    public String getCradType() {
        MifareClassic mfc = MifareClassic.get(tag);
@@ -161,6 +163,7 @@
     *
     * @param callback
     */
    @Override
    public void getAllData(final NFCCallMapback callback) {
        Map<String, List<byte[]>> map = new HashMap<>();
        MifareClassic mfc = MifareClassic.get(tag);
@@ -232,6 +235,7 @@
     *
     * @param callback
     */
    @Override
    public void getOneSectorData(NFCCallListback callback) {
@@ -305,6 +309,7 @@
     * @param b        块
     * @param callback
     */
    @Override
    public void getData(final int a, final int b, final NFCCallByteback callback) {
        new Thread(new Runnable() {
            @Override
@@ -543,6 +548,7 @@
     *
     * @return
     */
    @Override
    public BaseManagerToUserCard getManagerToUserCardData(BaseManagerToUserCard baseManagerToUserCard) {
        BaseManagerToUserCard managerToUserCard = null;
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcWriteHelper.java
@@ -47,6 +47,7 @@
     * @param userCard 用户卡内容
     * @param
     */
    @Override
    public boolean writeUserData(BaseUserCardCard userCard) {
        if (userCard != null) {
            int a = 1;
@@ -113,7 +114,13 @@
     * @param b   书写的块(从0开始数)
     * @param
     */
    @Override
    public boolean writeData(byte[] str, int a, int b) {
        return writeData(str, a, b, null);
    }
    @Override
    public boolean writeData(byte[] str, int a, int b, NFCCallBack callBack) {
        Log.i("NFCWreatActivity", "writeData: a=" + a + " b=" + b);
        if (str.length <= 16) {
            try {
@@ -126,35 +133,87 @@
                        int count = mfc.getSectorCount();
                        //如果传进来的扇区大了或者小了直接退出方法
                        if (a > count - 1 || a < 0) {
                            if (callBack != null) {
                                callBack.isSusses(false, "扇区错误--" + a);
                            }
                            return false;
                        }
                        //获取写的扇区的块的数量
                        int bCount = mfc.getBlockCountInSector(a);
                        //如果输入的块大了或者小了也是直接退出
                        if (b > bCount - 1 || b < 0) {
                            if (callBack != null) {
                                callBack.isSusses(false, "块区错误--" + b);
                            }
                            return false;
                        }
                        //验证扇区密码
                        boolean isOpen = false;
                        for (int i = 0; i < listKeyA.size(); i++) {
                            if (mfc.authenticateSectorWithKeyA(0, listKeyA.get(i))) {
                        if (listKeyA.size() != 0) {
                            for (int i = 0; i < listKeyA.size(); i++) {
                                if (mfc.authenticateSectorWithKeyA(0, listKeyA.get(i))) {
                                    isOpen = true;
                                    if (listKeyA.get(i).equals(defauleKey)) {
                                        //当前为默认白卡密码时写卡时修改密码
                                        changePasword(a, mfc);
                                    }
                                    break;
                                }
                            }
                        } else if (listA_PS.size() != 0 && listA_PS.size() > a) {
                            if (mfc.authenticateSectorWithKeyA(0, listA_PS.get(a))) {
                                isOpen = true;
                                if (listKeyA.get(i).equals(defauleKey)) {
                                if (listKeyA.get(a).equals(defauleKey)) {
                                    //当前为默认白卡密码时写卡时修改密码
                                    changePasword(a, mfc);
                                }
                                break;
                            }
                        }
                        if (isOpen) {
                            int bIndex = mfc.sectorToBlock(a);
                            //写卡
                            mfc.writeBlock(bIndex + b, str);
                            return true;
                            // 校验写入数据是否正确
                            boolean isVerified = true;
                            // 读取数据验证
                            byte[] readResult = mfc.readBlock(bIndex + b);
                            if (readResult == null) {
                                if (callBack != null) {
                                    callBack.isSusses(false, a + "扇区写卡时再次读取验证时失败");
                                }
                                return false;
                            }
                            for (int i = 0; i < str.length; i++) {
                                if (str[i] != readResult[i]) {
                                    isVerified = false;
                                    break;
                                }
                            }
                            if (isVerified) {
                                if (callBack != null) {
                                    callBack.isSusses(true, "写入成功并验证通过");
                                }
                                return true;
                            } else {
                                if (callBack != null) {
                                    callBack.isSusses(false, "写入验证失败");
                                }
                                return false;
                            }
                        }
                        if (callBack != null) {
                            callBack.isSusses(false, a + "扇区密码错误");
                        }
                        return false;
                    } catch (Exception e) {
                        e.printStackTrace();
                        if (callBack != null) {
                            callBack.isSusses(false, a + "扇区写卡报错" + e.getMessage());
                        }
                        return false;
                    } finally {
                        try {
@@ -179,12 +238,12 @@
     * @param a 书写的扇区
     *          //     * @param callback 返回监听
     */
    @Override
    public boolean changePasword(int a, MifareClassic mfc) {
        byte[] data = new byte[16];
        if (null != mfc) {
            try {
                //将密码转换为keyA
                byte[] dataA = HexUtil.hexToByteArray(companyKeyA);
                for (int i = 0; i < dataA.length; i++) {
@@ -218,6 +277,7 @@
     *
     * @return
     */
    @Override
    public boolean initCard() {
        try {
            MifareClassic mfc = MifareClassic.get(tag);
@@ -278,4 +338,6 @@
        }
        return false;
    }
}
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcWriteAdapter.java
@@ -16,19 +16,20 @@
 */
public class NfcWriteAdapter extends BaseNfcWriteHelper {
    NativeNfcWriteHelper nativeNfcWriteHelper;
    public NfcWriteAdapter(Intent intent, Activity activity) {
        switch (BaseNfcActivity.adapterType){
        switch (BaseNfcActivity.adapterType) {
            case ModelUtils.defaultType:
                nativeNfcWriteHelper=new NativeNfcWriteHelper(intent,activity);
                nativeNfcWriteHelper = new NativeNfcWriteHelper(intent, activity);
                break;
        }
    }
    @Override
    public boolean writeUserData(BaseUserCardCard userCard) {
        switch (BaseNfcActivity.adapterType){
        switch (BaseNfcActivity.adapterType) {
            case ModelUtils.defaultType:
                return  nativeNfcWriteHelper.writeUserData(userCard);
                return nativeNfcWriteHelper.writeUserData(userCard);
        }
        return false;
@@ -36,9 +37,19 @@
    @Override
    public boolean writeData(byte[] str, int a, int b) {
        switch (BaseNfcActivity.adapterType){
        switch (BaseNfcActivity.adapterType) {
            case ModelUtils.defaultType:
                return  nativeNfcWriteHelper.writeData(str,a,b);
                return nativeNfcWriteHelper.writeData(str, a, b);
        }
        return false;
    }
    @Override
    public boolean writeData(byte[] str, int a, int b, NFCCallBack callBack) {
        switch (BaseNfcActivity.adapterType) {
            case ModelUtils.defaultType:
                return nativeNfcWriteHelper.writeData(str, a, b,callBack);
        }
        return false;
@@ -46,9 +57,9 @@
    @Override
    public boolean changePasword(int a, MifareClassic mfc) {
        switch (BaseNfcActivity.adapterType){
        switch (BaseNfcActivity.adapterType) {
            case ModelUtils.defaultType:
                return  nativeNfcWriteHelper.changePasword(a,mfc);
                return nativeNfcWriteHelper.changePasword(a, mfc);
        }
        return false;
generallibrary/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.
        general-native-lib
             # Sets the library as a shared library.
             SHARED
             # Provides a relative path to your source file(s).
             src/main/cpp/general-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.
        general-native-lib
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )
generallibrary/build.gradle
@@ -8,7 +8,7 @@
    compileSdk 34
    defaultConfig {
        minSdk 24
        minSdk 23
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles "consumer-rules.pro"
@@ -27,14 +27,25 @@
    kotlinOptions {
        jvmTarget = '1.8'
    }
    dataBinding {
        enabled = true;
    }
    viewBinding {
        enabled = true;
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}
dependencies {
    implementation project(":baselibrary")
    implementation 'androidx.core:core-ktx:1.15.0'
    implementation 'androidx.appcompat:appcompat:1.7.0'
    implementation 'com.google.android.material:material:1.12.0'
    implementation 'androidx.core:core-ktx:1.12.0'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.11.0'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.2.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
@@ -62,7 +73,14 @@
    implementation 'com.pnikosis:materialish-progress:1.7'
    //列表
    compileOnly 'io.github.scwang90:refresh-layout-kernel:2.0.5'
    compileOnly 'io.github.scwang90:refresh-header-classics:2.0.5'
    compileOnly 'androidx.recyclerview:recyclerview:1.2.0'//经典刷新头
    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.3.2'
    //建议添加 ViewPager2 的明确依赖
    implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
    implementation "androidx.fragment:fragment:1.6.2"
    implementation files('../baselibrary/libs/avi.library-2.1.3.aar')
    implementation 'com.tencent.bugly:crashreport:4.1.9.3'
}
generallibrary/src/main/AndroidManifest.xml
@@ -1,4 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.dayu.henanlibrary">
    <uses-permission android:name="android.permission.NFC" />
    <!--用于访问网络,网络定位需要上网-->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- 要求当前设备必须要有NFC芯片 -->
    <uses-feature
        android:name="android.hardware.nfc"
        android:required="true" />
    <!--    <intent-filter>-->
    <!--        <action android:name="android.nfc.action.TAG_DISCOVERED" />-->
    <!--        <data android:mimeType="text/plain" />-->
    <!--    </intent-filter>-->
    <!--用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
    <!--用于访问GPS定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
    <!--用于获取运营商信息,用于支持提供运营商信息相关的接口-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
    <!--用于访问wifi网络信息,wifi信息会用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
    <!--用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
    <!--用于读取手机当前的状态-->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
    <!--用于写入缓存数据到扩展存储卡-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <!--用于申请调用A-GPS模块-->
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"></uses-permission>
    <application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <!--        <activity-->
        <!--            android:name="com.dayu.recharge.activity.LoginActivity"-->
        <!--            android:exported="true">-->
        <!--            <intent-filter>-->
        <!--                <action android:name="android.intent.action.MAIN" />-->
        <!--                <category android:name="android.intent.category.LAUNCHER" />-->
        <!--            </intent-filter>-->
        <!--        </activity>-->
        <activity android:name="com.dayu.general.activity.NewCardActivity" />
        <meta-data
            android:name="BUGLY_APP_VERSION"
            android:value="7.1" />
    </application>
</manifest>
generallibrary/src/main/cpp/general-native-lib.cpp
New file
@@ -0,0 +1,135 @@
#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 unsigned char XOR_KEY[] = {0x7A, 0xB3, 0xC9, 0xD5, 0xE1, 0xF8, 0x42, 0x91, 0x37, 0x8F, 0x5D,
                                 0x2E};
// 加密后的M1卡密码数组
const unsigned char ENCRYPTED_SECTOR_KEYS[] = {
        // 扇区0密码 (加密后)
        0x9C, 0x45, 0x36, 0x55, 0x8C, 0x7F, 0x35, 0x93, 0x4B, 0x78, 0x2A, 0x79,
        // 扇区1密码 (加密后)
        0xB4, 0x52, 0x91, 0x45, 0x99, 0x87, 0x3C, 0xA3, 0x6E, 0x5F, 0x1D, 0x5E,
        // 以下类似格式存储其他扇区密码...
        0x1E, 0x85, 0xEB, 0x51, 0xB9, 0x39, 0x02, 0x2E, 0x77, 0x1F, 0x3E, 0x93,
        0x22, 0x62, 0xBD, 0x83, 0x99, 0x2A, 0x2F, 0x19, 0x95, 0x07, 0x29, 0x2E,
        0x90, 0x18, 0xE0, 0x6A, 0xB7, 0x68, 0x34, 0x89, 0x42, 0x5B, 0x16, 0x47,
        0xA8, 0x0B, 0xB5, 0x97, 0xB4, 0x43, 0x1D, 0x62, 0x89, 0x73, 0x33, 0x2E,
        0x24, 0x9D, 0xB7, 0x46, 0x8D, 0x64, 0x49, 0x7A, 0x52, 0x41, 0x1C, 0x91,
        0x31, 0x78, 0x95, 0x52, 0x95, 0x39, 0x19, 0x4C, 0x81, 0x2A, 0x0D, 0x47,
        0xF5, 0x64, 0xA7, 0x93, 0xB9, 0x51, 0x27, 0x82, 0x43, 0x68, 0x31, 0x3F,
        0x55, 0x93, 0xB7, 0x68, 0x97, 0x9A, 0x37, 0x71, 0x52, 0x49, 0x17, 0x1E,
        0x8E, 0x93, 0xB5, 0x44, 0x8D, 0x42, 0x22, 0x84, 0x95, 0x33, 0x22, 0x93,
        0x42, 0x82, 0xA3, 0x35, 0x91, 0x33, 0x13, 0x93, 0x71, 0x21, 0x01, 0x71,
        0x37, 0x9F, 0xA6, 0x68, 0x92, 0x86, 0x46, 0x72, 0x43, 0x62, 0x12, 0x52,
        0x5D, 0x85, 0x93, 0x86, 0x82, 0x46, 0x31, 0x86, 0x57, 0x48, 0x16, 0x88,
        0x97, 0x73, 0xB5, 0x47, 0x95, 0x55, 0x36, 0x69, 0x49, 0x58, 0x18, 0x6A,
        0xEA, 0x46, 0x84, 0x93, 0x82, 0x19, 0x29, 0x91, 0x31, 0x1C, 0x0C, 0x7D
};
// 解密函数
void decrypt_key(const unsigned char *encrypted, char *decrypted, size_t len) {
    for (size_t i = 0; i < len; i++) {
        decrypted[i] = encrypted[i] ^ XOR_KEY[i % sizeof(XOR_KEY)];
    }
    decrypted[len] = '\0';
}
//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 JNICALL
Java_com_dayu_general_tool_GeBaseHelper_getM1SectorKeySecure(JNIEnv *env, jobject instance,
                                                             jobject contextObject,
                                                             jint sectorIndex) {
    // 获取包管理器相关方法ID
    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, "M1Card", "Current signature: %s", signStrng);
    // 验证签名并返回所有扇区密码
    if (strcmp(signStrng, RELEASE_SIGN) == 0) {
        size_t numKeys = sizeof(ENCRYPTED_SECTOR_KEYS) / 12; // 每个密钥12字节
        char *allKeys = new char[numKeys * 13]; // 为每个密钥预留12个字符+1个分隔符
        allKeys[0] = '\0';
        for (size_t i = 0; i < numKeys; i++) {
            char decrypted[13];
            decrypt_key(ENCRYPTED_SECTOR_KEYS + (i * 12), decrypted, 12);
            strcat(allKeys, decrypted);
            if (i < numKeys - 1) {
                strcat(allKeys, ",");
            }
        }
        jstring result = (env)->NewStringUTF(allKeys);
        delete[] allKeys;
        return result;
    } else {
        return (env)->NewStringUTF("signature_verification_failed");
    }
}
generallibrary/src/main/java/com/dayu/general/activity/BSCardFragment.kt
@@ -1,9 +1,37 @@
package com.dayu.general.activity
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.dayu.general.databinding.FragmentCardBinding
import com.tencent.bugly.proguard.v
class BSCardFragment :Fragment() {
    private var binding: FragmentCardBinding? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentCardBinding.inflate(LayoutInflater.from(context), container, false)
        initView()
        return binding?.root
    }
    private fun initView() {
        binding?.homeNewCard?.setOnClickListener {
            val intent = Intent(context, NewCardActivity::class.java)
            startActivity(intent)
        }
    }
}
}
generallibrary/src/main/java/com/dayu/general/activity/BaseActivity.kt
@@ -12,7 +12,7 @@
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        asynchBaseDao=BaseDaoSingleton.getAsynchInstance(this);
//        asynchBaseDao=BaseDaoSingleton.getAsynchInstance(this);
    }
generallibrary/src/main/java/com/dayu/general/activity/MainActivity.kt
@@ -1,28 +1,118 @@
package com.dayu.general.activity
import android.os.Bundle
import android.view.LayoutInflater
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.dayu.general.R
import com.dayu.general.adapter.TabAdapter
import com.dayu.general.databinding.ActivityMainBinding
class MainActivity : BaseActivity(){
class MainActivity : BaseActivity() {
    var binding: ActivityMainBinding? = null
    private val fragments: ArrayList<Fragment> = ArrayList()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setupFragments();
        binding = ActivityMainBinding.inflate(LayoutInflater.from(this))
        setContentView(binding?.root)
        setupFragments()
        initView()
        initTab()
    }
    private fun initView() {
        binding!!.BSCardLL.setOnClickListener { v -> changeBottomState(Tab.BSC) }
        binding!!.rechargeLL.setOnClickListener { v -> changeBottomState(Tab.RECHARGE) }
        binding!!.myLL.setOnClickListener { v -> changeBottomState(Tab.MY) }
    }
    private fun setupFragments() {
        fragments.add(BSCardFragment())
        fragments.add(RechargeFragment())
        fragments.add(BSCardFragment())
        fragments.add(MyFragment())
    }
    private fun initTab() {
        binding?.viewPager?.adapter = TabAdapter(this, fragments)
        binding?.viewPager?.currentItem = (1)
        binding?.viewPager?.offscreenPageLimit = 3
        binding?.viewPager?.isUserInputEnabled = false
    }
    private enum class Tab {
        BSC, RECHARGE, MY
    }
    /**
     * 修改底部状态
     */
    private fun changeBottomState(tab: Tab) {
        resetTabState()
        when (tab) {
            Tab.BSC -> updateTabUI(0, R.drawable.bottom_card_white, R.color.white)
            Tab.RECHARGE -> updateTabUI(1, R.drawable.bottom_recharge_white, R.color.white)
            Tab.MY -> updateTabUI(2, R.drawable.bottom_my_white, R.color.white)
        }
    }
    /**
     * 重置所有 Tab 的默认状态
     */
    private fun resetTabState() {
        binding!!.BSCardImg.setImageDrawable(
            ContextCompat.getDrawable(
                this,
                R.drawable.bottom_card_black
            )
        )
        binding!!.BSCardText.setTextColor(ContextCompat.getColor(this, R.color.black))
        binding!!.rechargeImg.setImageDrawable(
            ContextCompat.getDrawable(
                this,
                R.drawable.bottom_recharge_black
            )
        )
        binding!!.rechargeText.setTextColor(ContextCompat.getColor(this, R.color.black))
        binding!!.myImg.setImageDrawable(
            ContextCompat.getDrawable(
                this,
                R.drawable.bottom_my_black
            )
        )
        binding!!.myText.setTextColor(ContextCompat.getColor(this, R.color.black))
    }
    /**
     * 更新某个 Tab 的 UI 状态
     */
    private fun updateTabUI(position: Int, iconResId: Int, textColorResId: Int) {
        if (position == 1) {
            binding!!.viewPager.setCurrentItem(position, true)
        } else {
            binding!!.viewPager.setCurrentItem(position, false)
        }
        when (position) {
            0 -> {
                binding!!.BSCardImg.setImageDrawable(ContextCompat.getDrawable(this, iconResId))
                binding!!.BSCardText.setTextColor(ContextCompat.getColor(this, textColorResId))
            }
            1 -> {
                binding!!.rechargeImg.setImageDrawable(ContextCompat.getDrawable(this, iconResId))
                binding!!.rechargeText.setTextColor(ContextCompat.getColor(this, textColorResId))
            }
            2 -> {
                binding!!.myImg.setImageDrawable(ContextCompat.getDrawable(this, iconResId))
                binding!!.myText.setTextColor(ContextCompat.getColor(this, textColorResId))
            }
        }
    }
}
generallibrary/src/main/java/com/dayu/general/activity/MyFragment.kt
@@ -1,8 +1,20 @@
package com.dayu.general.activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.dayu.general.databinding.FragmentMyBinding
class MyFragment:Fragment() {
class MyFragment : Fragment() {
    var binding: FragmentMyBinding? = null;
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentMyBinding.inflate(inflater, container, false)
        return binding?.root
    }
}
generallibrary/src/main/java/com/dayu/general/activity/NewCardActivity.kt
New file
@@ -0,0 +1,16 @@
package com.dayu.general.activity
import android.os.Bundle
import android.view.LayoutInflater
import com.dayu.baselibrary.activity.BaseActivity
import com.dayu.general.databinding.ActivityNewCardGeBinding
class NewCardActivity:BaseActivity() {
    var binding:ActivityNewCardGeBinding? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding=  ActivityNewCardGeBinding.inflate(LayoutInflater.from(this))
        setContentView(binding?.root)
    }
}
generallibrary/src/main/java/com/dayu/general/activity/RechargeFragment.kt
@@ -1,6 +1,21 @@
package com.dayu.general.activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.dayu.general.databinding.FragmentRechargeBinding
class RechargeFragment:Fragment() {
class RechargeFragment : Fragment() {
    var binding: FragmentRechargeBinding? = null
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentRechargeBinding.inflate(inflater, container, false)
        return binding?.root;
    }
}
generallibrary/src/main/java/com/dayu/general/adapter/TabAdapter.kt
New file
@@ -0,0 +1,21 @@
package com.dayu.general.adapter
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
/**
 * author: zuo
 * Date: 2023/12/19
 * Time: 17:53
 * 备注:
 */
class TabAdapter(
    fragmentActivity: FragmentActivity,
    private val fragments: List<Fragment>
) : FragmentStateAdapter(fragmentActivity) {
    override fun createFragment(position: Int): Fragment = fragments[position]
    override fun getItemCount(): Int = fragments.size
}
generallibrary/src/main/java/com/dayu/general/bean/card/AreaCard.kt
New file
@@ -0,0 +1,105 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.BcdUtil
import com.dayu.baselibrary.tools.HexUtil
import java.io.Serializable
/**
 * 区域表号卡
 * 用于配置控制器的行政区域号,达到只有区域内用户才能刷卡操作的目的
 */
class AreaCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B0"  // 卡类型固定为0xB0
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
    }
    var areaNumber: Int = 0     // 国家行政区域号(12位BCD,精确到村)
    var projectCode: Int = 0    // 项目编码(HEX 1-255)
    /**
     * 写卡完成后校验是否写卡成功
     */
    fun equalsAreaCard(data: List<ByteArray>?): Boolean {
        if (data == null || data.isEmpty()) {
            return false
        }
        return data[0].contentEquals(getZeroBytes())
    }
    /**
     * 通过byte转bean
     */
    fun getBean(data: List<ByteArray>): AreaCard? {
        try {
            val areaCard = AreaCard()
            // 解析第0块
            val zero = data[0]
            // 解析国家行政区域号(0-5位)
            val areaCodeBytes = zero.copyOfRange(0, 6)
            areaCard.areaNumber = BcdUtil.bcdToStr(areaCodeBytes).toInt()
            // 解析项目编码(6位)
            areaCard.projectCode = HexUtil.get16To10LowHightByBytes(byteArrayOf(zero[6]))
            // 验证卡类型和识别码
            if (HexUtil.byteToHex(zero[8]) != CARD_TYPE ||
                zero[9] != IDENTIFY_CODE_A0 ||
                zero[10] != IDENTIFY_CODE_B1 ||
                zero[11] != IDENTIFY_CODE_C2 ||
                zero[12] != IDENTIFY_CODE_89) {
                return null
            }
            return areaCard
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }
    /**
     * 生成第0块数据
     */
    inner class Zero : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 设置国家行政区域号(BCD格式,6字节,0-5位)
                val areaCodeBytes = BcdUtil.strToBcd(String.format("%012d", areaNumber))
                System.arraycopy(areaCodeBytes, 0, data, 0, 6)
                // 设置项目编码(6位)
                data[6] = projectCode.toByte()
                // 设置备用位(7位)
                data[7] = 0x00
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(CARD_TYPE)
                // 设置识别码(9-12位)
                data[9] = IDENTIFY_CODE_A0
                data[10] = IDENTIFY_CODE_B1
                data[11] = IDENTIFY_CODE_C2
                data[12] = IDENTIFY_CODE_89
                // 设置备用位(13-14位)
                data[13] = 0x00
                data[14] = 0x00
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
}
generallibrary/src/main/java/com/dayu/general/bean/card/BaseCard.kt
New file
@@ -0,0 +1,48 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.dao.AppDatabase
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.bean.db.CardData
import com.dayu.general.dao.AppDataBase
import com.tencent.bugly.crashreport.CrashReport
open class BaseCard {
    var cardData: String? = null //标识码
    fun setCardData(baseDao: AppDataBase, cardType: String?) {
        try {
            val cardDataBean: CardData =
                baseDao.cardDataDao().findFirst(cardType)
            cardData = if (cardDataBean != null) {
                cardDataBean.cardIdentifying
            } else {
                CardCommon.getDefaultCardData(cardType)
            }
        } catch (e: Exception) {
            CrashReport.postCatchedException(e)
        }
    }
    /**
     * 前15个字节算术累加和 不含进位
     *
     * @param data 源数据
     * @return 16进制
     */
    fun getByteSum(data: ByteArray?): Byte {
        if (data != null) {
            var sum = 0
            for (b in data) {
                sum += b.toInt() and 0xFF // & 0xFF 可以将字节扩展为正整数,避免符号位的影响
            }
            var hex = HexUtil.get10to16CompleteHex(sum)
            hex = HexUtil.spaceHex(hex)
            val hexArr = hex.split(" ".toRegex()).dropLastWhile { it.isEmpty() }
                .toTypedArray()
            return HexUtil.hexToByte(hexArr[hexArr.size - 1])
        }
        return 0
    }
}
generallibrary/src/main/java/com/dayu/general/bean/card/CardCommon.kt
New file
@@ -0,0 +1,132 @@
package com.dayu.general.bean.card
class CardCommon {
    val ERROR: Int = -1
    //连接中断 提示用户重新连接或提示用户重新靠近卡片
    val ERROR_MOVE: Int = -2
    /**
     * 用户刷卡开泵前
     */
    val USER_CARD_TYPE_1: String = "A1"
    /**
     * 用户刷卡开泵后
     */
    val USER_CARD_TYPE_2: String = "A8"
    /**
     * 用户叠加充值
     */
    val USER_CARD_TYPE_3: String = "A2"
    /**
     * 设置区域表号卡
     */
    val REGION: String = "B0"
    /**
     * 设置用户电量单价卡
     */
    val ELECTRIC_PRICE: String = "B1"
    /**
     * 管理卡
     */
    val MANAGE_CRAD: String = "B2"
    /**
     * 清零卡
     */
    val CLEAN_CARD_TYPE: String = "C8"
    /**
     * 密码卡
     */
    val PASS_WORD_CRAD_TYPE: String = "B3"
    /**
     * 配置黑卡  当用户丢失卡时,需要在对应的控制器把此用户配置为黑户,防止非法用水
     */
    val BLACK: String = "B4"
    /**
     * 以下未用到
     * *****************************************************************************************************************************************
     */
    /**
     * 重新注册设备卡
     */
    val REGISTERED_CARD_TYPE: String = "BA"
    /**
     * 删除全部用户卡
     */
    val CLEAN_ALL_USER_CARD_TYPE: String = "BB"
    /**
     * 设置域名卡
     */
    val DOMAIN_CARD_TYPE: String = "C1"
    /**
     * 测试卡
     */
    val TEST_CARD_TYPE: String = "A4"
    /**
     * 配置设备注册信息卡
     */
    val CONFIGURATION_CARD_TYPE: String = "BC"
    /**
     * 配置水泵功率卡
     */
    val CONFIGURATION_POWER_CARD_TYPE: String = "BD"
    /**
     * 获取默认的卡标识
     *
     * @param cardType 卡片类型
     * @return 卡内容
     */
    fun getDefaultCardData(cardType: String?): String {
        var cardData = ""
        when (cardType) {
            CLEAN_CARD_TYPE -> cardData = "3668F7A30119"
            MANAGE_CRAD, REGISTERED_CARD_TYPE, CLEAN_ALL_USER_CARD_TYPE, TEST_CARD_TYPE, CONFIGURATION_CARD_TYPE, CONFIGURATION_POWER_CARD_TYPE, PASS_WORD_CRAD_TYPE, BLACK, ELECTRIC_PRICE -> cardData =
                "A0B1C289"
        }
        return cardData
    }
    companion object {
        fun getDefaultCardData(cardType: String?): String? {
            return getDefaultCardData(cardType)
        }
    }
}
generallibrary/src/main/java/com/dayu/general/bean/card/CheckCard.kt
New file
@@ -0,0 +1,93 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import java.io.Serializable
/**
 * 检查卡
 * 用于刷卡显示控制器基本信息:控制器ID号、水量单位、电量单价,未上报的数据条数等信息
 */
class CheckCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B3"              // 卡类型:检查卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
    }
    /**
     * 写卡完成后校验是否写卡成功
     */
    fun equalsCheckCard(data: List<ByteArray>?): Boolean {
        if (data == null || data.isEmpty()) {
            return false
        }
        return data[0].contentEquals(getZeroBytes())
    }
    /**
     * 通过byte转bean
     */
    fun getBean(data: List<ByteArray>): CheckCard? {
        try {
            val checkCard = CheckCard()
            // 解析第0块
            val zero = data[0]
            // 验证卡类型(8位)
            if (HexUtil.byteToHex(zero[8]) != CARD_TYPE) {
                return null
            }
            // 验证识别码(9-12位)
            if (zero[9] != IDENTIFY_CODE_A0 ||
                zero[10] != IDENTIFY_CODE_B1 ||
                zero[11] != IDENTIFY_CODE_C2 ||
                zero[12] != IDENTIFY_CODE_89) {
                return null
            }
            return checkCard
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }
    /**
     * 生成第0块数据
     */
    inner class Zero : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 设置备用位(0-7位)
                for (i in 0..7) {
                    data[i] = 0x00
                }
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(CARD_TYPE)
                // 设置识别码(9-12位)
                data[9] = IDENTIFY_CODE_A0
                data[10] = IDENTIFY_CODE_B1
                data[11] = IDENTIFY_CODE_C2
                data[12] = IDENTIFY_CODE_89
                // 设置备用位(13-14位)
                data[13] = 0x00
                data[14] = 0x00
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
}
generallibrary/src/main/java/com/dayu/general/bean/card/ClearCard.kt
New file
@@ -0,0 +1,93 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import java.io.Serializable
/**
 * 清零卡
 * 主要用于内部生产调试用
 */
class ClearCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "C1"              // 卡类型:清零卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
    }
    /**
     * 写卡完成后校验是否写卡成功
     */
    fun equalsClearCard(data: List<ByteArray>?): Boolean {
        if (data == null || data.isEmpty()) {
            return false
        }
        return data[0].contentEquals(getZeroBytes())
    }
    /**
     * 通过byte转bean
     */
    fun getBean(data: List<ByteArray>): ClearCard? {
        try {
            val clearCard = ClearCard()
            // 解析第0块
            val zero = data[0]
            // 验证卡类型(8位)
            if (HexUtil.byteToHex(zero[8]) != CARD_TYPE) {
                return null
            }
            // 验证识别码(9-12位)
            if (zero[9] != IDENTIFY_CODE_A0 ||
                zero[10] != IDENTIFY_CODE_B1 ||
                zero[11] != IDENTIFY_CODE_C2 ||
                zero[12] != IDENTIFY_CODE_89) {
                return null
            }
            return clearCard
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }
    /**
     * 生成第0块数据
     */
    inner class Zero : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 设置备用位(0-7位)
                for (i in 0..7) {
                    data[i] = 0x00
                }
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(CARD_TYPE)
                // 设置识别码(9-12位)
                data[9] = IDENTIFY_CODE_A0
                data[10] = IDENTIFY_CODE_B1
                data[11] = IDENTIFY_CODE_C2
                data[12] = IDENTIFY_CODE_89
                // 设置备用位(13-14位)
                data[13] = 0x00
                data[14] = 0x00
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
}
generallibrary/src/main/java/com/dayu/general/bean/card/DebugCard.kt
New file
@@ -0,0 +1,157 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import java.io.Serializable
/**
 * 调试卡
 * 主要用于安装调试用:
 * 1. 第一次刷卡时开启水泵或阀门
 * 2. 第二次刷卡关闭水泵或阀门
 * 3. 刷卡开启后1分钟内没有刷卡关闭,则自动关闭水泵或阀门
 */
class DebugCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B4"              // 卡类型:调试卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val AUTO_CLOSE_TIMEOUT = 60_000L  // 自动关闭超时时间(1分钟)
    }
    private var pumpOpenTime: Long = 0L  // 水泵开启时间
    private var isPumpOpen: Boolean = false  // 水泵状态
    /**
     * 写卡完成后校验是否写卡成功
     */
    fun equalsDebugCard(data: List<ByteArray>?): Boolean {
        if (data == null || data.isEmpty()) {
            return false
        }
        return data[0].contentEquals(getZeroBytes())
    }
    /**
     * 通过byte转bean
     */
    fun getBean(data: List<ByteArray>): DebugCard? {
        try {
            val debugCard = DebugCard()
            // 解析第0块
            val zero = data[0]
            // 验证卡类型(8位)
            if (HexUtil.byteToHex(zero[8]) != CARD_TYPE) {
                return null
            }
            // 验证识别码(9-12位)
            if (zero[9] != IDENTIFY_CODE_A0 ||
                zero[10] != IDENTIFY_CODE_B1 ||
                zero[11] != IDENTIFY_CODE_C2 ||
                zero[12] != IDENTIFY_CODE_89) {
                return null
            }
            return debugCard
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }
    /**
     * 生成第0块数据
     */
    inner class Zero : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 设置备用位(0-7位)
                for (i in 0..7) {
                    data[i] = 0x00
                }
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(CARD_TYPE)
                // 设置识别码(9-12位)
                data[9] = IDENTIFY_CODE_A0
                data[10] = IDENTIFY_CODE_B1
                data[11] = IDENTIFY_CODE_C2
                data[12] = IDENTIFY_CODE_89
                // 设置备用位(13-14位)
                data[13] = 0x00
                data[14] = 0x00
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    /**
     * 切换水泵状态
     * @return 当前水泵状态
     */
    fun togglePumpState(): Boolean {
        val currentTime = System.currentTimeMillis()
        if (!isPumpOpen) {
            // 开启水泵
            isPumpOpen = true
            pumpOpenTime = currentTime
        } else {
            // 关闭水泵
            isPumpOpen = false
            pumpOpenTime = 0L
        }
        return isPumpOpen
    }
    /**
     * 检查是否需要自动关闭水泵
     * @return true 如果需要自动关闭,false 否则
     */
    fun shouldAutoClose(): Boolean {
        if (!isPumpOpen) return false
        val currentTime = System.currentTimeMillis()
        return currentTime - pumpOpenTime >= AUTO_CLOSE_TIMEOUT
    }
    /**
     * 自动关闭水泵
     */
    fun autoClosePump() {
        isPumpOpen = false
        pumpOpenTime = 0L
    }
    /**
     * 获取水泵状态
     */
    fun isPumpOpen(): Boolean = isPumpOpen
    /**
     * 获取水泵开启剩余时间(毫秒)
     * @return 剩余时间,如果水泵关闭则返回0
     */
    fun getRemainingTime(): Long {
        if (!isPumpOpen) return 0L
        val currentTime = System.currentTimeMillis()
        val remainingTime = AUTO_CLOSE_TIMEOUT - (currentTime - pumpOpenTime)
        return if (remainingTime > 0) remainingTime else 0L
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
}
generallibrary/src/main/java/com/dayu/general/bean/card/DomainSettingCard.kt
New file
@@ -0,0 +1,213 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import java.io.Serializable
/**
 * 域名设置卡
 * 用于项目现场修改域名,通过刷卡方式修改域名
 */
class DomainSettingCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B6"              // 卡类型:域名设置卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val MAX_DOMAIN_ROUTE = 4          // 最大域名路数
        const val MAX_DOMAIN_LENGTH = 38        // 最大域名长度
    }
    var domainRouteNumber: Int = 1  // 域名序列号(1-4)
    var domain: String = ""         // 域名
    var domainLength: Int = 0       // 域名长度
    /**
     * 写卡完成后校验是否写卡成功
     */
    fun equalsDomainSettingCard(data: List<ByteArray>?): Boolean {
        if (data == null || data.size < 3) {
            return false
        }
        return data[0].contentEquals(getZeroBytes()) &&
               data[1].contentEquals(getOneBytes()) &&
               data[2].contentEquals(getTwoBytes())
    }
    /**
     * 通过byte转bean
     */
    fun getBean(data: List<ByteArray>): DomainSettingCard? {
        try {
            val domainSettingCard = DomainSettingCard()
            // 解析第0块
            val zero = data[0]
            // 验证卡类型(8位)
            if (HexUtil.byteToHex(zero[8]) != CARD_TYPE) {
                return null
            }
            // 验证识别码(9-12位)
            if (zero[9] != IDENTIFY_CODE_A0 ||
                zero[10] != IDENTIFY_CODE_B1 ||
                zero[11] != IDENTIFY_CODE_C2 ||
                zero[12] != IDENTIFY_CODE_89) {
                return null
            }
            // 解析域名路数(13位)
            val routeNumber = zero[13].toInt()
            if (routeNumber !in 1..MAX_DOMAIN_ROUTE) {
                return null
            }
            domainSettingCard.domainRouteNumber = routeNumber
            // 解析域名长度(14位)
            domainSettingCard.domainLength = zero[14].toInt()
            // 解析域名前8个字符(0-7位)
            val domainBuilder = StringBuilder()
            for (i in 0..7) {
                if (zero[i] != 0.toByte()) {
                    domainBuilder.append(zero[i].toInt().toChar())
                }
            }
            // 解析第1块 - 域名中间15个字符
            val one = data[1]
            for (i in 0..14) {
                if (one[i] != 0.toByte()) {
                    domainBuilder.append(one[i].toInt().toChar())
                }
            }
            // 解析第2块 - 域名剩余15个字符
            val two = data[2]
            for (i in 0..14) {
                if (two[i] != 0.toByte()) {
                    domainBuilder.append(two[i].toInt().toChar())
                }
            }
            domainSettingCard.domain = domainBuilder.toString()
            return domainSettingCard
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }
    /**
     * 生成第0块数据
     */
    inner class Zero : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 写入域名前8个字符(0-7位)
                domain.take(8).forEachIndexed { index, char ->
                    data[index] = char.code.toByte()
                }
                // 补0
                for (i in domain.length.coerceAtMost(8) until 8) {
                    data[i] = 0
                }
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(CARD_TYPE)
                // 设置识别码(9-12位)
                data[9] = IDENTIFY_CODE_A0
                data[10] = IDENTIFY_CODE_B1
                data[11] = IDENTIFY_CODE_C2
                data[12] = IDENTIFY_CODE_89
                // 设置域名路数(13位)
                data[13] = domainRouteNumber.toByte()
                // 设置域名长度(14位)
                data[14] = domain.length.toByte()
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    /**
     * 生成第1块数据 - 域名中间部分
     */
    inner class One : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 写入域名中间15个字符(0-14位)
                domain.drop(8).take(15).forEachIndexed { index, char ->
                    data[index] = char.code.toByte()
                }
                // 补0
                for (i in (domain.length - 8).coerceAtMost(15) until 15) {
                    data[i] = 0
                }
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    /**
     * 生成第2块数据 - 域名结尾部分
     */
    inner class Two : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 写入域名最后15个字符(0-14位)
                domain.drop(23).take(15).forEachIndexed { index, char ->
                    data[index] = char.code.toByte()
                }
                // 补0
                for (i in (domain.length - 23).coerceAtMost(15) until 15) {
                    data[i] = 0
                }
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    /**
     * 验证域名格式是否正确
     */
    fun isValidDomain(): Boolean {
        return domain.isNotEmpty() &&
               domain.length <= MAX_DOMAIN_LENGTH &&
               domain.matches(Regex("^[a-zA-Z0-9.-]+$"))
    }
    /**
     * 验证域名路数是否正确
     */
    fun isValidRouteNumber(): Boolean {
        return domainRouteNumber in 1..MAX_DOMAIN_ROUTE
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
    fun getOneBytes(): ByteArray = One().toBytes()
    fun getTwoBytes(): ByteArray = Two().toBytes()
}
generallibrary/src/main/java/com/dayu/general/bean/card/FetchDataCard.kt
New file
@@ -0,0 +1,132 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.BcdUtil
import com.dayu.baselibrary.tools.HexUtil
import java.io.Serializable
/**
 * 取数卡
 * 用于在用户卡丢失后,读取当前用户或挂起用户的卡内信息,作为补卡依据
 */
class FetchDataCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE_NEED_FETCH = "B1"    // 需要刷卡取数
        const val CARD_TYPE_FETCH_SUCCESS = "B2"  // 刷卡取数返写成功
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
    }
    var areaNumber: Int = 0      // 国家行政区域号(12位BCD,精确到村)
    var userNumber: Int = 0      // 用户编号(HEX)
    var cardType: String = CARD_TYPE_NEED_FETCH  // 卡类型:B1需要刷卡取数,B2刷卡取数返写成功
    var projectCode: Int = 0     // 项目编码(HEX 1-255)
    /**
     * 写卡完成后校验是否写卡成功
     */
    fun equalsFetchDataCard(data: List<ByteArray>?): Boolean {
        if (data == null || data.isEmpty()) {
            return false
        }
        return data[0].contentEquals(getZeroBytes())
    }
    /**
     * 通过byte转bean
     */
    fun getBean(data: List<ByteArray>): FetchDataCard? {
        try {
            val fetchDataCard = FetchDataCard()
            // 解析第0块
            val zero = data[0]
            // 解析国家行政区域号(0-5位)
            val areaCodeBytes = zero.copyOfRange(0, 6)
            fetchDataCard.areaNumber = BcdUtil.bcdToStr(areaCodeBytes).toInt()
            // 解析用户编号(6-7位)
            val userNumberBytes = zero.copyOfRange(6, 8)
            fetchDataCard.userNumber = HexUtil.get16To10LowHightByBytes(userNumberBytes)
            // 解析卡类型(8位)
            val cardType = HexUtil.byteToHex(zero[8])
            if (cardType != CARD_TYPE_NEED_FETCH && cardType != CARD_TYPE_FETCH_SUCCESS) {
                return null
            }
            fetchDataCard.cardType = cardType
            // 验证识别码(9-12位)
            if (zero[9] != IDENTIFY_CODE_A0 ||
                zero[10] != IDENTIFY_CODE_B1 ||
                zero[11] != IDENTIFY_CODE_C2 ||
                zero[12] != IDENTIFY_CODE_89) {
                return null
            }
            // 解析项目编码(13位)
            fetchDataCard.projectCode = HexUtil.get16To10LowHightByBytes(byteArrayOf(zero[13]))
            return fetchDataCard
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }
    /**
     * 生成第0块数据
     */
    inner class Zero : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 设置国家行政区域号(BCD格式,6字节,0-5位)
                val areaCodeBytes = BcdUtil.strToBcd(String.format("%012d", areaNumber))
                System.arraycopy(areaCodeBytes, 0, data, 0, 6)
                // 设置用户编号(6-7位)
                val userNumberBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(userNumber))
                System.arraycopy(userNumberBytes, 0, data, 6, 2)
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(cardType)
                // 设置识别码(9-12位)
                data[9] = IDENTIFY_CODE_A0
                data[10] = IDENTIFY_CODE_B1
                data[11] = IDENTIFY_CODE_C2
                data[12] = IDENTIFY_CODE_89
                // 设置项目编码(13位)
                data[13] = projectCode.toByte()
                // 设置备用位(14位)
                data[14] = 0x00
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    /**
     * 将卡片状态更新为取数成功
     */
    fun markAsFetchSuccess() {
        cardType = CARD_TYPE_FETCH_SUCCESS
    }
    /**
     * 检查是否已经取数成功
     */
    fun isFetchSuccess(): Boolean {
        return cardType == CARD_TYPE_FETCH_SUCCESS
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
}
generallibrary/src/main/java/com/dayu/general/bean/card/GpsCard.kt
New file
@@ -0,0 +1,93 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import java.io.Serializable
/**
 * GPS定位卡
 * 主要用于内部生产调试用
 */
class GpsCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B7"              // 卡类型:GPS定位卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
    }
    /**
     * 写卡完成后校验是否写卡成功
     */
    fun equalsGpsCard(data: List<ByteArray>?): Boolean {
        if (data == null || data.isEmpty()) {
            return false
        }
        return data[0].contentEquals(getZeroBytes())
    }
    /**
     * 通过byte转bean
     */
    fun getBean(data: List<ByteArray>): GpsCard? {
        try {
            val gpsCard = GpsCard()
            // 解析第0块
            val zero = data[0]
            // 验证卡类型(8位)
            if (HexUtil.byteToHex(zero[8]) != CARD_TYPE) {
                return null
            }
            // 验证识别码(9-12位)
            if (zero[9] != IDENTIFY_CODE_A0 ||
                zero[10] != IDENTIFY_CODE_B1 ||
                zero[11] != IDENTIFY_CODE_C2 ||
                zero[12] != IDENTIFY_CODE_89) {
                return null
            }
            return gpsCard
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }
    /**
     * 生成第0块数据
     */
    inner class Zero : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 设置备用位(0-7位)
                for (i in 0..7) {
                    data[i] = 0x00
                }
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(CARD_TYPE)
                // 设置识别码(9-12位)
                data[9] = IDENTIFY_CODE_A0
                data[10] = IDENTIFY_CODE_B1
                data[11] = IDENTIFY_CODE_C2
                data[12] = IDENTIFY_CODE_89
                // 设置备用位(13-14位)
                data[13] = 0x00
                data[14] = 0x00
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
}
generallibrary/src/main/java/com/dayu/general/bean/card/IpSettingCard.kt
New file
@@ -0,0 +1,219 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import java.io.Serializable
/**
 * IP地址设置卡
 * 用于项目现场修改IP地址,通过刷卡方式修改IP地址
 */
class IpSettingCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B5"              // 卡类型:IP设置卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val MAX_IP_ROUTE = 4              // 最大IP路数
    }
    var ipRouteNumber: Int = 1    // IP地址序列号(1-4)
    var ipAddress: String = ""    // IP地址
    var port: Int = 0            // 端口号
    /**
     * 写卡完成后校验是否写卡成功
     */
    fun equalsIpSettingCard(data: List<ByteArray>?): Boolean {
        if (data == null || data.size < 3) {
            return false
        }
        return data[0].contentEquals(getZeroBytes()) &&
               data[1].contentEquals(getOneBytes()) &&
               data[2].contentEquals(getTwoBytes())
    }
    /**
     * 通过byte转bean
     */
    fun getBean(data: List<ByteArray>): IpSettingCard? {
        try {
            val ipSettingCard = IpSettingCard()
            // 解析第0块
            val zero = data[0]
            // 验证卡类型(8位)
            if (HexUtil.byteToHex(zero[8]) != CARD_TYPE) {
                return null
            }
            // 验证识别码(9-12位)
            if (zero[9] != IDENTIFY_CODE_A0 ||
                zero[10] != IDENTIFY_CODE_B1 ||
                zero[11] != IDENTIFY_CODE_C2 ||
                zero[12] != IDENTIFY_CODE_89) {
                return null
            }
            // 解析IP路数(13位)
            val routeNumber = zero[13].toInt()
            if (routeNumber !in 1..MAX_IP_ROUTE) {
                return null
            }
            ipSettingCard.ipRouteNumber = routeNumber
            // 解析第1块 - IP地址
            val one = data[1]
            val ipBuilder = StringBuilder()
            for (i in 0..14) {
                ipBuilder.append(one[i].toInt().toChar())
            }
            ipSettingCard.ipAddress = ipBuilder.toString()
            // 解析第2块 - 端口号
            val two = data[2]
            val portBuilder = StringBuilder()
            for (i in 0..4) {
                portBuilder.append(two[i].toInt().toChar())
            }
            ipSettingCard.port = portBuilder.toString().toInt()
            return ipSettingCard
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }
    /**
     * 生成第0块数据
     */
    inner class Zero : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 设置备用位(0-7位)
                for (i in 0..7) {
                    data[i] = 0x00
                }
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(CARD_TYPE)
                // 设置识别码(9-12位)
                data[9] = IDENTIFY_CODE_A0
                data[10] = IDENTIFY_CODE_B1
                data[11] = IDENTIFY_CODE_C2
                data[12] = IDENTIFY_CODE_89
                // 设置IP路数(13位)
                data[13] = ipRouteNumber.toByte()
                // 设置备用位(14位)
                data[14] = 0x00
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    /**
     * 生成第1块数据 - IP地址
     */
    inner class One : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 格式化IP地址
                val formattedIp = formatIpAddress(ipAddress)
                // 写入IP地址(0-14位)
                formattedIp.forEachIndexed { index, char ->
                    data[index] = char.code.toByte()
                }
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    /**
     * 生成第2块数据 - 端口号
     */
    inner class Two : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 格式化端口号
                val formattedPort = String.format("%05d", port)
                // 写入端口号(0-4位)
                formattedPort.forEachIndexed { index, char ->
                    data[index] = char.code.toByte()
                }
                // 设置备用位(5-14位)
                for (i in 5..14) {
                    data[i] = 0x00
                }
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    /**
     * 格式化IP地址
     * 将IP地址格式化为标准格式:每组3位,不足补0
     */
    private fun formatIpAddress(ip: String): String {
        val parts = ip.split(".")
        if (parts.size != 4) throw IllegalArgumentException("Invalid IP address format")
        return parts.joinToString(".") { part ->
            String.format("%03d", part.toInt())
        }
    }
    /**
     * 验证IP地址格式是否正确
     */
    fun isValidIpAddress(): Boolean {
        return try {
            val parts = ipAddress.split(".")
            if (parts.size != 4) return false
            parts.all { part ->
                val num = part.toInt()
                num in 0..255
            }
        } catch (e: Exception) {
            false
        }
    }
    /**
     * 验证端口号是否正确
     */
    fun isValidPort(): Boolean {
        return port in 1..65535
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
    fun getOneBytes(): ByteArray = One().toBytes()
    fun getTwoBytes(): ByteArray = Two().toBytes()
}
generallibrary/src/main/java/com/dayu/general/bean/card/UserCard.kt
New file
@@ -0,0 +1,199 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.bean.BaseUserCardCard
import com.dayu.baselibrary.tools.BcdUtil
import com.dayu.baselibrary.tools.HexUtil
import java.io.Serializable
import java.util.*
/**
 * 通用项目用户卡结构
 */
class UserCard : BaseCard(), Serializable {
    var cardType: String = "A1" // 卡类型:A1终端写卡 A8刷卡开泵后值 A2叠加充值
    var areaNumber: Int = 0 // 国家行政区域号(12位BCD,精确到村)
    var userCode: String = "" // 用户编号BCD
    var userCodeNumber: Int = 0 // 用户卡编号(HEX)
    var phoneNumber: String = "" // 手机号(BCD)
    var projectCode: Int = 0 // 项目编码(HEX 1-255)
    var balance: Int = 0 // 剩余金额(2位小数点,单位元)
    var surplusWater: Int = 0 // 剩余水量(2位小数点,单位立方米)
    var waterPrice: Float = 0f // 水量单价(最大655.35,2位小数点。单位:m3/元)
    var electricPrice: Float = 0f // 电量单价(最大655.35,2位小数点。单位: 元/度)
    var rechargeDate: Calendar? = null // 充值时间
    /**
     * 写卡完成后校验是否写卡成功
     */
    fun equalsUserCard(data: List<ByteArray>?): Boolean {
        if (data == null || data.size < 3) {
            return false
        }
        val expectedBytes = arrayOf(getZeroBytes(), getOneBytes(), getTwoBytes())
        return data.zip(expectedBytes.toList()).all { (actual, expected) ->
            actual.contentEquals(expected)
        }
    }
    /**
     * 返回完整的用户编号
     */
    fun getMyUserCode(): String {
        return userCode + String.format("%04d", userCodeNumber)
    }
    /**
     * 通过byte转bean
     */
     fun getBean(data: List<ByteArray>): UserCard? {
        try {
            val userCard = UserCard()
            // 解析第0块
            val zero = data[0]
            userCard.apply {
                // 解析国家行政区域号(0-5位)
                val areaCodeBytes = zero.copyOfRange(0, 6)
                areaNumber = BcdUtil.bcdToStr(areaCodeBytes).toInt()
                // 解析用户卡编号(6-7位)
                val userCodeNumberBytes = zero.copyOfRange(6, 8)
                userCodeNumber = HexUtil.get16To10LowHightByBytes(userCodeNumberBytes)
                // 解析卡类型(8位)
                cardType = HexUtil.byteToHex(zero[8])
                // 解析手机号(9-14位)
                phoneNumber = BcdUtil.bcdToStr(zero.copyOfRange(9, 15))
            }
            // 解析第1块
            val one = data[1]
            userCard.apply {
                projectCode = HexUtil.get16To10LowHightByBytes(byteArrayOf(one[0]))
                balance = HexUtil.get16To10LowHightByBytes(one.copyOfRange(1, 5))
                surplusWater = HexUtil.get16To10LowHightByBytes(one.copyOfRange(5, 9))
                electricPrice = HexUtil.hexToFloatLowHigh(one.copyOfRange(9, 11))
                // 解析充值时间
                val year = HexUtil.getBcdToInt(one[11])
                val month = HexUtil.getBcdToInt(one[12])
                val day = HexUtil.getBcdToInt(one[13])
                val hour = HexUtil.getBcdToInt(one[14])
                Calendar.getInstance().apply {
                    set(2000 + year, month - 1, day, hour, 0, 0)
                    rechargeDate = this
                }
            }
            // 解析第2块
            val two = data[2]
            userCard.apply {
                waterPrice = HexUtil.hexToFloatLowHigh(two.copyOfRange(9, 11))
            }
            return userCard
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }
    // 内部类用于生成各个数据块
    inner class Zero : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 设置国家行政区域号(BCD格式,6字节,0-5位)
                val areaCodeBytes = BcdUtil.strToBcd(String.format("%012d", areaNumber))
                System.arraycopy(areaCodeBytes, 0, data, 0, 6)
                // 设置用户卡编号(HEX格式,2字节,6-7位)
                val userCodeBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(userCodeNumber))
                System.arraycopy(userCodeBytes, 0, data, 6, 2)
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(cardType)
                // 设置手机号(BCD格式,6字节,9-14位)
                val phoneBytes = BcdUtil.strToBcd(phoneNumber.padStart(12, '0'))
                System.arraycopy(phoneBytes, 0, data, 9, 6)
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    inner class One : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                data[0] = projectCode.toByte()
                // 设置余额
                val balanceBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(balance))
                System.arraycopy(balanceBytes, 0, data, 1, 4)
                // 设置剩余水量
                val waterBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(surplusWater))
                System.arraycopy(waterBytes, 0, data, 5, 4)
                // 设置电价
                val priceBytes = HexUtil.hexToByteArray(HexUtil.floatToHexLowHigh(electricPrice))
                System.arraycopy(priceBytes, 0, data, 9, 2)
                // 设置充值时间
                rechargeDate?.let {
                    data[11] = HexUtil.getIntToBCD(it.get(Calendar.YEAR) % 100)[0]
                    data[12] = HexUtil.getIntToBCD(it.get(Calendar.MONTH) + 1)[0]
                    data[13] = HexUtil.getIntToBCD(it.get(Calendar.DAY_OF_MONTH))[0]
                    data[14] = HexUtil.getIntToBCD(it.get(Calendar.HOUR_OF_DAY))[0]
                }
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    inner class Two : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 备份余额和水量数据
                val balanceBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(balance))
                System.arraycopy(balanceBytes, 0, data, 1, 4)
                val waterBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(surplusWater))
                System.arraycopy(waterBytes, 0, data, 5, 4)
                // 设置水价
                val priceBytes = HexUtil.hexToByteArray(HexUtil.floatToHexLowHigh(waterPrice))
                System.arraycopy(priceBytes, 0, data, 9, 2)
                // 设置充值时间
                rechargeDate?.let {
                    data[11] = HexUtil.getIntToBCD(it.get(Calendar.YEAR) % 100)[0]
                    data[12] = HexUtil.getIntToBCD(it.get(Calendar.MONTH) + 1)[0]
                    data[13] = HexUtil.getIntToBCD(it.get(Calendar.DAY_OF_MONTH))[0]
                    data[14] = HexUtil.getIntToBCD(it.get(Calendar.HOUR_OF_DAY))[0]
                }
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
    fun getOneBytes(): ByteArray = One().toBytes()
    fun getTwoBytes(): ByteArray = Two().toBytes()
}
generallibrary/src/main/java/com/dayu/general/bean/card/ValveTimeCard.kt
New file
@@ -0,0 +1,118 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import java.io.Serializable
/**
 * 配置开关阀时间卡
 * 主要用于内部生产调试用,设置开关阀时间
 */
class ValveTimeCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B8"              // 卡类型:配置开关阀时间卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
    }
    var valveTime: Int = 0    // 开关阀时间(秒)
    /**
     * 写卡完成后校验是否写卡成功
     */
    fun equalsValveTimeCard(data: List<ByteArray>?): Boolean {
        if (data == null || data.isEmpty()) {
            return false
        }
        return data[0].contentEquals(getZeroBytes())
    }
    /**
     * 通过byte转bean
     */
    fun getBean(data: List<ByteArray>): ValveTimeCard? {
        try {
            val valveTimeCard = ValveTimeCard()
            // 解析第0块
            val zero = data[0]
            // 验证卡类型(8位)
            if (HexUtil.byteToHex(zero[8]) != CARD_TYPE) {
                return null
            }
            // 验证识别码(9-12位)
            if (zero[9] != IDENTIFY_CODE_A0 ||
                zero[10] != IDENTIFY_CODE_B1 ||
                zero[11] != IDENTIFY_CODE_C2 ||
                zero[12] != IDENTIFY_CODE_89) {
                return null
            }
            // 解析开关阀时间(13-14位)
            val timeBytes = byteArrayOf(zero[13], zero[14])
            valveTimeCard.valveTime = HexUtil.get16To10LowHightByBytes(timeBytes)
            return valveTimeCard
        } catch (e: Exception) {
            e.printStackTrace()
            return null
        }
    }
    /**
     * 生成第0块数据
     */
    inner class Zero : BaseCard() {
        fun toBytes(): ByteArray {
            val data = ByteArray(16)
            try {
                // 设置备用位(0-7位)
                for (i in 0..7) {
                    data[i] = 0x00
                }
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(CARD_TYPE)
                // 设置识别码(9-12位)
                data[9] = IDENTIFY_CODE_A0
                data[10] = IDENTIFY_CODE_B1
                data[11] = IDENTIFY_CODE_C2
                data[12] = IDENTIFY_CODE_89
                // 设置开关阀时间(13-14位),低位在前高位在后
                val timeBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(valveTime))
                if (timeBytes.size >= 2) {
                    data[13] = timeBytes[0]  // 低位
                    data[14] = timeBytes[1]  // 高位
                }
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return data
        }
    }
    /**
     * 验证开关阀时间是否有效
     * @return true 如果时间有效,false 否则
     */
    fun isValidValveTime(): Boolean {
        return valveTime > 0 && valveTime <= 65535  // 两个字节最大值
    }
    /**
     * 获取开关阀时间的十六进制字符串表示
     * @return 十六进制字符串,如"0087"表示135秒
     */
    fun getValveTimeHex(): String {
        return String.format("%04X", valveTime)
    }
    fun getZeroBytes(): ByteArray = Zero().toBytes()
}
generallibrary/src/main/java/com/dayu/general/bean/db/CardData.kt
New file
@@ -0,0 +1,21 @@
package com.dayu.general.bean.db
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
class CardData {
    @PrimaryKey(autoGenerate = true)
    var id: Long = 0
    /**
     * 卡片类型
     */
    var cardType: String? = null
    /**
     * 卡标识
     */
    var cardIdentifying: String? = null
}
generallibrary/src/main/java/com/dayu/general/bean/db/PassWordCardBean.java
New file
@@ -0,0 +1,36 @@
package com.dayu.general.bean.db;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
/**
 * author: zuo
 * Date: 2024-03-01
 * Time: 17:56
 * 备注:密码卡密码
 */
@Entity
public class PassWordCardBean {
    @PrimaryKey(autoGenerate = true)
    public long id;
    private String passWord = "";
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getPassWord() {
        return passWord;
    }
    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }
}
generallibrary/src/main/java/com/dayu/general/dao/AppDataBase.kt
@@ -1,6 +1,11 @@
package com.dayu.general.dao
import androidx.room.Database
import androidx.room.RoomDatabase
import com.dayu.general.bean.db.CardData
import com.dayu.general.bean.db.PassWordCardBean
@Database(entities = [PassWordCardBean::class, CardData::class], version = 1, exportSchema = false)
abstract class AppDataBase : RoomDatabase() {
    abstract fun cardDataDao(): CardDataDao
}
generallibrary/src/main/java/com/dayu/general/dao/BaseDaoSingleton.kt
@@ -38,9 +38,9 @@
        return AsynchBaseDao
    }
    companion object {
        fun getAsynchInstance(baseActivity: BaseActivity): AppDataBase? {
           return getAsynchInstance(baseActivity)
        }
    }
//    companion object {
//        fun getAsynchInstance(baseActivity: BaseActivity): AppDataBase? {
//           return getAsynchInstance(baseActivity)
//        }
//    }
}
generallibrary/src/main/java/com/dayu/general/dao/CardDataDao.kt
New file
@@ -0,0 +1,20 @@
package com.dayu.general.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.dayu.general.bean.db.CardData
@Dao
interface CardDataDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(cardData: CardData)
    @Update
    fun update(cardData: CardData)
    @Query("select  * from CardData where cardType=:cardType limit 1")
    fun findFirst(cardType: String?): CardData
}
generallibrary/src/main/java/com/dayu/general/tool/GeBaseHelper.kt
New file
@@ -0,0 +1,43 @@
package com.dayu.general.tool
import android.content.Context
import android.util.Base64
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.baselibrary.tools.nfc.BaseNFCHelper
import java.nio.charset.StandardCharsets
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
class GeBaseHelper(private val context: Context) : BaseNFCHelper() {
    companion object {
        init {
            System.loadLibrary("general-native-lib")
        }
    }
    private external fun getM1SectorKeySecure(context: Context, sectorIndex: Int): String
    init {
        try {
            // 获取所有扇区密钥
            val allKeys: String = getM1SectorKeySecure(context, 0)
            val keys: Array<String> =
                allKeys.split(",").dropLastWhile { it.isEmpty() }.toTypedArray()
            for (i in keys.indices) {
                val key = keys[i]
                listA_PS.add(HexUtil.hexToByteArray(key))
            }
            defauleKey = HexUtil.hexToByteArray("FFFFFFFFFFFF")
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
    fun getKeyList(): List<ByteArray> {
        return listKeyA
    }
}
generallibrary/src/main/res/drawable/bottom_circle_bg.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/bottom_color" /> <!-- 按钮的背景色 -->
    <corners android:radius="90dp" /> <!-- 让按钮的四个角变成圆形 -->
    <corners android:radius="100dp" /> <!-- 让按钮的四个角变成圆形 -->
    <size android:width="100dp" android:height="100dp" /> <!-- 设置按钮的宽高 -->
</shape>
generallibrary/src/main/res/drawable/bottom_nav_background.xml
New file
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 阴影层 -->
    <item>
        <shape>
            <padding
                android:bottom="0dp"
                android:left="0dp"
                android:right="0dp"
                android:top="2dp" />
            <solid android:color="#10000000" />
            <corners
                android:topLeftRadius="18dp"
                android:topRightRadius="18dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding
                android:bottom="0dp"
                android:left="0dp"
                android:right="0dp"
                android:top="2dp" />
            <solid android:color="#15000000" />
            <corners
                android:topLeftRadius="18dp"
                android:topRightRadius="18dp" />
        </shape>
    </item>
    <!-- 主背景 -->
    <item>
        <shape>
            <solid android:color="#FFFFFF" />
            <corners
                android:topLeftRadius="18dp"
                android:topRightRadius="18dp" />
        </shape>
    </item>
</layer-list>
generallibrary/src/main/res/drawable/fab_background.xml
New file
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 阴影层 -->
    <item>
        <shape android:shape="oval">
            <solid android:color="#30000000" />
            <padding android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp" />
        </shape>
    </item>
    <!-- 主背景 -->
    <item>
        <shape android:shape="oval">
            <gradient
                android:angle="135"
                android:endColor="#1E88E5"
                android:centerColor="#4285F4"
                android:startColor="#5C9CE6"
                android:type="linear" />
        </shape>
    </item>
</layer-list>
generallibrary/src/main/res/drawable/nav_item_color.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#4285F4" android:state_selected="true" />
    <item android:color="#555555" />
</selector>
generallibrary/src/main/res/drawable/ripple_effect.xml
New file
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#20000000">
    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="#000000" />
            <corners android:radius="4dp" />
        </shape>
    </item>
</ripple>
generallibrary/src/main/res/drawable/rounded_button_bg.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="16dp" />
    <solid android:color="@color/bottom_color" />
</shape>
generallibrary/src/main/res/drawable/shadow_gradient.xml
New file
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:angle="90"
        android:endColor="#00000000"
        android:startColor="#20000000"
        android:type="linear" />
</shape>
generallibrary/src/main/res/drawable/shadow_gradient_strong.xml
New file
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:angle="90"
        android:endColor="#00000000"
        android:startColor="#30000000"
        android:type="linear" />
</shape>
generallibrary/src/main/res/drawable/tab_indicator.xml
New file
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#4285F4" />
    <corners android:radius="2dp" />
    <size android:height="3dp" android:width="20dp" />
</shape>
generallibrary/src/main/res/drawable/tab_ripple_effect.xml
New file
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#1A4285F4">
    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="#000000" />
            <corners android:radius="8dp" />
        </shape>
    </item>
</ripple>
generallibrary/src/main/res/layout/activity_main.xml
@@ -24,7 +24,7 @@
        android:orientation="horizontal">
        <LinearLayout
            android:id="@+id/orderLL"
            android:id="@+id/BSCardLL"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_weight="1"
@@ -37,7 +37,7 @@
                android:layout_height="33dp">
                <ImageView
                    android:id="@+id/orderImg"
                    android:id="@+id/BSCardImg"
                    android:layout_width="wrap_content"
                    android:layout_height="25dp"
                    android:layout_marginTop="8dp"
@@ -47,7 +47,7 @@
            </RelativeLayout>
            <TextView
                android:id="@+id/orderText"
                android:id="@+id/BSCardText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="3dp"
@@ -58,7 +58,7 @@
        </LinearLayout>
        <FrameLayout
            android:id="@+id/mapLL"
            android:id="@+id/rechargeLL"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
@@ -81,14 +81,14 @@
                android:orientation="vertical">
                <ImageView
                    android:id="@+id/mapImg"
                    android:id="@+id/rechargeImg"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:layout_marginTop="8dp"
                    android:src="@drawable/bottom_recharge_white" />
                <TextView
                    android:id="@+id/mapText"
                    android:id="@+id/rechargeText"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="充值"
generallibrary/src/main/res/layout/activity_new_card_ge.xml
New file
@@ -0,0 +1,311 @@
<?xml version="1.0" encoding="utf-8"?>
<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"
    android:background="#F5F7FA">
    <com.dayu.baselibrary.view.TitleBar
        android:id="@+id/titleBar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimen_title_height"
        android:background="@color/title_bar_bg"
        android:elevation="4dp"
        app:centerText="新卡开户"
        app:leftImage="@mipmap/icon_back" />
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/newCard_registBtn"
        android:layout_below="@+id/titleBar"
        android:fillViewport="true"
        android:scrollbars="none">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp">
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="16dp"
                app:cardCornerRadius="8dp"
                app:cardElevation="2dp">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="16dp"
                        android:text="基本信息"
                        android:textColor="#333333"
                        android:textSize="18sp"
                        android:textStyle="bold" />
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="16dp"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="@string/eq_no"
                            android:textColor="#666666"
                            android:textSize="@dimen/new_card_size" />
                        <TextView
                            android:id="@+id/newCard_arerNumber"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginStart="8dp"
                            android:inputType="number"
                            android:textColor="#333333"
                            android:textSize="@dimen/new_card_size" />
                    </LinearLayout>
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="16dp"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">
                        <TextView
                            android:layout_width="80dp"
                            android:layout_height="wrap_content"
                            android:text="姓名"
                            android:textColor="#666666"
                            android:textSize="@dimen/new_card_size" />
                        <LinearLayout
                            android:layout_width="0dp"
                            android:layout_height="wrap_content"
                            android:layout_weight="1"
                            android:background="#FFFFFF"
                            android:orientation="vertical">
                            <EditText
                                android:id="@+id/newCard_name"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:background="@null"
                                android:hint="请输入姓名"
                                android:inputType="textPersonName"
                                android:padding="12dp"
                                android:textSize="@dimen/new_card_size" />
                        </LinearLayout>
                        <ImageView
                            android:id="@+id/newCard_scanBtn"
                            android:layout_width="45dp"
                            android:layout_height="45dp"
                            android:background="?attr/selectableItemBackgroundBorderless"
                            android:padding="10dp"
                            android:src="@mipmap/icon_scan"
                            android:tint="#4285F4" />
                    </LinearLayout>
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="16dp"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">
                        <TextView
                            android:layout_width="80dp"
                            android:layout_height="wrap_content"
                            android:text="身份证号"
                            android:textColor="#666666"
                            android:textSize="@dimen/new_card_size" />
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:background="#FFFFFF"
                            android:orientation="vertical">
                            <EditText
                                android:id="@+id/newCard_id"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:background="@null"
                                android:digits="0123456789Xx"
                                android:hint="请输入身份证号"
                                android:inputType="text"
                                android:maxLength="18"
                                android:padding="12dp"
                                android:textSize="@dimen/new_card_size" />
                        </LinearLayout>
                    </LinearLayout>
                    <TextView
                        android:id="@+id/newCard_idTip"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="16dp"
                        android:text="扫描后请核对身份信息无误"
                        android:textColor="#FF4500"
                        android:visibility="gone" />
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="16dp"
                app:cardCornerRadius="8dp"
                app:cardElevation="2dp">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="16dp"
                        android:text="联系方式"
                        android:textColor="#333333"
                        android:textSize="18sp"
                        android:textStyle="bold" />
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="16dp"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">
                        <TextView
                            android:layout_width="80dp"
                            android:layout_height="wrap_content"
                            android:text="电话"
                            android:textColor="#666666"
                            android:textSize="@dimen/new_card_size" />
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:background="#FFFFFF"
                            android:orientation="vertical">
                            <EditText
                                android:id="@+id/newCard_phone"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:background="@null"
                                android:hint="请输入手机号码"
                                android:inputType="phone"
                                android:maxLength="11"
                                android:padding="12dp"
                                android:textSize="@dimen/new_card_size" />
                        </LinearLayout>
                    </LinearLayout>
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:cardCornerRadius="8dp"
                app:cardElevation="2dp">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="16dp"
                        android:text="费用信息"
                        android:textColor="#333333"
                        android:textSize="18sp"
                        android:textStyle="bold" />
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">
                        <TextView
                            android:layout_width="80dp"
                            android:layout_height="wrap_content"
                            android:text="工本费(元)"
                            android:textColor="#666666"
                            android:textSize="@dimen/new_card_size" />
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:background="#FFFFFF"
                            android:orientation="vertical">
                            <EditText
                                android:id="@+id/newCard_morny"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:background="@null"
                                android:hint="请输入工本费"
                                android:inputType="numberDecimal"
                                android:padding="12dp"
                                android:textSize="@dimen/new_card_size" />
                        </LinearLayout>
                    </LinearLayout>
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <!-- 隐藏的水权内水量部分 -->
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:visibility="gone">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="水权内水量:"
                    android:textSize="@dimen/new_card_size" />
                <EditText
                    android:id="@+id/newCard_water"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="number"
                    android:maxLength="5"
                    android:textSize="@dimen/new_card_size" />
            </LinearLayout>
        </LinearLayout>
    </ScrollView>
    <TextView
        android:id="@+id/newCard_registBtn"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_alignParentBottom="true"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="16dp"
        android:background="#4285F4"
        android:gravity="center"
        android:text="确认开户"
        android:textColor="#FFFFFF"
        android:textSize="16sp" />
</RelativeLayout>
generallibrary/src/main/res/layout/fragment_card.xml
New file
@@ -0,0 +1,341 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:background="@color/white">
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/titleBar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimen_title_height"
        android:background="@color/bottom_color"
        android:elevation="4dp"
        app:layout_constraintTop_toTopOf="parent">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="制卡"
            android:textColor="@color/white"
            android:textSize="@dimen/title_text_size"
            android:textStyle="bold" />
    </androidx.appcompat.widget.Toolbar>
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:fillViewport="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/titleBar">
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp">
            <androidx.cardview.widget.CardView
                android:id="@+id/home_newCard"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="8dp"
                android:clickable="true"
                android:focusable="true"
                android:foreground="?android:attr/selectableItemBackground"
                app:cardCornerRadius="12dp"
                app:cardElevation="4dp"
                app:layout_constraintEnd_toStartOf="@+id/home_redCard"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <ImageView
                        android:layout_width="70dp"
                        android:layout_height="70dp"
                        android:src="@drawable/home_add" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        android:text="新卡开户"
                        android:textColor="@color/text_selecter_color"
                        android:textSize="@dimen/home_text_size" />
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <androidx.cardview.widget.CardView
                android:id="@+id/home_recharge"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="8dp"
                android:clickable="true"
                android:focusable="true"
                android:foreground="?android:attr/selectableItemBackground"
                android:visibility="gone"
                app:cardCornerRadius="12dp"
                app:cardElevation="4dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <ImageView
                        android:layout_width="70dp"
                        android:layout_height="70dp"
                        android:src="@drawable/home_recharge" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        android:text="充值"
                        android:textColor="@color/text_selecter_color"
                        android:textSize="@dimen/home_text_size" />
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <androidx.cardview.widget.CardView
                android:id="@+id/home_redCard"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="8dp"
                android:clickable="true"
                android:focusable="true"
                android:foreground="?android:attr/selectableItemBackground"
                app:cardCornerRadius="12dp"
                app:cardElevation="4dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/home_newCard"
                app:layout_constraintTop_toTopOf="parent">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <ImageView
                        android:layout_width="70dp"
                        android:layout_height="70dp"
                        android:src="@drawable/home_read" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        android:text="读取卡片"
                        android:textColor="@color/text_selecter_color"
                        android:textSize="@dimen/home_text_size" />
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <androidx.cardview.widget.CardView
                android:id="@+id/home_loss"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="8dp"
                android:clickable="true"
                android:focusable="true"
                android:foreground="?android:attr/selectableItemBackground"
                app:cardCornerRadius="12dp"
                app:cardElevation="4dp"
                app:layout_constraintEnd_toStartOf="@+id/home_replacement"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/home_newCard">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <ImageView
                        android:layout_width="70dp"
                        android:layout_height="70dp"
                        android:src="@drawable/home_report" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        android:text="挂失"
                        android:textColor="@color/text_selecter_color"
                        android:textSize="@dimen/home_text_size" />
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <TextView
                android:id="@+id/home_reportLoss"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="解除挂失"
                android:textColor="@color/text_selecter_color"
                android:textSize="@dimen/home_text_size"
                android:visibility="gone"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
            <androidx.cardview.widget.CardView
                android:id="@+id/home_replacement"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="8dp"
                android:clickable="true"
                android:focusable="true"
                android:foreground="?android:attr/selectableItemBackground"
                app:cardCornerRadius="12dp"
                app:cardElevation="4dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/home_loss"
                app:layout_constraintTop_toBottomOf="@+id/home_redCard">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <ImageView
                        android:layout_width="70dp"
                        android:layout_height="70dp"
                        android:src="@drawable/home_replacement" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        android:text="补卡"
                        android:textColor="@color/text_selecter_color"
                        android:textSize="@dimen/home_text_size" />
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <androidx.cardview.widget.CardView
                android:id="@+id/home_admin"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="8dp"
                android:layout_marginBottom="16dp"
                android:clickable="true"
                android:focusable="true"
                android:foreground="?android:attr/selectableItemBackground"
                app:cardCornerRadius="12dp"
                app:cardElevation="4dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/home_loss"
                app:layout_constraintVertical_bias="0.0">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <ImageView
                        android:layout_width="70dp"
                        android:layout_height="70dp"
                        android:src="@drawable/home_system" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        android:text="管理系统"
                        android:textColor="@color/text_selecter_color"
                        android:textSize="@dimen/home_text_size" />
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <TextView
                android:id="@+id/home_parameter"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="参数设置"
                android:textColor="@color/text_selecter_color"
                android:textSize="@dimen/home_text_size"
                android:visibility="gone"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
            <androidx.cardview.widget.CardView
                android:id="@+id/home_my"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="8dp"
                android:clickable="true"
                android:focusable="true"
                android:foreground="?android:attr/selectableItemBackground"
                android:visibility="gone"
                app:cardCornerRadius="12dp"
                app:cardElevation="4dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/home_admin">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <ImageView
                        android:layout_width="70dp"
                        android:layout_height="70dp"
                        android:src="@drawable/home_my" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="8dp"
                        android:gravity="center"
                        android:text="个人中心"
                        android:textColor="@color/text_selecter_color"
                        android:textSize="@dimen/home_text_size" />
                </LinearLayout>
            </androidx.cardview.widget.CardView>
        </androidx.constraintlayout.widget.ConstraintLayout>
    </ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
generallibrary/src/main/res/layout/fragment_my.xml
New file
@@ -0,0 +1,355 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    android:background="#F5F5F5">
    <RelativeLayout
        android:id="@+id/header_layout"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimen_title_height"
        android:background="@color/bottom_color"
        android:elevation="4dp">
        <TextView
            android:id="@+id/titleBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="我的"
            android:textColor="@color/white"
            android:textSize="@dimen/title_text_size"
            android:textStyle="bold" />
    </RelativeLayout>
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp">
            <!-- 用户信息卡片 -->
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="16dp"
                app:cardCornerRadius="8dp"
                app:cardElevation="2dp"
                app:contentPadding="16dp">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="基本信息"
                        android:textColor="#333333"
                        android:textSize="16sp"
                        android:textStyle="bold"
                        android:layout_marginBottom="12dp"/>
                    <LinearLayout
                        android:id="@+id/my_village"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal"
                        android:visibility="gone"
                        android:layout_marginBottom="8dp">
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="设备编号:"
                            android:textSize="@dimen/text_size"
                            android:textColor="#666666" />
                        <TextView
                            android:id="@+id/my_villageNum"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:textSize="@dimen/text_size"
                            android:textColor="#333333" />
                    </LinearLayout>
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="8dp">
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="区域名称:"
                            android:textColor="#666666"
                            android:textSize="@dimen/text_size" />
                        <TextView
                            android:id="@+id/my_adName"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size" />
                    </LinearLayout>
                    <LinearLayout
                        android:id="@+id/my_admin"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="8dp"
                        android:orientation="horizontal">
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="区域号:"
                            android:textColor="#666666"
                            android:textSize="@dimen/text_size" />
                        <TextView
                            android:id="@+id/my_adminName"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size" />
                    </LinearLayout>
                    <LinearLayout
                        android:id="@+id/my_waterPriceLL"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal">
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="电单价(元/度):"
                            android:textColor="#666666"
                            android:textSize="@dimen/text_size" />
                        <TextView
                            android:id="@+id/my_waterPrice"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size" />
                    </LinearLayout>
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <!-- 记录管理卡片 -->
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="16dp"
                app:cardCornerRadius="8dp"
                app:cardElevation="2dp"
                app:contentPadding="16dp">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="记录管理"
                        android:textColor="#333333"
                        android:textSize="16sp"
                        android:textStyle="bold"
                        android:layout_marginBottom="12dp"/>
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:padding="8dp"
                        android:background="#F9F9F9">
                        <ImageView
                            android:id="@+id/card_icon"
                            android:layout_width="24dp"
                            android:layout_height="24dp"
                            android:layout_centerVertical="true"
                            android:src="@android:drawable/ic_menu_agenda"
                            android:tint="#666666" />
                        <TextView
                            android:id="@+id/my_newCardList_ll"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_centerVertical="true"
                            android:layout_marginStart="8dp"
                            android:layout_toEndOf="@+id/card_icon"
                            android:layout_toStartOf="@+id/my_newCardOut"
                            android:text="开卡记录"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size" />
                        <TextView
                            android:id="@+id/my_newCardOut"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignParentEnd="true"
                            android:layout_centerVertical="true"
                            android:background="@drawable/rounded_button_bg"
                            android:paddingStart="12dp"
                            android:paddingEnd="12dp"
                            android:paddingTop="4dp"
                            android:paddingBottom="4dp"
                            android:text="导出记录"
                            android:textColor="@color/white"
                            android:textSize="12sp" />
                    </RelativeLayout>
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:padding="8dp"
                        android:background="#F9F9F9">
                        <ImageView
                            android:id="@+id/recharge_icon"
                            android:layout_width="24dp"
                            android:layout_height="24dp"
                            android:layout_centerVertical="true"
                            android:src="@android:drawable/ic_menu_recent_history"
                            android:tint="#666666" />
                        <TextView
                            android:id="@+id/my_rechargeList_ll"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_centerVertical="true"
                            android:layout_marginStart="8dp"
                            android:layout_toEndOf="@+id/recharge_icon"
                            android:layout_toStartOf="@+id/my_rechargeOut"
                            android:text="充值记录"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size" />
                        <TextView
                            android:id="@+id/my_rechargeOut"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignParentEnd="true"
                            android:layout_centerVertical="true"
                            android:background="@drawable/rounded_button_bg"
                            android:paddingStart="12dp"
                            android:paddingEnd="12dp"
                            android:paddingTop="4dp"
                            android:paddingBottom="4dp"
                            android:text="导出记录"
                            android:textColor="@color/white"
                            android:textSize="12sp" />
                    </RelativeLayout>
                </LinearLayout>
            </androidx.cardview.widget.CardView>
            <!-- 设置卡片 -->
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:cardCornerRadius="8dp"
                app:cardElevation="2dp"
                app:contentPadding="16dp">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="系统设置"
                        android:textColor="#333333"
                        android:textSize="16sp"
                        android:textStyle="bold"
                        android:layout_marginBottom="12dp"/>
                    <TextView
                        android:id="@+id/sys_ip"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:background="#F9F9F9"
                        android:padding="12dp"
                        android:drawableStart="@android:drawable/ic_menu_manage"
                        android:drawablePadding="8dp"
                        android:drawableTint="#666666"
                        android:text="IP设置"
                        android:textColor="#333333"
                        android:textSize="@dimen/text_size"
                        android:visibility="gone" />
                    <TextView
                        android:id="@+id/card_replacement"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:background="#F9F9F9"
                        android:padding="12dp"
                        android:drawableStart="@android:drawable/ic_menu_edit"
                        android:drawablePadding="8dp"
                        android:drawableTint="#666666"
                        android:text="用户补卡"
                        android:textColor="#333333"
                        android:textSize="@dimen/text_size"
                        android:visibility="gone" />
                    <TextView
                        android:id="@+id/my_psw"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:background="#F9F9F9"
                        android:padding="12dp"
                        android:drawableStart="@android:drawable/ic_lock_lock"
                        android:drawablePadding="8dp"
                        android:drawableTint="#666666"
                        android:text="登录密码设置"
                        android:textColor="#333333"
                        android:textSize="@dimen/text_size"
                        android:visibility="gone" />
                    <TextView
                        android:id="@+id/my_testConnect"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="#F9F9F9"
                        android:padding="12dp"
                        android:drawableStart="@android:drawable/ic_menu_compass"
                        android:drawablePadding="8dp"
                        android:drawableTint="#666666"
                        android:text="未连接数据中心"
                        android:textColor="#333333"
                        android:textSize="@dimen/text_size"
                        android:visibility="gone" />
                </LinearLayout>
            </androidx.cardview.widget.CardView>
        </LinearLayout>
    </ScrollView>
    <com.wang.avi.AVLoadingIndicatorView
        android:id="@+id/avi"
        style="@style/AVLoadingIndicatorView"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:visibility="gone"
        app:indicatorColor="@color/title_bg"
        app:indicatorName="BallClipRotatePulseIndicator" />
</LinearLayout>
generallibrary/src/main/res/layout/fragment_recharge.xml
New file
@@ -0,0 +1,400 @@
<?xml version="1.0" encoding="utf-8"?>
<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"
    android:background="#F5F5F5">
    <RelativeLayout
        android:id="@+id/header_layout"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimen_title_height"
        android:background="@color/bottom_color"
        android:elevation="4dp">
        <TextView
            android:id="@+id/titleBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="充值"
            android:textColor="@color/white"
            android:textSize="@dimen/title_text_size"
            android:textStyle="bold" />
    </RelativeLayout>
    <LinearLayout
        android:id="@+id/recharge_read_LL"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/header_layout"
        android:orientation="vertical"
        android:visibility="visible">
        <androidx.cardview.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            app:cardCornerRadius="8dp"
            app:cardElevation="2dp">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:padding="16dp">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="16dp"
                    android:gravity="center"
                    android:text="请将卡贴在设备上进行读卡"
                    android:textColor="#333333"
                    android:textSize="@dimen/text_size"
                    android:textStyle="bold" />
                <ImageView
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    android:layout_gravity="center"
                    android:scaleType="fitCenter"
                    android:src="@mipmap/nfc_write" />
            </LinearLayout>
        </androidx.cardview.widget.CardView>
    </LinearLayout>
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/recharge_registBtn"
        android:layout_below="@+id/header_layout"
        android:fillViewport="true">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp">
            <LinearLayout
                android:id="@+id/recharge_text_LL"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:visibility="gone">
                <androidx.cardview.widget.CardView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:cardCornerRadius="8dp"
                    app:cardElevation="2dp">
                    <LinearLayout
                        android:id="@+id/recharge_LL"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        android:padding="16dp">
                        <TextView
                            android:id="@+id/red_recharge_water"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:text="充值水量:"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size"
                            android:visibility="gone" />
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:background="#F9F9F9"
                            android:padding="12dp"
                            android:orientation="vertical">
                            <TextView
                                android:id="@+id/recharge_tx"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_marginBottom="8dp"
                                android:text="充值金额(元):"
                                android:textColor="@color/red"
                                android:textSize="@dimen/new_card_size"
                                android:textStyle="bold" />
                            <EditText
                                android:id="@+id/recharge_water"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:background="@android:color/white"
                                android:hint="请输入充值的金额"
                                android:inputType="numberDecimal"
                                android:padding="12dp"
                                android:textSize="@dimen/new_card_size" />
                        </LinearLayout>
                    </LinearLayout>
                </androidx.cardview.widget.CardView>
                <androidx.cardview.widget.CardView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="16dp"
                    android:layout_marginTop="15dp"
                    app:cardCornerRadius="8dp"
                    app:cardElevation="2dp">
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        android:padding="16dp">
                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="12dp"
                            android:text="卡片信息"
                            android:textColor="#333333"
                            android:textSize="16sp"
                            android:textStyle="bold" />
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:orientation="horizontal">
                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:text="卡状态:"
                                android:textColor="#666666"
                                android:textSize="@dimen/text_size" />
                            <TextView
                                android:id="@+id/red_statu"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:textColor="@color/red"
                                android:textSize="@dimen/new_card_size" />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:orientation="horizontal">
                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:text="姓名:"
                                android:textColor="#666666"
                                android:textSize="@dimen/new_card_size" />
                            <TextView
                                android:id="@+id/userName"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:textColor="#333333"
                                android:textSize="@dimen/new_card_size" />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:orientation="horizontal">
                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:text="卡号:"
                                android:textColor="#666666"
                                android:textSize="@dimen/text_size" />
                            <TextView
                                android:id="@+id/red_initCode"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:text=""
                                android:textColor="#333333"
                                android:textSize="@dimen/new_card_size" />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:orientation="horizontal">
                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:text="用户编号:"
                                android:textColor="#666666"
                                android:textSize="@dimen/text_size" />
                            <TextView
                                android:id="@+id/red_userCode"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:text=""
                                android:textColor="#333333"
                                android:textSize="@dimen/new_card_size" />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:orientation="horizontal"
                            android:visibility="visible">
                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:text="充值后剩余金额:"
                                android:textColor="#666666"
                                android:textSize="@dimen/text_size" />
                            <TextView
                                android:id="@+id/red_remainder_blance"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:textColor="#333333"
                                android:textSize="@dimen/new_card_size" />
                        </LinearLayout>
                    </LinearLayout>
                </androidx.cardview.widget.CardView>
                <androidx.cardview.widget.CardView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="16dp"
                    app:cardCornerRadius="8dp"
                    app:cardElevation="2dp">
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        android:padding="16dp">
                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="12dp"
                            android:text="电量信息"
                            android:textColor="#333333"
                            android:textSize="16sp"
                            android:textStyle="bold" />
                        <TextView
                            android:id="@+id/red_balance_electric"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:background="#F9F9F9"
                            android:padding="12dp"
                            android:text="剩余电量:"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size"
                            android:visibility="visible" />
                        <TextView
                            android:id="@+id/red_rechargeDate"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:background="#F9F9F9"
                            android:padding="12dp"
                            android:text="最后购水日期:"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size"
                            android:visibility="visible" />
                        <TextView
                            android:id="@+id/red_rechargeElectric"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:background="#F9F9F9"
                            android:padding="12dp"
                            android:text="电量单价:"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size"
                            android:visibility="visible" />
                        <TextView
                            android:id="@+id/red_rechargeNumber"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:background="#F9F9F9"
                            android:padding="12dp"
                            android:text="充值次数:"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size"
                            android:visibility="gone" />
                        <TextView
                            android:id="@+id/red_total_water"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:background="#F9F9F9"
                            android:padding="12dp"
                            android:text="总用水量:"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size"
                            android:visibility="gone" />
                        <TextView
                            android:id="@+id/red_total_power"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:background="#F9F9F9"
                            android:padding="12dp"
                            android:text="总用电量:"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size"
                            android:visibility="gone" />
                        <TextView
                            android:id="@+id/red_waterPrice"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:background="#F9F9F9"
                            android:padding="12dp"
                            android:text="每立方米水价格:"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size"
                            android:visibility="gone" />
                    </LinearLayout>
                </androidx.cardview.widget.CardView>
            </LinearLayout>
        </LinearLayout>
    </ScrollView>
    <Button
        android:id="@+id/recharge_registBtn"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_margin="16dp"
        android:background="@drawable/rounded_button_bg"
        android:elevation="2dp"
        android:gravity="center"
        android:text="充值"
        android:textColor="@color/white"
        android:textSize="@dimen/new_card_size"
        android:textStyle="bold"
        android:visibility="gone" />
</RelativeLayout>
generallibrary/src/main/res/values/colors.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="bottom_color">#3D8BFF</color>
    <color name="black">#333</color>
    <color name="white">#fff</color>
    <color name="nav_item_color">#555555</color>
</resources>
generallibrary/src/main/res/values/dimens.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="title_text_size">20sp</dimen>
</resources>
henanlibrary/src/main/java/com/dayu/henanlibrary/tools/NFCWriteHelper.java
@@ -2,17 +2,10 @@
import android.app.Activity;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.MifareClassic;
import android.util.Log;
import com.dayu.baselibrary.tools.HexUtil;
import com.dayu.baselibrary.tools.nfc.BaseNfcWriteHelper;
import com.dayu.baselibrary.tools.nfc.NfcWriteAdapter;
import com.dayu.henanlibrary.card.UserCardHN;
import java.io.IOException;
/**
 * @author zx