package com.shlb.comb.activity; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; import android.text.InputType; import android.util.Log; import android.view.View; import android.view.ViewGroup; import com.blakequ.bluetooth_manager_lib.connect.BluetoothConnectManager; import com.blakequ.bluetooth_manager_lib.connect.BluetoothSubScribeData; import com.blakequ.bluetooth_manager_lib.connect.ConnectState; import com.blakequ.bluetooth_manager_lib.connect.ConnectStateListener; import com.blakequ.bluetooth_manager_lib.device.BluetoothLeDevice; import com.blakequ.bluetooth_manager_lib.util.BluetoothUtils; import com.blakequ.bluetooth_manager_lib.util.ByteUtils; import com.blankj.utilcode.util.LogUtils; import com.blankj.utilcode.util.ThreadUtils; import com.qmuiteam.qmui.util.QMUIDisplayHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUIDialogAction; import com.qmuiteam.qmui.widget.grouplist.QMUICommonListItemView; import com.qmuiteam.qmui.widget.grouplist.QMUIGroupListView; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; import com.shlb.comb.R; import com.shlb.comb.base.BaseActivity; import com.shlb.comb.event.UpdateEvent; import com.shlb.comb.util.CMD; import com.shlb.comb.util.CRCutil; import com.shlb.comb.util.Singletion; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; public class WriteActivity2 extends BaseActivity { QMUIGroupListView mGroupListView; QMUIRoundButton send; private BluetoothConnectManager connectManager; private BluetoothGatt gatt; private BluetoothGattCharacteristic characteristic; @Override protected void contentView() { setContentView(R.layout.activity_write); } @Override protected void initView() { super.initHead(); mGroupListView = findViewById(R.id.groupListView); send = findViewById(R.id.send); initTitlebar(); tv_center.setText("编址"); initGroupListView(); } @Override protected void initData() { String uuid = Singletion.getInstance().uuid; initWrite(uuid); } @Override protected void initEvent() { send.setOnClickListener(this); } @Override public void onClick(View v) { int id = v.getId(); if (id == R.id.iv_left) { finish(); } else if (id == R.id.iv_right) { } else if (id == R.id.send) { switch (curCmd){ case -1: Toast("请选择指令!"); break; case 1: //进入编址 writeCmd(CMD.GETINTO); break; case 2: //清除地址 writeCmd(CMD.CLEAN); break; case 3: String addrNos = item3.getDetailText().toString(); Integer addrNo = -1; try { addrNo = Integer.parseInt(addrNos); }catch (Exception e){ e.printStackTrace(); } if(addrNo == -1 ){ Toast("地址数据异常"); return; } String sNo = Integer.toHexString(addrNo); if(sNo.length()<2){ sNo = "0" + sNo; } String cmd = CMD.ADDR_PREFIX + sNo + CMD.ADDR_SUFFIX; byte[] bytes = invertStringToBytes(cmd); String crc = CRCutil.getCRC(bytes); String zl = cmd + crc; LogUtils.e("reszl", zl); writeCmd(zl); Toast("编址指令已发送!"); break; case 4: //退出编址 writeCmd(CMD.EXIT); break; case 5: String addrNos2 = item5.getDetailText().toString(); Integer addrNo2 = -1; try { addrNo2 = Integer.parseInt(addrNos2); }catch (Exception e){ e.printStackTrace(); } final Integer no2 = addrNo2; if(no2 == -1 ){ Toast("地址数据异常"); return; } ThreadUtils.executeBySingle(new ThreadUtils.SimpleTask() { @Override public Object doInBackground() throws Throwable { writeCmd(CMD.GETINTO); Thread.sleep(200); writeCmd(CMD.CLEAN); Thread.sleep(200); String sNo2 = Integer.toHexString(no2); // if(sNo2.length()<2){ sNo2 = "0" + sNo2; } String cmd = CMD.ADDR_PREFIX + sNo2 + CMD.ADDR_SUFFIX; byte[] bytes = invertStringToBytes(cmd); String crc = CRCutil.getCRC(bytes); String zl = cmd + crc; LogUtils.e("reszl", zl); Thread.sleep(200); writeCmd(zl); return null; } @Override public void onSuccess(Object result) { } }); Toast("编址指令已发送!"); break; } } } @Subscribe(threadMode = ThreadMode.MAIN) public void onEventReceiveNotify(UpdateEvent event) { if (event != null && event.getType() == UpdateEvent.Type.BLE_DATA) { BluetoothGattCharacteristic characteristic = (BluetoothGattCharacteristic) event.getObj(); final byte[] dataArr = characteristic.getValue(); final String flag = event.getMsg(); if (dataArr != null && dataArr.length > 0) { if (flag.equals("read")) { } else if (flag.equals("write")) { } else if (flag.equals("notify")) { //返回结果 String crc = CRCutil.getCRC(dataArr); LogUtils.e("resCRC", crc); //CRC计算结果为0时命令执行成功,自动执行退出命令 if (crc.equals("0")) { writeCmd(CMD.EXIT); Toast("操作成功,自动执行退出编址指令"); curCmd = -1; item6.setText("编址成功"); } //计算返回为0时 自动退出 LogUtils.e("res", ByteUtils.byteArrayToHexString(dataArr)); } else { Toast("解析返回信息失败!"); } } else { Toast("返回信息为空!"); } } } QMUICommonListItemView item1; QMUICommonListItemView item2; QMUICommonListItemView item3; QMUICommonListItemView item4; QMUICommonListItemView item5; QMUICommonListItemView item6; View.OnClickListener onClickListener; int curCmd = -1; String[] cmdName = {"进入编址", "清除地址", "编辑地址", "退出编址", "一键编址"}; private void initGroupListView() { item1 = mGroupListView.createItemView(null, cmdName[0], "", QMUICommonListItemView.HORIZONTAL, QMUICommonListItemView.ACCESSORY_TYPE_CHEVRON); item2 = mGroupListView.createItemView(null, cmdName[1], "", QMUICommonListItemView.HORIZONTAL, QMUICommonListItemView.ACCESSORY_TYPE_CHEVRON); item3 = mGroupListView.createItemView(null, cmdName[2], "点击选择编号", QMUICommonListItemView.HORIZONTAL, QMUICommonListItemView.ACCESSORY_TYPE_CHEVRON); item4 = mGroupListView.createItemView(null, cmdName[3], "", QMUICommonListItemView.HORIZONTAL, QMUICommonListItemView.ACCESSORY_TYPE_CHEVRON); onClickListener = new View.OnClickListener() { @Override public void onClick(View v) { if (v instanceof QMUICommonListItemView) { CharSequence text = ((QMUICommonListItemView) v).getText(); //进入编址 if (text.equals(cmdName[0])) { curCmd = 1; item6.setText(cmdName[0]); item6.setDetailText(""); //清除地址 } else if (text.equals(cmdName[1])) { curCmd = 2; item6.setText(cmdName[1]); item6.setDetailText(""); //编辑地址 } else if (text.equals(cmdName[2])) { showEditTextDialog(); //退出编址 } else if (text.equals(cmdName[3])) { curCmd = 4; item6.setText(cmdName[3]); item6.setDetailText(""); //一键编址 }else if (text.equals(cmdName[4])) { showQuickDialog(); } } } }; int size = QMUIDisplayHelper.dp2px(this, 20); QMUIGroupListView.newSection(this) .setTitle("Section 1:操作指令") .setDescription("") .setLeftIconSize(size, ViewGroup.LayoutParams.WRAP_CONTENT) .addItemView(item1, onClickListener) .addItemView(item2, onClickListener) .addItemView(item3, onClickListener) .addItemView(item4, onClickListener) .addTo(mGroupListView); item5 = mGroupListView.createItemView(cmdName[4]); item5.setOrientation(QMUICommonListItemView.VERTICAL); item5.setDetailText("进入-清除-编址-退出"); item5.setAccessoryType(QMUICommonListItemView.ACCESSORY_TYPE_CHEVRON); item6 = mGroupListView.createItemView("待选择"); item6.setOrientation(QMUICommonListItemView.HORIZONTAL); QMUIGroupListView.newSection(this) .setTitle("Section 2:快捷指令") .setDescription("") .setLeftIconSize(size, ViewGroup.LayoutParams.WRAP_CONTENT) .addItemView(item5, onClickListener) .addTo(mGroupListView); QMUIGroupListView.newSection(this) .setTitle("Section 3:当前指令") .setDescription("") .setLeftIconSize(size, ViewGroup.LayoutParams.WRAP_CONTENT) .addItemView(item6, onClickListener) .addTo(mGroupListView); } /** * 初始化写入服务 * * @param uu */ private void initWrite(String uu) { BluetoothLeDevice mDevice = Singletion.getInstance().mDevice; connectManager = BluetoothConnectManager.getInstance(this); connectManager.addConnectStateListener(listener); String uuid = uu; UUID serverUUid = null; gatt = connectManager.getBluetoothGatt(mDevice.getAddress()); if (gatt != null) { List list = gatt.getServices(); if (list != null) { for (BluetoothGattService service : list) { for (BluetoothGattCharacteristic characteristics : service.getCharacteristics()) { if (characteristics.getUuid().toString().equals(uuid)) { characteristic = characteristics; serverUUid = service.getUuid(); break; } } } } } if (serverUUid == null) { Toast("serverUUid不能为空!"); return; } //1.set service uuid connectManager.setServiceUUID(serverUUid.toString()); //2.clean history descriptor data connectManager.cleanSubscribeData(); //3.add subscribe params if (BluetoothUtils.isCharacteristicRead(characteristic.getProperties())) { connectManager.addBluetoothSubscribeData( new BluetoothSubScribeData.Builder().setCharacteristicRead(characteristic.getUuid()).build()); } if (BluetoothUtils.isCharacteristicNotify(characteristic.getProperties())) { connectManager.addBluetoothSubscribeData( new BluetoothSubScribeData.Builder().setCharacteristicNotify(characteristic.getUuid()).build() ); } connectManager.startSubscribe(gatt); } private void writeCmd(String cmd) { int len = cmd.length(); if (len > 0 && len % 2 == 0) { byte[] bytes = invertStringToBytes(cmd); if (bytes != null) { characteristic.setValue(bytes); gatt.writeCharacteristic(characteristic); runOnUiThread(()->{ item6.setDetailText(item6.getDetailText()+" 已发送"); }); } else { Log.e("tag", "write value fail"); } } else { runOnUiThread(()->{ Toast("指令错误!"); }); } } private byte[] invertStringToBytes(String value) { int len = value.length() / 2; if (len > 0) { byte[] bytes = new byte[len]; for (int i = 0; i < len; i++) { Integer val = Integer.valueOf(value.substring(i * 2, i * 2 + 2), 16); bytes[i] = val.byteValue(); } return bytes; } return null; } private List> getWriteData() { List> res = new ArrayList<>(); Map map1 = new HashMap<>(); map1.put("name", "进入编址状态"); map1.put("flag", "0"); map1.put("value", "A55A060100000000002F35"); res.add(map1); Map map2 = new HashMap<>(); map2.put("name", "退出编址状态"); map2.put("flag", "0"); map2.put("value", "A55A060400000000002F60"); res.add(map2); Map map3 = new HashMap<>(); map3.put("name", "编址"); map3.put("flag", "0"); map3.put("value", "A55A060300020000002F6F"); res.add(map3); Map map4 = new HashMap<>(); map4.put("name", "清除地址"); map4.put("flag", "0"); map4.put("value", "A55A060200000000002F06"); res.add(map4); return res; } private ConnectStateListener listener = new ConnectStateListener() { @Override public void onConnectStateChanged(String address, ConnectState state) { switch (state) { case CONNECTED: break; case CONNECTING: break; case NORMAL: break; } } }; /** * 输入编址序号后 执行编址指令 */ private void showEditTextDialog() { final QMUIDialog.EditTextDialogBuilder builder = new QMUIDialog.EditTextDialogBuilder(this); builder.setTitle("提示") .setPlaceholder("请输入编址号码(1-16)") .setInputType(InputType.TYPE_CLASS_TEXT) .addAction("取消", new QMUIDialogAction.ActionListener() { @Override public void onClick(QMUIDialog dialog, int index) { dialog.dismiss(); } }) .addAction("确定", new QMUIDialogAction.ActionListener() { @Override public void onClick(QMUIDialog dialog, int index) { String text = builder.getEditText().getText().toString(); Integer res = -1; try { res = Integer.parseInt(text); } catch (Exception e) { e.printStackTrace(); } if (res == null || res < 0 || res > 16) { Toast("请输入1-16数字"); } else { item3.setDetailText(text); curCmd = 3; item6.setText(cmdName[2]); item6.setDetailText(text); dialog.dismiss(); } } }) .create(com.qmuiteam.qmui.R.style.QMUI_Dialog).show(); } /** * 输入编址序号后 一键执行所有指令 */ private void showQuickDialog() { final QMUIDialog.EditTextDialogBuilder builder = new QMUIDialog.EditTextDialogBuilder(this); builder.setTitle("提示") .setPlaceholder("请输入编址号码(1-16)") .setInputType(InputType.TYPE_CLASS_TEXT) .addAction("取消", new QMUIDialogAction.ActionListener() { @Override public void onClick(QMUIDialog dialog, int index) { dialog.dismiss(); } }) .addAction("确定", new QMUIDialogAction.ActionListener() { @Override public void onClick(QMUIDialog dialog, int index) { String text = builder.getEditText().getText().toString(); Integer addrrNo = -1; try { addrrNo = Integer.parseInt(text); } catch (Exception e) { e.printStackTrace(); } if (addrrNo == null || addrrNo < 0 || addrrNo > 16) { Toast("请输入1-16数字"); } else { curCmd = 5; item5.setDetailText(text); item6.setText(cmdName[4]); item6.setDetailText(text); dialog.dismiss(); } } }) .create(com.qmuiteam.qmui.R.style.QMUI_Dialog).show(); } public void initTitlebar() { iv_right.setVisibility(View.VISIBLE); iv_left.setImageDrawable(getResources().getDrawable(R.mipmap.icon_back)); iv_right.setImageDrawable(getResources().getDrawable(R.mipmap.icon_topbar_overflow)); } }