From a6ee5a76cc99148d786a9ff15be2aa4b1cd8966d Mon Sep 17 00:00:00 2001 From: mhsgit <1411826764@qq.com> Date: Sun, 3 Mar 2024 16:54:20 +0800 Subject: [PATCH 1/2] Initial commit --- LICENSE | 201 +++++ README.md | 7 + build.gradle | 33 + client/.gitignore | 1 + client/build.gradle | 47 ++ client/proguard-rules.pro | 21 + client/src/main/AndroidManifest.xml | 52 ++ .../wallet/safnect/client/MainActivity.java | 26 + .../safnect/client/base/BaseActivity.kt | 25 + .../wallet/safnect/client/base/ClientApp.kt | 25 + .../safnect/client/device/BTActivity.kt | 231 ++++++ .../safnect/client/device/DKGActivity.kt | 203 +++++ .../client/device/adapter/DeviceAdapter.kt | 44 + .../client/devicemanager/DeviceConstant.kt | 10 + .../client/devicemanager/DeviceManager.kt | 274 +++++++ .../client/devicemanager/IDeviceManager.kt | 120 +++ .../drawable-v24/ic_launcher_foreground.xml | 30 + .../src/main/res/drawable/bt_spinner_bg.xml | 14 + .../main/res/drawable/common_blue_top_bg.xml | 5 + .../res/drawable/common_btn_blue_selector.xml | 39 + .../drawable/common_btn_white_selector.xml | 19 + .../res/drawable/ic_launcher_background.xml | 170 ++++ .../drawable/list_item_bg_white_selector.xml | 22 + .../res/drawable/list_item_bg_white_shape.xml | 12 + .../main/res/drawable/welcome_entry_btn.xml | 11 + .../main/res/layout/activity_device_list.xml | 122 +++ client/src/main/res/layout/activity_main.xml | 13 + .../main/res/layout/common_title_layout.xml | 28 + .../res/layout/device_spinner_item_layout.xml | 24 + client/src/main/res/layout/loading_layout.xml | 16 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 6 + client/src/main/res/mipmap-hdpi/app_logo.png | Bin 0 -> 68912 bytes client/src/main/res/mipmap-hdpi/back_icon.png | Bin 0 -> 513 bytes client/src/main/res/mipmap-hdpi/bt_icon.png | Bin 0 -> 1386 bytes client/src/main/res/mipmap-hdpi/btc_icon.png | Bin 0 -> 2637 bytes client/src/main/res/mipmap-hdpi/copy_icon.png | Bin 0 -> 483 bytes .../main/res/mipmap-hdpi/drop_down_arrow.png | Bin 0 -> 535 bytes client/src/main/res/mipmap-hdpi/eth_icon.png | Bin 0 -> 2227 bytes .../res/mipmap-hdpi/hardware_wallet_icon.png | Bin 0 -> 6507 bytes .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../res/mipmap-hdpi/no_transaction_record.png | Bin 0 -> 29713 bytes .../src/main/res/mipmap-hdpi/receive_icon.png | Bin 0 -> 1581 bytes .../src/main/res/mipmap-hdpi/scan_qr_code.png | Bin 0 -> 1194 bytes .../main/res/mipmap-hdpi/scan_qr_code2.png | Bin 0 -> 862 bytes .../res/mipmap-hdpi/share_wallet_icon.png | Bin 0 -> 6127 bytes client/src/main/res/mipmap-hdpi/success.png | Bin 0 -> 3153 bytes .../res/mipmap-hdpi/tab_icon_me_selected.png | Bin 0 -> 1203 bytes .../res/mipmap-hdpi/tab_icon_me_un_select.png | Bin 0 -> 1954 bytes .../mipmap-hdpi/tab_icon_trans_selected.png | Bin 0 -> 563 bytes .../tab_icon_transaction_selected.png | Bin 0 -> 1297 bytes .../tab_icon_transaction_un_select.png | Bin 0 -> 1090 bytes client/src/main/res/mipmap-hdpi/test.png | Bin 0 -> 1628 bytes .../main/res/mipmap-hdpi/transfer_icon.png | Bin 0 -> 886 bytes .../main/res/mipmap-hdpi/wallet_card_bg.png | Bin 0 -> 215312 bytes .../src/main/res/mipmap-hdpi/wallet_logo.png | Bin 0 -> 2249 bytes .../main/res/mipmap-hdpi/wallet_switch.png | Bin 0 -> 610 bytes .../src/main/res/mipmap-hdpi/welcome_bg.png | Bin 0 -> 130781 bytes client/src/main/res/mipmap-hdpi/wld_icon.png | Bin 0 -> 3217 bytes client/src/main/res/mipmap-mdpi/app_logo.png | Bin 0 -> 33610 bytes client/src/main/res/mipmap-mdpi/back_icon.png | Bin 0 -> 273 bytes client/src/main/res/mipmap-mdpi/bt_icon.png | Bin 0 -> 708 bytes client/src/main/res/mipmap-mdpi/btc_icon.png | Bin 0 -> 1623 bytes client/src/main/res/mipmap-mdpi/copy_icon.png | Bin 0 -> 330 bytes .../main/res/mipmap-mdpi/drop_down_arrow.png | Bin 0 -> 293 bytes client/src/main/res/mipmap-mdpi/eth_icon.png | Bin 0 -> 1379 bytes .../res/mipmap-mdpi/hardware_wallet_icon.png | Bin 0 -> 3418 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../res/mipmap-mdpi/no_transaction_record.png | Bin 0 -> 15291 bytes .../src/main/res/mipmap-mdpi/receive_icon.png | Bin 0 -> 874 bytes .../src/main/res/mipmap-mdpi/scan_qr_code.png | Bin 0 -> 725 bytes .../main/res/mipmap-mdpi/scan_qr_code2.png | Bin 0 -> 449 bytes .../res/mipmap-mdpi/share_wallet_icon.png | Bin 0 -> 3350 bytes client/src/main/res/mipmap-mdpi/success.png | Bin 0 -> 3153 bytes .../res/mipmap-mdpi/tab_icon_me_selected.png | Bin 0 -> 721 bytes .../res/mipmap-mdpi/tab_icon_me_un_select.png | Bin 0 -> 1063 bytes .../mipmap-mdpi/tab_icon_trans_selected.png | Bin 0 -> 349 bytes .../tab_icon_transaction_selected.png | Bin 0 -> 732 bytes .../tab_icon_transaction_un_select.png | Bin 0 -> 549 bytes client/src/main/res/mipmap-mdpi/test.png | Bin 0 -> 1085 bytes .../main/res/mipmap-mdpi/transfer_icon.png | Bin 0 -> 444 bytes .../main/res/mipmap-mdpi/wallet_card_bg.png | Bin 0 -> 94161 bytes .../src/main/res/mipmap-mdpi/wallet_logo.png | Bin 0 -> 1224 bytes .../main/res/mipmap-mdpi/wallet_switch.png | Bin 0 -> 334 bytes .../src/main/res/mipmap-mdpi/welcome_bg.png | Bin 0 -> 59356 bytes client/src/main/res/mipmap-mdpi/wld_icon.png | Bin 0 -> 1952 bytes client/src/main/res/mipmap-xhdpi/app_logo.png | Bin 0 -> 117697 bytes .../src/main/res/mipmap-xhdpi/back_icon.png | Bin 0 -> 459 bytes client/src/main/res/mipmap-xhdpi/bt_icon.png | Bin 0 -> 1522 bytes client/src/main/res/mipmap-xhdpi/btc_icon.png | Bin 0 -> 3112 bytes .../src/main/res/mipmap-xhdpi/copy_icon.png | Bin 0 -> 538 bytes .../main/res/mipmap-xhdpi/drop_down_arrow.png | Bin 0 -> 620 bytes client/src/main/res/mipmap-xhdpi/eth_icon.png | Bin 0 -> 2700 bytes .../res/mipmap-xhdpi/hardware_wallet_icon.png | Bin 0 -> 6852 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../mipmap-xhdpi/no_transaction_record.png | Bin 0 -> 34169 bytes .../main/res/mipmap-xhdpi/receive_icon.png | Bin 0 -> 2110 bytes .../main/res/mipmap-xhdpi/scan_qr_code.png | Bin 0 -> 1134 bytes .../main/res/mipmap-xhdpi/scan_qr_code2.png | Bin 0 -> 730 bytes .../res/mipmap-xhdpi/share_wallet_icon.png | Bin 0 -> 6177 bytes client/src/main/res/mipmap-xhdpi/success.png | Bin 0 -> 3153 bytes .../res/mipmap-xhdpi/tab_icon_me_selected.png | Bin 0 -> 1358 bytes .../mipmap-xhdpi/tab_icon_me_un_select.png | Bin 0 -> 1920 bytes .../mipmap-xhdpi/tab_icon_trans_selected.png | Bin 0 -> 703 bytes .../tab_icon_transaction_selected.png | Bin 0 -> 1619 bytes .../tab_icon_transaction_un_select.png | Bin 0 -> 1073 bytes client/src/main/res/mipmap-xhdpi/test.png | Bin 0 -> 2049 bytes .../main/res/mipmap-xhdpi/transfer_icon.png | Bin 0 -> 845 bytes .../main/res/mipmap-xhdpi/wallet_card_bg.png | Bin 0 -> 419764 bytes .../src/main/res/mipmap-xhdpi/wallet_logo.png | Bin 0 -> 2952 bytes .../main/res/mipmap-xhdpi/wallet_switch.png | Bin 0 -> 542 bytes .../src/main/res/mipmap-xhdpi/welcome_bg.png | Bin 0 -> 234551 bytes client/src/main/res/mipmap-xhdpi/wld_icon.png | Bin 0 -> 4293 bytes .../src/main/res/mipmap-xxhdpi/app_logo.png | Bin 0 -> 242498 bytes .../src/main/res/mipmap-xxhdpi/back_icon.png | Bin 0 -> 860 bytes client/src/main/res/mipmap-xxhdpi/bt_icon.png | Bin 0 -> 3006 bytes .../src/main/res/mipmap-xxhdpi/btc_icon.png | Bin 0 -> 5675 bytes .../src/main/res/mipmap-xxhdpi/copy_icon.png | Bin 0 -> 813 bytes .../res/mipmap-xxhdpi/drop_down_arrow.png | Bin 0 -> 1090 bytes .../src/main/res/mipmap-xxhdpi/eth_icon.png | Bin 0 -> 4904 bytes .../mipmap-xxhdpi/hardware_wallet_icon.png | Bin 0 -> 16177 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../mipmap-xxhdpi/no_transaction_record.png | Bin 0 -> 73713 bytes .../main/res/mipmap-xxhdpi/receive_icon.png | Bin 0 -> 3963 bytes .../main/res/mipmap-xxhdpi/scan_qr_code.png | Bin 0 -> 2085 bytes .../main/res/mipmap-xxhdpi/scan_qr_code2.png | Bin 0 -> 1317 bytes .../res/mipmap-xxhdpi/share_wallet_icon.png | Bin 0 -> 12791 bytes client/src/main/res/mipmap-xxhdpi/success.png | Bin 0 -> 6662 bytes .../mipmap-xxhdpi/tab_icon_me_selected.png | Bin 0 -> 2621 bytes .../mipmap-xxhdpi/tab_icon_me_un_select.png | Bin 0 -> 4089 bytes .../mipmap-xxhdpi/tab_icon_trans_selected.png | Bin 0 -> 1270 bytes .../tab_icon_transaction_selected.png | Bin 0 -> 3002 bytes .../tab_icon_transaction_un_select.png | Bin 0 -> 2030 bytes .../tab_icon_wallet_selected.png | Bin 0 -> 2020 bytes .../tab_icon_wallet_un_select.png | Bin 0 -> 2268 bytes client/src/main/res/mipmap-xxhdpi/test.png | Bin 0 -> 2049 bytes .../main/res/mipmap-xxhdpi/transfer_icon.png | Bin 0 -> 1554 bytes .../main/res/mipmap-xxhdpi/wallet_card_bg.png | Bin 0 -> 941763 bytes .../main/res/mipmap-xxhdpi/wallet_logo.png | Bin 0 -> 5661 bytes .../main/res/mipmap-xxhdpi/wallet_switch.png | Bin 0 -> 953 bytes .../src/main/res/mipmap-xxhdpi/welcome_bg.png | Bin 0 -> 487933 bytes .../src/main/res/mipmap-xxhdpi/wld_icon.png | Bin 0 -> 7575 bytes .../src/main/res/mipmap-xxxhdpi/app_logo.png | Bin 0 -> 551330 bytes .../src/main/res/mipmap-xxxhdpi/back_icon.png | Bin 0 -> 856 bytes .../src/main/res/mipmap-xxxhdpi/bt_icon.png | Bin 0 -> 2449 bytes .../src/main/res/mipmap-xxxhdpi/btc_icon.png | Bin 0 -> 4656 bytes .../src/main/res/mipmap-xxxhdpi/copy_icon.png | Bin 0 -> 962 bytes .../res/mipmap-xxxhdpi/drop_down_arrow.png | Bin 0 -> 1011 bytes .../src/main/res/mipmap-xxxhdpi/eth_icon.png | Bin 0 -> 3978 bytes .../mipmap-xxxhdpi/hardware_wallet_icon.png | Bin 0 -> 10210 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes .../mipmap-xxxhdpi/no_transaction_record.png | Bin 0 -> 68237 bytes .../main/res/mipmap-xxxhdpi/receive_icon.png | Bin 0 -> 2956 bytes .../main/res/mipmap-xxxhdpi/scan_qr_code.png | Bin 0 -> 1799 bytes .../main/res/mipmap-xxxhdpi/scan_qr_code2.png | Bin 0 -> 1162 bytes .../res/mipmap-xxxhdpi/share_wallet_icon.png | Bin 0 -> 9668 bytes .../src/main/res/mipmap-xxxhdpi/success.png | Bin 0 -> 6662 bytes .../mipmap-xxxhdpi/tab_icon_me_selected.png | Bin 0 -> 2687 bytes .../mipmap-xxxhdpi/tab_icon_me_un_select.png | Bin 0 -> 2828 bytes .../tab_icon_trans_selected.png | Bin 0 -> 1542 bytes .../tab_icon_transaction_selected.png | Bin 0 -> 3968 bytes .../tab_icon_transaction_un_select.png | Bin 0 -> 1810 bytes client/src/main/res/mipmap-xxxhdpi/test.png | Bin 0 -> 4194 bytes .../main/res/mipmap-xxxhdpi/transfer_icon.png | Bin 0 -> 1318 bytes .../res/mipmap-xxxhdpi/wallet_card_bg.png | Bin 0 -> 1884846 bytes .../main/res/mipmap-xxxhdpi/wallet_logo.png | Bin 0 -> 7339 bytes .../main/res/mipmap-xxxhdpi/wallet_switch.png | Bin 0 -> 827 bytes .../main/res/mipmap-xxxhdpi/welcome_bg.png | Bin 0 -> 752631 bytes .../src/main/res/mipmap-xxxhdpi/wld_icon.png | Bin 0 -> 10060 bytes client/src/main/res/values/dimen.xml | 6 + client/src/main/res/values/strings.xml | 75 ++ client/src/main/res/values/themes.xml | 116 +++ common/.gitignore | 1 + common/build.gradle | 84 ++ common/consumer-rules.pro | 0 common/proguard-rules.pro | 21 + common/src/main/AndroidManifest.xml | 6 + .../main/java/com/populstay/common/ExFun.kt | 121 +++ .../com/populstay/common/GlobalConstant.kt | 8 + .../com/populstay/common/base/BaseApp.java | 83 ++ .../java/com/populstay/common/bean/BTBean.kt | 12 + .../com/populstay/common/bean/CBleDevice.kt | 18 + .../java/com/populstay/common/bean/CPhone.kt | 16 + .../com/populstay/common/dimen/DimenUtil.java | 25 + .../common/loader/LoaderCreator.java | 45 ++ .../populstay/common/loader/LoaderStyle.java | 36 + .../populstay/common/loader/PageLoader.java | 67 ++ .../populstay/common/loader/PeachLoader.java | 114 +++ .../populstay/common/log/CrashHandler.java | 265 ++++++ .../log/CustomUncaughtExceptionHandler.java | 44 + .../com/populstay/common/log/DateUtil.java | 110 +++ .../com/populstay/common/log/LogToFile.java | 143 ++++ .../common/log/MyDiskLogStrategy.java | 117 +++ .../com/populstay/common/log/PeachLogger.java | 66 ++ .../common/repository/BLEByteArrayUtil.kt | 82 ++ .../common/repository/BlueToothBLEUtil.kt | 758 ++++++++++++++++++ .../common/repository/BluetoothQueueUtil.kt | 41 + .../populstay/common/repository/IBlueTooth.kt | 10 + common/src/main/res/layout/loading_layout.xml | 16 + common/src/main/res/values/colors.xml | 30 + common/src/main/res/values/themes.xml | 23 + gradle.properties | 25 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 +++++ gradlew.bat | 89 ++ server/.gitignore | 1 + server/build.gradle | 46 ++ server/proguard-rules.pro | 21 + server/src/main/AndroidManifest.xml | 48 ++ .../wallet/safnect/server/MainActivity.kt | 440 ++++++++++ .../wallet/safnect/server/ServerApp.kt | 25 + .../drawable-v24/ic_launcher_foreground.xml | 30 + .../res/drawable/ic_launcher_background.xml | 170 ++++ server/src/main/res/layout/activity_main.xml | 21 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 6 + .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes server/src/main/res/values/colors.xml | 10 + server/src/main/res/values/strings.xml | 19 + settings.gradle | 3 + 235 files changed, 5567 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 build.gradle create mode 100644 client/.gitignore create mode 100644 client/build.gradle create mode 100644 client/proguard-rules.pro create mode 100644 client/src/main/AndroidManifest.xml create mode 100644 client/src/main/java/com/populstay/wallet/safnect/client/MainActivity.java create mode 100644 client/src/main/java/com/populstay/wallet/safnect/client/base/BaseActivity.kt create mode 100644 client/src/main/java/com/populstay/wallet/safnect/client/base/ClientApp.kt create mode 100644 client/src/main/java/com/populstay/wallet/safnect/client/device/BTActivity.kt create mode 100644 client/src/main/java/com/populstay/wallet/safnect/client/device/DKGActivity.kt create mode 100644 client/src/main/java/com/populstay/wallet/safnect/client/device/adapter/DeviceAdapter.kt create mode 100644 client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/DeviceConstant.kt create mode 100644 client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/DeviceManager.kt create mode 100644 client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/IDeviceManager.kt create mode 100644 client/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 client/src/main/res/drawable/bt_spinner_bg.xml create mode 100644 client/src/main/res/drawable/common_blue_top_bg.xml create mode 100644 client/src/main/res/drawable/common_btn_blue_selector.xml create mode 100644 client/src/main/res/drawable/common_btn_white_selector.xml create mode 100644 client/src/main/res/drawable/ic_launcher_background.xml create mode 100644 client/src/main/res/drawable/list_item_bg_white_selector.xml create mode 100644 client/src/main/res/drawable/list_item_bg_white_shape.xml create mode 100644 client/src/main/res/drawable/welcome_entry_btn.xml create mode 100644 client/src/main/res/layout/activity_device_list.xml create mode 100644 client/src/main/res/layout/activity_main.xml create mode 100644 client/src/main/res/layout/common_title_layout.xml create mode 100644 client/src/main/res/layout/device_spinner_item_layout.xml create mode 100644 client/src/main/res/layout/loading_layout.xml create mode 100644 client/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 client/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 client/src/main/res/mipmap-hdpi/app_logo.png create mode 100644 client/src/main/res/mipmap-hdpi/back_icon.png create mode 100644 client/src/main/res/mipmap-hdpi/bt_icon.png create mode 100644 client/src/main/res/mipmap-hdpi/btc_icon.png create mode 100644 client/src/main/res/mipmap-hdpi/copy_icon.png create mode 100644 client/src/main/res/mipmap-hdpi/drop_down_arrow.png create mode 100644 client/src/main/res/mipmap-hdpi/eth_icon.png create mode 100644 client/src/main/res/mipmap-hdpi/hardware_wallet_icon.png create mode 100644 client/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 client/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 client/src/main/res/mipmap-hdpi/no_transaction_record.png create mode 100644 client/src/main/res/mipmap-hdpi/receive_icon.png create mode 100644 client/src/main/res/mipmap-hdpi/scan_qr_code.png create mode 100644 client/src/main/res/mipmap-hdpi/scan_qr_code2.png create mode 100644 client/src/main/res/mipmap-hdpi/share_wallet_icon.png create mode 100644 client/src/main/res/mipmap-hdpi/success.png create mode 100644 client/src/main/res/mipmap-hdpi/tab_icon_me_selected.png create mode 100644 client/src/main/res/mipmap-hdpi/tab_icon_me_un_select.png create mode 100644 client/src/main/res/mipmap-hdpi/tab_icon_trans_selected.png create mode 100644 client/src/main/res/mipmap-hdpi/tab_icon_transaction_selected.png create mode 100644 client/src/main/res/mipmap-hdpi/tab_icon_transaction_un_select.png create mode 100644 client/src/main/res/mipmap-hdpi/test.png create mode 100644 client/src/main/res/mipmap-hdpi/transfer_icon.png create mode 100644 client/src/main/res/mipmap-hdpi/wallet_card_bg.png create mode 100644 client/src/main/res/mipmap-hdpi/wallet_logo.png create mode 100644 client/src/main/res/mipmap-hdpi/wallet_switch.png create mode 100644 client/src/main/res/mipmap-hdpi/welcome_bg.png create mode 100644 client/src/main/res/mipmap-hdpi/wld_icon.png create mode 100644 client/src/main/res/mipmap-mdpi/app_logo.png create mode 100644 client/src/main/res/mipmap-mdpi/back_icon.png create mode 100644 client/src/main/res/mipmap-mdpi/bt_icon.png create mode 100644 client/src/main/res/mipmap-mdpi/btc_icon.png create mode 100644 client/src/main/res/mipmap-mdpi/copy_icon.png create mode 100644 client/src/main/res/mipmap-mdpi/drop_down_arrow.png create mode 100644 client/src/main/res/mipmap-mdpi/eth_icon.png create mode 100644 client/src/main/res/mipmap-mdpi/hardware_wallet_icon.png create mode 100644 client/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 client/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 client/src/main/res/mipmap-mdpi/no_transaction_record.png create mode 100644 client/src/main/res/mipmap-mdpi/receive_icon.png create mode 100644 client/src/main/res/mipmap-mdpi/scan_qr_code.png create mode 100644 client/src/main/res/mipmap-mdpi/scan_qr_code2.png create mode 100644 client/src/main/res/mipmap-mdpi/share_wallet_icon.png create mode 100644 client/src/main/res/mipmap-mdpi/success.png create mode 100644 client/src/main/res/mipmap-mdpi/tab_icon_me_selected.png create mode 100644 client/src/main/res/mipmap-mdpi/tab_icon_me_un_select.png create mode 100644 client/src/main/res/mipmap-mdpi/tab_icon_trans_selected.png create mode 100644 client/src/main/res/mipmap-mdpi/tab_icon_transaction_selected.png create mode 100644 client/src/main/res/mipmap-mdpi/tab_icon_transaction_un_select.png create mode 100644 client/src/main/res/mipmap-mdpi/test.png create mode 100644 client/src/main/res/mipmap-mdpi/transfer_icon.png create mode 100644 client/src/main/res/mipmap-mdpi/wallet_card_bg.png create mode 100644 client/src/main/res/mipmap-mdpi/wallet_logo.png create mode 100644 client/src/main/res/mipmap-mdpi/wallet_switch.png create mode 100644 client/src/main/res/mipmap-mdpi/welcome_bg.png create mode 100644 client/src/main/res/mipmap-mdpi/wld_icon.png create mode 100644 client/src/main/res/mipmap-xhdpi/app_logo.png create mode 100644 client/src/main/res/mipmap-xhdpi/back_icon.png create mode 100644 client/src/main/res/mipmap-xhdpi/bt_icon.png create mode 100644 client/src/main/res/mipmap-xhdpi/btc_icon.png create mode 100644 client/src/main/res/mipmap-xhdpi/copy_icon.png create mode 100644 client/src/main/res/mipmap-xhdpi/drop_down_arrow.png create mode 100644 client/src/main/res/mipmap-xhdpi/eth_icon.png create mode 100644 client/src/main/res/mipmap-xhdpi/hardware_wallet_icon.png create mode 100644 client/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 client/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 client/src/main/res/mipmap-xhdpi/no_transaction_record.png create mode 100644 client/src/main/res/mipmap-xhdpi/receive_icon.png create mode 100644 client/src/main/res/mipmap-xhdpi/scan_qr_code.png create mode 100644 client/src/main/res/mipmap-xhdpi/scan_qr_code2.png create mode 100644 client/src/main/res/mipmap-xhdpi/share_wallet_icon.png create mode 100644 client/src/main/res/mipmap-xhdpi/success.png create mode 100644 client/src/main/res/mipmap-xhdpi/tab_icon_me_selected.png create mode 100644 client/src/main/res/mipmap-xhdpi/tab_icon_me_un_select.png create mode 100644 client/src/main/res/mipmap-xhdpi/tab_icon_trans_selected.png create mode 100644 client/src/main/res/mipmap-xhdpi/tab_icon_transaction_selected.png create mode 100644 client/src/main/res/mipmap-xhdpi/tab_icon_transaction_un_select.png create mode 100644 client/src/main/res/mipmap-xhdpi/test.png create mode 100644 client/src/main/res/mipmap-xhdpi/transfer_icon.png create mode 100644 client/src/main/res/mipmap-xhdpi/wallet_card_bg.png create mode 100644 client/src/main/res/mipmap-xhdpi/wallet_logo.png create mode 100644 client/src/main/res/mipmap-xhdpi/wallet_switch.png create mode 100644 client/src/main/res/mipmap-xhdpi/welcome_bg.png create mode 100644 client/src/main/res/mipmap-xhdpi/wld_icon.png create mode 100644 client/src/main/res/mipmap-xxhdpi/app_logo.png create mode 100644 client/src/main/res/mipmap-xxhdpi/back_icon.png create mode 100644 client/src/main/res/mipmap-xxhdpi/bt_icon.png create mode 100644 client/src/main/res/mipmap-xxhdpi/btc_icon.png create mode 100644 client/src/main/res/mipmap-xxhdpi/copy_icon.png create mode 100644 client/src/main/res/mipmap-xxhdpi/drop_down_arrow.png create mode 100644 client/src/main/res/mipmap-xxhdpi/eth_icon.png create mode 100644 client/src/main/res/mipmap-xxhdpi/hardware_wallet_icon.png create mode 100644 client/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 client/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 client/src/main/res/mipmap-xxhdpi/no_transaction_record.png create mode 100644 client/src/main/res/mipmap-xxhdpi/receive_icon.png create mode 100644 client/src/main/res/mipmap-xxhdpi/scan_qr_code.png create mode 100644 client/src/main/res/mipmap-xxhdpi/scan_qr_code2.png create mode 100644 client/src/main/res/mipmap-xxhdpi/share_wallet_icon.png create mode 100644 client/src/main/res/mipmap-xxhdpi/success.png create mode 100644 client/src/main/res/mipmap-xxhdpi/tab_icon_me_selected.png create mode 100644 client/src/main/res/mipmap-xxhdpi/tab_icon_me_un_select.png create mode 100644 client/src/main/res/mipmap-xxhdpi/tab_icon_trans_selected.png create mode 100644 client/src/main/res/mipmap-xxhdpi/tab_icon_transaction_selected.png create mode 100644 client/src/main/res/mipmap-xxhdpi/tab_icon_transaction_un_select.png create mode 100644 client/src/main/res/mipmap-xxhdpi/tab_icon_wallet_selected.png create mode 100644 client/src/main/res/mipmap-xxhdpi/tab_icon_wallet_un_select.png create mode 100644 client/src/main/res/mipmap-xxhdpi/test.png create mode 100644 client/src/main/res/mipmap-xxhdpi/transfer_icon.png create mode 100644 client/src/main/res/mipmap-xxhdpi/wallet_card_bg.png create mode 100644 client/src/main/res/mipmap-xxhdpi/wallet_logo.png create mode 100644 client/src/main/res/mipmap-xxhdpi/wallet_switch.png create mode 100644 client/src/main/res/mipmap-xxhdpi/welcome_bg.png create mode 100644 client/src/main/res/mipmap-xxhdpi/wld_icon.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/app_logo.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/back_icon.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/bt_icon.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/btc_icon.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/copy_icon.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/drop_down_arrow.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/eth_icon.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/hardware_wallet_icon.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 client/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 client/src/main/res/mipmap-xxxhdpi/no_transaction_record.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/receive_icon.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/scan_qr_code.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/scan_qr_code2.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/share_wallet_icon.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/success.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/tab_icon_me_selected.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/tab_icon_me_un_select.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/tab_icon_trans_selected.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/tab_icon_transaction_selected.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/tab_icon_transaction_un_select.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/test.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/transfer_icon.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/wallet_card_bg.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/wallet_logo.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/wallet_switch.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/welcome_bg.png create mode 100644 client/src/main/res/mipmap-xxxhdpi/wld_icon.png create mode 100644 client/src/main/res/values/dimen.xml create mode 100644 client/src/main/res/values/strings.xml create mode 100644 client/src/main/res/values/themes.xml create mode 100644 common/.gitignore create mode 100644 common/build.gradle create mode 100644 common/consumer-rules.pro create mode 100644 common/proguard-rules.pro create mode 100644 common/src/main/AndroidManifest.xml create mode 100644 common/src/main/java/com/populstay/common/ExFun.kt create mode 100644 common/src/main/java/com/populstay/common/GlobalConstant.kt create mode 100644 common/src/main/java/com/populstay/common/base/BaseApp.java create mode 100644 common/src/main/java/com/populstay/common/bean/BTBean.kt create mode 100644 common/src/main/java/com/populstay/common/bean/CBleDevice.kt create mode 100644 common/src/main/java/com/populstay/common/bean/CPhone.kt create mode 100644 common/src/main/java/com/populstay/common/dimen/DimenUtil.java create mode 100644 common/src/main/java/com/populstay/common/loader/LoaderCreator.java create mode 100644 common/src/main/java/com/populstay/common/loader/LoaderStyle.java create mode 100644 common/src/main/java/com/populstay/common/loader/PageLoader.java create mode 100644 common/src/main/java/com/populstay/common/loader/PeachLoader.java create mode 100644 common/src/main/java/com/populstay/common/log/CrashHandler.java create mode 100644 common/src/main/java/com/populstay/common/log/CustomUncaughtExceptionHandler.java create mode 100644 common/src/main/java/com/populstay/common/log/DateUtil.java create mode 100644 common/src/main/java/com/populstay/common/log/LogToFile.java create mode 100644 common/src/main/java/com/populstay/common/log/MyDiskLogStrategy.java create mode 100644 common/src/main/java/com/populstay/common/log/PeachLogger.java create mode 100644 common/src/main/java/com/populstay/common/repository/BLEByteArrayUtil.kt create mode 100644 common/src/main/java/com/populstay/common/repository/BlueToothBLEUtil.kt create mode 100644 common/src/main/java/com/populstay/common/repository/BluetoothQueueUtil.kt create mode 100644 common/src/main/java/com/populstay/common/repository/IBlueTooth.kt create mode 100644 common/src/main/res/layout/loading_layout.xml create mode 100644 common/src/main/res/values/colors.xml create mode 100644 common/src/main/res/values/themes.xml create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 server/.gitignore create mode 100644 server/build.gradle create mode 100644 server/proguard-rules.pro create mode 100644 server/src/main/AndroidManifest.xml create mode 100644 server/src/main/java/com/populstay/wallet/safnect/server/MainActivity.kt create mode 100644 server/src/main/java/com/populstay/wallet/safnect/server/ServerApp.kt create mode 100644 server/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 server/src/main/res/drawable/ic_launcher_background.xml create mode 100644 server/src/main/res/layout/activity_main.xml create mode 100644 server/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 server/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 server/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 server/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 server/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 server/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 server/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 server/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 server/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 server/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 server/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 server/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 server/src/main/res/values/colors.xml create mode 100644 server/src/main/res/values/strings.xml create mode 100644 settings.gradle diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a617cc --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# AndroidBLEDemo +Android的蓝牙BLE实现Demo,使用MVI架构 + +**2023-07-11** +Demo中加入分包通讯和接收的实现,将MTU先改为512,然后通过计算大文本进行数据分包发送,接收时统一接收完成后进行组装。 + + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..ad4ebde --- /dev/null +++ b/build.gradle @@ -0,0 +1,33 @@ +buildscript { + ext.kotlin_version = "1.6.0" + repositories { + google() + jcenter() + mavenCentral() + maven { url "http://lib.gcssloop.com:8081/repository/gcssloop-central/" } + + } + dependencies { + classpath 'com.android.tools.build:gradle:4.1.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" + classpath 'com.google.protobuf:protobuf-gradle-plugin:0.9.4' + + + } +} + +allprojects { + repositories { + mavenCentral() + jcenter() + google() + maven { url "https://jitpack.io" } + // 私有仓库地址 + maven { url "http://lib.gcssloop.com:8081/repository/gcssloop-central/" } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/client/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/client/build.gradle b/client/build.gradle new file mode 100644 index 0000000..1b91b7e --- /dev/null +++ b/client/build.gradle @@ -0,0 +1,47 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'com.google.protobuf' +apply plugin: 'kotlin-kapt' + +android { + compileSdk 33 + defaultConfig { + applicationId "com.populstay.wallet.safnect.client" + minSdkVersion 21 + targetSdkVersion 33 + versionCode 1 + versionName "1.0" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + buildFeatures { + viewBinding true + } + + dataBinding { + //noinspection DataBindingWithoutKapt + enabled = true + } + + kotlinOptions { + jvmTarget = '1.8' + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kapt { + generateStubs = true + } +} + +dependencies { + implementation project(':common') +} \ No newline at end of file diff --git a/client/proguard-rules.pro b/client/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/client/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/client/src/main/AndroidManifest.xml b/client/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4e31704 --- /dev/null +++ b/client/src/main/AndroidManifest.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/src/main/java/com/populstay/wallet/safnect/client/MainActivity.java b/client/src/main/java/com/populstay/wallet/safnect/client/MainActivity.java new file mode 100644 index 0000000..02e6b85 --- /dev/null +++ b/client/src/main/java/com/populstay/wallet/safnect/client/MainActivity.java @@ -0,0 +1,26 @@ +package com.populstay.wallet.safnect.client; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import com.populstay.wallet.safnect.client.device.DKGActivity; + + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + findViewById(R.id.dkg_btn).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(MainActivity.this, DKGActivity.class)); + } + }); + } +} \ No newline at end of file diff --git a/client/src/main/java/com/populstay/wallet/safnect/client/base/BaseActivity.kt b/client/src/main/java/com/populstay/wallet/safnect/client/base/BaseActivity.kt new file mode 100644 index 0000000..f2ae99d --- /dev/null +++ b/client/src/main/java/com/populstay/wallet/safnect/client/base/BaseActivity.kt @@ -0,0 +1,25 @@ +package com.populstay.wallet.safnect.client.base + +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AppCompatActivity + +abstract class BaseActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStatusBarTextColor() + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + setStatusBarTextColor() + } + + fun setStatusBarTextColor(){ + //设置字体黑色 + window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + } + + abstract fun initTitleBar() +} diff --git a/client/src/main/java/com/populstay/wallet/safnect/client/base/ClientApp.kt b/client/src/main/java/com/populstay/wallet/safnect/client/base/ClientApp.kt new file mode 100644 index 0000000..00a0c96 --- /dev/null +++ b/client/src/main/java/com/populstay/wallet/safnect/client/base/ClientApp.kt @@ -0,0 +1,25 @@ +package com.populstay.wallet.safnect.client.base + +import android.annotation.SuppressLint +import android.content.Context +import com.populstay.common.base.BaseApp +import com.populstay.common.repository.BlueToothBLEUtil + +class ClientApp : BaseApp() { + + companion object { + @SuppressLint("StaticFieldLeak") + lateinit var mContext: Context + + @SuppressLint("StaticFieldLeak") + lateinit var instance: ClientApp + } + + override fun onCreate() { + super.onCreate() + instance = this + mContext = this + //初始化BlueToothBLEUtil + BlueToothBLEUtil.init(this) + } +} \ No newline at end of file diff --git a/client/src/main/java/com/populstay/wallet/safnect/client/device/BTActivity.kt b/client/src/main/java/com/populstay/wallet/safnect/client/device/BTActivity.kt new file mode 100644 index 0000000..28dda92 --- /dev/null +++ b/client/src/main/java/com/populstay/wallet/safnect/client/device/BTActivity.kt @@ -0,0 +1,231 @@ +package com.populstay.wallet.safnect.client.device + +import android.Manifest +import android.app.Activity +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattService +import android.bluetooth.BluetoothProfile +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import android.os.Bundle +import android.util.Log +import android.view.WindowManager +import android.widget.Toast +import androidx.annotation.RequiresApi +import androidx.lifecycle.lifecycleScope +import com.populstay.common.GlobalConstant +import com.populstay.common.bean.CBleDevice +import com.populstay.common.log.PeachLogger +import com.populstay.common.repository.BlueToothBLEUtil +import com.populstay.wallet.devicemanager.BTGattCallback +import com.populstay.wallet.devicemanager.DeviceConstant +import com.populstay.wallet.devicemanager.IBTListener +import com.populstay.wallet.devicemanager.IScanResult +import com.populstay.wallet.safnect.client.R +import com.populstay.wallet.safnect.client.base.BaseActivity +import com.populstay.wallet.safnect.client.devicemanager.DeviceManager +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.launch + +abstract class BTActivity : BaseActivity(),IScanResult, BTGattCallback , IBTListener , CoroutineScope by MainScope() { + + companion object{ + const val TAG = "BTActivity-->" + } + protected var mCurSelectDevice : CBleDevice? = null + protected var mBluetoothGattService : BluetoothGattService? = null + + protected fun connect(){ + mCurSelectDevice?.device?.address?.let { address-> + // todo 特别的大坑,重复连接,导致蓝牙数据回传方法多次回调onCharacteristicChanged + // todo 要先断开连接,才能二次连接,各种怀疑哎,kotlin协程问题、蓝牙传输问题。。。。。。 + DeviceManager.disconnect() + DeviceManager.connect(address,this) + } + } + + @RequiresApi(Build.VERSION_CODES.M) + protected fun startScan(){ + DeviceManager.startScanAndCheckBTStatus(this,this) + } + + protected fun stopScan(){ + DeviceManager.stopScan() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } + + var onConnectionStateChangeJob: Job? = null + // 设备连接状态 + override fun onConnectionStateChange( + gatt: BluetoothGatt?, + status: Int, + newState: Int + ) { + super.onConnectionStateChange(gatt, status, newState) + val address = gatt?.device?.address + PeachLogger.d(GlobalConstant.APP_TAG, "$TAG onConnectionStateChange Client status = $status newState = $newState address= $address") + onConnectionStateChangeJob?.cancel() + onConnectionStateChangeJob?.cancelChildren() + onConnectionStateChangeJob = lifecycleScope.launch { + if (!BlueToothBLEUtil.checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) { + return@launch + } + when (status) { + BluetoothGatt.GATT_SUCCESS -> { + BlueToothBLEUtil.refreshDeviceCache() + //连接状态 + when (newState) { + BluetoothProfile.STATE_CONNECTED -> { + // 连接成功 + gatt?.let { + PeachLogger.d(GlobalConstant.APP_TAG, "$TAG onConnectionStateChange Client 连接ok,开始发现服务 address= $address") + gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED) + // 去发现服务 + DeviceManager.discoverServices() + } + } + BluetoothProfile.STATE_DISCONNECTED -> { + // 连接断开 + gatt?.let { + // 重连 + gatt.connect() + PeachLogger.d(GlobalConstant.APP_TAG, "$TAG onConnectionStateChange Client 开始重连 address= $address") + } + } + else -> { + PeachLogger.d(GlobalConstant.APP_TAG, "$TAG onConnectionStateChange Client 断开了 address= $address") + // 断开了 + gatt?.disconnect() + } + } + } + else ->{ + PeachLogger.d(GlobalConstant.APP_TAG, "$TAG onConnectionStateChange Client 连接失败了 address= $address") + onConnectionFail() + } + } + } + } + + override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) { + super.onMtuChanged(gatt, mtu, status) + PeachLogger.d(GlobalConstant.APP_TAG, "$TAG onMtuChanged Client mtu = $mtu") + } + + var onServicesDiscoveredJob: Job? = null + // 发现服务 + override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) { + super.onServicesDiscovered(gatt, status) + onServicesDiscoveredJob?.cancel() + onServicesDiscoveredJob?.cancelChildren() + onServicesDiscoveredJob = lifecycleScope.launch { + when (status) { + BluetoothGatt.GATT_SUCCESS -> { + gatt?.let { gatt -> + PeachLogger.d(GlobalConstant.APP_TAG, "$TAG onServicesDiscovered Client status = $status 发现服务") + gatt.getService(BlueToothBLEUtil.getUUID(BlueToothBLEUtil.BLESERVER))?.let { service -> + mBluetoothGattService = service + val characteristicCommonRead = mBluetoothGattService?.getCharacteristic( + BlueToothBLEUtil.getUUID(BlueToothBLEUtil.BLECHARACTERISTIC_COMMON_READ)) + characteristicCommonRead?.let { + // 通知的监听,这一步很关键,不然外围设备端发送的数据将无法接收到。 + if (characteristicCommonRead.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0){ + BlueToothBLEUtil.setCharacteristicNotify(characteristicCommonRead , true) + } + } + } + } + + launch { + //连接成功后设置MTU通讯 + BlueToothBLEUtil.requestMTU(500) + } + + // 回调给子类处理 + onFoundService() + } + else -> { + PeachLogger.d(GlobalConstant.APP_TAG, "$TAG onServicesDiscovered Client 发现服务失败") + } + } + } + } + + // 特征值变化,副端向主端传值,主端监听到数据 + override fun onCharacteristicChanged( + gatt: BluetoothGatt?, + characteristic: BluetoothGattCharacteristic? + ) { + super.onCharacteristicChanged(gatt, characteristic) + lifecycleScope.launch { + + characteristic?.let { + characteristic?.value?.let { + if (characteristic.uuid == BlueToothBLEUtil.getUUID(BlueToothBLEUtil.BLECHARACTERISTIC_COMMON_READ)){ + val res = gatt?.device?.address?.let { address -> + BlueToothBLEUtil.getDataTag(address, BlueToothBLEUtil.BLECHARACTERISTIC_COMMON_READ) + }?.let { tag -> BlueToothBLEUtil.dealRecvByteArray(tag, it) } + try { + //接收完毕后进行数据处理 + if(res == true) { + //获取接收完的数据 + val recvByteArray = BlueToothBLEUtil.getRecvByteArray( BlueToothBLEUtil.getDataTag(gatt.device.address, + BlueToothBLEUtil.BLECHARACTERISTIC_COMMON_READ)) + PeachLogger.d(GlobalConstant.APP_TAG, "$TAG onCharacteristicWriteRequest recvByteArray= ${recvByteArray.toString()}") + onCharacteristicChanged(recvByteArray) + } + }catch (e : Exception){ + e.printStackTrace() + Log.e(GlobalConstant.APP_TAG, "$TAG onCharacteristicWriteRequest common msg= e = ${e.message}") + } + } + } + } + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == DeviceConstant.REQUEST_ENABLE_BT) { + if (resultCode == Activity.RESULT_OK) { + onBTRequestOpen() + } else { + // 用户未能成功打开蓝牙 + Toast.makeText(this@BTActivity, resources.getString(R.string.refused_turn_on_bluetooth), Toast.LENGTH_SHORT).show() + } + } + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + if (BlueToothBLEUtil.REQUEST_CODE_PERMISSIONS == requestCode) { + for (x in grantResults) { + if (x == PackageManager.PERMISSION_DENIED) { + //权限拒绝了 + return + } + } + onBTRequestPermissions() + } + } + + override fun onDestroy() { + super.onDestroy() + window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + stopScan() + DeviceManager.clearBleDeviceList() + } +} \ No newline at end of file diff --git a/client/src/main/java/com/populstay/wallet/safnect/client/device/DKGActivity.kt b/client/src/main/java/com/populstay/wallet/safnect/client/device/DKGActivity.kt new file mode 100644 index 0000000..a4b811f --- /dev/null +++ b/client/src/main/java/com/populstay/wallet/safnect/client/device/DKGActivity.kt @@ -0,0 +1,203 @@ +package com.populstay.wallet.safnect.client.device + +import android.bluetooth.BluetoothGattCharacteristic +import android.os.Build +import android.os.Bundle +import android.view.View +import android.widget.AdapterView +import android.widget.Toast +import androidx.annotation.RequiresApi +import androidx.lifecycle.lifecycleScope +import com.populstay.common.GlobalConstant +import com.populstay.common.bean.BTBean +import com.populstay.common.bean.CBleDevice +import com.populstay.common.loader.LoaderStyle +import com.populstay.common.loader.PeachLoader +import com.populstay.common.log.PeachLogger +import com.populstay.common.repository.BlueToothBLEUtil +import com.populstay.wallet.devicemanager.DeviceConstant +import com.populstay.wallet.safnect.client.R +import com.populstay.wallet.safnect.client.databinding.ActivityDeviceListBinding +import com.populstay.wallet.safnect.client.device.adapter.DeviceAdapter +import kotlinx.android.synthetic.main.activity_device_list.spinner +import kotlinx.android.synthetic.main.common_title_layout.view.back +import kotlinx.coroutines.launch + + +open class DKGActivity : BTActivity() { + + private lateinit var binding: ActivityDeviceListBinding + + private val mDataList by lazy { + mutableListOf() + } + + private val mDeviceAdapter by lazy { + DeviceAdapter(this@DKGActivity,mDataList) + } + + protected fun showLoading() { + PeachLoader.showLoading(this, LoaderStyle.BallSpinFadeLoaderIndicator.name) + } + + protected fun stopLoading() { + PeachLoader.stopLoading() + } + + @RequiresApi(Build.VERSION_CODES.M) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityDeviceListBinding.inflate(layoutInflater) + setContentView(binding.root) + initTitleBar() + initDeviceList() + startScan() + + binding.pairMyWallet.setOnClickListener { + showLoading() + // 开始连接 + connect() + } + } + + fun showMsg(msg :String){ + binding.showMsgTv.text = msg + } + + override fun onFoundService() { + // 开始分片,刚连接上,要缓一会才能发起dkg + binding.pairMyWallet.postDelayed({ + requestRunDKG() + },500) + } + + override fun onCharacteristicChanged(data: ByteArray) { + stopLoading() + showMsg("副端同意了DKG请求,可以开始DKG流程了:${String(data, Charsets.UTF_8)}") + // todo 这里开始DKG流程了 + } + + @RequiresApi(Build.VERSION_CODES.M) + override fun onConnectionFail() { + + Toast.makeText(this,resources.getString(R.string.connection_failed_scan_try),Toast.LENGTH_SHORT).show() + + BlueToothBLEUtil.clearBtData() + + stopScan() + startScan() + } + + override fun onScanStatus(state: Int) { + if (DeviceConstant.SCAN_STATUS_START == state){ + setScanningData() + } + } + override fun onScanResult(deviceList: List?) { + setDeviceData(deviceList) + updateConfirmBtnStatus() + } + + fun setScanningData(){ + mDataList.clear() + val scanBean = BTBean() + scanBean.name = "正在扫描" + scanBean.type = BTBean.TYPE_SCAN + mDataList.add(scanBean) + mDeviceAdapter.notifyDataSetChanged() + // 如果只有一项数据,则禁用 Spinner 的点击选择功能 + if (mDeviceAdapter.count == 1) { + spinner.isEnabled = false; + spinner.isClickable = false; + } + } + + fun setDeviceData(deviceList : List?){ + mCurSelectDevice = deviceList?.get(0) as CBleDevice? + mDataList.clear() + deviceList?.let { + mDataList.addAll(it) + } + mDeviceAdapter.notifyDataSetChanged() + spinner.isEnabled = true + spinner.isClickable = true + } + + private fun initDeviceList() { + + binding.spinner.adapter = mDeviceAdapter + spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { + val selectedItem = parent.getItemAtPosition(position) + if (selectedItem is CBleDevice){ + mCurSelectDevice = selectedItem + } + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + // 未选择任何项时的处理 + } + } + } + + override fun initTitleBar() { + binding.commonTitleLayout.back.setOnClickListener { + finish() + } + } + + private fun updateConfirmBtnStatus(){ + binding.pairMyWallet.isEnabled = null != mCurSelectDevice + } + + @RequiresApi(Build.VERSION_CODES.M) + override fun onBTRequestOpen() { + startScan() + } + + @RequiresApi(Build.VERSION_CODES.M) + override fun onBTRequestPermissions() { + startScan() + } + + private fun requestRunDKG(){ + PeachLogger.d(GlobalConstant.APP_TAG, " requestRunDKG 发起创建账号申请") + BlueToothBLEUtil.refreshDeviceCache() + BlueToothBLEUtil.clearBtData() + lifecycleScope.launch { + + + val characteristicCommonRead = mBluetoothGattService?.getCharacteristic( + BlueToothBLEUtil.getUUID(BlueToothBLEUtil.BLECHARACTERISTIC_COMMON_READ)) + characteristicCommonRead?.let { + // 通知的监听,这一步很关键,不然外围设备端发送的数据将无法接收到。 + if (characteristicCommonRead.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0){ + BlueToothBLEUtil.setCharacteristicNotify(characteristicCommonRead , true) + } + } + + // 发送消息分发私钥 + val characteristic = mBluetoothGattService?.getCharacteristic( + BlueToothBLEUtil.getUUID( + BlueToothBLEUtil.BLECHARACTERISTIC_COMMON_WRITE)) + characteristic?.let { + // 通知的监听,这一步很关键,不然外围设备端发送的数据将无法接收到。 + if (characteristic.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0){ + BlueToothBLEUtil.setCharacteristicNotify(characteristic , true) + } + + launch { + + // todo 据具体数据格式待定吧,先用最简单的方式调用通信 + // 01 代表主端向副端设备发起DKG请求 + BlueToothBLEUtil.writeCharacteristicSplit(characteristic, "01".toByteArray()) + } + } + } + } + + override fun onDestroy() { + super.onDestroy() + stopLoading() + } +} \ No newline at end of file diff --git a/client/src/main/java/com/populstay/wallet/safnect/client/device/adapter/DeviceAdapter.kt b/client/src/main/java/com/populstay/wallet/safnect/client/device/adapter/DeviceAdapter.kt new file mode 100644 index 0000000..36ce2fe --- /dev/null +++ b/client/src/main/java/com/populstay/wallet/safnect/client/device/adapter/DeviceAdapter.kt @@ -0,0 +1,44 @@ +package com.populstay.wallet.safnect.client.device.adapter + +import android.Manifest +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import com.populstay.common.bean.BTBean +import com.populstay.common.repository.BlueToothBLEUtil +import com.populstay.wallet.safnect.client.R +import kotlinx.android.synthetic.main.device_spinner_item_layout.view.name + + +class DeviceAdapter(val mContext: Context,val mDataList: List) : BaseAdapter() { + + override fun getCount(): Int { + return mDataList.size + } + + override fun getItem(position: Int): Any { + return mDataList[position] + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val itemView = LayoutInflater.from(mContext).inflate(R.layout.device_spinner_item_layout,null) + if (BTBean.TYPE_SCAN == mDataList[position].type){ + itemView.name.text = mContext.getString(R.string.searching) + itemView.name.setTextColor(mContext.resources.getColor(com.populstay.common.R.color.color_ff919599)) + }else { + if(BlueToothBLEUtil.checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)){ + itemView.name.text = mDataList[position].name ?: "N/A" + itemView.name.setTextColor(mContext.resources.getColor(com.populstay.common.R.color.color_ff1f2021)) + } + } + return itemView + } +} + + diff --git a/client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/DeviceConstant.kt b/client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/DeviceConstant.kt new file mode 100644 index 0000000..545c3fd --- /dev/null +++ b/client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/DeviceConstant.kt @@ -0,0 +1,10 @@ +package com.populstay.wallet.devicemanager + +object DeviceConstant { + + const val REQUEST_ENABLE_BT = 1 + + + const val SCAN_STATUS_START = 0 + const val SCAN_STATUS_END = 1 +} \ No newline at end of file diff --git a/client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/DeviceManager.kt b/client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/DeviceManager.kt new file mode 100644 index 0000000..5e30e68 --- /dev/null +++ b/client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/DeviceManager.kt @@ -0,0 +1,274 @@ +package com.populstay.wallet.safnect.client.devicemanager + +import android.Manifest +import android.app.Activity +import android.app.AlertDialog +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCallback +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor +import android.bluetooth.le.ScanCallback +import android.bluetooth.le.ScanResult +import android.content.DialogInterface +import android.content.Intent +import android.os.Build +import android.text.TextUtils +import android.util.Log +import androidx.annotation.RequiresApi +import com.populstay.common.bean.BTBean +import com.populstay.wallet.devicemanager.BTGattCallback +import com.populstay.wallet.devicemanager.DeviceConstant +import com.populstay.wallet.devicemanager.IDeviceManager +import com.populstay.wallet.devicemanager.IScanResult +import com.populstay.common.GlobalConstant +import com.populstay.wallet.safnect.client.R +import com.populstay.common.bean.CBleDevice +import com.populstay.common.repository.BlueToothBLEUtil +import pub.devrel.easypermissions.EasyPermissions + +object DeviceManager : IDeviceManager { + + const val TAG = "DeviceManager-->" + + private val mBleDeviceList = mutableListOf() + var mScanResult : IScanResult? = null + + var mBluetoothGattCallback : BTGattCallback? = null + + + @RequiresApi(Build.VERSION_CODES.M) + override fun startScanAndCheckBTStatus(callBack: IScanResult, activity : Activity) { + Log.d(GlobalConstant.APP_TAG, "$TAG checkBTStatus") + if (EasyPermissions.hasPermissions(activity, *(if (BlueToothBLEUtil.isAndroid12()) BlueToothBLEUtil.REQUIRED_BLEPERMISSIONS_12 else BlueToothBLEUtil.REQUIRED_BLEPERMISSIONS))) { + if (!BlueToothBLEUtil.isEnabled()) { + val builder: AlertDialog.Builder = AlertDialog.Builder(activity) + builder.setTitle(R.string.hint) + builder.setMessage(R.string.bluetooth_turned_on_hint) + builder.setPositiveButton( + R.string.yes, + DialogInterface.OnClickListener { _, _ -> + if(!BlueToothBLEUtil.checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) return@OnClickListener + + // 打开手机蓝牙开关 + val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) + activity.startActivityForResult(enableBtIntent, + DeviceConstant.REQUEST_ENABLE_BT + ) + }) + builder.setNegativeButton(R.string.no, DialogInterface.OnClickListener { _, _ -> + // 用户选择不打开蓝牙 + }) + builder.show() + }else{ + startScan(callBack) + } + } else { + // 如果没有上述权限 , 那么申请权限 + EasyPermissions.requestPermissions( + activity, + activity.resources.getString(R.string.rationale_hint), + BlueToothBLEUtil.REQUEST_CODE_PERMISSIONS, + *(if (BlueToothBLEUtil.isAndroid12()) BlueToothBLEUtil.REQUIRED_BLEPERMISSIONS_12 else BlueToothBLEUtil.REQUIRED_BLEPERMISSIONS) + ) + } + } + + override fun clearBleDeviceList() { + mBleDeviceList.clear() + } + + @RequiresApi(Build.VERSION_CODES.M) + override fun startScan(callBack: IScanResult) { + Log.d(GlobalConstant.APP_TAG, "$TAG startScan") + // 重新扫描,要把上一次的扫描设备清理掉 + mBleDeviceList.clear() + mScanResult = callBack + mScanResult?.onScanStatus(DeviceConstant.SCAN_STATUS_START) + BlueToothBLEUtil.scanBlueToothDevice(innerScanListener) + } + + override fun stopScan() { + Log.d(GlobalConstant.APP_TAG, "$TAG stopScan") + BlueToothBLEUtil.stopScanBlueToothDevice(innerScanListener) + } + + override fun connect(macAddress: String, callback: BTGattCallback) { + Log.d(GlobalConstant.APP_TAG, "$TAG connect macAddress = $macAddress") + stopScan() + mBluetoothGattCallback = callback + BlueToothBLEUtil.connect(macAddress, innerBluetoothGattCallback) + } + + override fun disconnect() { + Log.d(GlobalConstant.APP_TAG, "$TAG disconnect") + BlueToothBLEUtil.disConnect() + } + + override fun discoverServices() { + BlueToothBLEUtil.discoverServices() + } + + // 扫描回调 + private val innerScanListener = object : ScanCallback() { + override fun onScanResult(callbackType: Int, result: ScanResult?) { + super.onScanResult(callbackType, result) + try { + result?.let { + if(!BlueToothBLEUtil.checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) return@let + // 封装一下蓝牙设备数据 + val item = CBleDevice() + item.device = result.device + item.rssi = result.rssi + item.scanRecordBytes = result.scanRecord?.bytes + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + item.isConnectable = result.isConnectable + } + item.scanRecord = result.scanRecord + item.type = BTBean.TYPE_DEVICE + item.name = result.device.name + if (TextUtils.isEmpty(result.device.name) || TextUtils.isEmpty(result.device.name.trim())){ + item.name = "Wallet Device" + } + + Log.d(GlobalConstant.APP_TAG, "$TAG onScanResult name = ${result.device.name},address = ${result.device.address}") + + val idx = mBleDeviceList.indexOfFirst { idx -> + item.device?.address == idx.device?.address + } + if (idx < 0) { + mBleDeviceList.add(item) + } + mScanResult?.onScanStatus(DeviceConstant.SCAN_STATUS_END) + mScanResult?.onScanResult(mBleDeviceList) + } + } catch (e: Exception) { + e.printStackTrace() + Log.d(GlobalConstant.APP_TAG, "$TAG onScanResult e = ${e.message}") + } + } + } + + // 连接、通信回调 + private val innerBluetoothGattCallback = object : BluetoothGattCallback() { + + override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) { + super.onConnectionStateChange(gatt, status, newState) + mBluetoothGattCallback?.onConnectionStateChange(gatt, status, newState) + } + + override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) { + super.onMtuChanged(gatt, mtu, status) + mBluetoothGattCallback?.onMtuChanged(gatt, mtu, status) + } + + override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) { + super.onServicesDiscovered(gatt, status) + mBluetoothGattCallback?.onServicesDiscovered(gatt, status) + } + + @RequiresApi(Build.VERSION_CODES.S) + override fun onServiceChanged(gatt: BluetoothGatt) { + super.onServiceChanged(gatt) + mBluetoothGattCallback?.onServiceChanged(gatt) + } + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + override fun onCharacteristicChanged( + gatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + value: ByteArray + ) { + super.onCharacteristicChanged(gatt, characteristic, value) + mBluetoothGattCallback?.onCharacteristicChanged(gatt, characteristic, value) + } + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + override fun onCharacteristicRead( + gatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + value: ByteArray, + status: Int + ) { + super.onCharacteristicRead(gatt, characteristic, value, status) + mBluetoothGattCallback?.onCharacteristicRead(gatt, characteristic, value, status) + } + + override fun onCharacteristicWrite( + gatt: BluetoothGatt?, + characteristic: BluetoothGattCharacteristic?, + status: Int + ) { + super.onCharacteristicWrite(gatt, characteristic, status) + mBluetoothGattCallback?.onCharacteristicWrite(gatt, characteristic, status) + } + + override fun onCharacteristicChanged( + gatt: BluetoothGatt?, + characteristic: BluetoothGattCharacteristic? + ) { + super.onCharacteristicChanged(gatt, characteristic) + mBluetoothGattCallback?.onCharacteristicChanged(gatt, characteristic) + } + + override fun onCharacteristicRead( + gatt: BluetoothGatt?, + characteristic: BluetoothGattCharacteristic?, + status: Int + ) { + super.onCharacteristicRead(gatt, characteristic, status) + mBluetoothGattCallback?.onCharacteristicRead(gatt, characteristic, status) + } + + override fun onDescriptorRead( + gatt: BluetoothGatt?, + descriptor: BluetoothGattDescriptor?, + status: Int + ) { + super.onDescriptorRead(gatt, descriptor, status) + mBluetoothGattCallback?.onDescriptorRead(gatt, descriptor, status) + } + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + override fun onDescriptorRead( + gatt: BluetoothGatt, + descriptor: BluetoothGattDescriptor, + status: Int, + value: ByteArray + ) { + super.onDescriptorRead(gatt, descriptor, status, value) + mBluetoothGattCallback?.onDescriptorRead(gatt, descriptor, status, value) + } + + override fun onDescriptorWrite( + gatt: BluetoothGatt?, + descriptor: BluetoothGattDescriptor?, + status: Int + ) { + super.onDescriptorWrite(gatt, descriptor, status) + mBluetoothGattCallback?.onDescriptorWrite(gatt, descriptor, status) + } + + override fun onReliableWriteCompleted(gatt: BluetoothGatt?, status: Int) { + super.onReliableWriteCompleted(gatt, status) + mBluetoothGattCallback?.onReliableWriteCompleted(gatt, status) + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun onPhyRead(gatt: BluetoothGatt?, txPhy: Int, rxPhy: Int, status: Int) { + super.onPhyRead(gatt, txPhy, rxPhy, status) + mBluetoothGattCallback?.onPhyRead(gatt, txPhy, rxPhy, status) + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun onPhyUpdate(gatt: BluetoothGatt?, txPhy: Int, rxPhy: Int, status: Int) { + super.onPhyUpdate(gatt, txPhy, rxPhy, status) + mBluetoothGattCallback?.onPhyUpdate(gatt, txPhy, rxPhy, status) + } + + override fun onReadRemoteRssi(gatt: BluetoothGatt?, rssi: Int, status: Int) { + super.onReadRemoteRssi(gatt, rssi, status) + mBluetoothGattCallback?.onReadRemoteRssi(gatt, rssi, status) + } + } +} \ No newline at end of file diff --git a/client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/IDeviceManager.kt b/client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/IDeviceManager.kt new file mode 100644 index 0000000..e065d45 --- /dev/null +++ b/client/src/main/java/com/populstay/wallet/safnect/client/devicemanager/IDeviceManager.kt @@ -0,0 +1,120 @@ +package com.populstay.wallet.devicemanager + +import android.app.Activity +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor +import com.populstay.common.bean.CBleDevice + +interface IDeviceManager { + + fun startScanAndCheckBTStatus(callBack: IScanResult, activity : Activity) + fun startScan(callBack : IScanResult) + fun stopScan() + fun connect(macAddress: String, callback: BTGattCallback) + fun disconnect() + fun discoverServices() + + fun clearBleDeviceList() +} + +// 蓝牙开关和权限相关 +interface IBTListener{ + // 蓝牙请求打开ok + fun onBTRequestOpen() + // 蓝牙相关权限请求ok + fun onBTRequestPermissions() + // onServicesDiscovered + fun onFoundService() + fun onConnectionFail() + fun onCharacteristicChanged(data : ByteArray) + +} + +// 包装ScanCallback +interface IScanResult{ + fun onScanStatus(state :Int) + fun onScanResult(deviceList : List?) +} + +// 包装BluetoothGattCallback +interface BTGattCallback{ + fun onPhyUpdate(gatt: BluetoothGatt?, txPhy: Int, rxPhy: Int, status: Int) { + } + + fun onPhyRead(gatt: BluetoothGatt?, txPhy: Int, rxPhy: Int, status: Int) { + } + + fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) { + } + + fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) { + } + + + @Deprecated("") + fun onCharacteristicRead( + gatt: BluetoothGatt?, + characteristic: BluetoothGattCharacteristic?, + status: Int + ) { + } + + fun onCharacteristicRead( + gatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + value: ByteArray, + status: Int + ) { + } + + fun onCharacteristicWrite( + gatt: BluetoothGatt?, + characteristic: BluetoothGattCharacteristic?, + status: Int + ) { + } + + + @Deprecated("") + fun onCharacteristicChanged( + gatt: BluetoothGatt?, + characteristic: BluetoothGattCharacteristic? + ) { + } + + fun onCharacteristicChanged( + gatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + value: ByteArray + ) { + } + + + @Deprecated("") + fun onDescriptorRead(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) { + } + + fun onDescriptorRead( + gatt: BluetoothGatt, + descriptor: BluetoothGattDescriptor, + status: Int, + value: ByteArray + ) { + } + + fun onDescriptorWrite(gatt: BluetoothGatt?, descriptor: BluetoothGattDescriptor?, status: Int) { + } + + fun onReliableWriteCompleted(gatt: BluetoothGatt?, status: Int) { + } + + fun onReadRemoteRssi(gatt: BluetoothGatt?, rssi: Int, status: Int) { + } + + fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) { + } + + fun onServiceChanged(gatt: BluetoothGatt) { + } +} \ No newline at end of file diff --git a/client/src/main/res/drawable-v24/ic_launcher_foreground.xml b/client/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/client/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/client/src/main/res/drawable/bt_spinner_bg.xml b/client/src/main/res/drawable/bt_spinner_bg.xml new file mode 100644 index 0000000..2a966e8 --- /dev/null +++ b/client/src/main/res/drawable/bt_spinner_bg.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/client/src/main/res/drawable/common_blue_top_bg.xml b/client/src/main/res/drawable/common_blue_top_bg.xml new file mode 100644 index 0000000..9210e9e --- /dev/null +++ b/client/src/main/res/drawable/common_blue_top_bg.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/client/src/main/res/drawable/common_btn_blue_selector.xml b/client/src/main/res/drawable/common_btn_blue_selector.xml new file mode 100644 index 0000000..5f30264 --- /dev/null +++ b/client/src/main/res/drawable/common_btn_blue_selector.xml @@ -0,0 +1,39 @@ + + + + + + + #ccd8eef2 + 0 + 2 + + + + + + + #ccd8eef2 + 0 + 2 + + + + + + + #ccd8eef2 + 0 + 2 + + + + + + + + + + + + diff --git a/client/src/main/res/drawable/common_btn_white_selector.xml b/client/src/main/res/drawable/common_btn_white_selector.xml new file mode 100644 index 0000000..0bcfcc7 --- /dev/null +++ b/client/src/main/res/drawable/common_btn_white_selector.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/client/src/main/res/drawable/ic_launcher_background.xml b/client/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/client/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/main/res/drawable/list_item_bg_white_selector.xml b/client/src/main/res/drawable/list_item_bg_white_selector.xml new file mode 100644 index 0000000..bb419bc --- /dev/null +++ b/client/src/main/res/drawable/list_item_bg_white_selector.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/main/res/drawable/list_item_bg_white_shape.xml b/client/src/main/res/drawable/list_item_bg_white_shape.xml new file mode 100644 index 0000000..f00a73f --- /dev/null +++ b/client/src/main/res/drawable/list_item_bg_white_shape.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/client/src/main/res/drawable/welcome_entry_btn.xml b/client/src/main/res/drawable/welcome_entry_btn.xml new file mode 100644 index 0000000..edd4787 --- /dev/null +++ b/client/src/main/res/drawable/welcome_entry_btn.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/client/src/main/res/layout/activity_device_list.xml b/client/src/main/res/layout/activity_device_list.xml new file mode 100644 index 0000000..a473adc --- /dev/null +++ b/client/src/main/res/layout/activity_device_list.xml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/src/main/res/layout/activity_main.xml b/client/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..8a5a9b8 --- /dev/null +++ b/client/src/main/res/layout/activity_main.xml @@ -0,0 +1,13 @@ + + + +