From c584c193d5dd4290bcbeddd434e1d642db59eb13 Mon Sep 17 00:00:00 2001
From: JLChen <551775569@qq.com>
Date: 星期二, 09 十一月 2021 17:25:59 +0800
Subject: [PATCH] 2021-11-09 1.更新
---
HDLSDK/app/src/main/AndroidManifest.xml | 33
HDLSDK/hdl-connect/.gitignore | 1
HDLSDK/config.gradle | 7
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketBoot.java | 327 +++
HDLSDK/app/src/main/res/layout/activity_main.xml | 79
HDLSDK/app/src/main/res/layout/demo_item.xml | 28
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/ClientPool.java | 57
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/HDLSdk.java | 30
HDLSDK/.idea/jarRepositories.xml | 55
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/IpUtils.java | 72
HDLSDK/hdl-connect/src/androidTest/java/com/hdl/sdk/connect/ExampleInstrumentedTest.java | 26
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/listener/ConnectStatusListener.java | 27
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/listener/SendListener.java | 11
HDLSDK/hdl-common/src/main/AndroidManifest.xml | 5
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/MessageToByteEncoder.java | 24
HDLSDK/app/src/main/res/values/colors.xml | 10
HDLSDK/app/src/main/java/com/hdl/hdlsdk/App.java | 24
HDLSDK/hdl-common/consumer-rules.pro | 0
HDLSDK/hdl-socket/proguard-rules.pro | 21
HDLSDK/app/src/main/res/drawable-v24/ic_launcher_foreground.xml | 30
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IHandleMessage.java | 10
HDLSDK/app/.gitignore | 1
HDLSDK/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp | 0
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IMessagePipeLine.java | 11
HDLSDK/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml | 5
HDLSDK/.gitignore | 15
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/IdUtils.java | 12
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IHandleFlow.java | 12
HDLSDK/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp | 0
HDLSDK/app/src/main/java/com/hdl/hdlsdk/DemoBean.java | 28
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketRequest.java | 34
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/utils/ProtocolParse.java | 74
HDLSDK/gradle.properties | 19
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/HDLSocket.java | 650 +++++++
HDLSDK/app/src/main/res/mipmap-hdpi/ic_launcher.webp | 0
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/ThreadToolUtils.java | 72
HDLSDK/hdl-connect/src/test/java/com/hdl/sdk/connect/ExampleUnitTest.java | 17
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/PropertyUpRequest.java | 50
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/annotation/ConnectStatus.java | 31
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/config/TopicConstant.java | 52
HDLSDK/app/src/main/res/values-night/themes.xml | 16
HDLSDK/hdl-connect/consumer-rules.pro | 0
HDLSDK/hdl-common/src/test/java/com/hdl/sdk/common/ExampleUnitTest.java | 17
HDLSDK/hdl-socket/consumer-rules.pro | 0
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/DeviceControlRequest.java | 51
HDLSDK/app/src/main/java/com/hdl/hdlsdk/DemoAdapter.java | 26
HDLSDK/app/src/main/res/values/themes.xml | 16
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/BaseLocalResponse.java | 38
HDLSDK/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp | 0
HDLSDK/hdl-socket/src/main/AndroidManifest.xml | 5
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/gson/ParameterizedTypeImpl.java | 46
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/LogUtils.java | 51
HDLSDK/hdl-socket/README.md | 8
HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java | 144 +
HDLSDK/hdl-common/build.gradle | 34
HDLSDK/hdl-socket/build.gradle | 33
HDLSDK/gradle/wrapper/gradle-wrapper.jar | 0
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/event/EventDispatcher.java | 132 +
HDLSDK/.idea/misc.xml | 17
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/UdpClient.java | 206 ++
HDLSDK/hdl-connect/src/main/AndroidManifest.xml | 5
HDLSDK/app/src/androidTest/java/com/hdl/hdlsdk/ExampleInstrumentedTest.java | 26
HDLSDK/hdl-socket/src/test/java/com/hdl/sdk/socket/ExampleUnitTest.java | 17
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/ByteUtils.java | 134 +
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/FunctionAttributeRequest.java | 24
HDLSDK/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp | 0
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/LinkResponse.java | 55
HDLSDK/.idea/gradle.xml | 24
HDLSDK/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp | 0
HDLSDK/build.gradle | 30
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/BaseLocalRequest.java | 47
HDLSDK/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml | 5
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/LinkRequest.java | 64
HDLSDK/hdl-socket/.gitignore | 1
HDLSDK/gradle/wrapper/gradle-wrapper.properties | 6
HDLSDK/app/src/main/res/mipmap-xhdpi/ic_launcher.webp | 0
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/IClient.java | 37
HDLSDK/app/src/main/res/drawable/ic_launcher_background.xml | 170 ++
.gitignore | 81
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/IHDLClient.java | 52
HDLSDK/gradlew.bat | 89 +
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageDecoder.java | 81
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/gson/GsonConvert.java | 55
HDLSDK/settings.gradle | 6
HDLSDK/.idea/.gitignore | 3
HDLSDK/hdl-connect/proguard-rules.pro | 21
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/TcpClient.java | 176 ++
HDLSDK/app/src/test/java/com/hdl/hdlsdk/ExampleUnitTest.java | 17
HDLSDK/app/src/main/res/values/strings.xml | 3
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/event/EventListener.java | 10
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/SPUtils.java | 151 +
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/ByteToMessageDecoder.java | 20
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/PropertyReadRequest.java | 17
HDLSDK/app/src/main/res/mipmap-mdpi/ic_launcher.webp | 0
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageEncoder.java | 16
HDLSDK/.idea/compiler.xml | 6
HDLSDK/hdl-common/proguard-rules.pro | 21
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketOptions.java | 130 +
HDLSDK/app/build.gradle | 43
HDLSDK/gradlew | 185 ++
HDLSDK/app/proguard-rules.pro | 21
HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/MessagePipeLine.java | 51
HDLSDK/hdl-connect/build.gradle | 34
HDLSDK/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp | 0
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/GatewaySearchBean.java | 102 +
HDLSDK/hdl-socket/src/androidTest/java/com/hdl/sdk/socket/ExampleInstrumentedTest.java | 26
HDLSDK/hdl-common/.gitignore | 1
HDLSDK/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp | 0
HDLSDK/hdl-common/src/androidTest/java/com/hdl/sdk/common/ExampleInstrumentedTest.java | 26
109 files changed, 4,887 insertions(+), 2 deletions(-)
diff --git a/.gitignore b/.gitignore
index 3a36c6e..110ac68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,15 @@
+
+# Created by https://www.toptal.com/developers/gitignore/api/android
+# Edit at https://www.toptal.com/developers/gitignore?templates=android
+
+### Android ###
# Built application files
*.apk
+*.aar
*.ap_
+*.aab
-# Files for the Dalvik VM
+# Files for the ART/Dalvik VM
*.dex
# Java class files
@@ -11,6 +18,9 @@
# Generated files
bin/
gen/
+out/
+# Uncomment the following line in case you need and you don't have the release build type files in your app
+# release/
# Gradle files
.gradle/
@@ -22,5 +32,72 @@
# Proguard folder generated by Eclipse
proguard/
-#Log Files
+# Log Files
*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+.idea/jarRepositories.xml
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+#*.jks
+#*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+.cxx/
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+
+# Android Profiling
+*.hprof
+
+### Android Patch ###
+gen-external-apklibs
+output.json
+
+# Replacement of .externalNativeBuild directories introduced
+# with Android Studio 3.5.
+
+# End of https://www.toptal.com/developers/gitignore/api/android
\ No newline at end of file
diff --git a/HDLSDK/.gitignore b/HDLSDK/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/HDLSDK/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/HDLSDK/.idea/.gitignore b/HDLSDK/.idea/.gitignore
new file mode 100644
index 0000000..eaf91e2
--- /dev/null
+++ b/HDLSDK/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/HDLSDK/.idea/compiler.xml b/HDLSDK/.idea/compiler.xml
new file mode 100644
index 0000000..7d7ec2e
--- /dev/null
+++ b/HDLSDK/.idea/compiler.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="CompilerConfiguration">
+ <bytecodeTargetLevel target="11" />
+ </component>
+</project>
\ No newline at end of file
diff --git a/HDLSDK/.idea/gradle.xml b/HDLSDK/.idea/gradle.xml
new file mode 100644
index 0000000..7e69409
--- /dev/null
+++ b/HDLSDK/.idea/gradle.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="GradleMigrationSettings" migrationVersion="1" />
+ <component name="GradleSettings">
+ <option name="linkedExternalProjectsSettings">
+ <GradleProjectSettings>
+ <option name="testRunner" value="PLATFORM" />
+ <option name="distributionType" value="DEFAULT_WRAPPED" />
+ <option name="externalProjectPath" value="$PROJECT_DIR$" />
+ <option name="modules">
+ <set>
+ <option value="$PROJECT_DIR$" />
+ <option value="$PROJECT_DIR$/app" />
+ <option value="$PROJECT_DIR$/hdl-common" />
+ <option value="$PROJECT_DIR$/hdl-connect" />
+ <option value="$PROJECT_DIR$/hdl-socket" />
+ </set>
+ </option>
+ <option name="resolveModulePerSourceSet" value="false" />
+ <option name="useQualifiedModuleNames" value="true" />
+ </GradleProjectSettings>
+ </option>
+ </component>
+</project>
\ No newline at end of file
diff --git a/HDLSDK/.idea/jarRepositories.xml b/HDLSDK/.idea/jarRepositories.xml
new file mode 100644
index 0000000..fbe72e2
--- /dev/null
+++ b/HDLSDK/.idea/jarRepositories.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="RemoteRepositoriesConfiguration">
+ <remote-repository>
+ <option name="id" value="central" />
+ <option name="name" value="Maven Central repository" />
+ <option name="url" value="https://repo1.maven.org/maven2" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="jboss.community" />
+ <option name="name" value="JBoss Community repository" />
+ <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="maven" />
+ <option name="name" value="maven" />
+ <option name="url" value="https://maven.aliyun.com/repository/central" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="maven2" />
+ <option name="name" value="maven2" />
+ <option name="url" value="https://maven.aliyun.com/repository/google" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="maven5" />
+ <option name="name" value="maven5" />
+ <option name="url" value="https://maven.aliyun.com/repository/public/" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="maven4" />
+ <option name="name" value="maven4" />
+ <option name="url" value="https://maven.aliyun.com/repository/gradle-plugin" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="maven3" />
+ <option name="name" value="maven3" />
+ <option name="url" value="https://maven.aliyun.com/repository/jcenter" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="maven9" />
+ <option name="name" value="maven9" />
+ <option name="url" value="https://jitpack.io" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="maven8" />
+ <option name="name" value="maven8" />
+ <option name="url" value="https://maven.aliyun.com/repository/public" />
+ </remote-repository>
+ <remote-repository>
+ <option name="id" value="Google" />
+ <option name="name" value="Google" />
+ <option name="url" value="https://dl.google.com/dl/android/maven2/" />
+ </remote-repository>
+ </component>
+</project>
\ No newline at end of file
diff --git a/HDLSDK/.idea/misc.xml b/HDLSDK/.idea/misc.xml
new file mode 100644
index 0000000..2f09a86
--- /dev/null
+++ b/HDLSDK/.idea/misc.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="DesignSurface">
+ <option name="filePathToZoomLevelMap">
+ <map>
+ <entry key="..\:/job/me/Android/HDLSDK/app/src/main/res/layout/activity_main.xml" value="0.1" />
+ <entry key="..\:/job/me/Android/HDLSDK/app/src/main/res/layout/demo_item.xml" value="0.28958333333333336" />
+ </map>
+ </option>
+ </component>
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/build/classes" />
+ </component>
+ <component name="ProjectType">
+ <option name="id" value="Android" />
+ </component>
+</project>
\ No newline at end of file
diff --git a/HDLSDK/app/.gitignore b/HDLSDK/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/HDLSDK/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/HDLSDK/app/build.gradle b/HDLSDK/app/build.gradle
new file mode 100644
index 0000000..22b041f
--- /dev/null
+++ b/HDLSDK/app/build.gradle
@@ -0,0 +1,43 @@
+plugins {
+ id 'com.android.application'
+}
+
+android {
+ compileSdk 31
+
+ defaultConfig {
+ applicationId "com.hdl.hdlsdk"
+ minSdk 21
+ targetSdk 31
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+
+ implementation 'androidx.appcompat:appcompat:1.3.1'
+ implementation 'com.google.android.material:material:1.4.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
+
+ testImplementation 'junit:junit:4.+'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+
+ implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6'
+
+ implementation project(path: ':hdl-connect')
+}
\ No newline at end of file
diff --git a/HDLSDK/app/proguard-rules.pro b/HDLSDK/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/HDLSDK/app/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/HDLSDK/app/src/androidTest/java/com/hdl/hdlsdk/ExampleInstrumentedTest.java b/HDLSDK/app/src/androidTest/java/com/hdl/hdlsdk/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..4f7fa58
--- /dev/null
+++ b/HDLSDK/app/src/androidTest/java/com/hdl/hdlsdk/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.hdl.hdlsdk;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.hdl.hdlsdk", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/AndroidManifest.xml b/HDLSDK/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c9d8256
--- /dev/null
+++ b/HDLSDK/app/src/main/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.hdl.hdlsdk">
+
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
+ <uses-permission
+ android:name="android.permission.WRITE_EXTERNAL_STORAGE"
+ tools:ignore="ScopedStorage" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application
+ android:allowBackup="true"
+ android:name=".App"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.HDLSDK">
+ <activity
+ android:name=".MainActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/App.java b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/App.java
new file mode 100644
index 0000000..86fe706
--- /dev/null
+++ b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/App.java
@@ -0,0 +1,24 @@
+package com.hdl.hdlsdk;
+
+import android.app.Application;
+
+import com.hdl.sdk.common.HDLSdk;
+import com.hdl.sdk.connect.HDLSocket;
+
+/**
+ * Created by Tong on 2021/10/8.
+ */
+public class App extends Application {
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ HDLSdk.getInstance().init(this);
+ }
+
+ @Override
+ public void onTerminate() {
+ super.onTerminate();
+
+ }
+}
diff --git a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/DemoAdapter.java b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/DemoAdapter.java
new file mode 100644
index 0000000..18f6d76
--- /dev/null
+++ b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/DemoAdapter.java
@@ -0,0 +1,26 @@
+package com.hdl.hdlsdk;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.chad.library.adapter.base.BaseMultiItemQuickAdapter;
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.viewholder.BaseViewHolder;
+
+import java.util.List;
+
+/**
+ * Created by Tong on 2021/10/8.
+ */
+public class DemoAdapter extends BaseMultiItemQuickAdapter<DemoBean, BaseViewHolder> {
+
+ public DemoAdapter(@Nullable List<DemoBean> data) {
+ super(data);
+ addItemType(0,R.layout.demo_item);
+ }
+
+ @Override
+ protected void convert(@NonNull BaseViewHolder baseViewHolder, DemoBean demoBean) {
+ baseViewHolder.setText(R.id.tv_title,demoBean.getName());
+ }
+}
diff --git a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/DemoBean.java b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/DemoBean.java
new file mode 100644
index 0000000..ad185fa
--- /dev/null
+++ b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/DemoBean.java
@@ -0,0 +1,28 @@
+package com.hdl.hdlsdk;
+
+import com.chad.library.adapter.base.entity.MultiItemEntity;
+
+/**
+ * Created by Tong on 2021/10/8.
+ */
+public class DemoBean implements MultiItemEntity {
+
+ private String name;
+
+ public DemoBean(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public int getItemType() {
+ return 0;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java
new file mode 100644
index 0000000..31d24e3
--- /dev/null
+++ b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java
@@ -0,0 +1,144 @@
+package com.hdl.hdlsdk;
+
+import androidx.activity.result.ActivityResultCallback;
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import android.Manifest;
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.listener.OnItemClickListener;
+import com.google.gson.JsonObject;
+import com.hdl.sdk.common.config.TopicConstant;
+import com.hdl.sdk.common.utils.IdUtils;
+import com.hdl.sdk.common.utils.IpUtils;
+import com.hdl.sdk.connect.HDLSocket;
+import com.hdl.sdk.connect.bean.LinkRequest;
+import com.hdl.sdk.connect.protocol.LinkMessageDecoder;
+import com.hdl.sdk.connect.protocol.LinkMessageEncoder;
+import com.hdl.sdk.socket.SocketBoot;
+import com.hdl.sdk.socket.SocketOptions;
+import com.hdl.sdk.socket.client.UdpClient;
+import com.hdl.sdk.socket.codec.MessagePipeLine;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class MainActivity extends AppCompatActivity {
+
+ private DemoAdapter demoAdapter;
+ private RecyclerView rv;
+ private TextView tv;
+ private TextView responseTv;
+
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ responseTv = findViewById(R.id.response_tv);
+ tv = findViewById(R.id.state_tv);
+ rv = findViewById(R.id.rv);
+ rv.setLayoutManager(new LinearLayoutManager(this));
+
+ ActivityResultLauncher<String[]> launcher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
+ @Override
+ public void onActivityResult(Map<String, Boolean> result) {
+
+ }
+ });
+
+ launcher.launch(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE});
+
+ final List<DemoBean> beans = new ArrayList<>();
+ beans.add(new DemoBean("鎼滅储缃戝叧"));
+ beans.add(new DemoBean("鑾峰彇鍔熻兘鍒楄〃"));
+ beans.add(new DemoBean("鍔熻兘灞炴�ц鍙�"));
+ beans.add(new DemoBean("璁惧鎺у埗"));
+ beans.add(new DemoBean("鐘舵�佷笂鎶�"));
+ beans.add(new DemoBean("璇诲彇鐘舵��"));
+ demoAdapter = new DemoAdapter(beans);
+ rv.setAdapter(demoAdapter);
+
+
+ final SocketOptions options = new SocketOptions();
+
+ MessagePipeLine pipeLine = new MessagePipeLine();
+ pipeLine.add(new LinkMessageDecoder());
+ pipeLine.add(new LinkMessageEncoder());
+ options.setHandleMessage(pipeLine);
+ options.setEnabledHeartbeat(false);
+
+ demoAdapter.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
+ switch (position) {
+ case 0:
+ tv.setText("鎼滅储缃戝叧涓�");
+ responseTv.setText("");
+
+ HDLSocket.getInstance().searchGateway(new HDLSocket.CallBack() {
+ @Override
+ public void onError(String error) {
+ tv.setText("缃戝叧鑾峰彇澶辫触");
+ }
+
+ @Override
+ public void onResponse(String data) {
+ tv.setText("鑾峰彇缃戝叧鎴愬姛");
+ responseTv.setText(data);
+ }
+ });
+
+ break;
+ case 1:
+
+ tv.setText("鑾峰彇鍔熻兘鍒楄〃涓�");
+ responseTv.setText("");
+ HDLSocket.getInstance().getFunctionList(new HDLSocket.CallBack() {
+ @Override
+ public void onError(String error) {
+ tv.setText(error);
+ }
+
+ @Override
+ public void onResponse(String data) {
+ tv.setText("鑾峰彇鍔熻兘鍒楄〃鎴愬姛");
+ responseTv.setText(data);
+ }
+ });
+ break;
+ case 2:
+ //鍔熻兘灞炴�ц鍙�
+ // HDLSocket.getInstance().getFunctionAttribute();
+
+ break;
+ case 3:
+ //璁惧鎺у埗
+ // HDLSocket.getInstance().propertyDown();
+ break;
+ case 4:
+ //鐘舵�佷笂鎶�
+ //HDLSocket.getInstance().propertyUp();
+ break;
+ case 5:
+ //璇诲彇鐘舵��
+ // HDLSocket.getInstance().propertyRead();
+ break;
+ }
+ }
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/HDLSDK/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/HDLSDK/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="85.84757"
+ android:endY="92.4963"
+ android:startX="42.9492"
+ android:startY="49.59793"
+ android:type="linear">
+ <item
+ android:color="#44000000"
+ android:offset="0.0" />
+ <item
+ android:color="#00000000"
+ android:offset="1.0" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillType="nonZero"
+ android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000" />
+</vector>
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/res/drawable/ic_launcher_background.xml b/HDLSDK/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/HDLSDK/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillColor="#3DDC84"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/HDLSDK/app/src/main/res/layout/activity_main.xml b/HDLSDK/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..6fa6c2b
--- /dev/null
+++ b/HDLSDK/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,79 @@
+<?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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rv"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/scrollView"
+ app:layout_constraintHorizontal_weight="1"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="0dp"
+ android:background="#f4f4f4"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/scrollView"
+ app:layout_constraintStart_toEndOf="@id/rv"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.core.widget.NestedScrollView
+ android:id="@+id/scrollView"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_weight="2"
+ app:layout_constraintStart_toEndOf="@id/rv"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="10dp"
+ android:text="褰撳墠鐘舵�侊細" />
+
+ <TextView
+ android:id="@+id/state_tv"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="鏈搷浣�" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:background="#f5f5f5" />
+
+ <TextView
+ android:paddingStart="10dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:text="鍝嶅簲锛�" />
+
+ <TextView
+ android:id="@+id/response_tv"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp" />
+
+
+ </LinearLayout>
+ </androidx.core.widget.NestedScrollView>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/res/layout/demo_item.xml b/HDLSDK/app/src/main/res/layout/demo_item.xml
new file mode 100644
index 0000000..84a9aed
--- /dev/null
+++ b/HDLSDK/app/src/main/res/layout/demo_item.xml
@@ -0,0 +1,28 @@
+<?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="40dp">
+
+ <TextView
+ android:id="@+id/tv_title"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:gravity="center"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <View
+ android:layout_width="0dp"
+ android:layout_height="1dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="10dp"
+ android:background="#f5f5f5"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/HDLSDK/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/HDLSDK/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/HDLSDK/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-hdpi/ic_launcher.webp
Binary files differ
diff --git a/HDLSDK/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/HDLSDK/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Binary files differ
diff --git a/HDLSDK/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/HDLSDK/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-mdpi/ic_launcher.webp
Binary files differ
diff --git a/HDLSDK/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/HDLSDK/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Binary files differ
diff --git a/HDLSDK/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/HDLSDK/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Binary files differ
diff --git a/HDLSDK/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/HDLSDK/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/HDLSDK/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/HDLSDK/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Binary files differ
diff --git a/HDLSDK/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/HDLSDK/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/HDLSDK/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/HDLSDK/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Binary files differ
diff --git a/HDLSDK/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/HDLSDK/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
--- /dev/null
+++ b/HDLSDK/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/HDLSDK/app/src/main/res/values-night/themes.xml b/HDLSDK/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..ab52aa6
--- /dev/null
+++ b/HDLSDK/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,16 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <!-- Base application theme. -->
+ <style name="Theme.HDLSDK" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+ <!-- Primary brand color. -->
+ <item name="colorPrimary">@color/purple_200</item>
+ <item name="colorPrimaryVariant">@color/purple_700</item>
+ <item name="colorOnPrimary">@color/black</item>
+ <!-- Secondary brand color. -->
+ <item name="colorSecondary">@color/teal_200</item>
+ <item name="colorSecondaryVariant">@color/teal_200</item>
+ <item name="colorOnSecondary">@color/black</item>
+ <!-- Status bar color. -->
+ <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
+ <!-- Customize your theme here. -->
+ </style>
+</resources>
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/res/values/colors.xml b/HDLSDK/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..f8c6127
--- /dev/null
+++ b/HDLSDK/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="purple_200">#FFBB86FC</color>
+ <color name="purple_500">#FF6200EE</color>
+ <color name="purple_700">#FF3700B3</color>
+ <color name="teal_200">#FF03DAC5</color>
+ <color name="teal_700">#FF018786</color>
+ <color name="black">#FF000000</color>
+ <color name="white">#FFFFFFFF</color>
+</resources>
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/res/values/strings.xml b/HDLSDK/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..192b55f
--- /dev/null
+++ b/HDLSDK/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">HDLSDK</string>
+</resources>
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/res/values/themes.xml b/HDLSDK/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..dcf7fa1
--- /dev/null
+++ b/HDLSDK/app/src/main/res/values/themes.xml
@@ -0,0 +1,16 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <!-- Base application theme. -->
+ <style name="Theme.HDLSDK" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+ <!-- Primary brand color. -->
+ <item name="colorPrimary">@color/purple_500</item>
+ <item name="colorPrimaryVariant">@color/purple_700</item>
+ <item name="colorOnPrimary">@color/white</item>
+ <!-- Secondary brand color. -->
+ <item name="colorSecondary">@color/teal_200</item>
+ <item name="colorSecondaryVariant">@color/teal_700</item>
+ <item name="colorOnSecondary">@color/black</item>
+ <!-- Status bar color. -->
+ <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
+ <!-- Customize your theme here. -->
+ </style>
+</resources>
\ No newline at end of file
diff --git a/HDLSDK/app/src/test/java/com/hdl/hdlsdk/ExampleUnitTest.java b/HDLSDK/app/src/test/java/com/hdl/hdlsdk/ExampleUnitTest.java
new file mode 100644
index 0000000..eceb1d2
--- /dev/null
+++ b/HDLSDK/app/src/test/java/com/hdl/hdlsdk/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.hdl.hdlsdk;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/HDLSDK/build.gradle b/HDLSDK/build.gradle
new file mode 100644
index 0000000..1755efa
--- /dev/null
+++ b/HDLSDK/build.gradle
@@ -0,0 +1,30 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+apply from: "config.gradle"
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:4.2.2"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+
+allprojects {
+ repositories {
+ maven { url 'https://maven.aliyun.com/repository/google' }
+ maven { url 'https://maven.aliyun.com/repository/jcenter' }
+ maven { url 'https://maven.aliyun.com/repository/public' }
+ google()
+ maven { url "https://jitpack.io" }
+ }
+}
+
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/HDLSDK/config.gradle b/HDLSDK/config.gradle
new file mode 100644
index 0000000..582d32b
--- /dev/null
+++ b/HDLSDK/config.gradle
@@ -0,0 +1,7 @@
+ext {
+ minSdkVersion = 16
+ targetSdkVersion = 31
+ compileSdkVersion = 31
+ versionName = "1.0.0"
+
+}
\ No newline at end of file
diff --git a/HDLSDK/gradle.properties b/HDLSDK/gradle.properties
new file mode 100644
index 0000000..52f5917
--- /dev/null
+++ b/HDLSDK/gradle.properties
@@ -0,0 +1,19 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app"s APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
\ No newline at end of file
diff --git a/HDLSDK/gradle/wrapper/gradle-wrapper.jar b/HDLSDK/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
--- /dev/null
+++ b/HDLSDK/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/HDLSDK/gradle/wrapper/gradle-wrapper.properties b/HDLSDK/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..e85e154
--- /dev/null
+++ b/HDLSDK/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Sep 15 00:34:41 CST 2021
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/HDLSDK/gradlew b/HDLSDK/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/HDLSDK/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# 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
+#
+# https://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.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/HDLSDK/gradlew.bat b/HDLSDK/gradlew.bat
new file mode 100644
index 0000000..ac1b06f
--- /dev/null
+++ b/HDLSDK/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/HDLSDK/hdl-common/.gitignore b/HDLSDK/hdl-common/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/HDLSDK/hdl-common/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/HDLSDK/hdl-common/build.gradle b/HDLSDK/hdl-common/build.gradle
new file mode 100644
index 0000000..673c577
--- /dev/null
+++ b/HDLSDK/hdl-common/build.gradle
@@ -0,0 +1,34 @@
+plugins {
+ id 'com.android.library'
+}
+
+android {
+ compileSdkVersion rootProject.compileSdkVersion
+
+ defaultConfig {
+ minSdkVersion rootProject.minSdkVersion
+ targetSdkVersion rootProject.targetSdkVersion
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ api 'com.google.code.gson:gson:2.8.8'
+ api 'androidx.annotation:annotation:1.2.0'
+ api 'androidx.collection:collection:1.1.0'
+}
\ No newline at end of file
diff --git a/HDLSDK/hdl-common/consumer-rules.pro b/HDLSDK/hdl-common/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/HDLSDK/hdl-common/consumer-rules.pro
diff --git a/HDLSDK/hdl-common/proguard-rules.pro b/HDLSDK/hdl-common/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/HDLSDK/hdl-common/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/HDLSDK/hdl-common/src/androidTest/java/com/hdl/sdk/common/ExampleInstrumentedTest.java b/HDLSDK/hdl-common/src/androidTest/java/com/hdl/sdk/common/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..46d814a
--- /dev/null
+++ b/HDLSDK/hdl-common/src/androidTest/java/com/hdl/sdk/common/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.hdl.sdk.common;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.hdl.sdk.common.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/HDLSDK/hdl-common/src/main/AndroidManifest.xml b/HDLSDK/hdl-common/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ea4c4f9
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.hdl.sdk.common">
+
+</manifest>
\ No newline at end of file
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/HDLSdk.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/HDLSdk.java
new file mode 100644
index 0000000..120fc9d
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/HDLSdk.java
@@ -0,0 +1,30 @@
+package com.hdl.sdk.common;
+
+import android.content.Context;
+
+/**
+ * Created by Tong on 2021/9/28.
+ */
+public class HDLSdk {
+
+ private Context context;
+
+ private HDLSdk() {
+ }
+
+ private static class SingletonInstance {
+ private static final HDLSdk INSTANCE = new HDLSdk();
+ }
+
+ public static HDLSdk getInstance() {
+ return SingletonInstance.INSTANCE;
+ }
+
+ public void init(Context context) {
+ this.context = context.getApplicationContext();
+ }
+
+ public Context getContext() {
+ return context;
+ }
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/IHDLClient.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/IHDLClient.java
new file mode 100644
index 0000000..5c6007f
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/IHDLClient.java
@@ -0,0 +1,52 @@
+package com.hdl.sdk.common;
+
+/**
+ * Created by Tong on 2021/9/28.
+ * 鍖呭惈鎵�鏈夋搷浣�
+ */
+public interface IHDLClient {
+
+
+ /**
+ * 鎼滅储缃戝叧
+ */
+ void searchGateway();
+
+
+ /**
+ * 鑾峰彇缃戝叧璇︾粏淇℃伅
+ */
+ void getGatewayInfo();
+
+ /**
+ * 鑾峰彇璁惧鍒楄〃
+ */
+ void getDeviceList();
+
+ /**
+ * 鑾峰彇鍔熻兘鍒楄〃
+ */
+ void getFunctionList();
+
+ /**
+ * 鑾峰彇鍔熻兘灞炴��
+ */
+ void getFunctionAttribute();
+
+ /**
+ * 璁惧鎺у埗
+ */
+ void deviceControl();
+
+ /**
+ * 鑾峰彇璁惧鐘舵��
+ */
+ void getDeviceStatus();
+
+ /**
+ * 鏀瑰彉璁惧鐘舵��
+ */
+ void changeDeviceStatus();
+
+
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/config/TopicConstant.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/config/TopicConstant.java
new file mode 100644
index 0000000..ace530f
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/config/TopicConstant.java
@@ -0,0 +1,52 @@
+package com.hdl.sdk.common.config;
+
+/**
+ * Created by Tong on 2021/9/22.
+ */
+public class TopicConstant {
+
+ //鎼滅储缃戝叧
+ public static final String GATEWAY_SEARCH = "/user/all/custom/gateway/search";
+
+ //鎼滅储缃戝叧鍝嶅簲
+ public static final String GATEWAY_SEARCH_REPLY = "/user/all/custom/gateway/search_reply";
+
+ //缃戝叧璇︾粏淇℃伅鑾峰彇s=gw_id
+ public static final String GATEWAY_INFO = "/user/%s/custom/gateway/get";
+
+ //鑾峰彇鐗╃悊璁惧鍒楄〃
+ public static final String GET_DEVICE_LIST = " /user/%s/custom/device/list/get";
+
+ //鑾峰彇鐗╃悊璁惧鍒楄〃鍝嶅簲
+ public static final String GET_DEVICE_LIST_REPLY = " /user/%s/custom/device/list/get_reply";
+
+ //鑾峰彇鍔熻兘鍒楄〃
+ public static final String GET_FUNCTION_LIST = "/user/%s/custom/function/list/get";
+
+ //鑾峰彇鍔熻兘鍝嶅簲
+ public static final String GET_FUNCTION_LIST_REPLY = "/user/%s/custom/function/list/get_reply";
+
+ //鍔熻兘灞炴�ц鍙�
+ public static final String GET_FUNCTION_ATTRIBUTE = "/user/%s/custom/function/attribute/get";
+
+ //鍔熻兘灞炴�у搷搴�
+ public static final String GET_FUNCTION_ATTRIBUTE_REPLY = "/user/%s/custom/function/attribute/get_reply";
+
+ //鎺у埗
+ public static final String PROPERTY_DOWN = "/base/%s/thing/property/down";
+
+ //鎺у埗鍝嶅簲
+ public static final String PROPERTY_DOWN_REPLY = "/base/%s/thing/property/down_reply";
+
+ //鐘舵�佷笂鎶�
+ public static final String PROPERTY_UP = "/base/%s/thing/property/up";
+
+ //鐘舵�佷笂鎶ュ搷搴�
+ public static final String PROPERTY_UP_REPLY = "/base/%s/thing/property/up_reply";
+
+ //璇诲彇鐘舵��
+ public static final String PROPERTY_READ = "/base/%s/thing/property/read";
+
+ //璇诲彇鐘舵�佸搷搴�
+ public static final String PROPERTY_READ_REPLY = "/base/%s/thing/property/read_reply";
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/event/EventDispatcher.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/event/EventDispatcher.java
new file mode 100644
index 0000000..b17b3a8
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/event/EventDispatcher.java
@@ -0,0 +1,132 @@
+package com.hdl.sdk.common.event;
+
+import androidx.annotation.NonNull;
+import androidx.collection.ArrayMap;
+
+
+import com.hdl.sdk.common.utils.ThreadToolUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ExecutorService;
+
+
+/**
+ * Created by Tong on 2021/9/22.
+ * 浜嬩欢鍒嗗彂
+ */
+public class EventDispatcher {
+
+ private static final ArrayMap<Object, List<EventListener>> EVENT = new ArrayMap<>();
+
+ private static final ArrayMap<EventListener, Integer> TYPE = new ArrayMap<>();
+
+ private static final int MAIN_TYPE = 0;
+ private static final int IO_TYPE = 1;
+
+ private static final ExecutorService ioThread = ThreadToolUtils.getInstance().newFixedThreadPool(2);
+
+ private EventDispatcher() {
+ }
+
+ private static class SingletonInstance {
+ private static final EventDispatcher INSTANCE = new EventDispatcher();
+ }
+
+ public static EventDispatcher getInstance() {
+ return SingletonInstance.INSTANCE;
+ }
+
+ public synchronized void register(Object tag, EventListener listener) {
+ if (!EVENT.containsKey(tag)) {
+ EVENT.put(tag, new ArrayList<>());
+ }
+ List<EventListener> events = EVENT.get(tag);
+ if (events != null && !events.contains(listener)) {
+ events.add(listener);
+ }
+ TYPE.put(listener, MAIN_TYPE);
+ }
+
+ public synchronized void registerIo(Object tag, EventListener listener) {
+ if (!EVENT.containsKey(tag)) {
+ EVENT.put(tag, new ArrayList<>());
+ }
+ List<EventListener> events = EVENT.get(tag);
+ if (events != null && !events.contains(listener)) {
+ events.add(listener);
+ }
+ TYPE.put(listener, IO_TYPE);
+ }
+
+ public synchronized void remove(Object tag) {
+ ioThread.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (EVENT.containsKey(tag)) {
+ List<EventListener> list = EVENT.get(tag);
+ for (EventListener eventListener : list) {
+ TYPE.remove(eventListener);
+ }
+ EVENT.remove(tag);
+ }
+ } catch (Exception ignored) {
+
+ }
+
+ }
+ });
+ }
+
+ public synchronized void remove(Object tag, EventListener listener) {
+ ioThread.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (EVENT.containsKey(tag)) {
+ List<EventListener> ev = EVENT.get(tag);
+ if (ev != null && !ev.isEmpty()) {
+ TYPE.remove(listener);
+ ev.remove(listener);
+ }
+ }
+ } catch (Exception ignored) {
+
+ }
+
+ }
+ });
+ }
+
+ public synchronized void post(Object tag, @NonNull Object o) {
+ if (EVENT.containsKey(tag)) {
+ List<EventListener> list = EVENT.get(tag);
+ if (list != null && !list.isEmpty()) {
+ for (EventListener listener : list) {
+ ThreadToolUtils.getInstance().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (listener != null) {
+ listener.onMessage(o);
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+
+ public synchronized void clear() {
+ EVENT.clear();
+ TYPE.clear();
+ }
+
+ public synchronized void release() {
+ clear();
+ ioThread.shutdownNow();
+ }
+
+
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/event/EventListener.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/event/EventListener.java
new file mode 100644
index 0000000..eb82740
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/event/EventListener.java
@@ -0,0 +1,10 @@
+package com.hdl.sdk.common.event;
+
+/**
+ * Created by Tong on 2021/9/22.
+ */
+public interface EventListener {
+
+ void onMessage(Object msg);
+
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/ByteUtils.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/ByteUtils.java
new file mode 100644
index 0000000..ff641db
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/ByteUtils.java
@@ -0,0 +1,134 @@
+package com.hdl.sdk.common.utils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by Tong on 2021/9/23.
+ */
+public class ByteUtils {
+
+ public static byte[] toByteArray(List<Byte> list) {
+ Byte[] temps = list.toArray(new Byte[0]);
+ byte[] result = new byte[temps.length];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = temps[i];
+ }
+ return result;
+
+ }
+
+ public static List<Byte> toByteList(byte[] bytes) {
+ final List<Byte> list = new ArrayList<>();
+ for (byte aByte : bytes) {
+ list.add(aByte);
+ }
+ return list;
+
+ }
+
+ public static byte[] getRangeBytes(List<Byte> list, int start, int end) {
+ Byte[] temps = Arrays.copyOfRange(list.toArray(new Byte[0]), start, end);
+ byte[] result = new byte[temps.length];
+ for (int i = 0; i < temps.length; i++) {
+ result[i] = temps[i];
+ }
+ return result;
+
+ }
+
+ /**
+ * 鎷兼帴byte
+ */
+ public static byte[] concatBytes(byte[] bt1, byte[] bt2) {
+ if (bt1 == null) {
+ return bt2;
+ }
+ if (bt2 == null) {
+ return bt1;
+ }
+ byte[] bt3 = new byte[bt1.length + bt2.length];
+ System.arraycopy(bt1, 0, bt3, 0, bt1.length);
+ System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
+ return bt3;
+ }
+
+
+ public boolean endWith(Byte[] src, byte[] target) {
+ if (src.length < target.length) {
+ return false;
+ }
+ for (int i = 0; i < target.length; i++) {
+ if (target[target.length - i - 1] != src[src.length - i - 1]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public static int byteIndexOf(byte[] searched, byte[] find, int start) {
+ boolean matched;
+ int end = find.length - 1;
+ int skip = 0;
+ for (int index = start; index <= searched.length - find.length; ++index) {
+ matched = true;
+ if (find[0] != searched[index] || find[end] != searched[index + end]) continue;
+ else skip++;
+ if (end > 10)
+ if (find[skip] != searched[index + skip] || find[end - skip] != searched[index + end - skip])
+ continue;
+ else skip++;
+ for (int subIndex = skip; subIndex < find.length - skip; ++subIndex) {
+ if (find[subIndex] != searched[index + subIndex]) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) {
+ return index;
+ }
+ }
+ return -1;
+
+ }
+
+ public static int getByteIndexOf(byte[] sources, byte[] src) {
+ return getByteIndexOf(sources, src, 0, sources.length);
+ }
+
+ //鍒ゆ柇涓�涓猙yte鏁板�煎湪鍙﹀涓�涓猙yte鏁扮粍涓搴旂殑娓告爣鍊�
+ public static int getByteIndexOf(byte[] sources, byte[] src, int startIndex) {
+ return getByteIndexOf(sources, src, startIndex, sources.length);
+ }
+
+
+ //鍒ゆ柇涓�涓猙yte鏁板�煎湪鍙﹀涓�涓猙yte鏁扮粍涓搴旂殑娓告爣鍊硷紝鎸囧畾寮�濮嬬殑娓告爣鍜岀粨鏉熺殑娓告爣浣嶇疆
+ public static int getByteIndexOf(byte[] sources, byte[] src, int startIndex, int endIndex) {
+
+ if (sources == null || src == null || sources.length == 0 || src.length == 0) {
+ return -1;
+ }
+
+ if (endIndex > sources.length) {
+ endIndex = sources.length;
+ }
+
+ int i, j;
+ for (i = startIndex; i < endIndex; i++) {
+ if (sources[i] == src[0] && i + src.length < endIndex) {
+ for (j = 1; j < src.length; j++) {
+ if (sources[i + j] != src[j]) {
+ break;
+ }
+ }
+
+ if (j == src.length) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/IdUtils.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/IdUtils.java
new file mode 100644
index 0000000..97181a7
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/IdUtils.java
@@ -0,0 +1,12 @@
+package com.hdl.sdk.common.utils;
+
+import java.util.UUID;
+
+/**
+ * Created by Tong on 2021/10/8.
+ */
+public class IdUtils {
+ public static String getUUId() {
+ return UUID.randomUUID().toString().replaceAll("-", "");
+ }
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/IpUtils.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/IpUtils.java
new file mode 100644
index 0000000..f35cfb9
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/IpUtils.java
@@ -0,0 +1,72 @@
+package com.hdl.sdk.common.utils;
+
+import android.content.Context;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+
+import java.net.InetAddress;
+import java.net.InterfaceAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Enumeration;
+
+/**
+ * Created by Tong on 2021/9/27.
+ */
+public class IpUtils {
+
+ /**
+ * @return 骞挎挱鍦板潃
+ */
+ public static String getBroadcastAddress() {
+ try {
+ for (Enumeration<NetworkInterface> niEnum = NetworkInterface.getNetworkInterfaces();
+ niEnum.hasMoreElements(); ) {
+ NetworkInterface ni = niEnum.nextElement();
+ if (!ni.isLoopback()) {
+ for (InterfaceAddress interfaceAddress : ni.getInterfaceAddresses()) {
+ if (interfaceAddress.getBroadcast() != null) {
+ return interfaceAddress.getBroadcast().toString().substring(1);
+ }
+ }
+ }
+ }
+ } catch (SocketException e) {
+ e.printStackTrace();
+ }
+ return "255.255.255.255";
+ }
+
+ public static String getIP(Context application) {
+ WifiManager wifiManager = (WifiManager) application.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+ if (!wifiManager.isWifiEnabled()) {
+ try {
+ for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
+ NetworkInterface intf = en.nextElement();
+ for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
+ InetAddress inetAddress = enumIpAddr.nextElement();
+ if (!inetAddress.isLoopbackAddress()) {
+ return inetAddress.getHostAddress();
+ }
+ }
+ }
+ } catch (SocketException e) {
+ e.printStackTrace();
+ }
+ } else {
+ WifiInfo wifiInfo = wifiManager.getConnectionInfo();
+ int ipAddress = wifiInfo.getIpAddress();
+ return intToIp(ipAddress);
+ }
+ return null;
+ }
+
+
+ private static String intToIp(int i) {
+
+ return (i & 0xFF) + "." +
+ ((i >> 8) & 0xFF) + "." +
+ ((i >> 16) & 0xFF) + "." +
+ (i >> 24 & 0xFF);
+ }
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/LogUtils.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/LogUtils.java
new file mode 100644
index 0000000..22ab283
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/LogUtils.java
@@ -0,0 +1,51 @@
+package com.hdl.sdk.common.utils;
+
+/**
+ * Created by Tong on 2021/9/23.
+ */
+public class LogUtils {
+
+ private static final String TAG = "HDLSocket";
+
+ private boolean isEnabled = true;
+
+
+ private LogUtils() {
+ }
+
+ private static class SingletonInstance {
+ private static final LogUtils INSTANCE = new LogUtils();
+ }
+
+ public static LogUtils getInstance() {
+ return SingletonInstance.INSTANCE;
+ }
+
+ public boolean isEnabled() {
+ return isEnabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ isEnabled = enabled;
+ }
+
+ public static void d(String tag, String msg) {
+
+ }
+
+ public static void e(String tag, String msg) {
+
+ }
+
+ public static void w(String tag, String msg) {
+
+ }
+
+ public static void v(String tag, String msg) {
+
+ }
+
+ public static void i(String tag, String msg) {
+
+ }
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/SPUtils.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/SPUtils.java
new file mode 100644
index 0000000..bbdd808
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/SPUtils.java
@@ -0,0 +1,151 @@
+package com.hdl.sdk.common.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import androidx.annotation.NonNull;
+
+import com.hdl.sdk.common.HDLSdk;
+
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Created by Tong on 2021/9/28.
+ */
+public class SPUtils {
+ private static final String APP_PREFERENCES_KEY = "profile";
+ private static final SharedPreferences PREFERENCES =
+ HDLSdk.getInstance().getContext().getApplicationContext().getSharedPreferences(APP_PREFERENCES_KEY, Context.MODE_PRIVATE);
+
+ private static SharedPreferences getAppPreference() {
+ return PREFERENCES;
+ }
+
+
+ //======閫氱敤瀛樺偍========
+ public static void put(@NonNull final String key, final String value) {
+ getAppPreference().edit().putString(key, value).apply();
+ }
+
+
+ public static String getString(@NonNull final String key) {
+ return getString(key, "");
+ }
+
+
+ public static String getString(@NonNull final String key, final String defaultValue) {
+ return getAppPreference().getString(key, defaultValue);
+ }
+
+
+ public static void put(@NonNull final String key, final int value) {
+ put(key, value, false);
+ }
+
+
+ public static void put(@NonNull final String key, final int value, final boolean isCommit) {
+ getAppPreference().edit().putInt(key, value).apply();
+ }
+
+
+ public static int getInt(@NonNull final String key) {
+ return getInt(key, -1);
+ }
+
+
+ public static int getInt(@NonNull final String key, final int defaultValue) {
+ return getAppPreference().getInt(key, defaultValue);
+ }
+
+
+ public static void put(@NonNull final String key, final long value) {
+ getAppPreference().edit().putLong(key, value).apply();
+ }
+
+
+ public static long getLong(@NonNull final String key) {
+ return getLong(key, -1L);
+ }
+
+
+ public static long getLong(@NonNull final String key, final long defaultValue) {
+ return getAppPreference().getLong(key, defaultValue);
+ }
+
+
+ public static void put(@NonNull final String key, final float value) {
+ getAppPreference().edit().putFloat(key, value).apply();
+ }
+
+
+ public static float getFloat(@NonNull final String key) {
+ return getFloat(key, -1f);
+ }
+
+
+ public static float getFloat(@NonNull final String key, final float defaultValue) {
+ return getAppPreference().getFloat(key, defaultValue);
+ }
+
+
+ public static void put(@NonNull final String key, final boolean value) {
+ getAppPreference().edit().putBoolean(key, value).apply();
+ }
+
+
+ public static boolean getBoolean(@NonNull final String key) {
+ return getBoolean(key, false);
+ }
+
+
+ public static boolean getBoolean(@NonNull final String key, final boolean defaultValue) {
+ return getAppPreference().getBoolean(key, defaultValue);
+ }
+
+
+ public static void put(@NonNull final String key,
+ final Set<String> value
+ ) {
+
+ getAppPreference().edit().putStringSet(key, value).apply();
+
+ }
+
+
+ public static Set<String> getStringSet(@NonNull final String key) {
+ return getStringSet(key, Collections.<String>emptySet());
+ }
+
+
+ public static Set<String> getStringSet(@NonNull final String key,
+ final Set<String> defaultValue) {
+ return getAppPreference().getStringSet(key, defaultValue);
+ }
+
+
+ public static Map<String, ?> getAll() {
+ return getAppPreference().getAll();
+ }
+
+
+ public static boolean contains(@NonNull final String key) {
+ return getAppPreference().contains(key);
+ }
+
+
+ public static void remove(@NonNull final String key) {
+ getAppPreference().edit().remove(key).apply();
+ }
+
+ public static void clear() {
+ getAppPreference()
+ .edit()
+ .clear()
+ .apply();
+ }
+
+
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/ThreadToolUtils.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/ThreadToolUtils.java
new file mode 100644
index 0000000..d42da84
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/ThreadToolUtils.java
@@ -0,0 +1,72 @@
+package com.hdl.sdk.common.utils;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * Created by Tong on 2021/9/15.
+ */
+public class ThreadToolUtils {
+
+ private final Handler uiHandler = new Handler(Looper.getMainLooper());
+
+ //cpu 鏈�澶х嚎绋嬪绾抽噺
+ private final int coreSize = Runtime.getRuntime().availableProcessors() + 1;
+
+ private ThreadToolUtils() {
+ }
+
+ private static class SingletonInstance {
+ private static final ThreadToolUtils INSTANCE = new ThreadToolUtils();
+ }
+
+ public static ThreadToolUtils getInstance() {
+ return SingletonInstance.INSTANCE;
+ }
+
+
+ /**
+ * 绾跨▼鏁伴噺鍥哄畾鐨勭嚎绋嬫睜
+ */
+ public ExecutorService newFixedThreadPool(int size) {
+ if (size == 0 || coreSize < size) {
+ return Executors.newFixedThreadPool(coreSize);
+ }
+ return Executors.newFixedThreadPool(size);
+ }
+
+ /**
+ * 瀹氭椂浠诲姟绾跨▼姹�
+ */
+ public ScheduledExecutorService newScheduledThreadPool(int size) {
+ if (size == 0 || coreSize < size) {
+ return Executors.newScheduledThreadPool(coreSize);
+ }
+ return Executors.newScheduledThreadPool(size);
+ }
+
+ /**
+ * 鍗曚竴绾跨▼
+ */
+ public ExecutorService newSingleThreadPool() {
+ return Executors.newSingleThreadExecutor();
+ }
+
+
+ public ExecutorService newCachedThreadPool() {
+ return Executors.newCachedThreadPool();
+ }
+
+ /**
+ * 鍒囨崲鍥炰富绾跨▼
+ */
+ public void runOnUiThread(Runnable run) {
+ uiHandler.post(run);
+ }
+
+
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/gson/GsonConvert.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/gson/GsonConvert.java
new file mode 100644
index 0000000..f38cfa9
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/gson/GsonConvert.java
@@ -0,0 +1,55 @@
+package com.hdl.sdk.common.utils.gson;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+import java.lang.reflect.Type;
+
+/**
+ * Created by Tong on 2021/9/8.
+ */
+public class GsonConvert {
+
+ private static Gson gson = null;
+
+ public static Gson getGson() {
+ if (gson == null) {
+ synchronized (GsonConvert.class) {
+ if (gson == null) {
+ gson = new GsonBuilder()
+ .setPrettyPrinting()
+ .disableHtmlEscaping()
+ .registerTypeAdapter(String.class, new StringTypeAdapter())
+ .create();
+ }
+ }
+ }
+ return gson;
+ }
+
+ private static class StringTypeAdapter implements JsonSerializer<String>, JsonDeserializer<String> {
+ @Override
+ public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ throws JsonParseException {
+ if (json instanceof JsonPrimitive) {
+ return json.getAsString();
+ } else {
+ return json.toString();
+ }
+ }
+
+ @Override
+ public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) {
+ return new JsonPrimitive(src);
+ }
+ }
+
+
+}
diff --git a/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/gson/ParameterizedTypeImpl.java b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/gson/ParameterizedTypeImpl.java
new file mode 100644
index 0000000..fd122d8
--- /dev/null
+++ b/HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/utils/gson/ParameterizedTypeImpl.java
@@ -0,0 +1,46 @@
+package com.hdl.sdk.common.utils.gson;
+
+
+import androidx.annotation.NonNull;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * Created by Tong on 2021/9/17.
+ */
+public class ParameterizedTypeImpl implements ParameterizedType {
+
+ private final Type[] actualTypeArguments;
+ private final Type rawType;
+ private final Type ownerType;
+
+ public ParameterizedTypeImpl(Type rawType, Type[] actualTypeArguments, Type ownerType) {
+ this.ownerType = ownerType;
+ this.rawType = rawType;
+ this.actualTypeArguments = actualTypeArguments;
+ }
+
+ public static Type getType(Type rawType, Type[] actualTypeArguments) {
+ return new ParameterizedTypeImpl(rawType, actualTypeArguments, null);
+ }
+
+ @NonNull
+ @Override
+ public Type[] getActualTypeArguments() {
+ return actualTypeArguments;
+ }
+
+
+ @NonNull
+ @Override
+ public Type getRawType() {
+ return rawType;
+ }
+
+
+ @Override
+ public Type getOwnerType() {
+ return ownerType;
+ }
+}
diff --git a/HDLSDK/hdl-common/src/test/java/com/hdl/sdk/common/ExampleUnitTest.java b/HDLSDK/hdl-common/src/test/java/com/hdl/sdk/common/ExampleUnitTest.java
new file mode 100644
index 0000000..6e8323f
--- /dev/null
+++ b/HDLSDK/hdl-common/src/test/java/com/hdl/sdk/common/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.hdl.sdk.common;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/HDLSDK/hdl-connect/.gitignore b/HDLSDK/hdl-connect/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/HDLSDK/hdl-connect/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/HDLSDK/hdl-connect/build.gradle b/HDLSDK/hdl-connect/build.gradle
new file mode 100644
index 0000000..74a62e0
--- /dev/null
+++ b/HDLSDK/hdl-connect/build.gradle
@@ -0,0 +1,34 @@
+plugins {
+ id 'com.android.library'
+}
+
+android {
+ compileSdkVersion rootProject.compileSdkVersion
+
+ defaultConfig {
+ minSdkVersion rootProject.minSdkVersion
+ targetSdkVersion rootProject.targetSdkVersion
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ api project(path: ':hdl-socket')
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'com.google.android.material:material:1.3.0'
+}
\ No newline at end of file
diff --git a/HDLSDK/hdl-connect/consumer-rules.pro b/HDLSDK/hdl-connect/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/HDLSDK/hdl-connect/consumer-rules.pro
diff --git a/HDLSDK/hdl-connect/proguard-rules.pro b/HDLSDK/hdl-connect/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/HDLSDK/hdl-connect/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/HDLSDK/hdl-connect/src/androidTest/java/com/hdl/sdk/connect/ExampleInstrumentedTest.java b/HDLSDK/hdl-connect/src/androidTest/java/com/hdl/sdk/connect/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..32322d2
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/androidTest/java/com/hdl/sdk/connect/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.hdl.sdk.connect;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.hdl.sdk.connect.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/HDLSDK/hdl-connect/src/main/AndroidManifest.xml b/HDLSDK/hdl-connect/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c3b028e
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.hdl.sdk.connect">
+
+</manifest>
\ No newline at end of file
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/HDLSocket.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/HDLSocket.java
new file mode 100644
index 0000000..00cb3a2
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/HDLSocket.java
@@ -0,0 +1,650 @@
+package com.hdl.sdk.connect;
+
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.reflect.TypeToken;
+import com.hdl.sdk.common.config.TopicConstant;
+import com.hdl.sdk.common.event.EventDispatcher;
+import com.hdl.sdk.common.event.EventListener;
+import com.hdl.sdk.common.utils.IdUtils;
+import com.hdl.sdk.common.utils.IpUtils;
+import com.hdl.sdk.common.utils.SPUtils;
+import com.hdl.sdk.common.utils.ThreadToolUtils;
+import com.hdl.sdk.common.utils.gson.GsonConvert;
+import com.hdl.sdk.connect.bean.BaseLocalRequest;
+import com.hdl.sdk.connect.bean.BaseLocalResponse;
+import com.hdl.sdk.connect.bean.DeviceControlRequest;
+import com.hdl.sdk.connect.bean.FunctionAttributeRequest;
+import com.hdl.sdk.connect.bean.GatewaySearchBean;
+import com.hdl.sdk.connect.bean.LinkRequest;
+import com.hdl.sdk.connect.bean.LinkResponse;
+import com.hdl.sdk.connect.bean.PropertyReadRequest;
+import com.hdl.sdk.connect.bean.PropertyUpRequest;
+import com.hdl.sdk.connect.protocol.LinkMessageDecoder;
+import com.hdl.sdk.connect.protocol.LinkMessageEncoder;
+import com.hdl.sdk.socket.SocketBoot;
+import com.hdl.sdk.socket.SocketOptions;
+import com.hdl.sdk.socket.client.TcpClient;
+import com.hdl.sdk.socket.client.UdpClient;
+import com.hdl.sdk.socket.codec.MessagePipeLine;
+import com.hdl.sdk.socket.listener.ConnectStatusListener;
+import com.hdl.sdk.socket.listener.SendListener;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.ParameterizedType;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Created by Tong on 2021/9/26.
+ * 1銆侀�氳繃Udp 缁勬挱鎴栬�呭箍鎾悳绱㈢綉鍏�
+ * 2銆侀�氳繃Udp 鑾峰彇Tcp ip 绔彛缁熶竴8586
+ */
+public class HDLSocket {
+
+ private static final String GATEWAY_KEY = "gateway_key";
+ private static final String TCP_IP_KEY = "tcp_ip_key";
+ private String gatewayId;
+
+ public interface CallBack {
+
+ void onError(String error);
+
+ void onResponse(String data);
+
+ }
+
+ /**
+ * udp榛樿缁勬挱ip
+ */
+ private static final String UDP_GROUP_IP = "239.0.168.188";
+
+ /**
+ * udp榛樿绔彛
+ */
+ private static final int UDP_PORT = 8585;
+
+ /**
+ * tcp榛樿绔彛
+ */
+ private static final int TCP_PORT = 8586;
+
+ private String tcpIp;
+ private int tcpPort;
+
+ private int udpPort;
+ private String udpIp;
+
+ private static SocketBoot updBoot;
+ private SocketBoot tcpBoot;
+
+ private ConnectStatusListener statusListener;
+
+ private EventListener searchEvent;
+ private CallBack searchCallBack;
+ private ScheduledExecutorService searchGatewayThread;
+ private final AtomicInteger searchCount = new AtomicInteger(0);
+
+ private HDLSocket() {
+ statusListener = new ConnectStatusListener() {
+ @Override
+ public void onConnecting() {
+
+ }
+
+ @Override
+ public void onConnected() {
+
+ }
+
+ @Override
+ public void onConnectFailed() {
+
+ }
+ };
+ searchEvent = new EventListener() {
+ @Override
+ public void onMessage(Object msg) {
+ try {
+ if (msg instanceof LinkResponse) {
+ LinkResponse linkResponse = (LinkResponse) msg;
+ String data = linkResponse.getData();
+ if (!TextUtils.isEmpty(data)) {
+ final BaseLocalResponse<GatewaySearchBean> response = GsonConvert.getGson().fromJson(data, new TypeToken<BaseLocalResponse<GatewaySearchBean>>() {
+ }.getType());
+ GatewaySearchBean searchBean = response.getObjects();
+ if (searchBean != null) {
+ gatewayId = searchBean.getGatewayId();
+ if (!TextUtils.isEmpty(gatewayId)) {
+ SPUtils.put(GATEWAY_KEY, gatewayId);
+ }
+ tcpIp = searchBean.getIp_address();
+ if (!TextUtils.isEmpty(tcpIp)) {
+ SPUtils.put(TCP_IP_KEY, tcpIp);
+ }
+ }
+
+ if (searchCallBack != null) {
+ searchCallBack.onResponse(linkResponse.toString());
+ }
+ }
+
+ }
+ } catch (Exception e) {
+ if (searchCallBack != null) {
+ searchCallBack.onError("瑙f瀽澶辫触");
+ }
+ }
+
+
+ }
+ };
+ }
+
+ private static class SingletonInstance {
+ private static final HDLSocket INSTANCE = new HDLSocket();
+ }
+
+ public static HDLSocket getInstance() {
+ return SingletonInstance.INSTANCE;
+ }
+
+
+ private SocketOptions getUdpOptions() {
+ final SocketOptions options = new SocketOptions();
+ final MessagePipeLine pipeLine = new MessagePipeLine();
+ pipeLine.add(new LinkMessageDecoder());
+ pipeLine.add(new LinkMessageEncoder());
+ options.setHandleMessage(pipeLine);
+ options.setEnabledHeartbeat(false);
+ return options;
+ }
+
+ private SocketOptions getTcpOptions() {
+ final SocketOptions options = new SocketOptions();
+ final MessagePipeLine pipeLine = new MessagePipeLine();
+ pipeLine.add(new LinkMessageDecoder());
+ pipeLine.add(new LinkMessageEncoder());
+ options.setHandleMessage(pipeLine);
+ options.setEnabledHeartbeat(false);
+ return options;
+ }
+
+ private int getUdpPort() {
+ return UDP_PORT;
+ }
+
+ public int getTcpPort() {
+ return TCP_PORT;
+ }
+
+ public String getTcpIp() {
+ if (!TextUtils.isEmpty(tcpIp)) {
+ return tcpIp;
+ }
+ return SPUtils.getString(TCP_IP_KEY, "");
+ }
+
+ public String getGatewayId() {
+ if (!TextUtils.isEmpty(gatewayId)) {
+ return gatewayId;
+ }
+ return SPUtils.getString(GATEWAY_KEY, "");
+ }
+
+
+ private String getUdpIp() {
+ if (TextUtils.isEmpty(udpIp)) {
+ udpIp = UDP_GROUP_IP;
+ }
+ return udpIp;
+ }
+
+ public void searchGateway() {
+ searchGateway(null);
+ }
+
+ /**
+ * 缁勬挱鎼滅储
+ */
+ public void searchGateway(CallBack callBack) {
+ this.searchCallBack = callBack;
+
+ if (searchGatewayThread != null) {
+ searchGatewayThread.shutdownNow();
+ }
+
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while (TextUtils.isEmpty(gatewayId)) {
+ //鎼滅储缃戝叧
+ searchGateway(IdUtils.getUUId(), searchEvent);
+ try {
+ Thread.sleep(1000L);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }).start();
+ }
+
+
+ /**
+ * 閫氳繃缁勬挱鎼滅储缃戝叧
+ */
+ public void searchGateway(String msgId, EventListener eventListener) {
+ searchGateway(getUdpIp(), getUdpPort(), msgId, eventListener);
+ }
+
+ /**
+ * 閫氳繃骞挎挱鎼滅储缃戝叧
+ */
+ public void searchGatewayByBroadcast(String msgId, EventListener eventListener) {
+ searchGateway(IpUtils.getBroadcastAddress(), getUdpPort(), msgId, eventListener);
+ }
+
+ /**
+ * 榛樿鏄粍鎾悳绱㈢綉鍏�
+ */
+ public void searchGateway(String ip, int port, String msgId, EventListener eventListener) {
+
+ if (updBoot == null) {
+ updBoot = UdpClient.init(ip, port, getUdpOptions());
+ updBoot.connect();
+ }
+
+
+ String time = String.valueOf(System.currentTimeMillis());
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("id", msgId);
+ jsonObject.addProperty("time_stamp", time);
+
+ EventDispatcher.getInstance().registerIo(TopicConstant.GATEWAY_SEARCH_REPLY, eventListener);
+ LinkRequest message = new LinkRequest(TopicConstant.GATEWAY_SEARCH,
+ jsonObject.toString());
+
+ try {
+ updBoot.sendMsg(message.toString().getBytes("utf-8"));
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+
+ /**
+ * 鑾峰彇璁惧鍒楄〃
+ */
+ public void getDeviceList(CallBack callBack) {
+ if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
+ String time = String.valueOf(System.currentTimeMillis());
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("id", IdUtils.getUUId());
+ jsonObject.addProperty("time_stamp", time);
+
+ String topic = String.format(TopicConstant.GET_DEVICE_LIST, getGatewayId());
+
+ LinkRequest message = new LinkRequest(topic,
+ jsonObject.toString());
+
+ String replyTopic = String.format(TopicConstant.GET_DEVICE_LIST_REPLY, getGatewayId());
+ try {
+ sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
+ @Override
+ public void onSucceed() {
+
+ }
+
+ @Override
+ public void onError() {
+ if (callBack != null) {
+ callBack.onError("鑾峰彇璁惧鍒楄〃澶辫触");
+ }
+ }
+ });
+ } catch (UnsupportedEncodingException e) {
+ if (callBack != null) {
+ callBack.onError("鑾峰彇璁惧鍒楄〃澶辫触");
+ }
+ }
+ } else {
+ if (callBack != null) {
+ callBack.onError("ip鍦板潃涓㈠け");
+ }
+ }
+ }
+
+
+ /**
+ * 鑾峰彇鍔熻兘鍒楄〃
+ */
+ public void getFunctionList(CallBack callBack) {
+ if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
+ String time = String.valueOf(System.currentTimeMillis());
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("id", IdUtils.getUUId());
+ jsonObject.addProperty("time_stamp", time);
+
+ String topic = String.format(TopicConstant.GET_FUNCTION_LIST, getGatewayId());
+
+ LinkRequest message = new LinkRequest(topic,
+ jsonObject.toString());
+
+ String replyTopic = String.format(TopicConstant.GET_FUNCTION_LIST_REPLY, getGatewayId());
+ try {
+ sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
+ @Override
+ public void onSucceed() {
+
+ }
+
+ @Override
+ public void onError() {
+ if (callBack != null) {
+ callBack.onError("鑾峰彇鍔熻兘鍒楄〃澶辫触");
+ }
+ }
+ });
+ } catch (UnsupportedEncodingException e) {
+ if (callBack != null) {
+ callBack.onError("鑾峰彇鍔熻兘鍒楄〃澶辫触");
+ }
+ }
+ } else {
+ if (callBack != null) {
+ callBack.onError("ip鍦板潃涓㈠け");
+ }
+ }
+ }
+
+
+ /**
+ * 鑾峰彇鍔熻兘灞炴��
+ *
+ * @param callBack
+ * @param sid
+ */
+ public void getFunctionAttribute(CallBack callBack, String... sid) {
+ if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
+ String time = String.valueOf(System.currentTimeMillis());
+
+ final BaseLocalResponse<List<FunctionAttributeRequest>> data = new BaseLocalResponse<>();
+ data.setId(IdUtils.getUUId());
+ data.setTime_stamp(time);
+ List<FunctionAttributeRequest> list = new ArrayList<>();
+ for (String s : sid) {
+ list.add(new FunctionAttributeRequest(s));
+ }
+ data.setObjects(list);
+
+ String topic = String.format(TopicConstant.GET_FUNCTION_ATTRIBUTE, getGatewayId());
+ LinkRequest message = new LinkRequest(topic,
+ GsonConvert.getGson().toJson(data));
+
+ String replyTopic = String.format(TopicConstant.GET_FUNCTION_ATTRIBUTE_REPLY, getGatewayId());
+ try {
+ sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
+ @Override
+ public void onSucceed() {
+
+ }
+
+ @Override
+ public void onError() {
+ if (callBack != null) {
+ callBack.onError("鑾峰彇鍔熻兘灞炴�уけ璐�");
+ }
+ }
+ });
+ } catch (UnsupportedEncodingException e) {
+ if (callBack != null) {
+ callBack.onError("鑾峰彇鍔熻兘灞炴�уけ璐�");
+ }
+ }
+ } else {
+ if (callBack != null) {
+ callBack.onError("ip鍦板潃涓㈠け");
+ }
+ }
+ }
+
+ /**
+ * 璁惧鎺у埗
+ */
+ public void propertyDown(List<DeviceControlRequest> request, CallBack callBack) {
+
+ if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
+ String time = String.valueOf(System.currentTimeMillis());
+
+ final BaseLocalResponse<List<DeviceControlRequest>> data = new BaseLocalResponse<>();
+ data.setId(IdUtils.getUUId());
+ data.setTime_stamp(time);
+ data.setObjects(request);
+
+
+ String topic = String.format(TopicConstant.PROPERTY_DOWN, getGatewayId());
+ LinkRequest message = new LinkRequest(topic,
+ GsonConvert.getGson().toJson(request));
+
+ String replyTopic = String.format(TopicConstant.PROPERTY_DOWN_REPLY, getGatewayId());
+ try {
+ sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
+ @Override
+ public void onSucceed() {
+
+ }
+
+ @Override
+ public void onError() {
+ if (callBack != null) {
+ callBack.onError("鎺у埗鎸囦护鍙戦�佸け璐�");
+ }
+ }
+ });
+ } catch (UnsupportedEncodingException e) {
+ if (callBack != null) {
+ callBack.onError("鎺у埗鎸囦护鍙戦�佸け璐�");
+ }
+ }
+ } else {
+ if (callBack != null) {
+ callBack.onError("鎺у埗鎸囦护鍙戦�佸け璐�");
+ }
+ }
+
+ }
+
+ /**
+ * 鐘舵�佷笂鎶�
+ */
+ public void propertyUp(List<PropertyUpRequest> request, CallBack callBack) {
+ if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
+ String time = String.valueOf(System.currentTimeMillis());
+
+ final BaseLocalResponse<List<PropertyUpRequest>> data = new BaseLocalResponse<>();
+ data.setId(IdUtils.getUUId());
+ data.setTime_stamp(time);
+ data.setObjects(request);
+
+
+ String topic = String.format(TopicConstant.PROPERTY_UP, getGatewayId());
+ LinkRequest message = new LinkRequest(topic,
+ GsonConvert.getGson().toJson(request));
+
+ String replyTopic = String.format(TopicConstant.PROPERTY_UP_REPLY, getGatewayId());
+ try {
+ sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
+ @Override
+ public void onSucceed() {
+
+ }
+
+ @Override
+ public void onError() {
+ if (callBack != null) {
+ callBack.onError("鎸囦护鍙戦�佸け璐�");
+ }
+ }
+ });
+ } catch (UnsupportedEncodingException e) {
+ if (callBack != null) {
+ callBack.onError("鎸囦护鍙戦�佸け璐�");
+ }
+ }
+ } else {
+ if (callBack != null) {
+ callBack.onError("鎸囦护鍙戦�佸け璐�");
+ }
+ }
+ }
+
+ /**
+ * 璇诲彇鐘舵��
+ */
+ public void propertyRead(List<PropertyReadRequest> request, CallBack callBack) {
+ if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
+ String time = String.valueOf(System.currentTimeMillis());
+
+ final BaseLocalResponse<List<PropertyReadRequest>> data = new BaseLocalResponse<>();
+ data.setId(IdUtils.getUUId());
+ data.setTime_stamp(time);
+ data.setObjects(request);
+
+
+ String topic = String.format(TopicConstant.PROPERTY_READ, getGatewayId());
+ LinkRequest message = new LinkRequest(topic,
+ GsonConvert.getGson().toJson(request));
+
+ String replyTopic = String.format(TopicConstant.PROPERTY_READ_REPLY, getGatewayId());
+ try {
+ sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
+ @Override
+ public void onSucceed() {
+
+ }
+
+ @Override
+ public void onError() {
+ if (callBack != null) {
+ callBack.onError("鎸囦护鍙戦�佸け璐�");
+ }
+ }
+ });
+ } catch (UnsupportedEncodingException e) {
+ if (callBack != null) {
+ callBack.onError("鎸囦护鍙戦�佸け璐�");
+ }
+ }
+ } else {
+ if (callBack != null) {
+ callBack.onError("鎸囦护鍙戦�佸け璐�");
+ }
+ }
+ }
+
+ public SocketBoot getTcp() throws RuntimeException {
+ if (TextUtils.isEmpty(getTcpIp())) {
+ throw new RuntimeException("璇锋悳绱㈢綉鍏�");
+ }
+ if (tcpBoot == null) {
+ tcpBoot = TcpClient.init(getTcpIp(), getTcpPort(), getTcpOptions());
+ }
+ return tcpBoot;
+ }
+
+ /**
+ * 娓呯┖缂撳瓨
+ */
+ public void clearCache() {
+ SPUtils.remove(TCP_IP_KEY);
+ SPUtils.remove(GATEWAY_KEY);
+ }
+
+
+ /**
+ * 鍙戦�佹寚浠�
+ * 1绉掓病鍝嶅簲灏辫浠栭噸鏂板彂閫�,閲嶈瘯3娆�
+ */
+ public void sendMsg(byte[] data, String eventTag, CallBack callBack, SendListener sendListener) {
+
+ try {
+ final AtomicInteger sendCount = new AtomicInteger(0);
+
+ final ScheduledExecutorService threadPool = ThreadToolUtils.getInstance().newScheduledThreadPool(1);
+ final EventListener eventListener = new EventListener() {
+ @Override
+ public void onMessage(Object msg) {
+ if (msg instanceof LinkResponse) {
+
+ if (callBack != null) {
+ callBack.onResponse(msg.toString());
+ }
+ threadPool.shutdownNow();
+ }
+ }
+ };
+
+ threadPool.scheduleWithFixedDelay(new Runnable() {
+ @Override
+ public void run() {
+ if (sendCount.get() < 3) {
+ sendCount.set(sendCount.get() + 1);
+ getTcp().sendMsg(data);
+ } else {
+ threadPool.shutdownNow();
+ EventDispatcher.getInstance().remove(eventTag, eventListener);
+ ThreadToolUtils.getInstance().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (callBack != null) {
+ callBack.onError("鍙戦�佸け璐�");
+ }
+ }
+ });
+ }
+ }
+ }, 1000, 500, TimeUnit.MILLISECONDS);
+ EventDispatcher.getInstance().register(eventTag, eventListener);
+ getTcp().sendMsg(data, new SendListener() {
+ @Override
+ public void onSucceed() {
+ if (sendListener != null) {
+ sendListener.onSucceed();
+ }
+ }
+
+ @Override
+ public void onError() {
+ if (sendListener != null) {
+ sendListener.onError();
+ }
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ ThreadToolUtils.getInstance().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (callBack != null) {
+ callBack.onError("鍙戦�佸け璐�");
+ }
+ }
+ });
+ }
+
+ }
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/BaseLocalRequest.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/BaseLocalRequest.java
new file mode 100644
index 0000000..d2ae00f
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/BaseLocalRequest.java
@@ -0,0 +1,47 @@
+package com.hdl.sdk.connect.bean;
+
+import java.io.Serializable;
+
+/**
+ * Created by Tong on 2021/9/29.
+ */
+public class BaseLocalRequest<T> implements Serializable {
+
+
+ private String id;
+ private String code;
+ private String time_stamp;
+ private T objects;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getTime_stamp() {
+ return time_stamp;
+ }
+
+ public void setTime_stamp(String time_stamp) {
+ this.time_stamp = time_stamp;
+ }
+
+ public T getObjects() {
+ return objects;
+ }
+
+ public void setObjects(T objects) {
+ this.objects = objects;
+ }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/BaseLocalResponse.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/BaseLocalResponse.java
new file mode 100644
index 0000000..0a664a2
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/BaseLocalResponse.java
@@ -0,0 +1,38 @@
+package com.hdl.sdk.connect.bean;
+
+import java.io.Serializable;
+
+/**
+ * Created by Tong on 2021/9/29.
+ */
+public class BaseLocalResponse<T> implements Serializable {
+
+
+ private String id;
+ private String time_stamp;
+ private T objects;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getTime_stamp() {
+ return time_stamp;
+ }
+
+ public void setTime_stamp(String time_stamp) {
+ this.time_stamp = time_stamp;
+ }
+
+ public T getObjects() {
+ return objects;
+ }
+
+ public void setObjects(T objects) {
+ this.objects = objects;
+ }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/DeviceControlRequest.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/DeviceControlRequest.java
new file mode 100644
index 0000000..275b7fc
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/DeviceControlRequest.java
@@ -0,0 +1,51 @@
+package com.hdl.sdk.connect.bean;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Created by Tong on 2021/10/8.
+ */
+public class DeviceControlRequest implements Serializable {
+
+ private String sid;
+ private List<StatusBean> status;
+
+ public String getSid() {
+ return sid;
+ }
+
+ public void setSid(String sid) {
+ this.sid = sid;
+ }
+
+ public List<StatusBean> getStatus() {
+ return status;
+ }
+
+ public void setStatus(List<StatusBean> status) {
+ this.status = status;
+ }
+
+ public static class StatusBean implements Serializable {
+ private String key;
+ private String value;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+ }
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/FunctionAttributeRequest.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/FunctionAttributeRequest.java
new file mode 100644
index 0000000..03ad699
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/FunctionAttributeRequest.java
@@ -0,0 +1,24 @@
+package com.hdl.sdk.connect.bean;
+
+import java.io.Serializable;
+
+/**
+ * Created by Tong on 2021/10/8.
+ */
+public class FunctionAttributeRequest implements Serializable {
+
+ private String sid;
+
+ public FunctionAttributeRequest(String sid) {
+ this.sid = sid;
+ }
+
+ public String getSid() {
+ return sid;
+ }
+
+ public void setSid(String sid) {
+ this.sid = sid;
+ }
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/GatewaySearchBean.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/GatewaySearchBean.java
new file mode 100644
index 0000000..f3585fc
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/GatewaySearchBean.java
@@ -0,0 +1,102 @@
+package com.hdl.sdk.connect.bean;
+
+import java.io.Serializable;
+
+/**
+ * Created by Tong on 2021/9/29.
+ * 缃戝叧鎼滅储
+ */
+public class GatewaySearchBean implements Serializable {
+
+
+ private String device_model;
+ private String device_name;
+ private String device_mac;
+ private String gatewayId;
+ private String gatewayType;
+ private String gateway_type;
+ private String oid;
+ private String ip_address;
+ private String access_mode;
+ private String master;
+
+ public String getDevice_model() {
+ return device_model;
+ }
+
+ public void setDevice_model(String device_model) {
+ this.device_model = device_model;
+ }
+
+ public String getDevice_name() {
+ return device_name;
+ }
+
+ public void setDevice_name(String device_name) {
+ this.device_name = device_name;
+ }
+
+ public String getDevice_mac() {
+ return device_mac;
+ }
+
+ public void setDevice_mac(String device_mac) {
+ this.device_mac = device_mac;
+ }
+
+ public String getGatewayId() {
+ return gatewayId;
+ }
+
+ public void setGatewayId(String gatewayId) {
+ this.gatewayId = gatewayId;
+ }
+
+ public String getGatewayType() {
+ return gatewayType;
+ }
+
+ public void setGatewayType(String gatewayType) {
+ this.gatewayType = gatewayType;
+ }
+
+ public String getGateway_type() {
+ return gateway_type;
+ }
+
+ public void setGateway_type(String gateway_type) {
+ this.gateway_type = gateway_type;
+ }
+
+ public String getOid() {
+ return oid;
+ }
+
+ public void setOid(String oid) {
+ this.oid = oid;
+ }
+
+ public String getIp_address() {
+ return ip_address;
+ }
+
+ public void setIp_address(String ip_address) {
+ this.ip_address = ip_address;
+ }
+
+ public String getAccess_mode() {
+ return access_mode;
+ }
+
+ public void setAccess_mode(String access_mode) {
+ this.access_mode = access_mode;
+ }
+
+ public String getMaster() {
+ return master;
+ }
+
+ public void setMaster(String master) {
+ this.master = master;
+ }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/LinkRequest.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/LinkRequest.java
new file mode 100644
index 0000000..3634ce4
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/LinkRequest.java
@@ -0,0 +1,64 @@
+package com.hdl.sdk.connect.bean;
+
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Created by Tong on 2021/9/29.
+ */
+public class LinkRequest {
+ private String topic;
+ private String data;
+ private int length;
+
+ public LinkRequest() {
+ }
+
+ public LinkRequest(String topic, String data) {
+ this.topic = topic;
+ setData(data);
+ }
+
+ public String getTopic() {
+ return topic;
+ }
+
+ public void setTopic(String topic) {
+ this.topic = topic;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ if (!TextUtils.isEmpty(data)) {
+ setLength(data.length());
+ } else {
+ setLength(0);
+ }
+
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ private void setLength(int length) {
+ this.length = length;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "Topic:" +
+ getTopic() +
+ "\r\n" +
+ "Length:" +
+ getLength() +
+ "\r\n\r\n" +
+ getData();
+ }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/LinkResponse.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/LinkResponse.java
new file mode 100644
index 0000000..b35dcfc
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/LinkResponse.java
@@ -0,0 +1,55 @@
+package com.hdl.sdk.connect.bean;
+
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+
+import com.hdl.sdk.common.utils.gson.GsonConvert;
+
+import java.io.Serializable;
+
+/**
+ * Created by Tong on 2021/9/27.
+ */
+public class LinkResponse implements Serializable {
+
+ private String topic;
+ private String data;
+ private int length;
+
+ public String getTopic() {
+ return topic;
+ }
+
+ public void setTopic(String topic) {
+ this.topic = topic;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ if (!TextUtils.isEmpty(data)) {
+ setLength(data.length());
+ } else {
+ setLength(0);
+ }
+
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ private void setLength(int length) {
+ this.length = length;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return GsonConvert.getGson().toJson(this);
+ }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/PropertyReadRequest.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/PropertyReadRequest.java
new file mode 100644
index 0000000..43ddfdb
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/PropertyReadRequest.java
@@ -0,0 +1,17 @@
+package com.hdl.sdk.connect.bean;
+
+/**
+ * Created by Tong on 2021/10/8.
+ */
+public class PropertyReadRequest {
+
+ private String sid;
+
+ public String getSid() {
+ return sid;
+ }
+
+ public void setSid(String sid) {
+ this.sid = sid;
+ }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/PropertyUpRequest.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/PropertyUpRequest.java
new file mode 100644
index 0000000..61d660c
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/PropertyUpRequest.java
@@ -0,0 +1,50 @@
+package com.hdl.sdk.connect.bean;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Created by Tong on 2021/10/8.
+ */
+public class PropertyUpRequest implements Serializable {
+
+ private String sid;
+ private List<StatusBean> status;
+
+ public String getSid() {
+ return sid;
+ }
+
+ public void setSid(String sid) {
+ this.sid = sid;
+ }
+
+ public List<StatusBean> getStatus() {
+ return status;
+ }
+
+ public void setStatus(List<StatusBean> status) {
+ this.status = status;
+ }
+
+ public static class StatusBean implements Serializable{
+ private String key;
+ private String value;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+ }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageDecoder.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageDecoder.java
new file mode 100644
index 0000000..26679ab
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageDecoder.java
@@ -0,0 +1,81 @@
+package com.hdl.sdk.connect.protocol;
+
+
+import com.hdl.sdk.common.event.EventDispatcher;
+import com.hdl.sdk.common.utils.ByteUtils;
+import com.hdl.sdk.connect.bean.LinkResponse;
+import com.hdl.sdk.connect.utils.ProtocolParse;
+import com.hdl.sdk.socket.codec.ByteToMessageDecoder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Tong on 2021/9/22.
+ * link鍗忚绮樺寘鎷嗗寘
+ */
+public class LinkMessageDecoder extends ByteToMessageDecoder<LinkResponse> {
+
+ private final List<Byte> bytes;
+
+ private final byte[] head = "Topic:".getBytes();
+ private final byte[] body = "\r\n\r\n".getBytes();
+
+ public LinkMessageDecoder() {
+ this.bytes = new ArrayList<>();
+ }
+
+ @Override
+ protected LinkResponse decoder(Object msg) throws Exception {
+ LinkResponse response = new LinkResponse();
+ if (msg instanceof byte[]) {
+ //瑙f瀽娴�
+ byte[] data = (byte[]) msg;
+ bytes.addAll(ByteUtils.toByteList(data));
+
+ byte[] byteArray = ByteUtils.toByteArray(bytes);
+ int headIndex = ByteUtils.getByteIndexOf(byteArray, head);
+ if (headIndex > 0) {
+ //绉诲姩鍒癶ead 寮�濮嬩綅缃�
+ bytes.subList(0, headIndex).clear();
+ byteArray = ByteUtils.toByteArray(bytes);
+ }
+
+ int bodyIndex = ByteUtils.getByteIndexOf(byteArray, body);
+ if (bodyIndex < 0) {
+ //澶撮儴鏈幏鍙栧畬鎴�
+ return null;
+ }
+ int bodyStartIndex = bodyIndex + body.length;
+
+ //瑙f瀽澶撮儴
+ ProtocolParse parse = new ProtocolParse(byteArray);
+ response.setTopic(parse.getTopic());
+
+ int bodyLength = parse.getLength();
+ if (bodyLength > 0) {
+ if (byteArray.length >= bodyLength + bodyStartIndex) {
+ byte[] body = ByteUtils.getRangeBytes(bytes, bodyStartIndex, bodyStartIndex + bodyLength);
+ response.setData(new String(body, "utf-8"));
+
+ if (byteArray.length >= bodyLength + bodyStartIndex) {
+ //淇濆瓨浣欑暀
+ byte[] remaining = ByteUtils.getRangeBytes(bytes, bodyStartIndex + bodyLength, byteArray.length);
+ bytes.clear();
+ for (byte b : remaining) {
+ bytes.add(b);
+ }
+ }
+ //瑙f瀽瀹屾垚,topic鍙戦�佷竴娆�
+ EventDispatcher.getInstance().post(response.getTopic(), response);
+ return response;
+ }
+ } else if (bodyLength == 0) {
+ //body涓虹┖
+ return response;
+ }
+
+ }
+ return null;
+ }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageEncoder.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageEncoder.java
new file mode 100644
index 0000000..d24f715
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageEncoder.java
@@ -0,0 +1,16 @@
+package com.hdl.sdk.connect.protocol;
+
+
+import com.hdl.sdk.socket.codec.MessageToByteEncoder;
+
+/**
+ * Created by Tong on 2021/9/22.
+ * link鍗忚鍚堝寘
+ */
+public class LinkMessageEncoder extends MessageToByteEncoder {
+
+ @Override
+ protected byte[] encode(byte[] data) throws Exception {
+ return data;
+ }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/utils/ProtocolParse.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/utils/ProtocolParse.java
new file mode 100644
index 0000000..d29c09d
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/utils/ProtocolParse.java
@@ -0,0 +1,74 @@
+package com.hdl.sdk.connect.utils;
+
+import android.text.TextUtils;
+
+/**
+ * Created by Tong on 2021/9/22.
+ * 瑙f瀽Link鍗忚
+ */
+public class ProtocolParse {
+
+ private String topic;
+ private int length;
+ private int dataIndex;
+
+ public ProtocolParse(byte[] bytes) {
+ parse(bytes);
+ }
+
+ private void parse(byte[] bytes) {
+ try {
+ String[] split = new String(bytes, "utf-8").split("\r\n");
+ setTopic(parseTopic(split));
+ setLength(parseLength(split));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static String parseTopic(String[] bytes) {
+ try {
+ for (String s : bytes) {
+ if (s.startsWith("Topic:")) {
+ return s.replace("Topic:", "");
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private static int parseLength(String[] bytes) {
+ try {
+ for (String s : bytes) {
+ if (!TextUtils.isEmpty(s) && s.startsWith("Length:")) {
+ return Integer.parseInt(s.replace("Length:", ""));
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return -1;
+ }
+
+
+
+ public String getTopic() {
+ return topic;
+ }
+
+ public void setTopic(String topic) {
+ this.topic = topic;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+
+}
diff --git a/HDLSDK/hdl-connect/src/test/java/com/hdl/sdk/connect/ExampleUnitTest.java b/HDLSDK/hdl-connect/src/test/java/com/hdl/sdk/connect/ExampleUnitTest.java
new file mode 100644
index 0000000..652b170
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/test/java/com/hdl/sdk/connect/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.hdl.sdk.connect;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/HDLSDK/hdl-socket/.gitignore b/HDLSDK/hdl-socket/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/HDLSDK/hdl-socket/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/HDLSDK/hdl-socket/README.md b/HDLSDK/hdl-socket/README.md
new file mode 100644
index 0000000..40be08b
--- /dev/null
+++ b/HDLSDK/hdl-socket/README.md
@@ -0,0 +1,8 @@
+# hdl-socket搴�
+
+##璇存槑
+tcp+udp 閫氱敤灏佽,瀹炵幇鍩烘湰杩炴帴
+
+##鐢ㄦ硶
+1銆佸垱寤篢cp瀵硅薄
+2銆佸垱寤篣dp瀵硅薄
diff --git a/HDLSDK/hdl-socket/build.gradle b/HDLSDK/hdl-socket/build.gradle
new file mode 100644
index 0000000..ecffc90
--- /dev/null
+++ b/HDLSDK/hdl-socket/build.gradle
@@ -0,0 +1,33 @@
+plugins {
+ id 'com.android.library'
+}
+
+android {
+ compileSdkVersion rootProject.compileSdkVersion
+
+ defaultConfig {
+ minSdkVersion rootProject.minSdkVersion
+ targetSdkVersion rootProject.targetSdkVersion
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles "consumer-rules.pro"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ api project(path: ':hdl-common')
+
+}
\ No newline at end of file
diff --git a/HDLSDK/hdl-socket/consumer-rules.pro b/HDLSDK/hdl-socket/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/HDLSDK/hdl-socket/consumer-rules.pro
diff --git a/HDLSDK/hdl-socket/proguard-rules.pro b/HDLSDK/hdl-socket/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/HDLSDK/hdl-socket/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/HDLSDK/hdl-socket/src/androidTest/java/com/hdl/sdk/socket/ExampleInstrumentedTest.java b/HDLSDK/hdl-socket/src/androidTest/java/com/hdl/sdk/socket/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..903bb2e
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/androidTest/java/com/hdl/sdk/socket/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.hdl.sdk.socket;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.hdl.sdk.socket.test", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/HDLSDK/hdl-socket/src/main/AndroidManifest.xml b/HDLSDK/hdl-socket/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..92ea344
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.hdl.sdk.socket">
+
+</manifest>
\ No newline at end of file
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketBoot.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketBoot.java
new file mode 100644
index 0000000..a66c148
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketBoot.java
@@ -0,0 +1,327 @@
+package com.hdl.sdk.socket;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.collection.ArrayMap;
+
+import com.hdl.sdk.common.utils.ThreadToolUtils;
+import com.hdl.sdk.socket.annotation.ConnectStatus;
+import com.hdl.sdk.socket.client.IClient;
+import com.hdl.sdk.socket.listener.SendListener;
+
+import java.net.ConnectException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Created by Tong on 2021/9/26.
+ * Tcp/Udp 鍚姩鍣�
+ */
+public class SocketBoot {
+
+ private ExecutorService connectThread;
+ private ScheduledExecutorService heartbeatThread;
+ private ExecutorService sendThread;
+ private ExecutorService receiveThread;
+ private ScheduledExecutorService delayThread;
+
+ private final IClient client;
+
+ /**
+ * socket鏄惁鍦ㄨ繍琛�
+ */
+ private final AtomicBoolean isRun = new AtomicBoolean(false);
+
+ private final AtomicBoolean isOpenRetry = new AtomicBoolean(false);
+
+ private final AtomicInteger resendCount = new AtomicInteger(0);
+
+ private final BlockingQueue<SocketRequest> mMessageQueue = new LinkedBlockingDeque<>();
+
+ private final ArrayMap<String, SendListener> sendMap = new ArrayMap<>();
+
+ public SocketBoot(IClient client) {
+ this.client = client;
+ }
+
+ public ScheduledExecutorService getHeartBeat() {
+ if (heartbeatThread == null) {
+ heartbeatThread = ThreadToolUtils.getInstance().newScheduledThreadPool(1);
+ }
+ return heartbeatThread;
+ }
+
+ public void connect() {
+ resendCount.set(0);
+ resetConnect(true);
+ isOpenRetry.set(true);
+ }
+
+ public synchronized void resetConnect(boolean isFirst) {
+ final int maxRetry = client.getOptions().getMaxRetry();
+ if (maxRetry == 0 && resendCount.get() > 0 ||
+ (maxRetry > 0 && maxRetry + 1 < resendCount.get())) {
+ Log.d("====", "===閲嶈繛娆℃暟杈惧埌鏈�澶�==");
+ return;
+ }
+ if (!client.isConnect()) {
+ if (connectThread == null) {
+ connectThread = ThreadToolUtils.getInstance().newFixedThreadPool(1);
+ }
+ connectThread.execute(new Runnable() {
+ @Override
+ public void run() {
+ client.onConnectStatus(ConnectStatus.CONNECTING);
+ if (!isFirst) {
+ try {
+ resendCount.set(resendCount.get() + 1);
+ Thread.sleep(300L);
+ Log.d("====", "==閲嶈繛绗�" + resendCount + "娆�==");
+ } catch (Exception ignored) {
+ }
+ }
+ try {
+ client.connect();
+ isRun.set(true);
+ if (client.isConnect()) {
+ Log.d("====", "====杩炴帴鎴愬姛====");
+ startHeartbeat();
+
+ initSendThread();
+ initReceiveThread();
+
+ client.onConnectStatus(ConnectStatus.CONNECTED);
+ resendCount.set(0);
+ } else {
+ throw new ConnectException();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.d("====", "===杩炴帴澶辫触===" + e);
+ //鍐嶅垽鏂竴涓嬫湁娌℃湁杩炴帴
+ if (!client.isConnect()) {
+ isRun.set(false);
+ client.onConnectStatus(ConnectStatus.DISCONNECT);
+ stopHeartbeat();
+ disconnectError();
+ }
+ }
+ }
+ });
+ }
+ }
+
+ public void initSendThread() {
+ if (sendThread == null) {
+ sendThread = ThreadToolUtils.getInstance().newFixedThreadPool(1);
+ }
+ sendThread.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (isRun.get()) {
+ if (client.isConnect()) {
+ Log.d("=====", "==鍙戦�佹暟鎹�==");
+ try {
+ SocketRequest socketRequest = mMessageQueue.take();
+ final String action = socketRequest.getAction();
+ try {
+ client.sendMsg(socketRequest.getData());
+ if (!TextUtils.isEmpty(action)) {
+ SendListener sendListener = sendMap.get(action);
+ if (sendListener != null) {
+ sendListener.onSucceed();
+ }
+ }
+ } catch (Exception e) {
+ if (!TextUtils.isEmpty(action)) {
+ SendListener sendListener = sendMap.get(action);
+ if (sendListener != null) {
+ sendListener.onError();
+ }
+ }
+
+ stopHeartbeat();
+ if (sendThread != null) {
+ sendThread.shutdownNow();
+ }
+ if (isRun.get()) {
+ disconnectError();
+ }
+
+ }
+ } catch (InterruptedException ignored) {
+
+ }
+
+ }
+
+ }
+ Log.d("=====", "==鍙戦�佺嚎绋嬪叧闂�==");
+ }
+ });
+
+ }
+
+ public void initReceiveThread() {
+ if (receiveThread == null) {
+ receiveThread = ThreadToolUtils.getInstance().newFixedThreadPool(1);
+ }
+ receiveThread.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (isRun.get()) {
+ if (client.isConnect()) {
+ try {
+ //璇诲彇鏁版嵁
+ client.onHandleResponse();
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.d("====", "鏂紑杩炴帴" + e.getMessage());
+ disconnectError();
+ }
+ }
+ }
+ }
+ });
+
+ }
+
+
+ public void startHeartbeat() {
+ if (heartbeatThread != null) {
+ heartbeatThread.shutdownNow();
+ heartbeatThread = null;
+ }
+ if (client.getOptions() == null || client.getOptions().getHeartbeatTimeInterval() <= 0 || !client.getOptions().isEnabledHeartbeat()) {
+ return;
+ }
+ getHeartBeat().scheduleWithFixedDelay(new Runnable() {
+ @Override
+ public void run() {
+ if (isRun.get()) {
+ Log.d("====", "===鍙戦�佸績璺冲寘===");
+ if (client.getOptions() != null) {
+ final byte[] heartBeat = client.getOptions().getHeartbeatData();
+ if (heartBeat != null) {
+ sendMsg(heartBeat, false, null);
+ } else {
+ sendMsg(new byte[0], false, null);
+ }
+ }
+ }
+ }
+ }, client.getOptions().getHeartbeatTimeInterval(), client.getOptions().getHeartbeatTimeInterval(), TimeUnit.MILLISECONDS);
+ }
+
+ public void stopHeartbeat() {
+ if (heartbeatThread != null) {
+ heartbeatThread.shutdownNow();
+ heartbeatThread = null;
+ }
+ }
+
+ public void sendMsg(byte[] msg) {
+ sendMsg(msg, true, null);
+ }
+
+ public void sendMsg(byte[] msg, SendListener listener) {
+ sendMsg(msg, true, listener);
+ }
+
+ /**
+ * @param listener 涓�鑸儏鍐垫棤闇�鐩戝惉
+ */
+ private void sendMsg(byte[] msg, boolean isRefreshRetry, SendListener listener) {
+ if (isRefreshRetry) {
+ //閲嶇疆杩炴帴娆℃暟
+ resendCount.set(0);
+ }
+ try {
+ SocketRequest request = new SocketRequest(msg);
+ if (listener != null && !TextUtils.isEmpty(request.getAction())) {
+ sendMap.put(request.getAction(), listener);
+ }
+ mMessageQueue.put(request);
+ } catch (InterruptedException ignored) {
+
+ }
+ if (!client.isConnect()) {
+ resetConnect(false);
+ }
+
+ }
+
+ /**
+ * 鍙戠敓閿欒锛岄噸杩�
+ */
+ private void disconnectError() {
+ disconnect();
+ isRun.set(false);
+ if (isOpenRetry.get()) {
+ if (delayThread != null) {
+ delayThread.shutdownNow();
+ }
+ delayThread = ThreadToolUtils.getInstance().newScheduledThreadPool(1);
+ delayThread.schedule(new Runnable() {
+ @Override
+ public void run() {
+ if (!client.isConnect() && isOpenRetry.get()) {
+ resetConnect(false);
+ }
+
+ }
+ }, 3000, TimeUnit.MILLISECONDS);
+ }
+
+ }
+
+ private synchronized void disconnect() {
+ if (client.isConnect()) {
+ client.disconnect();
+ //鏂紑杩炴帴
+ client.onConnectStatus(ConnectStatus.DISCONNECT);
+ }
+ }
+
+ public synchronized void close() {
+ isOpenRetry.set(false);
+ isRun.set(false);
+ if (connectThread != null) {
+ connectThread.shutdownNow();
+ connectThread = null;
+ }
+ if (heartbeatThread != null) {
+ heartbeatThread.shutdownNow();
+ heartbeatThread = null;
+ }
+ if (sendThread != null) {
+ sendThread.shutdownNow();
+ sendThread = null;
+ }
+ if (receiveThread != null) {
+ receiveThread.shutdownNow();
+ receiveThread = null;
+ }
+ sendMap.clear();
+ client.disconnect();
+ mMessageQueue.clear();
+
+ }
+
+ public synchronized void release() {
+ close();
+ if (client != null && client.getOptions() != null) {
+ client.getOptions().clearConnectStatusListener();
+ }
+ }
+
+ public boolean isConnect() {
+ return client.isConnect();
+ }
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketOptions.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketOptions.java
new file mode 100644
index 0000000..83a3bc5
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketOptions.java
@@ -0,0 +1,130 @@
+package com.hdl.sdk.socket;
+
+
+import com.hdl.sdk.socket.codec.IHandleMessage;
+import com.hdl.sdk.socket.listener.ConnectStatusListener;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Tong on 2021/9/22.
+ * socket閰嶇疆
+ */
+public class SocketOptions {
+
+ //璁剧疆璇诲彇缂撳瓨
+ private int readMaxBufferSize = 512;
+
+ //鍙戦�佸績璺冲寘
+ private boolean isEnabledHeartbeat = true;
+
+ //蹇冭烦鍖�
+ private byte[] heartbeatData;
+
+ //蹇冭烦鍖呮椂闂撮棿闅�
+ private long heartbeatTimeInterval = 300L;
+
+ //澶勭悊鏁版嵁
+ private IHandleMessage handleMessage;
+
+ //鐩戝惉鐘舵��
+ private List<ConnectStatusListener> mConnectStatusListener;
+
+ //鏈�澶ч噸杩炴鏁�,灏忎簬0鏃犻檺娆℃暟,绛変簬0涓嶉噸杩�
+ private int maxRetry = -1;
+
+ private boolean isTcpNoDelay;
+ private boolean isReuseAddress;
+ //淇濇寔娲诲姩鐘舵��
+ private boolean isKeepAlive;
+ private boolean isOOBInline;
+ private int sendBufferSize;
+ private int receiveBufferSize;
+ private int soTimeout;
+ private boolean soLinger;
+
+
+ public IHandleMessage getHandleMessage() {
+ return handleMessage;
+ }
+
+ public void setHandleMessage(IHandleMessage handleMessage) {
+ this.handleMessage = handleMessage;
+ }
+
+ public boolean isEnabledHeartbeat() {
+ return isEnabledHeartbeat;
+ }
+
+ public void setEnabledHeartbeat(boolean enabledHeartbeat) {
+ isEnabledHeartbeat = enabledHeartbeat;
+ }
+
+ public byte[] getHeartbeatData() {
+ return heartbeatData;
+ }
+
+ public void setHeartbeatData(byte[] heartbeatData) {
+ this.heartbeatData = heartbeatData;
+ }
+
+ public void setHeartbeatData(String heartbeatData) {
+ try {
+ this.heartbeatData = heartbeatData.getBytes("utf-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public long getHeartbeatTimeInterval() {
+ return heartbeatTimeInterval;
+ }
+
+ public void setHeartbeatTimeInterval(long heartbeatTimeInterval) {
+ this.heartbeatTimeInterval = heartbeatTimeInterval;
+ }
+
+ public void clearConnectStatusListener() {
+ if (mConnectStatusListener != null && !mConnectStatusListener.isEmpty()) {
+ mConnectStatusListener.clear();
+ }
+ }
+
+ public void addConnectStatusListener(ConnectStatusListener connectStatusListener) {
+ if (mConnectStatusListener == null) {
+ mConnectStatusListener = new ArrayList<>();
+ }
+ mConnectStatusListener.add(connectStatusListener);
+ }
+
+ public void removeConnectStatusListener(ConnectStatusListener connectStatusListener) {
+ if (mConnectStatusListener != null) {
+ mConnectStatusListener.remove(connectStatusListener);
+ }
+ }
+
+
+ public List<ConnectStatusListener> getConnectStatusListener() {
+ return mConnectStatusListener;
+ }
+
+
+ public int getMaxRetry() {
+ return maxRetry;
+ }
+
+ public void setMaxRetry(int maxRetry) {
+ this.maxRetry = maxRetry;
+ }
+
+ public int getReadMaxBufferSize() {
+ return readMaxBufferSize;
+ }
+
+ public void setReadMaxBufferSize(int readMaxBufferSize) {
+ this.readMaxBufferSize = readMaxBufferSize;
+ }
+
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketRequest.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketRequest.java
new file mode 100644
index 0000000..924719e
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/SocketRequest.java
@@ -0,0 +1,34 @@
+package com.hdl.sdk.socket;
+
+import java.util.UUID;
+
+/**
+ * Created by Tong on 2021/9/22.
+ */
+public class SocketRequest {
+
+ private String action;
+
+ private byte[] data;
+
+ public SocketRequest(byte[] data) {
+ this.data = data;
+ action = UUID.randomUUID().toString();
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public void setData(byte[] data) {
+ this.data = data;
+ }
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/annotation/ConnectStatus.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/annotation/ConnectStatus.java
new file mode 100644
index 0000000..2ec7809
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/annotation/ConnectStatus.java
@@ -0,0 +1,31 @@
+package com.hdl.sdk.socket.annotation;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Created by Tong on 2021/9/22.
+ */
+@Target({ElementType.TYPE_PARAMETER, ElementType.PARAMETER})
+@IntDef({ConnectStatus.CONNECTING,
+ ConnectStatus.CONNECTED,
+ ConnectStatus.DISCONNECT})
+public @interface ConnectStatus {
+
+ /**
+ * 杩炴帴涓�
+ */
+ int CONNECTING = 0;
+
+ /**
+ * 杩炴帴鎴愬姛
+ */
+ int CONNECTED = 1;
+
+ /**
+ * 杩炴帴鍏抽棴
+ */
+ int DISCONNECT = 2;
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/ClientPool.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/ClientPool.java
new file mode 100644
index 0000000..9faeeb1
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/ClientPool.java
@@ -0,0 +1,57 @@
+package com.hdl.sdk.socket.client;
+
+import android.net.Uri;
+
+
+import androidx.collection.ArrayMap;
+
+import java.net.DatagramSocket;
+import java.net.Socket;
+import java.net.SocketException;
+
+/**
+ * Created by Tong on 2021/10/8.
+ */
+public class ClientPool {
+
+ private final ArrayMap<String, Socket> mTcpPool = new ArrayMap<>();
+ private final ArrayMap<String, DatagramSocket> mUdpPool = new ArrayMap<>();
+
+ private ClientPool() {
+ }
+
+ private static class SingletonInstance {
+ private static final ClientPool INSTANCE = new ClientPool();
+ }
+
+ public static ClientPool getInstance() {
+ return SingletonInstance.INSTANCE;
+ }
+
+ public Socket getTcpSocket(String ip, int port) {
+ final StringBuilder key = new StringBuilder();
+ key.append(ip).append(":").append(port);
+ if (mTcpPool.containsKey(key)) {
+ Socket socket = mTcpPool.get(key);
+ if (socket != null && !socket.isClosed()) {
+ return socket;
+ }
+
+ }
+ return new Socket();
+ }
+
+ public DatagramSocket getUdpSocket(String ip, int port) throws SocketException {
+ final StringBuilder key = new StringBuilder();
+ key.append(ip).append(":").append(port);
+ if (mUdpPool.containsKey(key)) {
+ DatagramSocket socket = mUdpPool.get(key);
+ if (socket != null && !socket.isClosed()) {
+ return socket;
+ }
+
+ }
+ return new DatagramSocket(port);
+ }
+
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/IClient.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/IClient.java
new file mode 100644
index 0000000..e768514
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/IClient.java
@@ -0,0 +1,37 @@
+package com.hdl.sdk.socket.client;
+
+
+import com.hdl.sdk.socket.SocketOptions;
+
+/**
+ * Created by Tong on 2021/9/22.
+ */
+public interface IClient {
+
+ void connect() throws Exception;
+
+ void disconnect();
+
+ /**
+ * 鏄惁宸茬粡杩炴帴
+ */
+ boolean isConnect();
+
+
+ SocketOptions getOptions();
+
+ /**
+ * 鐩戝惉鏁版嵁
+ */
+ void onHandleResponse() throws Exception;
+
+ /**
+ * 鍙戦�佹秷鎭�
+ */
+ void sendMsg(byte[] msg) throws Exception;
+
+ /**
+ * 杩炴帴鐘舵��
+ */
+ void onConnectStatus(int status);
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/TcpClient.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/TcpClient.java
new file mode 100644
index 0000000..51a03d8
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/TcpClient.java
@@ -0,0 +1,176 @@
+package com.hdl.sdk.socket.client;
+
+
+
+import com.hdl.sdk.common.utils.ThreadToolUtils;
+import com.hdl.sdk.socket.SocketBoot;
+import com.hdl.sdk.socket.SocketOptions;
+import com.hdl.sdk.socket.annotation.ConnectStatus;
+import com.hdl.sdk.socket.codec.IHandleMessage;
+import com.hdl.sdk.socket.listener.ConnectStatusListener;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.List;
+
+
+/**
+ * Created by Tong on 2021/9/15.
+ */
+public final class TcpClient implements IClient {
+
+ private SocketOptions socketOptions;
+
+ private final String ip;
+ private final int port;
+
+ private Socket mSocket;
+
+ private byte[] readBuffer;
+
+ private TcpClient(String ip, int port, SocketOptions socketOptions) {
+ this.socketOptions = socketOptions;
+ this.ip = ip;
+ this.port = port;
+ }
+
+ public static SocketBoot init(String ip, int port, SocketOptions options) {
+ return new SocketBoot(new TcpClient(ip, port, options));
+ }
+
+
+ @Override
+ public void connect() throws Exception {
+ mSocket = getSocket();
+ SocketOptions options = getOptions();
+ mSocket.connect(new InetSocketAddress(ip, port));
+ mSocket.setTcpNoDelay(true);
+ mSocket.setReuseAddress(true);
+ mSocket.setKeepAlive(true);
+ readBuffer = new byte[options.getReadMaxBufferSize()];
+ }
+
+
+ @Override
+ public void disconnect() {
+ if (mSocket != null) {
+ try {
+ mSocket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public boolean isConnect() {
+ if (mSocket == null) {
+ return false;
+ }
+
+ return mSocket.isConnected() && !mSocket.isClosed();
+ }
+
+
+ @Override
+ public synchronized SocketOptions getOptions() {
+ if (socketOptions == null) {
+ socketOptions = new SocketOptions();
+ }
+ return socketOptions;
+ }
+
+ @Override
+ public void onHandleResponse() throws Exception {
+ final InputStream stream = getInputStream();
+
+ if (stream != null && getOptions() != null) {
+ readBuffer = new byte[1024];
+ while ((getInputStream().read(readBuffer)) != -1) {
+ IHandleMessage handleMessage = getOptions().getHandleMessage();
+ if (handleMessage != null) {
+ handleMessage.read(readBuffer);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void sendMsg(byte[] msg) throws Exception {
+ final OutputStream outputStream = getOutStream();
+ if (outputStream != null && getOptions() != null) {
+ try {
+ IHandleMessage handleMessage = getOptions().getHandleMessage();
+ handleMessage.write(handleMessage.write(msg));
+ getOutStream().write(msg);
+
+ } finally {
+ outputStream.flush();
+ }
+ }
+ }
+
+
+ /**
+ * 澶勭悊杩炴帴鐘舵��
+ */
+ public void onConnectStatus(int status) {
+ ThreadToolUtils.getInstance().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final List<ConnectStatusListener> list = getOptions().getConnectStatusListener();
+ if (list != null && !list.isEmpty()) {
+ for (ConnectStatusListener listener : list) {
+ switch (status) {
+ case ConnectStatus
+ .CONNECTING:
+ listener.onConnecting();
+ break;
+ case ConnectStatus
+ .CONNECTED:
+ listener.onConnected();
+ break;
+ case ConnectStatus
+ .DISCONNECT:
+ listener.onConnectFailed();
+ break;
+ }
+ }
+ }
+ }
+ });
+ }
+
+
+ private synchronized Socket getSocket() {
+ return new Socket();
+ }
+
+ private InputStream getInputStream() {
+ if (mSocket != null && mSocket.isConnected() && !mSocket.isClosed()) {
+ try {
+ return mSocket.getInputStream();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+
+ private OutputStream getOutStream() {
+ if (mSocket != null && mSocket.isConnected() && !mSocket.isClosed()) {
+ try {
+ return mSocket.getOutputStream();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/UdpClient.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/UdpClient.java
new file mode 100644
index 0000000..fc81bb6
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/UdpClient.java
@@ -0,0 +1,206 @@
+package com.hdl.sdk.socket.client;
+
+
+import android.util.Log;
+
+import com.hdl.sdk.common.HDLSdk;
+import com.hdl.sdk.common.utils.IpUtils;
+import com.hdl.sdk.common.utils.ThreadToolUtils;
+import com.hdl.sdk.socket.SocketBoot;
+import com.hdl.sdk.socket.SocketOptions;
+import com.hdl.sdk.socket.annotation.ConnectStatus;
+import com.hdl.sdk.socket.codec.IHandleMessage;
+import com.hdl.sdk.socket.listener.ConnectStatusListener;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+
+/**
+ * Created by Tong on 2021/9/15.
+ * 缁勬挱闇�瑕乤ndroid.permission.CHANGE_WIFI_MULTICAST_STATE鏉冮檺
+ * MulticastSocket
+ */
+public class UdpClient implements IClient {
+
+ private static DatagramSocket mSocket;
+
+ private DatagramPacket receivePacket;
+
+ private final int BUFFER = 4 * 1024;
+
+ private final byte[] receiveByte;
+
+ private final String ip;
+
+ private final int port;
+
+ private int monitorPort;
+ private int sendPort;
+
+ private SocketOptions socketOptions;
+
+ private final AtomicBoolean isConnect = new AtomicBoolean(false);
+
+ /**
+ * @param sendPort -1 琛ㄧず闅忔満绔彛
+ */
+ private UdpClient(String ip, int port, int monitorPort, int sendPort, SocketOptions socketOptions) {
+ this.socketOptions = socketOptions;
+ this.ip = ip;
+ this.port = port;
+ this.sendPort = sendPort;
+ this.monitorPort = monitorPort;
+ this.receiveByte = new byte[BUFFER];
+ }
+
+ public UdpClient(String ip, int port) {
+ this.ip = ip;
+ this.port = port;
+ this.receiveByte = new byte[BUFFER];
+ }
+
+ public static SocketBoot init(String ip, int port, int monitorPort, int sendPort, SocketOptions options) {
+ return new SocketBoot(new UdpClient(ip, port, monitorPort, sendPort, options));
+ }
+
+ public static SocketBoot init(String ip, int port, int monitorPort, SocketOptions options) {
+ return init(ip, port, monitorPort, -1, options);
+ }
+
+ public static SocketBoot init(String ip, int port, SocketOptions options) {
+ return init(ip, port, port, -1, options);
+ }
+
+ @Override
+ public void connect() throws Exception {
+
+ try {
+ mSocket = ClientPool.getInstance().getUdpSocket(ip, monitorPort);
+ mSocket.setBroadcast(true);
+ mSocket.setReuseAddress(true);
+
+ isConnect.set(true);
+ if (receivePacket == null) {
+ receivePacket = new DatagramPacket(receiveByte, BUFFER);
+ }
+ } catch (Exception e) {
+ isConnect.set(false);
+ throw e;
+ }
+
+
+ }
+
+ @Override
+ public void disconnect() {
+ if (mSocket != null) {
+ mSocket.close();
+ }
+ isConnect.set(false);
+ }
+
+ @Override
+ public boolean isConnect() {
+ return isConnect.get();
+ }
+
+ @Override
+ public synchronized SocketOptions getOptions() {
+ if (socketOptions == null) {
+ socketOptions = new SocketOptions();
+ }
+ return socketOptions;
+ }
+
+ @Override
+ public void onHandleResponse() throws Exception {
+ if (receivePacket == null || mSocket == null) {
+ return;
+ }
+ try {
+ mSocket.receive(receivePacket);
+ } catch (IOException e) {
+ e.printStackTrace();
+ isConnect.set(false);
+ }
+ if (receivePacket.getLength() == 0) {
+ return;
+ }
+ //鎺掗櫎鑷繁鍙戝嚭鍘荤殑
+ try {
+ if (receivePacket.getAddress().getHostAddress()
+ .equals(IpUtils.getIP(HDLSdk.getInstance().getContext()))) {
+ return;
+ }
+ } catch (Exception ignored) {
+
+ }
+
+ IHandleMessage handleMessage = getOptions().getHandleMessage();
+ if (handleMessage != null) {
+ handleMessage.read(receivePacket.getData());
+ }
+ final String receive = new String(receivePacket.getData(), 0, receivePacket.getLength());
+
+ Log.d("---->", receive + " from " + receivePacket.getAddress().getHostAddress() + ":" + receivePacket.getPort());
+
+ //閲嶇疆闀垮害
+ if (receivePacket != null) {
+ receivePacket.setLength(BUFFER);
+ }
+ }
+
+ @Override
+ public void sendMsg(byte[] msg) throws Exception {
+ if (msg == null) {
+ msg = new byte[1];
+ }
+ InetAddress serverAddress = InetAddress.getByName(ip);
+ final DatagramPacket sendPacket = new DatagramPacket(msg, msg.length, serverAddress, port);
+ if (sendPort < 0) {
+ final DatagramSocket sendSocket = new DatagramSocket();
+ sendSocket.send(sendPacket);
+ sendSocket.close();
+ } else if (sendPort == monitorPort) {
+ mSocket.send(sendPacket);
+ } else {
+ final DatagramSocket sendSocket = new DatagramSocket(sendPort);
+ sendSocket.send(sendPacket);
+ sendSocket.close();
+ }
+
+ }
+
+ @Override
+ public void onConnectStatus(int status) {
+ ThreadToolUtils.getInstance().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final List<ConnectStatusListener> list = getOptions().getConnectStatusListener();
+ if (list != null && !list.isEmpty()) {
+ for (ConnectStatusListener listener : list) {
+ switch (status) {
+ case ConnectStatus
+ .CONNECTING:
+ listener.onConnecting();
+ break;
+ case ConnectStatus
+ .CONNECTED:
+ listener.onConnected();
+ break;
+ case ConnectStatus
+ .DISCONNECT:
+ listener.onConnectFailed();
+ break;
+ }
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/ByteToMessageDecoder.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/ByteToMessageDecoder.java
new file mode 100644
index 0000000..ec8da44
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/ByteToMessageDecoder.java
@@ -0,0 +1,20 @@
+package com.hdl.sdk.socket.codec;
+
+/**
+ * Created by Tong on 2021/9/22.
+ */
+public abstract class ByteToMessageDecoder<T> implements IHandleFlow<T> {
+
+ protected abstract T decoder(Object msg)
+ throws Exception;
+
+ @Override
+ public final T read(Object data) throws Exception {
+ return decoder(data);
+ }
+
+ @Override
+ public final byte[] write(byte[] data) {
+ return data;
+ }
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IHandleFlow.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IHandleFlow.java
new file mode 100644
index 0000000..ef62efe
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IHandleFlow.java
@@ -0,0 +1,12 @@
+package com.hdl.sdk.socket.codec;
+
+/**
+ * Created by Tong on 2021/9/23.
+ */
+public interface IHandleFlow<T> {
+
+ T read(Object data) throws Exception;
+
+ byte[] write(byte[] data) throws Exception;
+
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IHandleMessage.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IHandleMessage.java
new file mode 100644
index 0000000..3234d83
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IHandleMessage.java
@@ -0,0 +1,10 @@
+package com.hdl.sdk.socket.codec;
+
+/**
+ * Created by Tong on 2021/9/27.
+ */
+public interface IHandleMessage {
+ void read(byte[] data) throws Exception;
+
+ byte[] write(byte[] data) throws Exception;
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IMessagePipeLine.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IMessagePipeLine.java
new file mode 100644
index 0000000..5acb78a
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/IMessagePipeLine.java
@@ -0,0 +1,11 @@
+package com.hdl.sdk.socket.codec;
+
+/**
+ * Created by Tong on 2021/9/23.
+ */
+public interface IMessagePipeLine {
+
+ void add(IHandleFlow flow);
+
+ void clear();
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/MessagePipeLine.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/MessagePipeLine.java
new file mode 100644
index 0000000..b5e8195
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/MessagePipeLine.java
@@ -0,0 +1,51 @@
+package com.hdl.sdk.socket.codec;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Created by Tong on 2021/9/23.
+ */
+public class MessagePipeLine implements IMessagePipeLine, IHandleMessage {
+
+ public final static List<IHandleFlow> queue = new ArrayList<>();
+
+ @Override
+ public void add(IHandleFlow flow) {
+ queue.add(flow);
+ }
+
+ @Override
+ public synchronized void clear() {
+ queue.clear();
+ }
+
+ @Override
+ public void read(byte[] data) throws Exception {
+ Object out = data;
+ for (int i = 0; i < queue.size(); i++) {
+ IHandleFlow flow = queue.get(i);
+ Object read = flow.read(out);
+ try {
+ out = Objects.requireNonNull(read);
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ @Override
+ public byte[] write(byte[] data) throws Exception {
+ byte[] out = data;
+ for (int i = 0; i < queue.size(); i++) {
+ IHandleFlow flow = queue.get(i);
+ byte[] write = flow.write(out);
+ try {
+ out = Objects.requireNonNull(write);
+ } catch (Exception ignored) {
+
+ }
+ }
+ return new byte[0];
+ }
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/MessageToByteEncoder.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/MessageToByteEncoder.java
new file mode 100644
index 0000000..13a8201
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/codec/MessageToByteEncoder.java
@@ -0,0 +1,24 @@
+package com.hdl.sdk.socket.codec;
+
+
+/**
+ * Created by Tong on 2021/9/22.
+ */
+public abstract class MessageToByteEncoder implements IHandleFlow {
+
+
+ protected abstract byte[] encode(byte[] data)
+ throws Exception;
+
+ @Override
+ public final Object read(Object data) {
+ return data;
+ }
+
+ @Override
+ public byte[] write(byte[] data) throws Exception {
+ return encode(data);
+ }
+
+
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/listener/ConnectStatusListener.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/listener/ConnectStatusListener.java
new file mode 100644
index 0000000..17ac30f
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/listener/ConnectStatusListener.java
@@ -0,0 +1,27 @@
+package com.hdl.sdk.socket.listener;
+
+/**
+ * Created by Tong on 2021/9/22.
+ * 杩炴帴鐘舵��
+ */
+public interface ConnectStatusListener {
+
+ /**
+ * 杩炴帴涓�
+ */
+ default void onConnecting() {
+ }
+
+ /**
+ * 杩炴帴鎴愬姛
+ */
+ default void onConnected() {
+ }
+
+ /**
+ * 杩炴帴澶辫触
+ */
+ default void onConnectFailed() {
+ }
+
+}
diff --git a/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/listener/SendListener.java b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/listener/SendListener.java
new file mode 100644
index 0000000..9ecb288
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/listener/SendListener.java
@@ -0,0 +1,11 @@
+package com.hdl.sdk.socket.listener;
+
+/**
+ * Created by Tong on 2021/9/22.
+ */
+public interface SendListener {
+
+ void onSucceed();
+
+ void onError();
+}
diff --git a/HDLSDK/hdl-socket/src/test/java/com/hdl/sdk/socket/ExampleUnitTest.java b/HDLSDK/hdl-socket/src/test/java/com/hdl/sdk/socket/ExampleUnitTest.java
new file mode 100644
index 0000000..a59034b
--- /dev/null
+++ b/HDLSDK/hdl-socket/src/test/java/com/hdl/sdk/socket/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.hdl.sdk.socket;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/HDLSDK/settings.gradle b/HDLSDK/settings.gradle
new file mode 100644
index 0000000..5a72944
--- /dev/null
+++ b/HDLSDK/settings.gradle
@@ -0,0 +1,6 @@
+
+include ':app'
+include ':hdl-socket'
+include ':hdl-connect'
+include ':hdl-common'
+
--
Gitblit v1.8.0