diff --git a/gradle.properties b/gradle.properties
index 1ad6d6642..334992c02 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -26,5 +26,5 @@ android.enableJetifier=true
android.useAndroidX=true
android.useDeprecatedNdk=true
-versionCode=43
-versionName=4.11.3
\ No newline at end of file
+versionCode=45
+versionName=4.11.5
\ No newline at end of file
diff --git a/iFish7/src/main/AndroidManifest.xml b/iFish7/src/main/AndroidManifest.xml
index aa1aa03d5..2435574dd 100644
--- a/iFish7/src/main/AndroidManifest.xml
+++ b/iFish7/src/main/AndroidManifest.xml
@@ -194,6 +194,12 @@
android:exported="false"
android:launchMode="singleTop"
android:theme="@style/Transparent" />
+
+
adapterView, View view, int i, long l) {
+ BluetoothDevice bluetoothDevice = (BluetoothDevice) lvDevicesAdapter.getItem(i);
+ tvName.setText(bluetoothDevice.getName());
+ tvAddress.setText(bluetoothDevice.getAddress());
+ curBluetoothDevice = bluetoothDevice;
+ }
+ });
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.bt_search: //搜索蓝牙
+ Toast.makeText(BlueTooth2Activity.this,"",Toast.LENGTH_SHORT).show();
+ llDataSendReceive.setVisibility(View.GONE);
+ llDeviceList.setVisibility(View.VISIBLE);
+ searchBtDevice();
+ break;
+
+ case R.id.bt_connect: //连接蓝牙
+ if(!curConnState) {
+ startConnectDevice(curBluetoothDevice, MY_BLUETOOTH_UUID, 10000);
+ }else{
+ Toast.makeText(this, "当前设备已连接", Toast.LENGTH_SHORT).show();
+ }
+ break;
+
+ case R.id.bt_disconnect: //断开连接
+ if(curConnState) {
+ clearConnectedThread();
+ }else{
+ Toast.makeText(this, "当前设备未连接", Toast.LENGTH_SHORT).show();
+ }
+ break;
+
+ case R.id.bt_bound: //配对设备
+ if(!curBondState) {
+ boundDevice(curBluetoothDevice);
+ }else{
+ Toast.makeText(this, "当前设备已经与系统蓝牙建立配对", Toast.LENGTH_SHORT).show();
+ }
+ break;
+
+ case R.id.bt_disBound: //解除配对
+ if(curBondState) {
+ disBoundDevice(curBluetoothDevice);
+ }else{
+ Toast.makeText(this, "当前设备尚未与系统蓝牙建立配对", Toast.LENGTH_SHORT).show();
+ }
+ break;
+
+ case R.id.bt_to_send: //发送数据
+ if(curConnState){
+ String sendMsg = etSendMsg.getText().toString();
+ if(sendMsg.isEmpty()){
+ Toast.makeText(this, "发送数据为空!", Toast.LENGTH_SHORT).show();
+ return;
+ }
+ sendData(sendMsg,true); //以16进制字符串形式发送数据
+ }else{
+ Toast.makeText(this, "请先连接当前设备", Toast.LENGTH_SHORT).show();
+ }
+ break;
+ }
+ }
+
+
+ ////////////////////////////////// 搜索设备 /////////////////////////////////////////////////
+ @SuppressLint("MissingPermission")
+ private void searchBtDevice() {
+ if (bluetoothAdapter.isDiscovering()) { //当前正在搜索设备...
+ return;
+ }
+ //开始搜索
+ bluetoothAdapter.startDiscovery();
+ }
+
+ ////////////////////////////////// 配对/接触配对设备 ////////////////////////////////////////////
+ /**
+ * 执行绑定 反射
+ * @param bluetoothDevice 蓝牙设备
+ * @return true 执行绑定 false 未执行绑定
+ */
+ public boolean boundDevice(BluetoothDevice bluetoothDevice){
+ if(bluetoothDevice == null){
+ Log.e(TAG,"boundDevice-->bluetoothDevice == null");
+ return false;
+ }
+
+ try {
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && false) {
+ L.i(bluetoothDevice.getName()+"jjia--------1--------type="+bluetoothDevice.getType());
+ return bluetoothDevice.createBond();
+ }else {
+ L.i(bluetoothDevice.getName()+"jjia--------2--------type="+bluetoothDevice.getType());
+// return ClsUtils.createBond(BluetoothDevice.class,bluetoothDevice);
+ return ClsUtils.connn(bluetoothDevice,MY_BLUETOOTH_UUID);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return true;
+ }
+
+ /**
+ * 执行解绑 反射
+ * @param bluetoothDevice 蓝牙设备
+ * @return true 执行解绑 false未执行解绑
+ */
+ public boolean disBoundDevice(BluetoothDevice bluetoothDevice){
+ if(bluetoothDevice == null){
+ Log.e(TAG,"disBoundDevice-->bluetoothDevice == null");
+ return false;
+ }
+
+ try {
+ return ClsUtils.removeBond(BluetoothDevice.class,bluetoothDevice);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return true;
+ }
+
+ ////////////////////////////////// 连接设备 ///////////////////////////////////////////////
+ /**
+ * 开始连接设备
+ * @param bluetoothDevice 蓝牙设备
+ * @param uuid 发起连接的UUID
+ * @param conOutTime 连接超时时间
+ */
+ public void startConnectDevice(final BluetoothDevice bluetoothDevice, String uuid, long conOutTime){
+ if(bluetoothDevice == null){
+ Log.e(TAG,"startConnectDevice-->bluetoothDevice == null");
+ return;
+ }
+ if(bluetoothAdapter == null){
+ Log.e(TAG,"startConnectDevice-->bluetooth3Adapter == null");
+ return;
+ }
+ //发起连接
+ connectThread = new ConnectThread(bluetoothAdapter,curBluetoothDevice,uuid);
+ connectThread.setOnBluetoothConnectListener(new ConnectThread.OnBluetoothConnectListener() {
+ @SuppressLint("MissingPermission")
+ @Override
+ public void onStartConn() {
+ Log.d(TAG,"startConnectDevice-->开始连接..." + bluetoothDevice.getName() + "-->" + bluetoothDevice.getAddress());
+ }
+
+
+ @Override
+ public void onConnSuccess(BluetoothSocket bluetoothSocket) {
+ //移除连接超时
+ mHandler.removeCallbacks(connectOuttimeRunnable);
+ Log.d(TAG,"startConnectDevice-->移除连接超时");
+ Log.w(TAG,"startConnectDevice-->连接成功");
+
+ Message message = new Message();
+ message.what = CONNECT_SUCCESS;
+ mHandler.sendMessage(message);
+
+ //标记当前连接状态为true
+ curConnState = true;
+ //管理连接,收发数据
+ managerConnectSendReceiveData(bluetoothSocket);
+ }
+
+ @Override
+ public void onConnFailure(String errorMsg) {
+ Log.e(TAG,"startConnectDevice-->" + errorMsg);
+
+ Message message = new Message();
+ message.what = CONNECT_FAILURE;
+ mHandler.sendMessage(message);
+
+ //标记当前连接状态为false
+ curConnState = false;
+
+ //断开管理连接
+ clearConnectedThread();
+ }
+ });
+
+ connectThread.start();
+ //设置连接超时时间
+ mHandler.postDelayed(connectOuttimeRunnable,conOutTime);
+
+ }
+
+ //连接超时
+ private Runnable connectOuttimeRunnable = new Runnable() {
+ @Override
+ public void run() {
+ Log.e(TAG,"startConnectDevice-->连接超时" );
+
+ Message message = new Message();
+ message.what = CONNECT_FAILURE;
+ mHandler.sendMessage(message);
+
+ //标记当前连接状态为false
+ curConnState = false;
+ //断开管理连接
+ clearConnectedThread();
+ }
+ };
+
+ ////////////////////////////////////// 断开连接 //////////////////////////////////////////////
+ /**
+ * 断开已有的连接
+ */
+ public void clearConnectedThread(){
+ Log.d(TAG,"clearConnectedThread-->即将断开");
+
+ //connectedThread断开已有连接
+ if(connectedThread == null){
+ Log.e(TAG,"clearConnectedThread-->connectedThread == null");
+ return;
+ }
+ connectedThread.terminalClose(connectThread);
+
+ //等待线程运行完后再断开
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ connectedThread.cancel(); //释放连接
+
+ connectedThread = null;
+ }
+ },10);
+
+ Log.w(TAG,"clearConnectedThread-->成功断开连接");
+ Message message = new Message();
+ message.what = DISCONNECT_SUCCESS;
+ mHandler.sendMessage(message);
+
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /////////////////////////////////// 管理已有连接、收发数据 //////////////////////////////////
+
+ /**
+ * 管理已建立的连接,收发数据
+ * @param bluetoothSocket 已建立的连接
+ */
+ public void managerConnectSendReceiveData(BluetoothSocket bluetoothSocket){
+ //管理已有连接
+ connectedThread = new ConnectedThread(bluetoothSocket);
+ connectedThread.start();
+ connectedThread.setOnSendReceiveDataListener(new ConnectedThread.OnSendReceiveDataListener() {
+ @Override
+ public void onSendDataSuccess(byte[] data) {
+ Log.w(TAG,"发送数据成功,长度" + data.length + "->" + bytes2HexString(data,data.length));
+ Message message = new Message();
+ message.what = SEND_SUCCESS;
+ message.obj = "发送数据成功,长度" + data.length + "->" + bytes2HexString(data,data.length);
+ mHandler.sendMessage(message);
+ }
+
+ @Override
+ public void onSendDataError(byte[] data,String errorMsg) {
+ Log.e(TAG,"发送数据出错,长度" + data.length + "->" + bytes2HexString(data,data.length));
+ Message message = new Message();
+ message.what = SEND_FAILURE;
+ message.obj = "发送数据出错,长度" + data.length + "->" + bytes2HexString(data,data.length);
+ mHandler.sendMessage(message);
+ }
+
+ @Override
+ public void onReceiveDataSuccess(byte[] buffer) {
+ Log.w(TAG,"成功接收数据,长度" + buffer.length + "->" + bytes2HexString(buffer,buffer.length));
+ Message message = new Message();
+ message.what = RECEIVE_SUCCESS;
+ message.obj = "成功接收数据,长度" + buffer.length + "->" + bytes2HexString(buffer,buffer.length);
+ mHandler.sendMessage(message);
+ }
+
+ @Override
+ public void onReceiveDataError(String errorMsg) {
+ Log.e(TAG,"接收数据出错:" + errorMsg);
+ Message message = new Message();
+ message.what = RECEIVE_FAILURE;
+ message.obj = "接收数据出错:" + errorMsg;
+ mHandler.sendMessage(message);
+ }
+ });
+ }
+
+ ///////////////////////////////// 发送数据 /////////////////////////////////////////////////
+
+ /**
+ * 发送数据
+ * @param data 要发送的数据 字符串
+ * @param isHex 是否是16进制字符串
+ * @return true 发送成功 false 发送失败
+ */
+ public boolean sendData(String data,boolean isHex){
+ if(connectedThread == null){
+ Log.e(TAG,"sendData:string -->connectedThread == null");
+ return false;
+ }
+ if(data == null || data.length() == 0){
+ Log.e(TAG,"sendData:string-->要发送的数据为空");
+ return false;
+ }
+
+ if(isHex){ //是16进制字符串
+ data.replace(" ",""); //取消空格
+ //检查16进制数据是否合法
+ if(data.length() % 2 != 0){
+ //不合法,最后一位自动填充0
+ String lasts = "0" + data.charAt(data.length() - 1);
+ data = data.substring(0,data.length() - 2) + lasts;
+ }
+ Log.d(TAG,"sendData:string -->准备写入:" + data); //加空格显示
+ return connectedThread.write(hexString2Bytes(data));
+ }
+
+ //普通字符串
+ Log.d(TAG,"sendData:string -->准备写入:" + data);
+ return connectedThread.write(data.getBytes());
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+
+ /////////////////////////////// 数据类型转换 //////////////////////////////////////////////
+ /**
+ * 字节数组-->16进制字符串
+ * @param b 字节数组
+ * @param length 字节数组长度
+ * @return 16进制字符串 有空格类似“0A D5 CD 8F BD E5 F8”
+ */
+ public static String bytes2HexString(byte[] b, int length) {
+ StringBuffer result = new StringBuffer();
+ String hex;
+ for (int i = 0; i < length; i++) {
+ hex = Integer.toHexString(b[i] & 0xFF);
+ if (hex.length() == 1) {
+ hex = '0' + hex;
+ }
+ result.append(hex.toUpperCase()).append(" ");
+ }
+ return result.toString();
+ }
+
+ /**
+ * hexString2Bytes
+ * 16进制字符串-->字节数组
+ * @param src 16进制字符串
+ * @return 字节数组
+ */
+ public static byte[] hexString2Bytes(String src) {
+ int l = src.length() / 2;
+ byte[] ret = new byte[l];
+ for (int i = 0; i < l; i++) {
+ ret[i] = (byte) Integer
+ .valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();
+ }
+ return ret;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 初始化蓝牙
+ */
+ @SuppressLint("MissingPermission")
+ private void initBluetooth() {
+ bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ if (bluetoothAdapter == null) {
+ Toast.makeText(this, "当前手机设备不支持蓝牙", Toast.LENGTH_SHORT).show();
+ } else {
+ //手机设备支持蓝牙,判断蓝牙是否已开启
+ if (bluetoothAdapter.isEnabled()) {
+ Toast.makeText(this, "手机蓝牙已开启", Toast.LENGTH_SHORT).show();
+ } else {
+ //蓝牙没有打开,去打开蓝牙。推荐使用第二种打开蓝牙方式
+ //第一种方式:直接打开手机蓝牙,没有任何提示
+// bluetoothAdapter.enable(); //BLUETOOTH_ADMIN权限
+ //第二种方式:友好提示用户打开蓝牙
+ Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ startActivity(enableBtIntent);
+ }
+ }
+ }
+
+ /**
+ * 初始化蓝牙广播
+ */
+ private void initBtBroadcast() {
+ //注册广播接收
+ btBroadcastReceiver = new BtBroadcastReceiver();
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); //开始扫描
+ intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//扫描结束
+ intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//搜索到设备
+ intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); //配对状态监听
+ registerReceiver(btBroadcastReceiver,intentFilter);
+
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ //注销广播接收
+ unregisterReceiver(btBroadcastReceiver);
+ }
+
+ /**
+ * 蓝牙广播接收器
+ */
+ private class BtBroadcastReceiver extends BroadcastReceiver {
+
+ @SuppressLint("MissingPermission")
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (TextUtils.equals(action, BluetoothAdapter.ACTION_DISCOVERY_STARTED)) { //开启搜索
+ Log.d(TAG,"开启搜索...");
+ Message message = new Message();
+ message.what = START_DISCOVERY;
+ mHandler.sendMessage(message);
+
+ } else if (TextUtils.equals(action, BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {//完成搜素
+ Log.d(TAG,"停止搜索...");
+ Message message = new Message();
+ message.what = STOP_DISCOVERY;
+ mHandler.sendMessage(message);
+
+ } else if (TextUtils.equals(action, BluetoothDevice.ACTION_FOUND)) { //3.0搜索到设备
+ //蓝牙设备
+ BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ //信号强度
+ int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
+
+ Log.w(TAG, "扫描到设备:" + bluetoothDevice.getName() + "-->" + bluetoothDevice.getAddress());
+ Message message = new Message();
+ message.what = DISCOVERY_DEVICE;
+ message.obj = bluetoothDevice;
+ mHandler.sendMessage(message);
+
+ }else if(TextUtils.equals(action,BluetoothDevice.ACTION_BOND_STATE_CHANGED)){
+ BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ int bondSate = bluetoothDevice.getBondState();
+ L.i(bluetoothDevice.getName()+"jjia----------------bondSate="+bondSate);
+ switch(bondSate) {
+ case BluetoothDevice.BOND_NONE:
+ Log.d(TAG, "已解除配对");
+ Message message1 = new Message();
+ message1.what = DEVICE_BOND_NONE;
+ mHandler.sendMessage(message1);
+ break;
+
+ case BluetoothDevice.BOND_BONDING:
+ Log.d(TAG, "正在配对...");
+ Message message2 = new Message();
+ message2.what = DEVICE_BONDING;
+ mHandler.sendMessage(message2);
+ break;
+
+ case BluetoothDevice.BOND_BONDED:
+ Log.d(TAG, "已配对");
+ Message message3 = new Message();
+ message3.what = DEVICE_BONDED;
+ mHandler.sendMessage(message3);
+ break;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/iFish7/src/main/java/com/ifish/activity/BluetoothActivity.java b/iFish7/src/main/java/com/ifish/activity/BluetoothActivity.java
index c6095d426..2678bf4bc 100644
--- a/iFish7/src/main/java/com/ifish/activity/BluetoothActivity.java
+++ b/iFish7/src/main/java/com/ifish/activity/BluetoothActivity.java
@@ -18,6 +18,7 @@ import android.widget.TextView;
import com.ifish.adapter.BlueToothController;
import com.ifish.baseclass.BaseActivity;
+import com.ifish.bluetooth.ClsUtils;
import com.ifish.utils.BlueToothUtil;
import com.ifish.utils.L;
import com.ifish.utils.ToastUtil;
@@ -26,7 +27,7 @@ import com.ifish.utils.ToastUtil;
public class BluetoothActivity extends BaseActivity {
BlueToothController blueToothController = new BlueToothController();
-
+ public static final String MY_BLUETOOTH_UUID = "00001101-0000-1000-8000-00805F9B34FB"; //蓝牙通讯
IntentFilter foundFilter = null;
TextView name ;
Button tv_pair;
@@ -50,7 +51,14 @@ public class BluetoothActivity extends BaseActivity {
@Override
public void onClick(View view) {
if (bluetoothDevice!=null){
- BlueToothUtil.Companion.boundDevice(bluetoothDevice);
+ try {
+
+ L.i("jjia---------getBondState----"+bluetoothDevice.getBondState());
+ ClsUtils.createBond1( bluetoothDevice);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+// BlueToothUtil.Companion.boundDevice(bluetoothDevice,MY_BLUETOOTH_UUID);
}
}
});
@@ -75,7 +83,7 @@ public class BluetoothActivity extends BaseActivity {
if (!TextUtils.isEmpty(deviceName) &&
(
// deviceName.contains("ifishly") ||
- deviceName.equals("ifishly-fee0")
+ deviceName.startsWith("ifishly")
// deviceName.contains("LE-Bose")
)
diff --git a/iFish7/src/main/java/com/ifish/activity/FeedFishSettingActivity.java b/iFish7/src/main/java/com/ifish/activity/FeedFishSettingActivity.java
index b5655369b..5644a6ce6 100644
--- a/iFish7/src/main/java/com/ifish/activity/FeedFishSettingActivity.java
+++ b/iFish7/src/main/java/com/ifish/activity/FeedFishSettingActivity.java
@@ -416,22 +416,22 @@ public class FeedFishSettingActivity extends BaseActivity {
}else if(v == add_rel_setting){ //添加关联设备
showTimeSelected();
}else if(v == rl_xunhuan_bang){ //循环泵
- showOpenOrCloseDialog(4,R.drawable.xunhuanbang,"循环泵",event.isLight_status1());
+ showOpenOrCloseDialog(4,R.drawable.xunhuanbang,"循环泵",event.isLight_status4());
}else if(v == rl_zengyang_bang){ //增氧泵
String type = Commons.DEVICE.get(Commons.DevicePosition).type;
if(Device.TYPE_5F.equals(type)){ //海水
- showOpenOrCloseDialog(1,R.drawable.addobang,"蛋分器",event.isLight_status2());
+ showOpenOrCloseDialog(1,R.drawable.addobang,"蛋分器",event.isLight_status1());
}else{ //淡水
- showOpenOrCloseDialog(1,R.drawable.addobang,"增氧泵",event.isLight_status2());
+ showOpenOrCloseDialog(1,R.drawable.addobang,"增氧泵",event.isLight_status1());
}
}else if(v == rl_light1){ //灯光1
- showOpenOrCloseDialog(2,R.drawable.linght1,"灯光1",event.isLight_status3());
+ showOpenOrCloseDialog(2,R.drawable.linght1,"灯光1",event.isLight_status2());
}else if(v == rl_light2){ //灯光2
- showOpenOrCloseDialog(3,R.drawable.linght2,"灯光2",event.isLight_status4());
+ showOpenOrCloseDialog(3,R.drawable.linght2,"灯光2",event.isLight_status3());
}else if(v == rl_zaolangbang){ //造浪泵
- showOpenOrCloseDialog(6,R.drawable.zaolangbang,"造浪泵",event.isLight_status5());
+ showOpenOrCloseDialog(6,R.drawable.zaolangbang,"造浪泵",event.isLight_status6());
}else if(v == rl_shajun_light){ //杀菌灯
- showOpenOrCloseDialog(5,R.drawable.shajundeng,"杀菌灯",event.isLight_status6());
+ showOpenOrCloseDialog(5,R.drawable.shajundeng,"杀菌灯",event.isLight_status5());
}
}
diff --git a/iFish7/src/main/java/com/ifish/adapter/BlueToothController.java b/iFish7/src/main/java/com/ifish/adapter/BlueToothController.java
index fd0230816..8a75141fa 100644
--- a/iFish7/src/main/java/com/ifish/adapter/BlueToothController.java
+++ b/iFish7/src/main/java/com/ifish/adapter/BlueToothController.java
@@ -28,13 +28,10 @@ public class BlueToothController {
}
+ @SuppressLint("MissingPermission")
public void open(Activity activity) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
- if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
-
- ToastUtil.show(activity,"请");
- return;
- }
+// Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
activity.startActivityForResult(intent, 11);
}
diff --git a/iFish7/src/main/java/com/ifish/bluetooth/ClsUtils.java b/iFish7/src/main/java/com/ifish/bluetooth/ClsUtils.java
new file mode 100644
index 000000000..c1136e45e
--- /dev/null
+++ b/iFish7/src/main/java/com/ifish/bluetooth/ClsUtils.java
@@ -0,0 +1,197 @@
+package com.ifish.bluetooth;
+
+import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothSocket;
+import android.util.Log;
+
+import com.ifish.utils.L;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.UUID;
+
+public class ClsUtils {
+
+ public static BluetoothDevice remoteDevice = null;
+
+ /**
+ * 与设备配对 参考源码:platform/packages/apps/Settings.git
+ * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
+ */
+ @SuppressLint("MissingPermission")
+ static public boolean connn(BluetoothDevice btDevice,String uuid){
+ try {
+ BluetoothSocket socket = btDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(uuid));
+ socket.connect();
+
+ return true;
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+
+ }
+
+ static public boolean createBond1(BluetoothDevice btDevice)
+ throws Exception {
+ Method createBondMethod = btDevice.getClass().getMethod("createBond");
+ Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
+ return returnValue.booleanValue();
+ }
+
+
+ @SuppressWarnings("unchecked")
+ static public boolean createBond(@SuppressWarnings("rawtypes") Class btClass, BluetoothDevice btDevice)
+ throws Exception {
+ Method createBondMethod = btClass.getMethod("createBond");
+ Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
+ return returnValue.booleanValue();
+ }
+
+ //自动配对设置Pin值
+ static public boolean autoBond(Class btClass,BluetoothDevice device,String strPin) throws Exception {
+ Method autoBondMethod = btClass.getMethod("setPin",new Class[]{byte[].class});
+ Boolean result = (Boolean)autoBondMethod.invoke(device,new Object[]{strPin.getBytes()});
+ return result;
+ }
+
+ static public void setPairingConfirmation(BluetoothDevice device){
+ try {
+ Field field = device.getClass().getDeclaredField("sService");
+ field.setAccessible(true);
+
+ Object service = field.get(device);
+ Method method = service.getClass().getDeclaredMethod("setPairingConfirmation",
+ BluetoothDevice.class, boolean.class);
+ method.setAccessible(true);
+ method.invoke(service, device, true);
+
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * 与设备解除配对 参考源码:platform/packages/apps/Settings.git
+ * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
+ */
+ @SuppressWarnings("unchecked")
+ static public boolean removeBond(Class btClass, BluetoothDevice btDevice)
+ throws Exception {
+ Method removeBondMethod = btClass.getMethod("removeBond");
+ Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
+ return returnValue.booleanValue();
+ }
+
+ @SuppressWarnings("unchecked")
+ static public boolean setPin(Class btClass, BluetoothDevice btDevice,
+ String str) throws Exception {
+ try {
+ Method removeBondMethod = btClass.getDeclaredMethod("setPin",
+ new Class[]
+ {byte[].class});
+ Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice,
+ new Object[]
+ {str.getBytes()});
+ } catch (SecurityException e) {
+ // throw new RuntimeException(e.getMessage());
+ e.printStackTrace();
+ } catch (IllegalArgumentException e) {
+ // throw new RuntimeException(e.getMessage());
+ e.printStackTrace();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return true;
+
+ }
+
+ // 取消用户输入
+ //cancelPairingUserInput()取消用户输入密钥框,
+ // 个人觉得一般情况下不要和
+ // setPin(setPasskey、setPairingConfirmation、 setRemoteOutOfBandData)一起用,
+ // 这几个方法都会remove掉map里面的key:value(也就是互斥的 )
+ @SuppressWarnings("unchecked")
+ static public boolean cancelPairingUserInput(Class btClass,
+ BluetoothDevice device)
+
+ throws Exception {
+ Method createBondMethod = btClass.getMethod("cancelPairingUserInput");
+ // cancelBondProcess()
+ Boolean returnValue = (Boolean) createBondMethod.invoke(device);
+
+ return returnValue.booleanValue();
+ }
+
+ // 取消配对
+ @SuppressWarnings("unchecked")
+ static public boolean cancelBondProcess(Class btClass,
+ BluetoothDevice device)
+ throws Exception {
+ Method createBondMethod = btClass.getMethod("cancelBondProcess");
+ Boolean returnValue = (Boolean) createBondMethod.invoke(device);
+ return returnValue.booleanValue();
+ }
+
+ /**
+ * @param clsShow
+ */
+ @SuppressWarnings("unchecked")
+ static public void printAllInform(Class clsShow) {
+ try {
+ // 取得所有方法
+ Method[] hideMethod = clsShow.getMethods();
+ int i = 0;
+ for (; i < hideMethod.length; i++) {
+ //Log.e("method name", hideMethod.getName() + ";and the i is:"
+ // + i);
+ }
+ // 取得所有常量
+ Field[] allFields = clsShow.getFields();
+ for (i = 0; i < allFields.length; i++) {
+ //Log.e("Field name", allFields.getName());
+ }
+ } catch (SecurityException e) {
+ // throw new RuntimeException(e.getMessage());
+ e.printStackTrace();
+ } catch (IllegalArgumentException e) {
+ // throw new RuntimeException(e.getMessage());
+ e.printStackTrace();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Clears the internal cache and forces a refresh of the services from the * remote device.
+ */
+ public static boolean refreshDeviceCache(BluetoothGatt mBluetoothGatt) {
+ if (mBluetoothGatt != null) {
+ try {
+ BluetoothGatt localBluetoothGatt = mBluetoothGatt;
+ Method localMethod = localBluetoothGatt.getClass().getMethod("refresh", new Class[0]);
+ if (localMethod != null) {
+ boolean bool = ((Boolean) localMethod.invoke(localBluetoothGatt, new Object[0])).booleanValue();
+ return bool;
+ }
+ } catch (Exception localException) {
+ Log.i("Config", "An exception occured while refreshing device");
+ }
+ }
+ return false;
+ }
+}
diff --git a/iFish7/src/main/java/com/ifish/bluetooth/ConnectThread.java b/iFish7/src/main/java/com/ifish/bluetooth/ConnectThread.java
new file mode 100644
index 000000000..62eba2b5a
--- /dev/null
+++ b/iFish7/src/main/java/com/ifish/bluetooth/ConnectThread.java
@@ -0,0 +1,136 @@
+package com.ifish.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSocket;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.UUID;
+
+
+/**
+ * 发起蓝牙连接
+ */
+public class ConnectThread extends Thread {
+ private static final String TAG = "ConnectThread";
+ private final BluetoothAdapter mBluetoothAdapter;
+ private BluetoothSocket mmSocket;
+ private final BluetoothDevice mmDevice;
+
+ public ConnectThread(BluetoothAdapter bluetoothAdapter,BluetoothDevice bluetoothDevice,String uuid) {
+ this.mBluetoothAdapter = bluetoothAdapter;
+ this.mmDevice = bluetoothDevice;
+
+ //使用一个临时变量,等会赋值给mmSocket
+ //因为mmSocket是静态的
+ BluetoothSocket tmp = null ;
+
+ if(mmSocket != null){
+ Log.e(TAG,"ConnectThread-->mmSocket != null先去释放");
+ try {
+ mmSocket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ Log.d(TAG,"ConnectThread-->mmSocket != null已释放");
+
+ //1、获取BluetoothSocket
+ try {
+ //建立安全的蓝牙连接,会弹出配对框
+ tmp = mmDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
+
+ } catch (IOException e) {
+ Log.e(TAG,"ConnectThread-->获取BluetoothSocket异常!" + e.getMessage());
+ }
+
+ mmSocket = tmp;
+ if(mmSocket != null){
+ Log.w(TAG,"ConnectThread-->已获取BluetoothSocket");
+ }
+
+ }
+
+ @Override
+ public void run(){
+
+ //连接之前先取消发现设备,否则会大幅降低连接尝试的速度,并增加连接失败的可能性
+ if(mBluetoothAdapter == null){
+ Log.e(TAG,"ConnectThread:run-->mBluetoothAdapter == null");
+ return;
+ }
+ //取消发现设备
+ if(mBluetoothAdapter.isDiscovering()){
+ mBluetoothAdapter.cancelDiscovery();
+ }
+
+ if(mmSocket == null){
+ Log.e(TAG,"ConnectThread:run-->mmSocket == null");
+ return;
+ }
+
+ //2、通过socket去连接设备
+ try {
+ Log.d(TAG,"ConnectThread:run-->去连接...");
+ if(onBluetoothConnectListener != null){
+ onBluetoothConnectListener.onStartConn(); //开始去连接回调
+ }
+ mmSocket.connect(); //connect()为阻塞调用,连接失败或 connect() 方法超时(大约 12 秒之后),它将会引发异常
+
+ if(onBluetoothConnectListener != null){
+ onBluetoothConnectListener.onConnSuccess(mmSocket); //连接成功回调
+ Log.w(TAG,"ConnectThread:run-->连接成功");
+ }
+
+ } catch (IOException e) {
+ Log.e(TAG,"ConnectThread:run-->连接异常!" + e.getMessage());
+
+ if(onBluetoothConnectListener != null){
+ onBluetoothConnectListener.onConnFailure("连接异常:" + e.getMessage());
+ }
+
+ //释放
+ cancel();
+ }
+
+ }
+
+ /**
+ * 释放
+ */
+ public void cancel() {
+ try {
+ if (mmSocket != null && mmSocket.isConnected()) {
+ Log.d(TAG,"ConnectThread:cancel-->mmSocket.isConnected() = " + mmSocket.isConnected());
+ mmSocket.close();
+ mmSocket = null;
+ return;
+ }
+
+ if (mmSocket != null) {
+ mmSocket.close();
+ mmSocket = null;
+ }
+
+ Log.d(TAG,"ConnectThread:cancel-->关闭已连接的套接字释放资源");
+
+ } catch (IOException e) {
+ Log.e(TAG,"ConnectThread:cancel-->关闭已连接的套接字释放资源异常!" + e.getMessage());
+ }
+ }
+
+ private OnBluetoothConnectListener onBluetoothConnectListener;
+
+ public void setOnBluetoothConnectListener(OnBluetoothConnectListener onBluetoothConnectListener) {
+ this.onBluetoothConnectListener = onBluetoothConnectListener;
+ }
+
+ //连接状态监听者
+ public interface OnBluetoothConnectListener{
+ void onStartConn(); //开始连接
+ void onConnSuccess(BluetoothSocket bluetoothSocket); //连接成功
+ void onConnFailure(String errorMsg); //连接失败
+ }
+
+}
diff --git a/iFish7/src/main/java/com/ifish/bluetooth/ConnectedThread.java b/iFish7/src/main/java/com/ifish/bluetooth/ConnectedThread.java
new file mode 100644
index 000000000..61d288900
--- /dev/null
+++ b/iFish7/src/main/java/com/ifish/bluetooth/ConnectedThread.java
@@ -0,0 +1,206 @@
+package com.ifish.bluetooth;
+
+import android.bluetooth.BluetoothSocket;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+
+/**
+ * 管理连接
+ * 1、发送数据
+ * 2、接收数据
+ */
+public class ConnectedThread extends Thread{
+ private static final String TAG = "ConnectedThread";
+ private BluetoothSocket mmSocket;
+ private InputStream mmInStream;
+ private OutputStream mmOutStream;
+ //是否是主动断开
+ private boolean isStop = false;
+ //发起蓝牙连接的线程
+ private ConnectThread connectThread;
+
+ public void terminalClose(ConnectThread connectThread){
+ isStop = true;
+ this.connectThread = connectThread;
+ }
+
+ public ConnectedThread(BluetoothSocket socket){
+ mmSocket = socket;
+
+ InputStream tmpIn = null;
+ OutputStream tmpOut = null;
+
+ //使用临时对象获取输入和输出流,因为成员流是静态类型
+
+ //1、获取 InputStream 和 OutputStream
+ try {
+ tmpIn = socket.getInputStream();
+ tmpOut = socket.getOutputStream();
+
+ } catch (IOException e) {
+ Log.e(TAG,"ConnectedThread-->获取InputStream 和 OutputStream异常!");
+ }
+
+ mmInStream = tmpIn;
+ mmOutStream = tmpOut;
+
+ if(mmInStream != null){
+ Log.d(TAG,"ConnectedThread-->已获取InputStream");
+ }
+
+ if(mmOutStream != null){
+ Log.d(TAG,"ConnectedThread-->已获取OutputStream");
+ }
+
+ }
+
+ public void run(){
+ //最大缓存区 存放流
+ byte[] buffer = new byte[1024 * 2]; //buffer store for the stream
+ //从流的read()方法中读取的字节数
+ int bytes = 0; //bytes returned from read()
+
+ //持续监听输入流直到发生异常
+ while(!isStop){
+ try {
+
+ if(mmInStream == null){
+ Log.e(TAG,"ConnectedThread:run-->输入流mmInStream == null");
+ break;
+ }
+ //先判断是否有数据,有数据再读取
+ if(mmInStream.available() != 0){
+ //2、接收数据
+ bytes = mmInStream.read(buffer); //从(mmInStream)输入流中(读取内容)读取的一定数量字节数,并将它们存储到缓冲区buffer数组中,bytes为实际读取的字节数
+ byte[] b = Arrays.copyOf(buffer,bytes); //存放实际读取的数据内容
+ Log.w(TAG,"ConnectedThread:run-->收到消息,长度" + b.length + "->" + bytes2HexString(b, b.length)); //有空格的16进制字符串
+ if(onSendReceiveDataListener != null){
+ onSendReceiveDataListener.onReceiveDataSuccess(b); //成功收到消息
+ }
+ }
+
+ } catch (IOException e) {
+ Log.e(TAG,"ConnectedThread:run-->接收消息异常!" + e.getMessage());
+ if(onSendReceiveDataListener != null){
+ onSendReceiveDataListener.onReceiveDataError("接收消息异常:" + e.getMessage()); //接收消息异常
+ }
+ //关闭流和socket
+ boolean isClose = cancel();
+ if(isClose){
+ Log.e(TAG,"ConnectedThread:run-->接收消息异常,成功断开连接!");
+ }
+ break;
+ }
+ }
+ //关闭流和socket
+ boolean isClose = cancel();
+ if(isClose){
+ Log.d(TAG,"ConnectedThread:run-->接收消息结束,断开连接!");
+ }
+ }
+
+ //发送数据
+ public boolean write(byte[] bytes){
+ try {
+
+ if(mmOutStream == null){
+ Log.e(TAG, "mmOutStream == null");
+ return false;
+ }
+
+ //发送数据
+ mmOutStream.write(bytes);
+ Log.d(TAG, "写入成功:"+ bytes2HexString(bytes, bytes.length));
+ if(onSendReceiveDataListener != null){
+ onSendReceiveDataListener.onSendDataSuccess(bytes); //发送数据成功回调
+ }
+ return true;
+
+ } catch (IOException e) {
+ Log.e(TAG, "写入失败:"+ bytes2HexString(bytes, bytes.length));
+ if(onSendReceiveDataListener != null){
+ onSendReceiveDataListener.onSendDataError(bytes,"写入失败"); //发送数据失败回调
+ }
+ return false;
+ }
+ }
+
+ /**
+ * 释放
+ * @return true 断开成功 false 断开失败
+ */
+ public boolean cancel(){
+ try {
+ if(mmInStream != null){
+ mmInStream.close(); //关闭输入流
+ }
+ if(mmOutStream != null){
+ mmOutStream.close(); //关闭输出流
+ }
+ if(mmSocket != null){
+ mmSocket.close(); //关闭socket
+ }
+ if(connectThread != null){
+ connectThread.cancel();
+ }
+
+ connectThread = null;
+ mmInStream = null;
+ mmOutStream = null;
+ mmSocket = null;
+
+ Log.w(TAG,"ConnectedThread:cancel-->成功断开连接");
+ return true;
+
+ } catch (IOException e) {
+ // 任何一部分报错,都将强制关闭socket连接
+ mmInStream = null;
+ mmOutStream = null;
+ mmSocket = null;
+
+ Log.e(TAG, "ConnectedThread:cancel-->断开连接异常!" + e.getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * 字节数组-->16进制字符串
+ * @param b 字节数组
+ * @param length 字节数组长度
+ * @return 16进制字符串 有空格类似“0A D5 CD 8F BD E5 F8”
+ */
+ public static String bytes2HexString(byte[] b, int length) {
+ StringBuffer result = new StringBuffer();
+ String hex;
+ for (int i = 0; i < length; i++) {
+ hex = Integer.toHexString(b[i] & 0xFF);
+ if (hex.length() == 1) {
+ hex = '0' + hex;
+ }
+ result.append(hex.toUpperCase()).append(" ");
+ }
+ return result.toString();
+ }
+
+ private OnSendReceiveDataListener onSendReceiveDataListener;
+
+ public void setOnSendReceiveDataListener(OnSendReceiveDataListener onSendReceiveDataListener) {
+ this.onSendReceiveDataListener = onSendReceiveDataListener;
+ }
+
+ //收发数据监听者
+ public interface OnSendReceiveDataListener{
+ void onSendDataSuccess(byte[] data); //发送数据结束
+ void onSendDataError(byte[] data, String errorMsg); //发送数据出错
+ void onReceiveDataSuccess(byte[] buffer); //接收到数据
+ void onReceiveDataError(String errorMsg); //接收数据出错
+ }
+
+
+
+}
diff --git a/iFish7/src/main/java/com/ifish/bluetooth/LVDevicesAdapter.java b/iFish7/src/main/java/com/ifish/bluetooth/LVDevicesAdapter.java
new file mode 100644
index 000000000..d5e55712b
--- /dev/null
+++ b/iFish7/src/main/java/com/ifish/bluetooth/LVDevicesAdapter.java
@@ -0,0 +1,115 @@
+package com.ifish.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import com.ifish.activity.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 搜索到的设备列表适配器
+ */
+public class LVDevicesAdapter extends BaseAdapter {
+
+ private Context context;
+ private List list;
+
+ public LVDevicesAdapter(Context context) {
+ this.context = context;
+ list = new ArrayList<>();
+ }
+
+ @Override
+ public int getCount() {
+ return list == null ? 0 : list.size();
+ }
+
+ @Override
+ public Object getItem(int i) {
+ if(list == null){
+ return null;
+ }
+ return list.get(i);
+ }
+
+ @Override
+ public long getItemId(int i) {
+ return i;
+ }
+
+ @Override
+ public View getView(int i, View view, ViewGroup viewGroup) {
+ DeviceViewHolder viewHolder;
+ if(view == null){
+ view = LayoutInflater.from(context).inflate(R.layout.layout_lv_devices_item,null);
+ viewHolder = new DeviceViewHolder();
+ viewHolder.tvDeviceName = view.findViewById(R.id.tv_device_name);
+ viewHolder.tvDeviceAddress = view.findViewById(R.id.tv_device_address);
+ view.setTag(viewHolder);
+ }else{
+ viewHolder = (DeviceViewHolder) view.getTag();
+ }
+
+ if(list.get(i).getName() == null){
+ viewHolder.tvDeviceName.setText("NULL");
+ }else{
+ viewHolder.tvDeviceName.setText(list.get(i).getName());
+ }
+
+ viewHolder.tvDeviceAddress.setText(list.get(i).getAddress());
+
+ return view;
+ }
+
+ /**
+ * 初始化所有设备列表
+ * @param bluetoothDevices
+ */
+ public void addAllDevice(List bluetoothDevices){
+ if(list != null){
+ list.clear();
+ }
+ for (BluetoothDevice bluetoothDevice : bluetoothDevices) {
+ list.add(bluetoothDevice);
+ }
+ notifyDataSetChanged();
+ }
+
+ /**
+ * 添加列表子项
+ * @param bluetoothDevice
+ */
+ public void addDevice(BluetoothDevice bluetoothDevice){
+ if(list == null){
+ return;
+ }
+ if(!list.contains(bluetoothDevice)){
+ list.add(bluetoothDevice);
+ }
+ notifyDataSetChanged(); //刷新
+ }
+
+ /**
+ * 清空列表
+ */
+ public void clear(){
+ if(list != null){
+ list.clear();
+ }
+ notifyDataSetChanged(); //刷新
+ }
+
+ class DeviceViewHolder {
+
+ TextView tvDeviceName;
+ TextView tvDeviceAddress;
+ }
+
+}
diff --git a/iFish7/src/main/java/com/ifish/utils/BlueToothUtil.kt b/iFish7/src/main/java/com/ifish/utils/BlueToothUtil.kt
index 9dfb01b0c..86503c099 100644
--- a/iFish7/src/main/java/com/ifish/utils/BlueToothUtil.kt
+++ b/iFish7/src/main/java/com/ifish/utils/BlueToothUtil.kt
@@ -8,10 +8,10 @@ class BlueToothUtil {
companion object{
@SuppressLint("MissingPermission")
- fun boundDevice(devicex: BluetoothDevice?){
+ fun boundDevice(devicex: BluetoothDevice?,ii:String){
var method = BluetoothDevice::class.java.getMethod("createBond")
method.invoke(devicex)
- var clientSocket = devicex!!.createRfcommSocketToServiceRecord(UUID.fromString(devicex.address))
+ var clientSocket = devicex!!.createRfcommSocketToServiceRecord(UUID.fromString(ii))
clientSocket.connect()
}
diff --git a/iFish7/src/main/res/layout/bindtwodevice_activity.xml b/iFish7/src/main/res/layout/bindtwodevice_activity.xml
index a73df12aa..f48393a63 100644
--- a/iFish7/src/main/res/layout/bindtwodevice_activity.xml
+++ b/iFish7/src/main/res/layout/bindtwodevice_activity.xml
@@ -57,6 +57,16 @@
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/device_petdevice"
+ android:visibility="gone"
+ android:scaleType="fitXY" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/iFish7/src/main/res/layout/layout_lv_devices_item.xml b/iFish7/src/main/res/layout/layout_lv_devices_item.xml
new file mode 100644
index 000000000..dbced3c3d
--- /dev/null
+++ b/iFish7/src/main/res/layout/layout_lv_devices_item.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
\ No newline at end of file