| | |
| | | <set>
|
| | | <option value="$PROJECT_DIR$" />
|
| | | <option value="$PROJECT_DIR$/com.hdl.sdk" />
|
| | | <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" />
|
| | |
| | | public void onSuccess(String msg) { |
| | | tv.setText("认证成功"); |
| | | responseTv.setText(msg.toString()); |
| | | Log.i("TAG", "onSuccess: 认证成功"); |
| | | } |
| | | }); |
| | | } |
| | |
| | | // embed(name: 'hdl-connect-release',ext: 'aar') |
| | | // embed(name: 'hdl-socket-release',ext: 'aar') |
| | | |
| | | embed project(path: ':hdl-common', configuration:'default') |
| | | // embed project(path: ':hdl-common', configuration:'default') |
| | | embed project(path: ':hdl-connect', configuration:'default') |
| | | embed project(path: ':hdl-socket', configuration:'default') |
| | | // embed project(path: ':hdl-socket', configuration:'default') |
| | | } |
| | | |
| | | //打包的 |
| | |
| | | minSdkVersion rootProject.minSdkVersion |
| | | targetSdkVersion rootProject.targetSdkVersion |
| | | versionCode 2 |
| | | versionName "1.0.15" |
| | | versionName "1.0.21" |
| | | |
| | | consumerProguardFiles "consumer-rules.pro" |
| | | } |
| | |
| | | } |
| | | |
| | | dependencies { |
| | | api project(path: ':hdl-socket') |
| | | // api project(path: ':hdl-socket') |
| | | api 'com.google.code.gson:gson:2.8.8' |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.common; |
| | | |
| | | import android.content.Context; |
| | | import android.util.Log; |
| | | |
| | | import com.hdl.sdk.common.config.TopicConstant; |
| | | import com.hdl.sdk.common.exception.HDLLinkException; |
| | | import com.hdl.sdk.common.utils.IdUtils; |
| | | import com.hdl.sdk.common.utils.LogUtils; |
| | | import com.hdl.sdk.common.utils.gson.GsonConvert; |
| | | import com.hdl.sdk.connect.HDLLink; |
| | | import com.hdl.sdk.connect.bean.LinkResponse; |
| | | import com.hdl.sdk.connect.bean.request.BroadcastRequest; |
| | | import com.hdl.sdk.connect.callback.HDLLinkResponseCallBack; |
| | | import com.hdl.sdk.connect.config.HDLLinkConfig; |
| | | import com.hdl.sdk.connect.socket.HDLAuthSocket; |
| | | import com.hdl.sdk.connect.socket.HDLSocket; |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/28. |
| | | */ |
| | | public class HDLSdk { |
| | | |
| | | private Context context; |
| | | |
| | | /** |
| | | * 获取当前版本 |
| | | * |
| | | * @return |
| | | */ |
| | | public String getVersion() { |
| | | return version; |
| | | } |
| | | |
| | | private String version = "1.0.22"; |
| | | |
| | | 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(); |
| | | HDLSocket.getInstance().broadcastRequest(); |
| | | LogUtils.i("HDLSdk Version:" + version); |
| | | } |
| | | |
| | | |
| | | public Context getContext() { |
| | | return context; |
| | | } |
| | | |
| | | /** |
| | | * 设置打印是否开启 |
| | | * |
| | | * @param enable |
| | | */ |
| | | public void setLogEnabled(boolean enable) { |
| | | LogUtils.setEnabled(enable); |
| | | } |
| | | } |
New file |
| | |
| | | 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(); |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.common.config; |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/22. |
| | | */ |
| | | public class TopicConstant { |
| | | |
| | | //网关广播入网指令 |
| | | public static final String GATEWAY_AUTH_BROADCAST = "/user/all/custom/device/network_access/broadcast"; |
| | | |
| | | //设备入网和认证 |
| | | public static final String DEIVCE_AUTH_REQUEST = "/user/all/custom/device/network_access/request"; |
| | | |
| | | //设备入网和认证响应 |
| | | public static final String DEIVCE_AUTH_REQUEST_REPLY = "/user/all/custom/device/network_access/request_reply"; |
| | | |
| | | //搜索网关 |
| | | 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"; |
| | | |
| | | //8.1获取场景列表 |
| | | public static final String SCENE_LIST_GET = "/user/%s/custom/scene/list/get"; |
| | | |
| | | //8.2获取场景 |
| | | public static final String SCENE_GET = "/user/%s/custom/scene/get"; |
| | | |
| | | //8.3执行场景 |
| | | public static final String SCENE_CONTROL = "/user/%s/custom/scene/execute"; |
| | | |
| | | //8.4场景增加 |
| | | public static final String SCENE_ADD = "/user/%s/custom/scene/add"; |
| | | |
| | | //8.5场景编辑 |
| | | public static final String SCENE_EDIT = "/user/%s/custom/scene/edit"; |
| | | |
| | | //8.6场景删除 |
| | | public static final String SCENE_DELETE = "/user/%s/custom/scene/delete"; |
| | | |
| | | //link tcp 登录 |
| | | public static final String GATEWAY_LOGIN = "/user/%s/custom/gateway/login"; |
| | | |
| | | /** |
| | | * 设备连接TCP之前广播 |
| | | */ |
| | | public static final String BROADCAST="/user/all/custom/gateway/broadcast"; |
| | | |
| | | /** |
| | | * 主网关回复 |
| | | */ |
| | | public static final String BROADCAST_REPLY="/user/all/custom/gateway/broadcast_reply"; |
| | | |
| | | /** |
| | | * 心跳检测 |
| | | */ |
| | | public static final String HEARTBEAT="/user/%s/custom/gateway/heartbeat"; |
| | | /** |
| | | * 心跳检测回复 |
| | | */ |
| | | public static final String HEARTBEAT_REPLY="/user/%s/custom/gateway/heartbeat_reply"; |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.common.event; |
| | | |
| | | |
| | | import android.util.ArrayMap; |
| | | |
| | | import com.hdl.sdk.common.utils.LogUtils; |
| | | import com.hdl.sdk.common.utils.ThreadToolUtils; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.ExecutorService; |
| | | |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/22. |
| | | * 事件分发 |
| | | */ |
| | | public class EventDispatcher { |
| | | |
| | | private static final List<EventListener> ALL_TOPICS_EVENT = new ArrayList<>();//所有主题消息 |
| | | |
| | | private static final ConcurrentHashMap<Object, List<EventListener>> EVENT = new ConcurrentHashMap<>(); |
| | | |
| | | private static final ConcurrentHashMap<EventListener, Integer> TYPE = new ConcurrentHashMap<>(); |
| | | |
| | | private static final int MAIN_TYPE = 0; |
| | | private static final int IO_TYPE = 1; |
| | | |
| | | private static final ExecutorService ioThread = ThreadToolUtils.getInstance().newFixedThreadPool(3); |
| | | |
| | | |
| | | private EventDispatcher() { |
| | | } |
| | | |
| | | // private static class SingletonInstance { |
| | | private static final EventDispatcher instance = new EventDispatcher(); |
| | | // } |
| | | |
| | | public static EventDispatcher getInstance() { |
| | | return instance; |
| | | } |
| | | |
| | | public void register(Object tag, EventListener listener) { |
| | | synchronized (this) { |
| | | try { |
| | | LogUtils.i("注册主题:" + tag); |
| | | if (tag == null) return; |
| | | if (!EVENT.containsKey(tag)) { |
| | | EVENT.put(tag, new ArrayList<>()); |
| | | } |
| | | if (listener == null) { |
| | | LogUtils.i("监听事件为空"); |
| | | return; |
| | | } |
| | | Objects.requireNonNull(EVENT.get(tag)).add(listener); |
| | | TYPE.put(listener, MAIN_TYPE); |
| | | } catch (Exception e) { |
| | | LogUtils.e("register:" + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public void registerIo(Object tag, EventListener listener) { |
| | | synchronized (this) { |
| | | LogUtils.i("注册主题:" + tag); |
| | | if (tag == null) return; |
| | | if (!EVENT.containsKey(tag)) { |
| | | EVENT.put(tag, new ArrayList<>()); |
| | | } |
| | | try { |
| | | if (listener == null) { |
| | | LogUtils.i("监听事件为空"); |
| | | return; |
| | | } |
| | | Objects.requireNonNull(EVENT.get(tag)).add(listener); |
| | | TYPE.put(listener, IO_TYPE); |
| | | } catch (Exception e) { |
| | | LogUtils.e("registerIo:" + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public void remove(Object tag) { |
| | | synchronized (this) { |
| | | if (tag == null) { |
| | | return; |
| | | } |
| | | try { |
| | | if (EVENT.containsKey(tag)) { |
| | | LogUtils.i("移除key:" + tag); |
| | | List<EventListener> list = EVENT.get(tag); |
| | | for (EventListener eventListener : list) { |
| | | if (eventListener == null) { |
| | | continue; |
| | | } |
| | | TYPE.remove(eventListener); |
| | | } |
| | | EVENT.remove(tag); |
| | | } |
| | | } catch (Exception ignored) { |
| | | LogUtils.e("移除event异常1:" + ignored.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public void remove(Object tag, EventListener listener) { |
| | | synchronized (this) { |
| | | try { |
| | | if (tag == null || listener == null) { |
| | | return; |
| | | } |
| | | if (EVENT.containsKey(tag)) { |
| | | LogUtils.i("移除key:" + tag); |
| | | List<EventListener> ev = EVENT.get(tag); |
| | | if (ev != null && !ev.isEmpty()) { |
| | | TYPE.remove(listener); |
| | | ev.remove(listener); |
| | | } |
| | | } |
| | | } catch (Exception ignored) { |
| | | LogUtils.e("移除event异常1:" + ignored.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public synchronized void post(Object tag, Object o) { |
| | | if (tag == null) { |
| | | LogUtils.i("post tag为空"); |
| | | return; |
| | | } |
| | | try { |
| | | if (EVENT.containsKey(tag)) { |
| | | LogUtils.i("post:" + tag); |
| | | List<EventListener> list = EVENT.get(tag); |
| | | if (list != null && !list.isEmpty()) { |
| | | for (EventListener listener : list) { |
| | | if (listener == null) { |
| | | continue; |
| | | } |
| | | ThreadToolUtils.getInstance().runOnUiThread(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | try { |
| | | if (listener != null) { |
| | | listener.onMessage(o); |
| | | } |
| | | } catch (Exception e) { |
| | | LogUtils.e("post异常1:" + e.getMessage()); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | //所有主题的Listener通知 |
| | | if (ALL_TOPICS_EVENT != null && !ALL_TOPICS_EVENT.isEmpty()) { |
| | | for (EventListener listener : ALL_TOPICS_EVENT) { |
| | | if (listener == null) { |
| | | continue; |
| | | } |
| | | ThreadToolUtils.getInstance().runOnUiThread(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | try { |
| | | if (listener != null) { |
| | | listener.onMessage(o); |
| | | } |
| | | } catch (Exception e) { |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | LogUtils.e("post异常2:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 注册所有主题消息的监听 |
| | | * |
| | | * @param listener |
| | | */ |
| | | public synchronized void registerAllTopicsListener(EventListener listener) { |
| | | if (listener == null) { |
| | | return; |
| | | } |
| | | try { |
| | | if (ALL_TOPICS_EVENT != null && !ALL_TOPICS_EVENT.contains(listener)) { |
| | | ALL_TOPICS_EVENT.add(listener); |
| | | } |
| | | TYPE.put(listener, MAIN_TYPE); |
| | | } catch (Exception e) { |
| | | LogUtils.e("registerAllTopicsListener:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 取消所有主题消息的监听 |
| | | * |
| | | * @param listener |
| | | */ |
| | | public synchronized void removeAllTopicsListener(EventListener listener) { |
| | | try { |
| | | ioThread.execute(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | try { |
| | | if (listener == null) { |
| | | return; |
| | | } |
| | | if (ALL_TOPICS_EVENT != null && !ALL_TOPICS_EVENT.isEmpty()) { |
| | | TYPE.remove(listener); |
| | | ALL_TOPICS_EVENT.remove(listener); |
| | | } |
| | | } catch (Exception ignored) { |
| | | LogUtils.e("移除event异常1:" + ignored.getMessage()); |
| | | } |
| | | |
| | | } |
| | | }); |
| | | } catch (Exception e) { |
| | | LogUtils.e("移除event异常2:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | public synchronized void clear() { |
| | | ALL_TOPICS_EVENT.clear(); |
| | | EVENT.clear(); |
| | | TYPE.clear(); |
| | | } |
| | | |
| | | public synchronized void release() { |
| | | clear(); |
| | | ioThread.shutdownNow(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.common.event; |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/22. |
| | | */ |
| | | public interface EventListener { |
| | | |
| | | void onMessage(Object msg); |
| | | |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.common.exception; |
| | | |
| | | /** |
| | | * Created by jlchen on 11/15/21. |
| | | * |
| | | * @Description : HDLError |
| | | */ |
| | | public enum HDLLinkCode { |
| | | |
| | | HDL_DATA_ERROR(-2000,"参数异常"), |
| | | HDL_DATA_NULL_ERROR(-2001,"参数不能为空"), |
| | | HDL_AUTH_ERROR(-2002,"认证失败"), |
| | | HDL_SEND_ERROR(-2003,"发送失败"), |
| | | HDL_TIMEOUT_ERROR(-2004,"超时"), |
| | | HDL_UNAUTHORIZED_ERROR(-2005,"未认证,请先认证"), |
| | | HDL_AUTH_ERROR_GATEWAY_NOT_REGISTERED(-2006,"认证失败,网关未注册到云端"), |
| | | HDL_SEARCH_GATEWAY_TIMEOUT_ERROR(-2007,"搜索网关失败,超时"), |
| | | HDL_AUTH_MAC_KEY_ERROR_(-2008,"认证失败,该MAC对应的设备密钥不存在"), |
| | | HDL_GET_DEVICE_LIST_ERROR(-2100,"获取设备列表失败"), |
| | | HDL_GET_FUNCTION_LIST_ERROR(-2101,"获取功能列表失败"), |
| | | HDL_GET_FUNCTION_PROPERTIES_ERROR(-2102,"获取功能属性失败"), |
| | | HDL_CONTROL_FAILURE_ERROR(-2103,"控制失败"); |
| | | |
| | | private String msg; |
| | | private int code; |
| | | |
| | | private HDLLinkCode(int code, String msg) { |
| | | this.msg = msg; |
| | | this.code = code; |
| | | } |
| | | |
| | | public String getMsg() { |
| | | return msg; |
| | | } |
| | | |
| | | public void setMsg(String msg) { |
| | | this.msg = msg; |
| | | } |
| | | |
| | | public int getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(int code) { |
| | | this.code = code; |
| | | } |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.common.exception; |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Created by Tong on 2021/11/11. |
| | | */ |
| | | public class HDLLinkException extends RuntimeException { |
| | | |
| | | private int code = 0; |
| | | private String msg = ""; |
| | | private Throwable rawThrowable; |
| | | |
| | | public HDLLinkException() { |
| | | } |
| | | |
| | | public HDLLinkException(String msg) { |
| | | this.msg = msg; |
| | | } |
| | | |
| | | public HDLLinkException(int code, String msg) { |
| | | this.code = code; |
| | | this.msg = msg; |
| | | } |
| | | |
| | | public HDLLinkException(int code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | public HDLLinkException(Throwable rawThrowable) { |
| | | this.rawThrowable = rawThrowable; |
| | | } |
| | | |
| | | public int getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(int code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | public |
| | | String getMsg() { |
| | | return msg; |
| | | } |
| | | |
| | | public void setMsg(String msg) { |
| | | this.msg = msg; |
| | | } |
| | | |
| | | public Throwable getRawThrowable() { |
| | | return rawThrowable; |
| | | } |
| | | |
| | | public void setRawThrowable(Throwable rawThrowable) { |
| | | this.rawThrowable = rawThrowable; |
| | | } |
| | | |
| | | public static HDLLinkException getErrorWithCode(HDLLinkCode code){ |
| | | return new HDLLinkException(code.getCode(), code.getMsg()); |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | package com.hdl.sdk.common.utils; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | 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); |
| | | } |
| | | |
| | | //判断一个byte数值在另外一个byte数组中对应的游标值 |
| | | public static int getByteIndexOf(byte[] sources, byte[] src, int startIndex) { |
| | | return getByteIndexOf(sources, src, startIndex, sources.length); |
| | | } |
| | | |
| | | |
| | | //判断一个byte数值在另外一个byte数组中对应的游标值,指定开始的游标和结束的游标位置 |
| | | 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; |
| | | } |
| | | |
| | | /** |
| | | * 字符串to Bytes |
| | | * @param str 字符串 |
| | | * @return |
| | | */ |
| | | public static byte[] stringToBytes(String str) { |
| | | try { |
| | | // 使用指定的字符集将此字符串编码为byte序列并存到一个byte数组中 |
| | | return str.getBytes("utf-8"); |
| | | } catch (UnsupportedEncodingException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return new byte[]{}; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | 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("-", ""); |
| | | } |
| | | } |
New file |
| | |
| | | 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 boolean isLocalIpAddress(String ipAddress) { |
| | | try { |
| | | for (Enumeration<NetworkInterface> niEnum = NetworkInterface.getNetworkInterfaces(); |
| | | niEnum.hasMoreElements(); ) { |
| | | NetworkInterface ni = niEnum.nextElement(); |
| | | for (InterfaceAddress interfaceAddress : ni.getInterfaceAddresses()) { |
| | | if (ipAddress.equals(interfaceAddress.getAddress().getHostAddress())) { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | } catch (SocketException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | 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); |
| | | } |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.common.utils; |
| | | |
| | | import android.util.Log; |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/23. |
| | | */ |
| | | public class LogUtils { |
| | | |
| | | private static final String TAG = "HDLSDK"; |
| | | |
| | | private static boolean isEnabled = true; |
| | | |
| | | public static boolean isEnabled() { |
| | | return isEnabled; |
| | | } |
| | | |
| | | public static void setEnabled(boolean enabled) { |
| | | isEnabled = enabled; |
| | | } |
| | | |
| | | public static void d(String tag, String msg) { |
| | | if (tag != null && msg != null && isEnabled) { |
| | | Log.d(TAG, tag + "-- " + msg); |
| | | } |
| | | } |
| | | |
| | | public static void e(String tag, String msg) { |
| | | if (tag != null && msg != null && isEnabled) { |
| | | Log.e(TAG, tag + "-- " + msg); |
| | | } |
| | | } |
| | | |
| | | public static void w(String tag, String msg) { |
| | | if (tag != null && msg != null && isEnabled) { |
| | | Log.w(TAG, tag + "-- " + msg); |
| | | } |
| | | } |
| | | |
| | | public static void v(String tag, String msg) { |
| | | if (tag != null && msg != null && isEnabled) { |
| | | Log.v(TAG, tag + "-- " + msg); |
| | | } |
| | | } |
| | | |
| | | public static void i(String tag, String msg) { |
| | | if (tag != null && msg != null && isEnabled) { |
| | | Log.i(TAG, tag + "-- " + msg); |
| | | } |
| | | } |
| | | |
| | | public static void i(String msg) { |
| | | if (msg != null && isEnabled) { |
| | | Log.i(TAG, msg); |
| | | } |
| | | } |
| | | |
| | | public static void e(String msg) { |
| | | if (msg != null && isEnabled) { |
| | | Log.e(TAG, msg); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.common.utils; |
| | | |
| | | import android.content.Context; |
| | | import android.content.SharedPreferences; |
| | | |
| | | |
| | | 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(final String key, final String value) { |
| | | getAppPreference().edit().putString(key, value).apply(); |
| | | } |
| | | |
| | | |
| | | public static String getString(final String key) { |
| | | return getString(key, ""); |
| | | } |
| | | |
| | | |
| | | public static String getString(final String key, final String defaultValue) { |
| | | return getAppPreference().getString(key, defaultValue); |
| | | } |
| | | |
| | | |
| | | public static void put(final String key, final int value) { |
| | | put(key, value, false); |
| | | } |
| | | |
| | | |
| | | public static void put(final String key, final int value, final boolean isCommit) { |
| | | getAppPreference().edit().putInt(key, value).apply(); |
| | | } |
| | | |
| | | |
| | | public static int getInt(final String key) { |
| | | return getInt(key, -1); |
| | | } |
| | | |
| | | |
| | | public static int getInt(final String key, final int defaultValue) { |
| | | return getAppPreference().getInt(key, defaultValue); |
| | | } |
| | | |
| | | |
| | | public static void put(final String key, final long value) { |
| | | getAppPreference().edit().putLong(key, value).apply(); |
| | | } |
| | | |
| | | |
| | | public static long getLong(final String key) { |
| | | return getLong(key, -1L); |
| | | } |
| | | |
| | | |
| | | public static long getLong(final String key, final long defaultValue) { |
| | | return getAppPreference().getLong(key, defaultValue); |
| | | } |
| | | |
| | | |
| | | public static void put(final String key, final float value) { |
| | | getAppPreference().edit().putFloat(key, value).apply(); |
| | | } |
| | | |
| | | |
| | | public static float getFloat(final String key) { |
| | | return getFloat(key, -1f); |
| | | } |
| | | |
| | | |
| | | public static float getFloat(final String key, final float defaultValue) { |
| | | return getAppPreference().getFloat(key, defaultValue); |
| | | } |
| | | |
| | | |
| | | public static void put(final String key, final boolean value) { |
| | | getAppPreference().edit().putBoolean(key, value).apply(); |
| | | } |
| | | |
| | | |
| | | public static boolean getBoolean(final String key) { |
| | | return getBoolean(key, false); |
| | | } |
| | | |
| | | |
| | | public static boolean getBoolean(final String key, final boolean defaultValue) { |
| | | return getAppPreference().getBoolean(key, defaultValue); |
| | | } |
| | | |
| | | |
| | | public static void put(final String key, |
| | | final Set<String> value |
| | | ) { |
| | | |
| | | getAppPreference().edit().putStringSet(key, value).apply(); |
| | | |
| | | } |
| | | |
| | | |
| | | public static Set<String> getStringSet(final String key) { |
| | | return getStringSet(key, Collections.<String>emptySet()); |
| | | } |
| | | |
| | | |
| | | public static Set<String> getStringSet(final String key, |
| | | final Set<String> defaultValue) { |
| | | return getAppPreference().getStringSet(key, defaultValue); |
| | | } |
| | | |
| | | |
| | | public static Map<String, ?> getAll() { |
| | | return getAppPreference().getAll(); |
| | | } |
| | | |
| | | |
| | | public static boolean contains(final String key) { |
| | | return getAppPreference().contains(key); |
| | | } |
| | | |
| | | |
| | | public static void remove(final String key) { |
| | | getAppPreference().edit().remove(key).apply(); |
| | | } |
| | | |
| | | public static void clear() { |
| | | getAppPreference() |
| | | .edit() |
| | | .clear() |
| | | .apply(); |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | 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 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); |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | 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); |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.common.utils.gson; |
| | | |
| | | |
| | | 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); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Type[] getActualTypeArguments() { |
| | | return actualTypeArguments; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Type getRawType() { |
| | | return rawType; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Type getOwnerType() { |
| | | return ownerType; |
| | | } |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.connect.bean; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * Created by Tong on 2022/09/23. |
| | | */ |
| | | |
| | | public class LoginRequest implements Serializable { |
| | | |
| | | |
| | | private String clientType; |
| | | private String version; |
| | | |
| | | public String getClientType() { |
| | | return clientType; |
| | | } |
| | | |
| | | public void setClientType(String clientType) { |
| | | this.clientType = clientType; |
| | | } |
| | | |
| | | public String getVersion() { |
| | | return version; |
| | | } |
| | | |
| | | public void setVersion(String version) { |
| | | this.version = version; |
| | | } |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.connect.bean.response; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * Created by jlchen on 11/12/21. |
| | | * |
| | | * @Description : DeviceInfoResponse |
| | | */ |
| | | public class DeviceInfoResponse extends BaseResponse { |
| | | private GatewayObjects objects; |
| | | |
| | | public GatewayObjects getObjects() { |
| | | return objects; |
| | | } |
| | | |
| | | public void setObjects(GatewayObjects value) { |
| | | this.objects = value; |
| | | } |
| | | |
| | | public class GatewayObjects implements Serializable { |
| | | private String ip_address; |
| | | private String gatewayId; |
| | | private String oid; |
| | | private String homeId; |
| | | private String mac; |
| | | |
| | | public String getIPAddress() { |
| | | return ip_address; |
| | | } |
| | | |
| | | public void setIPAddress(String value) { |
| | | this.ip_address = value; |
| | | } |
| | | |
| | | public String getGatewayID() { |
| | | return gatewayId; |
| | | } |
| | | |
| | | public void setGatewayID(String value) { |
| | | this.gatewayId = value; |
| | | } |
| | | |
| | | public String getOID() { |
| | | return oid; |
| | | } |
| | | |
| | | public void setOID(String value) { |
| | | this.oid = value; |
| | | } |
| | | |
| | | public String getHomeId() { |
| | | return homeId; |
| | | } |
| | | |
| | | public void setHomeId(String homeId) { |
| | | this.homeId = homeId; |
| | | } |
| | | |
| | | public String getMac() { |
| | | return mac; |
| | | } |
| | | |
| | | public void setMac(String mac) { |
| | | this.mac = mac; |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | import android.util.Log;
|
| | |
|
| | | 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.exception.HDLLinkException;
|
| | | import com.hdl.sdk.common.utils.IdUtils;
|
| | | import com.hdl.sdk.common.utils.LogUtils;
|
| | | 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.HDLLink;
|
| | | import com.hdl.sdk.connect.bean.LoginRequest;
|
| | | import com.hdl.sdk.connect.bean.request.BroadcastRequest;
|
| | | import com.hdl.sdk.connect.bean.response.AuthenticateResponse;
|
| | | import com.hdl.sdk.connect.bean.response.BaseLocalResponse;
|
| | | import com.hdl.sdk.connect.bean.request.DeviceControlRequest;
|
| | | import com.hdl.sdk.connect.bean.request.FunctionAttributeRequest;
|
| | | import com.hdl.sdk.connect.bean.LinkRequest;
|
| | | import com.hdl.sdk.connect.bean.LinkResponse;
|
| | | import com.hdl.sdk.connect.bean.request.PropertyReadRequest;
|
| | | import com.hdl.sdk.connect.bean.response.DeviceInfoResponse;
|
| | | import com.hdl.sdk.connect.callback.HDLLinkCallBack;
|
| | | import com.hdl.sdk.connect.callback.HDLLinkResponseCallBack;
|
| | | import com.hdl.sdk.connect.config.HDLLinkConfig;
|
| | |
| | | statusListener = new ConnectStatusListener() {
|
| | | @Override
|
| | | public void onConnecting() {
|
| | | broadcastRequest();
|
| | | //broadcastRequest();
|
| | | }
|
| | |
|
| | | @Override
|
| | |
| | | };
|
| | | }
|
| | |
|
| | | public boolean isBroadcast = false;
|
| | |
|
| | | /**
|
| | | * 广播自身信息给主网关
|
| | | */
|
| | | private void broadcastRequest() {
|
| | | public void broadcastRequest() {
|
| | |
|
| | | new Thread(new Runnable() {
|
| | | @Override
|
| | | public void run() {
|
| | | try {
|
| | | LogUtils.i("广播设备本身信息");
|
| | | while (true) {
|
| | | try {
|
| | | Thread.sleep(1000);
|
| | | // LogUtils.i("checkIfCertified=" + HDLLink.getInstance().checkIfCertified() + " getTcp().connected=" + getTcp().connected);
|
| | | try {
|
| | | if (!HDLLink.getInstance().checkIfCertified() || getTcp().connected) {
|
| | | continue;
|
| | | }
|
| | | } catch (Exception e) {
|
| | |
|
| | | String time = String.valueOf(System.currentTimeMillis());
|
| | | if (null == HDLLinkConfig.getInstance().getDeviceInfoBean()) {
|
| | | LogUtils.i("DeviceInfoBean为空,请设置当前对象");
|
| | | return;
|
| | | }
|
| | | LogUtils.i("广播设备本身信息");
|
| | | String time = String.valueOf(System.currentTimeMillis());
|
| | | if (null == HDLLinkConfig.getInstance().getDeviceInfoBean()) {
|
| | | LogUtils.i("DeviceInfoBean为空,请设置当前对象");
|
| | | continue;
|
| | | }
|
| | | BroadcastRequest request = new BroadcastRequest(IdUtils.getUUId(), time, HDLLinkConfig.getInstance().getDeviceInfoBean(), "200");
|
| | | HDLAuthSocket.getInstance().udpSendMsg(TopicConstant.BROADCAST, GsonConvert.getGson().toJson(request), true, new HDLLinkResponseCallBack() {
|
| | | @Override
|
| | | public void onSuccess(LinkResponse msg) {
|
| | | getTcp();
|
| | | String data = msg.getData();
|
| | | if (!TextUtils.isEmpty(data)) {
|
| | | DeviceInfoResponse response = GsonConvert.getGson().fromJson(data, new TypeToken<DeviceInfoResponse>() {
|
| | | }.getType());
|
| | | HDLLinkConfig.getInstance().setIpAddress(response.getObjects().getIPAddress());
|
| | | HDLLinkConfig.getInstance().reSaveConfig();
|
| | | }
|
| | | isBroadcast = true;
|
| | | LogUtils.i("广播信息给主网关成功!");
|
| | | }
|
| | |
|
| | | @Override
|
| | | public void onError(HDLLinkException e) {
|
| | | isBroadcast = false;
|
| | | LogUtils.i("广播信息给主网关失败!");
|
| | | }
|
| | | });
|
| | | // HDLAuthSocket.getInstance().udpSendMsg(TopicConstant.BROADCAST, GsonConvert.getGson().toJson(request), true);
|
| | | //HDLAuthSocket.getInstance().udpSendMsg(TopicConstant.BROADCAST, GsonConvert.getGson().toJson(request), true);
|
| | | } catch (Exception e) {
|
| | | LogUtils.e("广播设备本身信息失败,失败信息:" + e.getMessage());
|
| | | }
|
| | | BroadcastRequest request = new BroadcastRequest(IdUtils.getUUId(), time, HDLLinkConfig.getInstance().getDeviceInfoBean(), "200");
|
| | | HDLAuthSocket.getInstance().udpSendMsg(TopicConstant.BROADCAST, GsonConvert.getGson().toJson(request), true, new HDLLinkResponseCallBack() {
|
| | | @Override
|
| | | public void onSuccess(LinkResponse msg) {
|
| | | LogUtils.i("广播信息给主网关成功!");
|
| | | }
|
| | |
|
| | | @Override
|
| | | public void onError(HDLLinkException e) {
|
| | | LogUtils.i("广播信息给主网关失败!");
|
| | | }
|
| | | });
|
| | | HDLAuthSocket.getInstance().udpSendMsg(TopicConstant.BROADCAST, GsonConvert.getGson().toJson(request), true);
|
| | | HDLAuthSocket.getInstance().udpSendMsg(TopicConstant.BROADCAST, GsonConvert.getGson().toJson(request), true);
|
| | | } catch (Exception e) {
|
| | | LogUtils.e("广播设备本身信息失败,失败信息:" + e.getMessage());
|
| | | }
|
| | |
|
| | | }
|
| | | }).start();
|
| | | }
|
| | |
|
| | | // private static class SingletonInstance {
|
| | | // private static class SingletonInstance {
|
| | | // }
|
| | | private static final HDLSocket instance = new HDLSocket();
|
| | |
|
| | |
| | | }
|
| | |
|
| | | SocketOptions options;
|
| | |
|
| | | private SocketOptions getTcpOptions() {
|
| | | if(null!=options){
|
| | | if (null != options) {
|
| | | return options;
|
| | | }
|
| | | options = new SocketOptions();
|
| | |
| | | throw new RuntimeException("请搜索网关");
|
| | | }
|
| | | //如果没有初始化,或者网关IP更改了,就重新初始化
|
| | | if (tcpBoot == null||!getTcpOptions().getIp().equals(getTcpIp())) {
|
| | | if (tcpBoot == null || !getTcpOptions().getIp().equals(getTcpIp())) {
|
| | | tcpBoot = TcpClient.init(getTcpIp(), getTcpPort(), getTcpOptions());
|
| | | tcpBoot.SetHeartbeat(new IHeartbeat() {
|
| | | @Override
|
| | | public void heartbeat() {
|
| | |
|
| | | if(HDLLinkConfig.getInstance().getDeviceInfoBean()==null||HDLLinkConfig.getInstance().getDeviceInfoBean().getOID()==null) {
|
| | | if (HDLLinkConfig.getInstance().getDeviceInfoBean() == null || HDLLinkConfig.getInstance().getDeviceInfoBean().getOID() == null) {
|
| | | LogUtils.i("DeviceInfoBean为空,需要设置才能正常心跳");
|
| | | return;
|
| | | }
|
| | |
| | | }
|
| | |
|
| | | /**
|
| | | * 场景控制
|
| | | * @param sids 场景sid列表
|
| | | * 场景控制
|
| | | *
|
| | | * @param sids 场景sid列表
|
| | | * @param callBack 回调
|
| | | */
|
| | | public void controlScene(List<String> sids, HDLLinkCallBack callBack) {
|
| | |
| | | }
|
| | | }
|
| | | } else {
|
| | | if (callBack != null) {
|
| | | callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_SEND_ERROR));
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * tcp登录方便获取状态
|
| | | *
|
| | | * @param clientType 客户端类型
|
| | | * 应用:app;
|
| | | * 调试软件:program;
|
| | | * 第三方:third_party;
|
| | | * 网关:gateway;
|
| | | * 其它:other
|
| | | * @param version 协议版本
|
| | | */
|
| | | public void tcpLogin(String clientType, String version, HDLLinkCallBack callBack) {
|
| | | final String msgId = IdUtils.getUUId();
|
| | | String time = String.valueOf(System.currentTimeMillis());
|
| | | final BaseLocalResponse<LoginRequest> data = new BaseLocalResponse<>();
|
| | | data.setId(msgId);
|
| | | data.setTime_stamp(time);
|
| | |
|
| | | final LoginRequest request = new LoginRequest();
|
| | | request.setVersion(version);
|
| | | request.setClientType(clientType);
|
| | |
|
| | | data.setObjects(request);
|
| | |
|
| | | String topic = String.format(TopicConstant.GATEWAY_LOGIN, HDLLinkConfig.getInstance().getGatewayId());
|
| | | LinkRequest message = new LinkRequest(topic,
|
| | | GsonConvert.getGson().toJson(data));
|
| | |
|
| | | String replyTopic = topic + "_reply";
|
| | | try {
|
| | | sendMsg(message.getSendBytes(), replyTopic, callBack, new SendListener() {
|
| | | @Override
|
| | | public void onSucceed() {
|
| | | LogUtils.i("tcpLogin onSucceed");
|
| | | }
|
| | |
|
| | | @Override
|
| | | public void onError() {
|
| | | if (callBack != null) {
|
| | | callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_SEND_ERROR));
|
| | | }
|
| | | }
|
| | | });
|
| | | } catch (Exception e) {
|
| | | if (callBack != null) {
|
| | | callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_SEND_ERROR));
|
| | | }
|
| | |
| | | /**
|
| | | * 通用TCP发送指令 只发一次,不监听回复,不重发
|
| | | *
|
| | | * @param topic 发送数据
|
| | | * @param bodyStr 回复的主题
|
| | | * @param topic 发送数据
|
| | | * @param bodyStr 回复的主题
|
| | | */
|
| | | public void tcpSendMsg(String topic, String bodyStr) {
|
| | | try {
|
| | |
| | | LinkRequest message = new LinkRequest(topic, bodyStr);
|
| | | getTcp().sendMsg(message.getSendBytes());
|
| | | } catch (Exception e) {
|
| | | LogUtils.e("tcpSendMsg", "发送失败 :"+e.getMessage());
|
| | | LogUtils.e("tcpSendMsg", "发送失败 :" + e.getMessage());
|
| | | }
|
| | | }
|
| | |
|
| | |
| | | public void sendMsg(byte[] data, String eventTag, HDLLinkCallBack callBack, SendListener sendListener) {
|
| | |
|
| | | try {
|
| | | if(eventTag!=null) {
|
| | | if (eventTag != null) {
|
| | | final AtomicInteger sendCount = new AtomicInteger(0);
|
| | |
|
| | | final ScheduledExecutorService threadPool = ThreadToolUtils.getInstance().newScheduledThreadPool(1);
|
New file |
| | |
| | | package com.hdl.sdk.socket; |
| | | |
| | | import android.text.TextUtils; |
| | | |
| | | import com.hdl.sdk.common.HDLSdk; |
| | | import com.hdl.sdk.common.utils.LogUtils; |
| | | import com.hdl.sdk.common.utils.ThreadToolUtils; |
| | | import com.hdl.sdk.connect.socket.HDLSocket; |
| | | import com.hdl.sdk.socket.annotation.ConnectStatus; |
| | | import com.hdl.sdk.socket.client.IClient; |
| | | import com.hdl.sdk.socket.client.IHeartbeat; |
| | | import com.hdl.sdk.socket.client.TcpClient; |
| | | import com.hdl.sdk.socket.listener.SendListener; |
| | | |
| | | import java.util.concurrent.BlockingQueue; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.ConcurrentMap; |
| | | import java.util.concurrent.ExecutorService; |
| | | import java.util.concurrent.LinkedBlockingDeque; |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/26. |
| | | * Tcp/Udp 启动器 |
| | | */ |
| | | public class SocketBoot { |
| | | |
| | | private ExecutorService connectThread; |
| | | private ExecutorService sendThread; |
| | | private ExecutorService receiveThread; |
| | | private ExecutorService heartbeatThread; |
| | | |
| | | private final IClient client; |
| | | private IHeartbeat iHeartbeat; |
| | | |
| | | public void SetHeartbeat(IHeartbeat iHeartbeat) { |
| | | this.iHeartbeat = iHeartbeat; |
| | | } |
| | | |
| | | /** |
| | | * 当前接收到数据的时间 |
| | | */ |
| | | private static long time = System.currentTimeMillis(); |
| | | |
| | | /** |
| | | * tcp是否已经连接 |
| | | */ |
| | | public boolean connected = false; |
| | | |
| | | public IClient getClient() { |
| | | return client; |
| | | } |
| | | |
| | | private final BlockingQueue<SocketRequest> mMessageQueue = new LinkedBlockingDeque<>(); |
| | | |
| | | private final ConcurrentMap<String, SendListener> sendMap = new ConcurrentHashMap<>(); |
| | | |
| | | public SocketBoot(IClient client) { |
| | | this.client = client; |
| | | initConnectThread(); |
| | | initReceiveThread(); |
| | | initSendThread(); |
| | | initHeartbeat(); |
| | | } |
| | | |
| | | /** |
| | | * 连接tcp,内部维护掉,可以不用开放外部,根据这个业务我特性处理好 |
| | | */ |
| | | private synchronized void connect() { |
| | | try { |
| | | LogUtils.i("TCP连接"); |
| | | client.onConnectStatus(ConnectStatus.CONNECTING); |
| | | Thread.sleep(1000); |
| | | client.connect(); |
| | | connected = true; |
| | | HDLSocket.getInstance().tcpLogin("third_party", HDLSdk.getInstance().getVersion(),null); |
| | | LogUtils.i("TCP连接成功"); |
| | | client.onConnectStatus(ConnectStatus.CONNECTED); |
| | | } catch (Exception e) { |
| | | LogUtils.e("连接异常" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 初始化发送线程,只需要初始化一次 |
| | | */ |
| | | private void initSendThread() { |
| | | if (sendThread == null) { |
| | | sendThread = ThreadToolUtils.getInstance().newFixedThreadPool(1); |
| | | sendThread.execute(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | while (true) { |
| | | try { |
| | | if (!connected) { |
| | | Thread.sleep(200); |
| | | continue; |
| | | } |
| | | SocketRequest socketRequest = mMessageQueue.take(); |
| | | // final String sendStr = new String(socketRequest.getData(), 0, socketRequest.getData().length); |
| | | // LogUtils.i("发送数据:" + sendStr); |
| | | if (System.currentTimeMillis() - socketRequest.getTime() > 10000) { |
| | | continue; |
| | | } |
| | | 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) { |
| | | HDLSocket.getInstance().isBroadcast=false; |
| | | connected = false; |
| | | |
| | | LogUtils.e("发送失败:" + e.getMessage()); |
| | | if (!TextUtils.isEmpty(action)) { |
| | | SendListener sendListener = sendMap.get(action); |
| | | if (sendListener != null) { |
| | | sendListener.onError(); |
| | | } |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 初始化接收线程,只需要初始化一次 |
| | | */ |
| | | public void initReceiveThread() { |
| | | if (receiveThread == null) { |
| | | receiveThread = ThreadToolUtils.getInstance().newFixedThreadPool(1); |
| | | receiveThread.execute(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | while (true) { |
| | | try { |
| | | if (connected) { |
| | | //读取数据 |
| | | client.onHandleResponse(); |
| | | time = System.currentTimeMillis(); |
| | | } else { |
| | | try { |
| | | Thread.sleep(1000); |
| | | } catch (Exception ee) { |
| | | |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | HDLSocket.getInstance().isBroadcast= false; |
| | | connected = false; |
| | | |
| | | LogUtils.e("接收数据线程异常" + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 初始化重新连接线程 |
| | | */ |
| | | private void initConnectThread() { |
| | | if (connectThread == null) { |
| | | connectThread = ThreadToolUtils.getInstance().newFixedThreadPool(1); |
| | | //一定时间检测一次连接情况,没有连接就执行连接,连接统一由这里维护 |
| | | connectThread.execute(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | while (true) { |
| | | try { |
| | | // LogUtils.i("initConnectThread: connected=" + connected + " isBroadcast=" + HDLSocket.getInstance().isBroadcast); |
| | | if (!connected && HDLSocket.getInstance().isBroadcast) { |
| | | reconect(); |
| | | } |
| | | Thread.sleep(3 * 1000); |
| | | } catch (Exception e) { |
| | | LogUtils.e("定时连接失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 初始化重新心跳线程 |
| | | */ |
| | | private void initHeartbeat() { |
| | | if (heartbeatThread == null) { |
| | | heartbeatThread = ThreadToolUtils.getInstance().newFixedThreadPool(1); |
| | | heartbeatThread.execute(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | while (true) { |
| | | try { |
| | | //10秒 |
| | | if (connected && 10 * 1000 < (System.currentTimeMillis() - time)) { |
| | | time = System.currentTimeMillis(); |
| | | //心跳检测 |
| | | if (iHeartbeat != null) |
| | | iHeartbeat.heartbeat(); |
| | | } |
| | | Thread.sleep(1000); |
| | | } catch (Exception e) { |
| | | LogUtils.e("定时心跳检测网关异常:" + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 重新连接 |
| | | */ |
| | | private void reconect() { |
| | | disconnect(); |
| | | connect(); |
| | | } |
| | | |
| | | /** |
| | | * 发送无需回调 |
| | | * |
| | | * @param msg 发送的数据 |
| | | */ |
| | | public void sendMsg(byte[] msg) { |
| | | sendMsg(msg, null); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @param listener 一般情况无需监听 |
| | | */ |
| | | public void sendMsg(byte[] msg, SendListener listener) { |
| | | try { |
| | | SocketRequest request = new SocketRequest(msg); |
| | | if (listener != null && !TextUtils.isEmpty(request.getAction())) { |
| | | sendMap.put(request.getAction(), listener); |
| | | } |
| | | mMessageQueue.put(request); |
| | | } catch (Exception e) { |
| | | LogUtils.e("发送数据失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 关闭连接 |
| | | */ |
| | | private synchronized void disconnect() { |
| | | try { |
| | | client.disconnect(); |
| | | //断开连接 |
| | | client.onConnectStatus(ConnectStatus.DISCONNECT); |
| | | } catch (Exception e) { |
| | | |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | 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 { |
| | | |
| | | //发送目标地址IP |
| | | private String ip=""; |
| | | private int port; |
| | | |
| | | //处理数据 |
| | | private IHandleMessage handleMessage; |
| | | |
| | | //监听状态 |
| | | private List<ConnectStatusListener> mConnectStatusListener; |
| | | |
| | | |
| | | public String getIp() { |
| | | return ip; |
| | | } |
| | | |
| | | public int getPort() { |
| | | return port; |
| | | } |
| | | |
| | | public void setPort(int port) { |
| | | this.port = port; |
| | | } |
| | | |
| | | public void setIp(String ip) { |
| | | this.ip = ip; |
| | | } |
| | | |
| | | public IHandleMessage getHandleMessage() { |
| | | return handleMessage; |
| | | } |
| | | |
| | | public void setHandleMessage(IHandleMessage handleMessage) { |
| | | this.handleMessage = handleMessage; |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket; |
| | | |
| | | import com.hdl.sdk.socket.client.IClient; |
| | | |
| | | import java.net.DatagramSocket; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.SocketException; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | /** |
| | | * Created by Tong on 2021/10/19. |
| | | * 计划参考generic-pool、Commons Pool进行完善 |
| | | */ |
| | | public class SocketPool { |
| | | |
| | | private final ConcurrentHashMap<String, IClient> mPool; |
| | | private final ConcurrentHashMap<String, DatagramSocket> mUdpClientPool; |
| | | |
| | | private SocketPool() { |
| | | mPool = new ConcurrentHashMap<>(); |
| | | mUdpClientPool = new ConcurrentHashMap<>(); |
| | | } |
| | | |
| | | private static final SocketPool instance = new SocketPool(); |
| | | |
| | | public static SocketPool getInstance() { |
| | | return instance; |
| | | } |
| | | |
| | | public void clear() { |
| | | mPool.clear(); |
| | | mUdpClientPool.clear(); |
| | | } |
| | | |
| | | public synchronized DatagramSocket getUdpSocket(InetSocketAddress address) throws SocketException { |
| | | DatagramSocket socket; |
| | | final String key = address.toString(); |
| | | if (mUdpClientPool.containsKey(key)) { |
| | | socket = mUdpClientPool.get(key); |
| | | if (socket != null && !socket.isClosed()) { |
| | | return socket; |
| | | } else { |
| | | socket = new DatagramSocket(address); |
| | | } |
| | | } else { |
| | | socket = new DatagramSocket(address); |
| | | } |
| | | mUdpClientPool.put(address.toString(), socket); |
| | | return socket; |
| | | } |
| | | } |
New file |
| | |
| | | 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; |
| | | |
| | | private long time = System.currentTimeMillis(); |
| | | |
| | | 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; |
| | | } |
| | | |
| | | public long getTime() { |
| | | return time; |
| | | } |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.annotation; |
| | | |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/22. |
| | | */ |
| | | |
| | | public class ConnectStatus { |
| | | |
| | | /** |
| | | * 连接中 |
| | | */ |
| | | public static final int CONNECTING = 0; |
| | | |
| | | /** |
| | | * 连接成功 |
| | | */ |
| | | public static final int CONNECTED = 1; |
| | | |
| | | /** |
| | | * 连接关闭 |
| | | */ |
| | | public static final int DISCONNECT = 2; |
| | | } |
New file |
| | |
| | | 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(); |
| | | |
| | | |
| | | SocketOptions getOptions(); |
| | | |
| | | /** |
| | | * 监听数据 |
| | | */ |
| | | void onHandleResponse() throws Exception; |
| | | |
| | | /** |
| | | * 发送消息 |
| | | */ |
| | | void sendMsg(byte[] msg) throws Exception; |
| | | |
| | | /** |
| | | * 连接状态 |
| | | */ |
| | | void onConnectStatus(int status); |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.client; |
| | | |
| | | /** |
| | | * Created by hxb on 2022/2/16. |
| | | */ |
| | | public interface IHeartbeat { |
| | | void heartbeat(); |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.client; |
| | | |
| | | import com.hdl.sdk.socket.SocketOptions; |
| | | import com.hdl.sdk.socket.udp.UdpSocketOptions; |
| | | |
| | | import java.net.InetSocketAddress; |
| | | import java.net.SocketAddress; |
| | | |
| | | /** |
| | | * Created by hxb on 2021/12/12. |
| | | */ |
| | | public interface IUdpClient { |
| | | |
| | | /** |
| | | * 绑定端口 |
| | | */ |
| | | void bind() throws Exception; |
| | | |
| | | /** |
| | | * 关闭当前连接 |
| | | * @return |
| | | */ |
| | | boolean close(); |
| | | |
| | | |
| | | UdpSocketOptions getOptions(); |
| | | |
| | | /** |
| | | * 监听数据 |
| | | */ |
| | | void onHandleResponse() throws Exception; |
| | | |
| | | /** |
| | | * 发送数据 |
| | | * @param ipAddress 目标IP |
| | | * @param port 端口 |
| | | * @param msg 发送数据 |
| | | * @throws Exception |
| | | */ |
| | | void sendMsg(String ipAddress,int port, byte[] msg) throws Exception; |
| | | |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.client; |
| | | |
| | | |
| | | |
| | | import com.hdl.sdk.common.utils.ByteUtils; |
| | | import com.hdl.sdk.common.utils.LogUtils; |
| | | 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.net.SocketAddress; |
| | | import java.net.StandardSocketOptions; |
| | | import java.util.ArrayList; |
| | | 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 final static List<TcpClient> tcpClientList = new ArrayList(); |
| | | |
| | | /** |
| | | * 从连接池中找出当前IP及端口的连接客户端 |
| | | * @param ipAdderss 连接IP地址 |
| | | * @param port 连接端口 |
| | | * @return |
| | | */ |
| | | public static TcpClient getTcpClientByIP(String ipAdderss,int port) { |
| | | for(TcpClient tcpClient:tcpClientList){ |
| | | if(tcpClient.ip.equals(ipAdderss)&&tcpClient.port==port) |
| | | { |
| | | return tcpClient; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private byte[] readBuffer = new byte[4*1024]; |
| | | |
| | | private TcpClient(String ip, int port, SocketOptions socketOptions) { |
| | | this.socketOptions = socketOptions; |
| | | this.ip = ip; |
| | | this.port = port; |
| | | socketOptions.setIp(ip); |
| | | socketOptions.setPort(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), 3 * 1000); |
| | | mSocket.setTcpNoDelay(true); |
| | | mSocket.setReuseAddress(true); |
| | | // mSocket.setKeepAlive(true); |
| | | mSocket.setSoTimeout(25 * 1000); |
| | | |
| | | tcpClientList.add(this); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void disconnect() { |
| | | if (mSocket != null) { |
| | | try { |
| | | mSocket.close(); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @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) { |
| | | while ( true) { |
| | | int len=getInputStream().read(readBuffer); |
| | | if(len<=0){ |
| | | throw new Exception("接收异常,接收数据长度len="+len); |
| | | } |
| | | |
| | | IHandleMessage handleMessage = getOptions().getHandleMessage(); |
| | | if (handleMessage != null) { |
| | | byte []bytes = new byte[len]; |
| | | System.arraycopy(readBuffer,0,bytes,0,len); |
| | | //完整的数据才回调 |
| | | handleMessage.read(bytes,ip); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void sendMsg(byte[] msg) throws Exception { |
| | | final OutputStream outputStream = getOutStream(); |
| | | if (outputStream != null && getOptions() != null) { |
| | | IHandleMessage handleMessage = getOptions().getHandleMessage(); |
| | | handleMessage.write(handleMessage.write(msg)); |
| | | outputStream.write(msg); |
| | | 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; |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.client; |
| | | |
| | | |
| | | import android.text.TextUtils; |
| | | |
| | | import com.hdl.sdk.common.utils.IpUtils; |
| | | import com.hdl.sdk.common.utils.LogUtils; |
| | | import com.hdl.sdk.socket.SocketBoot; |
| | | import com.hdl.sdk.socket.SocketOptions; |
| | | import com.hdl.sdk.socket.SocketPool; |
| | | import com.hdl.sdk.socket.udp.UdpSocketBoot; |
| | | import com.hdl.sdk.socket.udp.UdpSocketOptions; |
| | | import com.hdl.sdk.socket.codec.IHandleMessage; |
| | | |
| | | import java.io.IOException; |
| | | import java.net.DatagramPacket; |
| | | import java.net.DatagramSocket; |
| | | import java.net.InetAddress; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.SocketAddress; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | |
| | | |
| | | /** |
| | | * Created by hxb on 2021/12/12. |
| | | */ |
| | | public class UdpClient implements IUdpClient { |
| | | |
| | | /** |
| | | * 当前socket |
| | | */ |
| | | private DatagramSocket mSocket; |
| | | |
| | | /** |
| | | * 接收数据包 |
| | | */ |
| | | private DatagramPacket receivePacket; |
| | | |
| | | /** |
| | | * 缓冲区大小 |
| | | */ |
| | | private final int BUFFER = 2 * 1024; |
| | | |
| | | /** |
| | | * 本地监听IP地址 |
| | | */ |
| | | private String ipAddress; |
| | | /** |
| | | * 本地监听端口 |
| | | */ |
| | | private int port; |
| | | |
| | | /** |
| | | * socket配置信息 |
| | | */ |
| | | private UdpSocketOptions socketOptions; |
| | | |
| | | /** |
| | | * 初始化参数 |
| | | * @param ipAddress 本地监听端口 |
| | | * @param port 本地监听端口 |
| | | * @param socketOptions |
| | | */ |
| | | private UdpClient(String ipAddress,int port, UdpSocketOptions socketOptions) { |
| | | this.ipAddress = ipAddress; |
| | | this.port = port; |
| | | this.socketOptions = socketOptions; |
| | | byte[] receiveByte = new byte[BUFFER]; |
| | | receivePacket = new DatagramPacket(receiveByte, receiveByte.length); |
| | | } |
| | | |
| | | /** |
| | | * 初始化参数 |
| | | * @param ipAddress 本地监听IP地址 |
| | | * @param port 本地监听端口 |
| | | * @param options |
| | | * @return |
| | | */ |
| | | public static UdpSocketBoot init(String ipAddress, int port, UdpSocketOptions options) { |
| | | return new UdpSocketBoot(new UdpClient(ipAddress, port, options)); |
| | | } |
| | | |
| | | /** |
| | | * 初始化参数 |
| | | * @param port 本地监听端口 |
| | | * @param options |
| | | * @return |
| | | */ |
| | | public static UdpSocketBoot init(int port, UdpSocketOptions options) { |
| | | return init("0.0.0.0", port, options); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void bind() throws Exception { |
| | | try { |
| | | //已经绑定过就不用再绑定 |
| | | if (null != mSocket) { |
| | | return; |
| | | } |
| | | if (TextUtils.isEmpty(ipAddress)) { |
| | | mSocket = SocketPool.getInstance().getUdpSocket(new InetSocketAddress(port)); |
| | | }else { |
| | | mSocket = SocketPool.getInstance().getUdpSocket(new InetSocketAddress(ipAddress,port)); |
| | | } |
| | | mSocket.setBroadcast(true); |
| | | // mSocket.setReuseAddress(true); |
| | | |
| | | } catch (Exception e) { |
| | | LogUtils.e("初始化Socket 失败:" + e.getMessage()); |
| | | throw e; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean close() { |
| | | try { |
| | | mSocket.close(); |
| | | } catch (Exception e) { |
| | | |
| | | } |
| | | mSocket = null; |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public UdpSocketOptions getOptions() { |
| | | return this.socketOptions; |
| | | } |
| | | |
| | | @Override |
| | | public void onHandleResponse() throws Exception { |
| | | if (mSocket == null) { |
| | | return; |
| | | } |
| | | try { |
| | | mSocket.receive(receivePacket); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | if (receivePacket.getLength() == 0) { |
| | | return; |
| | | } |
| | | //排除自己发出去的 |
| | | try { |
| | | if (IpUtils.isLocalIpAddress(receivePacket.getAddress().getHostAddress())) |
| | | return; |
| | | } catch (Exception ignored) { |
| | | |
| | | } |
| | | |
| | | try { |
| | | LogUtils.i("接收到Udp数据包,网络地址:" + receivePacket.getAddress().getHostAddress() + ":" + receivePacket.getPort()); |
| | | |
| | | IHandleMessage handleMessage = getOptions().getHandleMessage(); |
| | | if (handleMessage != null) { |
| | | byte[] data = new byte[receivePacket.getLength()]; |
| | | System.arraycopy(receivePacket.getData(), 0, data, 0, data.length); |
| | | handleMessage.read(data,receivePacket.getAddress().getHostAddress()); |
| | | } |
| | | |
| | | } catch (Exception e) { |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void sendMsg(String ipAddress,int port, byte[] msg) throws Exception { |
| | | if (msg == null) { |
| | | return; |
| | | } |
| | | final DatagramPacket sendPacket = new DatagramPacket(msg, msg.length, InetAddress.getByName(ipAddress), port); |
| | | mSocket.send(sendPacket); |
| | | } |
| | | } |
New file |
| | |
| | | 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,String ipaddress) |
| | | throws Exception; |
| | | |
| | | @Override |
| | | public final T read(Object data,String ipaddress) throws Exception { |
| | | return decoder(data,ipaddress); |
| | | } |
| | | |
| | | @Override |
| | | public final byte[] write(byte[] data) { |
| | | return data; |
| | | } |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.codec; |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/23. |
| | | */ |
| | | public interface IHandleFlow<T> { |
| | | |
| | | T read(Object data,String ipaddress) throws Exception; |
| | | |
| | | byte[] write(byte[] data) throws Exception; |
| | | |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.codec; |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/27. |
| | | */ |
| | | public interface IHandleMessage { |
| | | void read(byte[] data,String ipaddress) throws Exception; |
| | | |
| | | byte[] write(byte[] data) throws Exception; |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.codec; |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/23. |
| | | */ |
| | | public interface IMessagePipeLine { |
| | | |
| | | void add(IHandleFlow flow); |
| | | |
| | | void clear(); |
| | | } |
New file |
| | |
| | | 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 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,String ipaddress) throws Exception { |
| | | Object out = data; |
| | | for (int i = 0; i < queue.size(); i++) { |
| | | IHandleFlow flow = queue.get(i); |
| | | Object read = flow.read(out,ipaddress); |
| | | 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]; |
| | | } |
| | | } |
New file |
| | |
| | | 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,String ipaddress) { |
| | | return data; |
| | | } |
| | | |
| | | @Override |
| | | public byte[] write(byte[] data) throws Exception { |
| | | return encode(data); |
| | | } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | 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() { |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.listener; |
| | | |
| | | /** |
| | | * Created by Tong on 2021/9/22. |
| | | */ |
| | | public interface SendListener { |
| | | |
| | | void onSucceed(); |
| | | |
| | | void onError(); |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.udp; |
| | | |
| | | import android.text.TextUtils; |
| | | |
| | | import com.hdl.sdk.common.utils.LogUtils; |
| | | import com.hdl.sdk.common.utils.ThreadToolUtils; |
| | | import com.hdl.sdk.socket.SocketRequest; |
| | | import com.hdl.sdk.socket.client.IUdpClient; |
| | | import com.hdl.sdk.socket.listener.SendListener; |
| | | |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.ConcurrentMap; |
| | | import java.util.concurrent.ExecutorService; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | /** |
| | | * Created by hxb on 2021/12/12. |
| | | */ |
| | | public class UdpSocketBoot { |
| | | |
| | | private final IUdpClient client; |
| | | |
| | | private final AtomicBoolean isOpenRetry = new AtomicBoolean(false); |
| | | |
| | | private final AtomicInteger resendCount = new AtomicInteger(0); |
| | | |
| | | private ExecutorService receiveThread; |
| | | |
| | | private final ConcurrentMap<String, SendListener> sendMap = new ConcurrentHashMap<>(); |
| | | |
| | | public UdpSocketBoot(IUdpClient client) { |
| | | this.client = client; |
| | | } |
| | | |
| | | /** |
| | | * 绑定 socket |
| | | * @throws Exception 可能端口冲突 |
| | | */ |
| | | public void bind() throws Exception { |
| | | client.bind(); |
| | | initReceiveThread(); |
| | | } |
| | | |
| | | /** |
| | | * 初始化接收线程 |
| | | */ |
| | | private void initReceiveThread() { |
| | | if(null!=receiveThread){ |
| | | return; |
| | | } |
| | | receiveThread = ThreadToolUtils.getInstance().newFixedThreadPool(1); |
| | | receiveThread.execute(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | while (true) { |
| | | try { |
| | | client.onHandleResponse(); |
| | | } catch (Exception e) { |
| | | LogUtils.i("接收线程异常:"+e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 发送数据 |
| | | * @param ipAddress 目的的IP地址 |
| | | * @param port 端口 |
| | | * @param msg 发送数据 |
| | | * @param listener 发送回调 |
| | | */ |
| | | public void sendMsg(String ipAddress,int port,byte[] msg, SendListener listener) { |
| | | sendMsg(ipAddress,port, msg, true, listener); |
| | | } |
| | | |
| | | /** |
| | | * 发送数据 |
| | | * @param ipAddress 目的的IP地址 |
| | | * @param port 端口 |
| | | * @param msg 发送数据 |
| | | */ |
| | | public void sendMsg(String ipAddress,int port,byte[] msg) { |
| | | sendMsg(ipAddress,port, msg, true, null); |
| | | } |
| | | |
| | | /** |
| | | * 发送数据 |
| | | * @param ipAddress 目的IP地址 |
| | | * @param port 端口 |
| | | * @param msg 发送的数据 |
| | | * @param isRefreshRetry 是否要重发 |
| | | * @param listener 发送回调 |
| | | */ |
| | | public void sendMsg(String ipAddress,int port, 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); |
| | | } |
| | | LogUtils.i("发送目标IP和端口", ipAddress + ":" + port); |
| | | client.sendMsg(ipAddress, port, msg); |
| | | } catch (Exception e) { |
| | | LogUtils.i("发送失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 关闭当前socket |
| | | */ |
| | | public synchronized void close() { |
| | | isOpenRetry.set(false); |
| | | sendMap.clear(); |
| | | receiveThread.shutdown(); |
| | | receiveThread=null; |
| | | client.close(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.hdl.sdk.socket.udp; |
| | | |
| | | |
| | | 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 hxb on 2021/12/12. |
| | | */ |
| | | public class UdpSocketOptions { |
| | | |
| | | //处理数据 |
| | | private IHandleMessage handleMessage; |
| | | |
| | | public IHandleMessage getHandleMessage() { |
| | | return handleMessage; |
| | | } |
| | | |
| | | public void setHandleMessage(IHandleMessage handleMessage) { |
| | | this.handleMessage = handleMessage; |
| | | } |
| | | } |
| | |
| | | |
| | | //include ':app' |
| | | include ':hdl-socket' |
| | | //include ':hdl-socket' |
| | | include ':hdl-connect' |
| | | include ':hdl-common' |
| | | //include ':hdl-common' |
| | | include ':com.hdl.sdk' |
| | |
| | | implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6' |
| | | implementation 'com.google.code.gson:gson:2.8.8' |
| | | // implementation project(path: ':hdl-connect') |
| | | implementation files('libs\\com.hdl.sdk-v1.0.17.aar') |
| | | implementation files('libs\\com.hdl.sdk-v1.0.20.aar') |
| | | } |