diff --git a/commonbt/src/main/AndroidManifest.xml b/commonbt/src/main/AndroidManifest.xml
index 7b80fd7..3ff51be 100644
--- a/commonbt/src/main/AndroidManifest.xml
+++ b/commonbt/src/main/AndroidManifest.xml
@@ -25,13 +25,25 @@
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat"/>
+
+
+
+
+
+
diff --git a/commonbt/src/main/java/com/common/bluetooth/BtConstants.kt b/commonbt/src/main/java/com/common/bluetooth/BtConstants.kt
index ea514ae..a33e5d0 100644
--- a/commonbt/src/main/java/com/common/bluetooth/BtConstants.kt
+++ b/commonbt/src/main/java/com/common/bluetooth/BtConstants.kt
@@ -2,6 +2,7 @@ package com.common.bluetooth
import android.content.Context
import android.provider.Settings
+import java.nio.charset.StandardCharsets
import java.util.*
/**
@@ -13,6 +14,8 @@ import java.util.*
object BtConstants {
const val BT_NAME = "innovation bt"
+ val DEFAULT_CHARSET = StandardCharsets.UTF_8
+
/**
* 蓝牙类型
*/
@@ -80,6 +83,10 @@ object BtConstants {
*/
const val MAX_MTU = 35
+ /**
+ * 经典蓝牙连接UUID
+ */
+ val CLASSIC_BT_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
val UUID_SERVICE = UUID.fromString("66f564dc-121f-3e7f-80b1-f005d3f194c9")
val UUID_CHARACTERISTIC_NOTIFY = UUID.fromString("66f564dd-121f-3e7f-80b1-f005d3f194c9")
val UUID_CHARACTERISTIC_WRITE = UUID.fromString("66f564de-121f-3e7f-80b1-f005d3f194c9")
diff --git a/commonbt/src/main/java/com/common/bluetooth/BtDemoActivity.java b/commonbt/src/main/java/com/common/bluetooth/BtDemoActivity.java
index 6310fa0..a8f1d75 100644
--- a/commonbt/src/main/java/com/common/bluetooth/BtDemoActivity.java
+++ b/commonbt/src/main/java/com/common/bluetooth/BtDemoActivity.java
@@ -22,6 +22,7 @@ import com.common.bluetooth.bean.CommonMsg;
import com.common.bluetooth.bean.KeyboardEvent;
import com.common.bluetooth.callback.BLEClientListener;
import com.common.bluetooth.databinding.ActivityMainBinding;
+import com.common.bluetooth.utils.BtUtils;
import com.common.bluetooth.view.BtDeviceListAdapter;
import com.google.gson.Gson;
@@ -131,10 +132,23 @@ public class BtDemoActivity extends AppCompatActivity {
}
}));
});
+
+ mBinding.btcServerBuild.setOnClickListener(v -> {
+ BtManager.INSTANCE.initServer(this, BtConstants.BLUETOOTH_TYPE.CLASSIC);
+ BtManager.INSTANCE.setMsgReceiverListener(msg -> {
+ Log.d(TAG, new String(msg));
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mBinding.btcReceiveContent.setText(new String(msg));
+ }
+ });
+ });
+ });
}
private void checkBluetooth() {
- BtManager.INSTANCE.initClient(this, BtConstants.BLUETOOTH_TYPE.BLE);
+ BtManager.INSTANCE.initClient(this, BtConstants.BLUETOOTH_TYPE.CLASSIC);
BtManager.INSTANCE.btPermissionCheck(this, PERMISSION_REQUEST_LOCATION);
}
diff --git a/commonbt/src/main/java/com/common/bluetooth/BtManager.kt b/commonbt/src/main/java/com/common/bluetooth/BtManager.kt
index af1e96e..6fdf0f7 100644
--- a/commonbt/src/main/java/com/common/bluetooth/BtManager.kt
+++ b/commonbt/src/main/java/com/common/bluetooth/BtManager.kt
@@ -11,20 +11,25 @@ import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.os.Build
import android.os.IBinder
-import android.util.Log.d
-import android.util.Log.e
+import android.util.Log.*
import androidx.core.content.ContextCompat.checkSelfPermission
import com.common.bluetooth.BtConstants.BLUETOOTH_TYPE
-import com.common.bluetooth.adapter.BluetoothClientBLEAdapter
+import com.common.bluetooth.service.ble.BluetoothClientBLEAdapter
import com.common.bluetooth.bean.CommonMsg
import com.common.bluetooth.callback.BLEClientListener
-import com.common.bluetooth.callback.BleMsgReceiverListener
+import com.common.bluetooth.callback.BtMsgListener
+import com.common.bluetooth.callback.BtServiceListener
+import com.common.bluetooth.callback.MsgReceiverListener
import com.common.bluetooth.interfaces.IBluetoothClient
-import com.common.bluetooth.service.BLEClientService
-import com.common.bluetooth.service.BLEClientService.BLEClientBinder
-import com.common.bluetooth.service.BLEReceiveService
-import com.common.bluetooth.service.BLEReceiveService.ReceiverBinder
-import com.common.bluetooth.service.BluetoothLeClient
+import com.common.bluetooth.service.ble.BLEClientService
+import com.common.bluetooth.service.ble.BLEClientService.BLEClientBinder
+import com.common.bluetooth.service.ble.BLEReceiveService
+import com.common.bluetooth.service.ble.BLEReceiveService.ReceiverBinder
+import com.common.bluetooth.service.ble.BluetoothLeClient
+import com.common.bluetooth.service.bt.BTCClientService
+import com.common.bluetooth.service.bt.BTCReceiverService
+import com.common.bluetooth.service.bt.BluetoothClassicClient
+import com.common.bluetooth.service.bt.BluetoothClientClassicAdapter
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observer
import io.reactivex.rxjava3.disposables.Disposable
@@ -45,34 +50,59 @@ object BtManager {
private var mBtClient: IBluetoothClient? = null
/**
- * 客户端服务
+ * BLE客户端服务
*/
private var clientService: BLEClientService? = null
/**
- * 服务端服务
+ * 经典蓝牙客户端服务
+ */
+ private var classicClientService: BTCClientService? = null
+
+ /**
+ * BLE服务端服务
*/
private var serverService: BLEReceiveService? = null
+ /**
+ * 经典蓝牙服务端服务
+ */
+ private var classicServerService: BTCReceiverService? = null
+
/**
* 消息接收监听
*/
- var msgReceiverListener: BleMsgReceiverListener? = null
+ var msgReceiverListener: MsgReceiverListener? = null
/**
* 蓝牙客户端监听
*/
var clientListener: BLEClientListener? = null
+ /**
+ * 蓝牙服务链接监听
+ */
+ var btServiceListener: BtServiceListener? = null
+
/**
* 是否绑定了服务端
*/
- private var isBindServer: AtomicBoolean = AtomicBoolean(false)
+ private var isBindBleServer: AtomicBoolean = AtomicBoolean(false)
/**
* 是否绑定了客户端
*/
- private var isBindClient: AtomicBoolean = AtomicBoolean(false)
+ private var isBindBleClient: AtomicBoolean = AtomicBoolean(false)
+
+ /**
+ * 是否绑定了服务端
+ */
+ private var isBindClassicServer: AtomicBoolean = AtomicBoolean(false)
+
+ /**
+ * 是否绑定了客户端
+ */
+ private var isBindClassicClient: AtomicBoolean = AtomicBoolean(false)
/**
* 当前使用的编码 默认是UTF-8
@@ -89,77 +119,180 @@ object BtManager {
* 初始化蓝牙服务端模块
*/
fun initServer(context: Context, btType: BLUETOOTH_TYPE) {
- mBtClient = BluetoothClientBLEAdapter(BluetoothLeClient.getInstance(context))
+ if (btType == BLUETOOTH_TYPE.BLE) {
+ mBtClient = BluetoothClientBLEAdapter(
+ BluetoothLeClient.getInstance(context)
+ )
+ initBleReceiverService(context)
+ } else if (btType == BLUETOOTH_TYPE.CLASSIC) {
+ mBtClient = BluetoothClientClassicAdapter(BluetoothClassicClient(context))
+ initClassicReceiverService(context)
+ }
mBtClient!!.checkBluetoothDevice(btType)
- initReceiverService(context)
+
}
/**
* 初始化蓝牙客户端模块
*/
fun initClient(context: Activity, btType: BLUETOOTH_TYPE) {
- mBtClient = BluetoothClientBLEAdapter(BluetoothLeClient.getInstance(context))
+ if (btType == BLUETOOTH_TYPE.BLE) {
+ mBtClient = BluetoothClientBLEAdapter(
+ BluetoothLeClient.getInstance(context)
+ )
+ initBleClientService(context)
+ } else if (btType == BLUETOOTH_TYPE.CLASSIC) {
+ mBtClient = BluetoothClientClassicAdapter(
+ BluetoothClassicClient(context)
+ )
+ initClassicClientService(context)
+ }
mBtClient!!.checkBluetoothDevice(btType)
- initClientService(context)
}
-
/**
* 初始化接收端服务
*/
- private fun initReceiverService(context: Context) {
+ private fun initBleReceiverService(context: Context) {
val intent = Intent(context, BLEReceiveService::class.java)
// 标志位BIND_AUTO_CREATE是的服务中onCreate得到执行,onStartCommand不会执行
- context.bindService(intent, receiverConn, Context.BIND_AUTO_CREATE)
- isBindServer.set(true)
+ context.bindService(intent, bleReceiverConn, Context.BIND_AUTO_CREATE)
+ isBindBleServer.set(true)
+ }
+
+ private fun initClassicReceiverService(context: Context) {
+ val intent = Intent(context, BTCReceiverService::class.java)
+ // 标志位BIND_AUTO_CREATE是的服务中onCreate得到执行,onStartCommand不会执行
+ context.bindService(intent, classicReceiverConn, Context.BIND_AUTO_CREATE)
+ isBindClassicServer.set(true)
}
/**
* 初始化客户端服务
*/
- private fun initClientService(context: Context) {
+ private fun initBleClientService(context: Context) {
val intent = Intent(context, BLEClientService::class.java)
// 标志位BIND_AUTO_CREATE是的服务中onCreate得到执行,onStartCommand不会执行
- context.bindService(intent, clientConn, Context.BIND_AUTO_CREATE)
- isBindClient.set(true)
+ context.bindService(intent, bleClientConn, Context.BIND_AUTO_CREATE)
+ isBindBleClient.set(true)
}
- private val receiverConn: ServiceConnection = object : ServiceConnection {
- override fun onServiceConnected(name: ComponentName, service: IBinder) {
- serverService = (service as ReceiverBinder).service
- serverService?.setMsgReceiveListener(object : BleMsgReceiverListener {
- override fun onMsgReceive(msg: ByteArray) {
- msgReceiverListener?.onMsgReceive(msg)
- }
- })
+ private fun initClassicClientService(context: Context) {
+ val intent = Intent(context, BTCClientService::class.java)
+ // 标志位BIND_AUTO_CREATE是的服务中onCreate得到执行,onStartCommand不会执行
+ context.bindService(intent, classicClientConn, Context.BIND_AUTO_CREATE)
+ isBindClassicClient.set(true)
+ }
+
+ private val bleReceiverConn: ServiceConnection by lazy {
+ object : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ serverService = (service as ReceiverBinder).service
+ serverService?.setMsgReceiveListener(object : MsgReceiverListener {
+ override fun onMsgReceive(msg: ByteArray) {
+ msgReceiverListener?.onMsgReceive(msg)
+ }
+ })
+ btServiceListener?.onServiceReady()
+ }
+
+ override fun onServiceDisconnected(name: ComponentName) {
+ serverService = null
+ btServiceListener?.onServiceDisConnected()
+ }
}
+ }
+
+ private val classicReceiverConn: ServiceConnection by lazy {
+ object : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ classicServerService = (service as BTCReceiverService.ClassicReceiverBinder).service
+ classicServerService?.setMsgReceiveListener(object : BtMsgListener() {
+ override fun socketNotify(state: Int, msg: String) {
+ msgReceiverListener?.onMsgReceive(msg.toByteArray())
+ }
+ })
+ btServiceListener?.onServiceReady()
+ }
- override fun onServiceDisconnected(name: ComponentName) {}
+ override fun onServiceDisconnected(name: ComponentName) {
+ classicServerService = null
+ btServiceListener?.onServiceDisConnected()
+ }
+ }
}
- private val clientConn: ServiceConnection = object : ServiceConnection {
- override fun onServiceConnected(name: ComponentName, service: IBinder) {
- clientService = (service as BLEClientBinder).service
- clientService?.setClientListener(object : BLEClientListener {
- override fun onResult(result: CommonMsg) {
- // 如果连接成功,更新连接的设备
- if (result.msgType == BtConstants.CONNECT_SUCCESS) {
- curConnectMac = result.msg
- } else if (result.msgType == BtConstants.DISCONNECT) {
- curConnectMac = ""
+ private val bleClientConn: ServiceConnection by lazy {
+ object : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ clientService = (service as BLEClientBinder).service
+ clientService?.setClientListener(object : BLEClientListener {
+ override fun onResult(result: CommonMsg) {
+ // 如果连接成功,更新连接的设备
+ if (result.msgType == BtConstants.CONNECT_SUCCESS) {
+ curConnectMac = result.msg
+ } else if (result.msgType == BtConstants.DISCONNECT) {
+ curConnectMac = ""
+ }
+ clientListener?.onResult(result)
}
- clientListener?.onResult(result)
- }
- override fun onNotifyMsgReceive(msg: ByteArray) {
- clientListener?.onNotifyMsgReceive(msg)
- }
- })
+ override fun onNotifyMsgReceive(msg: ByteArray) {
+ clientListener?.onNotifyMsgReceive(msg)
+ }
+ })
+ btServiceListener?.onServiceReady()
+ }
+
+ override fun onServiceDisconnected(name: ComponentName) {
+ clientService = null
+ clientListener?.onResult(
+ CommonMsg(
+ BtConstants.DISCONNECT,
+ "disconnect from server"
+ )
+ )
+ btServiceListener?.onServiceDisConnected()
+ }
}
+ }
+
+ private val classicClientConn: ServiceConnection by lazy {
+ object : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ classicClientService = (service as BTCClientService.ClassicClientBinder).service
+ classicClientService?.setMsgReceiveListener(object : BtMsgListener() {
+ override fun socketNotify(state: Int, msg: String) {
+ when (state) {
+ CONNECTED -> {
+ curConnectMac = msg
+ clientListener?.onResult(
+ CommonMsg(
+ BtConstants.CONNECT_SUCCESS,
+ msg
+ )
+ )
+ }
+ DISCONNECTED -> {
+ curConnectMac = ""
+ clientListener?.onResult(CommonMsg(BtConstants.DISCONNECT, msg))
+ }
+ MSG -> {
+ clientListener?.onNotifyMsgReceive(msg.toByteArray())
+ }
+ else -> {
+ e(TAG, "got error state:$state")
+ }
+ }
+ }
+ })
+ btServiceListener?.onServiceReady()
+ }
- override fun onServiceDisconnected(name: ComponentName) {
- clientService = null
- clientListener?.onResult(CommonMsg(BtConstants.DISCONNECT, "disconnect from server"))
+ override fun onServiceDisconnected(name: ComponentName) {
+ classicClientService = null
+ btServiceListener?.onServiceDisConnected()
+ }
}
}
@@ -205,10 +338,16 @@ object BtManager {
* @param mac MAC地址
*/
fun connect(mac: String) {
- if (clientService == null) {
- e(TAG, "writeMsg pls init first")
- } else {
+ if (clientService != null) {
clientService!!.connect(mac, true)
+ } else {
+ w(TAG, "init clientService first")
+ }
+
+ if (classicClientService != null) {
+ classicClientService!!.connect(mac)
+ } else {
+ w(TAG, "init classicClientService first")
}
}
@@ -241,11 +380,17 @@ object BtManager {
* @param msg 传输的内容
*/
fun write(msg: ByteArray) {
- if (clientService == null) {
- e(TAG, "writeMsg pls init first")
- } else {
+ if (clientService != null) {
clientService!!.write(msg)
}
+
+ if (classicClientService != null) {
+ classicClientService!!.write(msg)
+ }
+
+ if (classicServerService != null) {
+ classicServerService!!.write(msg)
+ }
}
/**
@@ -301,19 +446,28 @@ object BtManager {
*/
fun sendNotify(msg: ByteArray) {
serverService?.sendNotify(msg)
+ classicServerService?.write(msg)
}
/**
* 释放链接
*/
fun release(context: Context?) {
- if (isBindServer.get()) {
- context?.unbindService(receiverConn)
- isBindServer.set(false)
+ if (isBindBleServer.get()) {
+ context?.unbindService(bleReceiverConn)
+ isBindBleServer.set(false)
+ }
+ if (isBindClassicServer.get()) {
+ context?.unbindService(classicReceiverConn)
+ isBindClassicServer.set(false)
+ }
+ if (isBindBleClient.get()) {
+ context?.unbindService(bleClientConn)
+ isBindBleClient.set(false)
}
- if (isBindClient.get()) {
- context?.unbindService(clientConn)
- isBindClient.set(false)
+ if (isBindClassicClient.get()) {
+ context?.unbindService(classicClientConn)
+ isBindClassicServer.set(false)
}
}
}
\ No newline at end of file
diff --git a/commonbt/src/main/java/com/common/bluetooth/callback/BtMsgListener.kt b/commonbt/src/main/java/com/common/bluetooth/callback/BtMsgListener.kt
new file mode 100644
index 0000000..1bc35e5
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/callback/BtMsgListener.kt
@@ -0,0 +1,33 @@
+package com.common.bluetooth.callback
+
+/**
+ * 经典蓝牙监听
+ *
+ * @author wangym
+ * @since 2021-12-1
+ */
+abstract class BtMsgListener {
+ /**
+ * 通知
+ * @param state 消息类型
+ * @param msg 消息内容
+ */
+ open fun socketNotify(state: Int, msg: String) {}
+
+ companion object {
+ /**
+ * 断开连接
+ */
+ const val DISCONNECTED = 0
+
+ /**
+ * 连接成功
+ */
+ const val CONNECTED = 1
+
+ /**
+ * 消息
+ */
+ const val MSG = 2
+ }
+}
\ No newline at end of file
diff --git a/commonbt/src/main/java/com/common/bluetooth/callback/BtServiceListener.kt b/commonbt/src/main/java/com/common/bluetooth/callback/BtServiceListener.kt
new file mode 100644
index 0000000..7e82915
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/callback/BtServiceListener.kt
@@ -0,0 +1,19 @@
+package com.common.bluetooth.callback
+
+/**
+ * BT服务监听
+ *
+ * @author wangym
+ * @since 2021-12-9
+ */
+interface BtServiceListener {
+ /**
+ * 服务准备完毕
+ */
+ fun onServiceReady()
+
+ /**
+ * 服务断开
+ */
+ fun onServiceDisConnected()
+}
\ No newline at end of file
diff --git a/commonbt/src/main/java/com/common/bluetooth/callback/BleMsgReceiverListener.kt b/commonbt/src/main/java/com/common/bluetooth/callback/MsgReceiverListener.kt
similarity index 84%
rename from commonbt/src/main/java/com/common/bluetooth/callback/BleMsgReceiverListener.kt
rename to commonbt/src/main/java/com/common/bluetooth/callback/MsgReceiverListener.kt
index 5986236..bea99f4 100644
--- a/commonbt/src/main/java/com/common/bluetooth/callback/BleMsgReceiverListener.kt
+++ b/commonbt/src/main/java/com/common/bluetooth/callback/MsgReceiverListener.kt
@@ -3,7 +3,7 @@ package com.common.bluetooth.callback
/**
* BLE数据接收监听
*/
-interface BleMsgReceiverListener {
+interface MsgReceiverListener {
/**
* 接收的消息
*
diff --git a/commonbt/src/main/java/com/common/bluetooth/interfaces/IBluetoothClient.kt b/commonbt/src/main/java/com/common/bluetooth/interfaces/IBluetoothClient.kt
index 963d151..c0ec305 100644
--- a/commonbt/src/main/java/com/common/bluetooth/interfaces/IBluetoothClient.kt
+++ b/commonbt/src/main/java/com/common/bluetooth/interfaces/IBluetoothClient.kt
@@ -24,7 +24,7 @@ interface IBluetoothClient {
* false 如果当前正在进行扫描操作则会抛出 [com.common.bluetooth.exception.BluetoothSearchConflictException] 错误
* @return 扫描结果的列表(无重复设备)
*/
- fun search(millis: Int, cancel: Boolean): Observable
+ fun search(millis: Long, cancel: Boolean): Observable
/**
* 停止扫描
@@ -38,7 +38,7 @@ interface IBluetoothClient {
* @param mac 需要连接蓝牙设备的地址
* @return 成功,返回连接设备的地址
*/
- fun connect(mac: String?): Observable
+ fun connect(mac: String): Observable
/**
* 断开蓝牙连接, 释放蓝牙连接占用的蓝牙服务
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothCommon.kt b/commonbt/src/main/java/com/common/bluetooth/service/BluetoothCommon.kt
new file mode 100644
index 0000000..3122067
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/service/BluetoothCommon.kt
@@ -0,0 +1,120 @@
+package com.common.bluetooth.service
+
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothManager
+import android.content.Context
+import android.content.pm.PackageManager
+import android.util.Log
+import com.common.bluetooth.BtConstants.BLUETOOTH_TYPE
+import com.common.bluetooth.interfaces.IBluetoothSearch
+import com.common.bluetooth.service.bt.BluetoothClassicBase
+import com.common.bluetooth.service.bt.BluetoothClassicSearcher
+
+/**
+ * 通用蓝牙
+ *
+ * @author wangym
+ * @since 2021-12-1
+ */
+open class BluetoothCommon(val mContext: Context) {
+ val TAG = "BluetoothCommon"
+ var mBluetoothAdapter: BluetoothAdapter? = null
+ var mBluetoothManager: BluetoothManager? = null
+ var mBluetoothSearcher: IBluetoothSearch? = null
+
+ /**
+ * 检查蓝牙设备是否支持
+ *
+ * @param btType 蓝牙类型
+ */
+ fun checkBtDevice(btType: BLUETOOTH_TYPE): Boolean {
+ if (btType === BLUETOOTH_TYPE.BLE) {
+ // 检查当前手机是否支持ble 蓝牙
+ if (!mContext.packageManager
+ .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
+ ) {
+ Log.e(TAG, "not support ble device")
+ return false
+ }
+ }
+
+ // For API level 18 and above, get a reference to BluetoothAdapter
+ // through BluetoothManager.
+ if (mBluetoothManager == null) {
+ mBluetoothManager = mContext
+ .getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
+ if (mBluetoothManager == null) {
+ Log.e(TAG, "Unable to initialize BluetoothManager.")
+ return false
+ }
+ }
+ if (mBluetoothAdapter == null) {
+ mBluetoothAdapter = mBluetoothManager?.adapter
+ if (mBluetoothAdapter == null) {
+ Log.e(TAG, "Unable to obtain a BluetoothAdapter.")
+ return false
+ }
+ }
+ return true
+ }
+
+ /**
+ * 通过MAC地址获取设备对象
+ *
+ * @param mac mac地址
+ * @return 设备对象
+ */
+ fun getBtDeviceByMac(mac: String?): BluetoothDevice? {
+ if (mBluetoothAdapter == null) {
+ Log.e(TAG, "getBtDeviceByMac mBluetoothAdapter is null")
+ return null
+ }
+ return mBluetoothAdapter!!.getRemoteDevice(mac)
+ }
+
+ /**
+ * 初始化BluetoothAdapter
+ * Initializes a reference to the local Bluetooth adapter.
+ *
+ * @return Return true if the initialization is successful.
+ */
+ fun openBt(): Boolean {
+ if (mBluetoothAdapter == null) {
+ Log.e(TAG, "BluetoothManager do not init")
+ return false
+ }
+ return mBluetoothAdapter!!.isEnabled() || mBluetoothAdapter!!.enable()
+ }
+
+ fun closeBt(): Boolean {
+ if (mBluetoothAdapter == null) {
+ Log.e(TAG, "BluetoothManager do not init")
+ return false
+ }
+ return mBluetoothAdapter!!.disable()
+ }
+
+ /**
+ * 获取已配对蓝牙设备信息
+ */
+ fun getBondedDevices(): Set? {
+ return mBluetoothAdapter?.bondedDevices
+ }
+
+ /**
+ * 获取蓝牙扫描对象
+ *
+ * @return 蓝牙扫描对象
+ */
+ fun getBluetoothSearcher(): IBluetoothSearch {
+ if (mBluetoothSearcher == null) {
+ synchronized(BluetoothClassicBase::class.java) {
+ if (mBluetoothSearcher == null) {
+ mBluetoothSearcher = BluetoothClassicSearcher(mContext, mBluetoothAdapter)
+ }
+ }
+ }
+ return mBluetoothSearcher!!
+ }
+}
\ No newline at end of file
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothConnectService.java b/commonbt/src/main/java/com/common/bluetooth/service/BluetoothConnectService.java
deleted file mode 100644
index 4631051..0000000
--- a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothConnectService.java
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.common.bluetooth.service;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothServerSocket;
-import android.bluetooth.BluetoothSocket;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-import com.common.bluetooth.BtConstants;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.UUID;
-
-/**
- * This class does all the work for setting up and managing Bluetooth
- * connections with other devices. It has a thread that listens for
- * incoming connections, a thread for connecting with a device, and a
- * thread for performing data transmissions when connected.
- */
-public class BluetoothConnectService {
- // Debugging
- private static final String TAG = "BluetoothConnectService";
-
- // Name for the SDP record when creating server socket
- private static final String NAME_SECURE = "BluetoothChatSecure";
- private static final String NAME_INSECURE = "BluetoothChatInsecure";
-
- // Unique UUID for this application
- private final UUID CURRENT_UUID;
-
- // Member fields
- private final BluetoothAdapter mAdapter;
- private final Handler mHandler;
- private AcceptThread mSecureAcceptThread;
- private AcceptThread mInsecureAcceptThread;
- private ConnectThread mConnectThread;
- private ConnectedThread mConnectedThread;
- private int mState;
- private int mNewState;
-
- // Constants that indicate the current connection state
- public static final int STATE_NONE = 0; // we're doing nothing
- public static final int STATE_LISTEN = 1; // now listening for incoming connections
- public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
- public static final int STATE_CONNECTED = 3; // now connected to a remote device
-
- /**
- * Constructor. Prepares a new BluetoothChat session.
- *
- * @param context The UI Activity Context
- * @param handler A Handler to send messages back to the UI Activity
- */
- public BluetoothConnectService(Context context, Handler handler) {
- CURRENT_UUID = BtConstants.INSTANCE.getUUid(context);
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- mState = STATE_NONE;
- mNewState = mState;
- mHandler = handler;
- }
-
- /**
- * Update UI title according to the current state of the chat connection
- */
- private synchronized void updateUserInterfaceTitle() {
- mState = getState();
- Log.d(TAG, "updateUserInterfaceTitle() " + mNewState + " -> " + mState);
- mNewState = mState;
-
- // Give the new state to the Handler so the UI Activity can update
- mHandler.obtainMessage(BtConstants.MESSAGE_STATE_CHANGE, mNewState, -1).sendToTarget();
- }
-
- /**
- * Return the current connection state.
- */
- public synchronized int getState() {
- return mState;
- }
-
- /**
- * Start the chat service. Specifically start AcceptThread to begin a
- * session in listening (server) mode. Called by the Activity onResume()
- */
- public synchronized void start() {
- Log.d(TAG, "start");
-
- // Cancel any thread attempting to make a connection
- if (mConnectThread != null) {
- mConnectThread.cancel();
- mConnectThread = null;
- }
-
- // Cancel any thread currently running a connection
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
-
- // Start the thread to listen on a BluetoothServerSocket
- if (mSecureAcceptThread == null) {
- mSecureAcceptThread = new AcceptThread(false);
- mSecureAcceptThread.start();
- }
- if (mInsecureAcceptThread == null) {
- mInsecureAcceptThread = new AcceptThread(false);
- mInsecureAcceptThread.start();
- }
- // Update UI title
- updateUserInterfaceTitle();
- }
-
- /**
- * Start the ConnectThread to initiate a connection to a remote device.
- *
- * @param device The BluetoothDevice to connect
- */
- public synchronized void connect(BluetoothDevice device) {
- Log.d(TAG, "connect to: " + device);
-
- // Cancel any thread attempting to make a connection
- if (mState == STATE_CONNECTING) {
- if (mConnectThread != null) {
- mConnectThread.cancel();
- mConnectThread = null;
- }
- }
-
- // Cancel any thread currently running a connection
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
-
- // Start the thread to connect with the given device
- mConnectThread = new ConnectThread(device, false);
- mConnectThread.start();
- // Update UI title
- updateUserInterfaceTitle();
- }
-
- /**
- * Start the ConnectedThread to begin managing a Bluetooth connection
- *
- * @param socket The BluetoothSocket on which the connection was made
- * @param device The BluetoothDevice that has been connected
- */
- public synchronized void connected(BluetoothSocket socket, BluetoothDevice
- device, final String socketType) {
- Log.d(TAG, "connected, Socket Type:" + socketType);
-
- // Cancel the thread that completed the connection
- if (mConnectThread != null) {
- mConnectThread.cancel();
- mConnectThread = null;
- }
-
- // Cancel any thread currently running a connection
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
-
- // Cancel the accept thread because we only want to connect to one device
- if (mSecureAcceptThread != null) {
- mSecureAcceptThread.cancel();
- mSecureAcceptThread = null;
- }
- if (mInsecureAcceptThread != null) {
- mInsecureAcceptThread.cancel();
- mInsecureAcceptThread = null;
- }
-
- // Start the thread to manage the connection and perform transmissions
- mConnectedThread = new ConnectedThread(socket, socketType);
- mConnectedThread.start();
-
- // Send the name of the connected device back to the UI Activity
- Message msg = mHandler.obtainMessage(BtConstants.MESSAGE_DEVICE_NAME);
- Bundle bundle = new Bundle();
- bundle.putString(BtConstants.DEVICE_NAME, device.getName());
- msg.setData(bundle);
- mHandler.sendMessage(msg);
- // Update UI title
- updateUserInterfaceTitle();
- }
-
- /**
- * Stop all threads
- */
- public synchronized void stop() {
- Log.d(TAG, "stop");
-
- if (mConnectThread != null) {
- mConnectThread.cancel();
- mConnectThread = null;
- }
-
- if (mConnectedThread != null) {
- mConnectedThread.cancel();
- mConnectedThread = null;
- }
-
- if (mSecureAcceptThread != null) {
- mSecureAcceptThread.cancel();
- mSecureAcceptThread = null;
- }
-
- if (mInsecureAcceptThread != null) {
- mInsecureAcceptThread.cancel();
- mInsecureAcceptThread = null;
- }
- mState = STATE_NONE;
- // Update UI title
- updateUserInterfaceTitle();
- }
-
- /**
- * Write to the ConnectedThread in an unsynchronized manner
- *
- * @param out The bytes to write
- * @see ConnectedThread#write(byte[])
- */
- public void write(byte[] out) {
- // Create temporary object
- ConnectedThread r;
- // Synchronize a copy of the ConnectedThread
- synchronized (this) {
- if (mState != STATE_CONNECTED) return;
- r = mConnectedThread;
- }
- // Perform the write unsynchronized
- r.write(out);
- }
-
- /**
- * Indicate that the connection attempt failed and notify the UI Activity.
- */
- private void connectionFailed() {
- // Send a failure message back to the Activity
- Message msg = mHandler.obtainMessage(BtConstants.MESSAGE_TOAST);
- Bundle bundle = new Bundle();
- bundle.putString(BtConstants.TOAST, "Unable to connect device");
- msg.setData(bundle);
- mHandler.sendMessage(msg);
-
- mState = STATE_NONE;
- // Update UI title
- updateUserInterfaceTitle();
-
- // Start the service over to restart listening mode
- BluetoothConnectService.this.start();
- }
-
- /**
- * Indicate that the connection was lost and notify the UI Activity.
- */
- private void connectionLost() {
- // Send a failure message back to the Activity
- Message msg = mHandler.obtainMessage(BtConstants.MESSAGE_TOAST);
- Bundle bundle = new Bundle();
- bundle.putString(BtConstants.TOAST, "Device connection was lost");
- msg.setData(bundle);
- mHandler.sendMessage(msg);
-
- mState = STATE_NONE;
- // Update UI title
- updateUserInterfaceTitle();
-
- // Start the service over to restart listening mode
- BluetoothConnectService.this.start();
- }
-
- /**
- * This thread runs while listening for incoming connections. It behaves
- * like a server-side client. It runs until a connection is accepted
- * (or until cancelled).
- */
- private class AcceptThread extends Thread {
- // The local server socket
- private final BluetoothServerSocket mmServerSocket;
- private String mSocketType;
-
- public AcceptThread(boolean secure) {
- BluetoothServerSocket tmp = null;
- mSocketType = secure ? "Secure" : "Insecure";
-
- // Create a new listening server socket
- try {
- tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
- CURRENT_UUID);
- } catch (IOException e) {
- Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);
- }
- mmServerSocket = tmp;
- mState = STATE_LISTEN;
- }
-
- public void run() {
- Log.d(TAG, "Socket Type: " + mSocketType +
- "BEGIN mAcceptThread" + this);
- setName("AcceptThread" + mSocketType);
-
- BluetoothSocket socket = null;
-
- // Listen to the server socket if we're not connected
- while (mState != STATE_CONNECTED) {
- try {
- // This is a blocking call and will only return on a
- // successful connection or an exception
- socket = mmServerSocket.accept();
- } catch (IOException e) {
- Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
- break;
- }
-
- // If a connection was accepted
- if (socket != null) {
- synchronized (BluetoothConnectService.this) {
- switch (mState) {
- case STATE_LISTEN:
- case STATE_CONNECTING:
- // Situation normal. Start the connected thread.
- connected(socket, socket.getRemoteDevice(),
- mSocketType);
- break;
- case STATE_NONE:
- case STATE_CONNECTED:
- // Either not ready or already connected. Terminate new socket.
- try {
- socket.close();
- } catch (IOException e) {
- Log.e(TAG, "Could not close unwanted socket", e);
- }
- break;
- }
- }
- }
- }
- Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);
-
- }
-
- public void cancel() {
- Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
- try {
- mmServerSocket.close();
- } catch (IOException e) {
- Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);
- }
- }
- }
-
-
- /**
- * This thread runs while attempting to make an outgoing connection
- * with a device. It runs straight through; the connection either
- * succeeds or fails.
- */
- private class ConnectThread extends Thread {
- private BluetoothSocket mmSocket;
- private final BluetoothDevice mmDevice;
- private String mSocketType;
-
- public ConnectThread(BluetoothDevice device, boolean secure) {
- mmDevice = device;
- BluetoothSocket tmp = null;
- mSocketType = secure ? "Secure" : "Insecure";
-
- // Get a BluetoothSocket for a connection with the
- // given BluetoothDevice
- try {
- tmp = device.createRfcommSocketToServiceRecord(
- CURRENT_UUID);
- } catch (IOException e) {
- Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
- }
- mmSocket = tmp;
- mState = STATE_CONNECTING;
- }
-
- public void run() {
- Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
- setName("ConnectThread" + mSocketType);
-
- // Always cancel discovery because it will slow down a connection
- mAdapter.cancelDiscovery();
-
- // Make a connection to the BluetoothSocket
- try {
- // This is a blocking call and will only return on a
- // successful connection or an exception
- mmSocket.connect();
- } catch (IOException e) {
- // Unable to connect; close the socket and return.
- Log.e(TAG, e.toString());
- try {
- mmSocket.close();
- } catch (IOException ie) {
- connectionFailed();
- }
- return;
- }
-
- // Reset the ConnectThread because we're done
- synchronized (BluetoothConnectService.this) {
- mConnectThread = null;
- }
-
- // Start the connected thread
- connected(mmSocket, mmDevice, mSocketType);
- }
-
- public void cancel() {
- try {
- mmSocket.close();
- } catch (IOException e) {
- Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
- }
- }
- }
-
- /**
- * This thread runs during a connection with a remote device.
- * It handles all incoming and outgoing transmissions.
- */
- private class ConnectedThread extends Thread {
- private final BluetoothSocket mmSocket;
- private final InputStream mmInStream;
- private final OutputStream mmOutStream;
-
- public ConnectedThread(BluetoothSocket socket, String socketType) {
- Log.d(TAG, "create ConnectedThread: " + socketType);
- mmSocket = socket;
- InputStream tmpIn = null;
- OutputStream tmpOut = null;
-
- // Get the BluetoothSocket input and output streams
- try {
- tmpIn = socket.getInputStream();
- tmpOut = socket.getOutputStream();
- } catch (IOException e) {
- Log.e(TAG, "temp sockets not created", e);
- }
-
- mmInStream = tmpIn;
- mmOutStream = tmpOut;
- mState = STATE_CONNECTED;
- }
-
- public void run() {
- Log.i(TAG, "BEGIN mConnectedThread");
- byte[] buffer = new byte[1024];
- int bytes;
-
- // Keep listening to the InputStream while connected
- while (mState == STATE_CONNECTED) {
- try {
- // Read from the InputStream
- bytes = mmInStream.read(buffer);
-
- // Send the obtained bytes to the UI Activity
- mHandler.obtainMessage(BtConstants.MESSAGE_READ, bytes, -1, buffer)
- .sendToTarget();
- } catch (IOException e) {
- Log.e(TAG, "disconnected", e);
- connectionLost();
- break;
- }
- }
- }
-
- /**
- * Write to the connected OutStream.
- *
- * @param buffer The bytes to write
- */
- public void write(byte[] buffer) {
- try {
- mmOutStream.write(buffer);
-
- // Share the sent message back to the UI Activity
- mHandler.obtainMessage(BtConstants.MESSAGE_WRITE, -1, -1, buffer)
- .sendToTarget();
- } catch (IOException e) {
- Log.e(TAG, "Exception during write", e);
- }
- }
-
- public void cancel() {
- try {
- mmSocket.close();
- } catch (IOException e) {
- Log.e(TAG, "close() of connect socket failed", e);
- }
- }
- }
-}
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothLeClient.java b/commonbt/src/main/java/com/common/bluetooth/service/BluetoothLeClient.java
deleted file mode 100644
index cee6db1..0000000
--- a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothLeClient.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package com.common.bluetooth.service;
-
-import android.annotation.SuppressLint;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.util.Log;
-
-import com.common.bluetooth.BtConstants;
-import com.common.bluetooth.interfaces.IBluetoothSearch;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 蓝牙操作管理类
- *
- * @author wangym
- * @since 2021-10-19
- */
-public class BluetoothLeClient {
- @SuppressLint("StaticFieldLeak")
- private static volatile BluetoothLeClient mInstance;
-
- private final static String TAG = "BluetoothLeClient";
- private final Context mContext;
- private static Handler mBluetoothWorker;
- private BluetoothAdapter mBluetoothAdapter;
- private BluetoothManager mBluetoothManager;
- private IBluetoothSearch mBluetoothSearcher;
-
- private final Map mGattConnectorMap
- = new ConcurrentHashMap<>();
-
- private BluetoothLeClient(Context context) {
- mContext = context.getApplicationContext();
-
- HandlerThread thread = new HandlerThread("bluetooth client worker");
- thread.start();
- mBluetoothWorker = new Handler(thread.getLooper());
- }
-
- public static BluetoothLeClient getInstance(Context context) {
- if (mInstance == null) {
- synchronized (BluetoothLeClient.class) {
- if (mInstance == null) {
- mInstance = new BluetoothLeClient(context);
- }
- }
- }
-
- return mInstance;
- }
-
- /**
- * 检查蓝牙设备是否支持
- *
- * @param btType 蓝牙类型
- */
- public boolean checkBtDevice(BtConstants.BLUETOOTH_TYPE btType) {
- if (btType == BtConstants.BLUETOOTH_TYPE.BLE) {
- // 检查当前手机是否支持ble 蓝牙
- if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
- Log.e(TAG, "not support ble device");
- return false;
- }
- }
-
- // For API level 18 and above, get a reference to BluetoothAdapter
- // through BluetoothManager.
- if (mBluetoothManager == null) {
- mBluetoothManager = (BluetoothManager) mContext
- .getSystemService(Context.BLUETOOTH_SERVICE);
- if (mBluetoothManager == null) {
- Log.e(TAG, "Unable to initialize BluetoothManager.");
- return false;
- }
- }
-
- if (mBluetoothAdapter == null) {
- mBluetoothAdapter = mBluetoothManager.getAdapter();
- if (mBluetoothAdapter == null) {
- Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
- return false;
- }
- }
- return true;
- }
-
- /**
- * 初始化BluetoothAdapter
- * Initializes a reference to the local Bluetooth adapter.
- *
- * @return Return true if the initialization is successful.
- */
- public boolean openBt() {
- if (mBluetoothAdapter == null) {
- Log.e(TAG, "BluetoothManager do not init");
- return false;
- }
- return mBluetoothAdapter.isEnabled() || mBluetoothAdapter.enable();
- }
-
- public boolean closeBt() {
- if (mBluetoothAdapter == null) {
- Log.e(TAG, "BluetoothManager do not init");
- return false;
- }
- return mBluetoothAdapter.disable();
- }
-
- public IBluetoothSearch getBluetoothSearcher() {
- if (mBluetoothSearcher == null) {
- synchronized (BluetoothLeClient.class) {
- if (mBluetoothSearcher == null) {
- if (mBluetoothAdapter == null) {
- String err = "cannot create BluetoothLeSearcher instance because not " +
- "initialize, please call initialize() method";
- Log.e(TAG, err);
- return null;
- }
-
- mBluetoothSearcher = new BluetoothLeSearcher(mContext, mBluetoothAdapter, mBluetoothWorker);
- }
- }
- }
-
- return mBluetoothSearcher;
- }
-
- public BluetoothLeConnector getBluetoothLeConnector(String mac) {
- BluetoothLeConnector result;
- if ((result = mGattConnectorMap.get(mac)) != null) {
- return result;
- }
-
- result = new BluetoothLeConnector(mContext, mBluetoothAdapter, mac, mBluetoothWorker);
- mGattConnectorMap.put(mac, result);
- return result;
- }
-
- public void cleanConnector(String mac) {
- BluetoothLeConnector result;
- if ((result = mGattConnectorMap.get(mac)) != null) {
- mGattConnectorMap.remove(mac);
- result.disconnect();
- result.setOnDataAvailableListener(null);
- }
- }
-
- /**
- * 在不在需要连接蓝牙设备的时候,
- * 或者生命周期暂停的时候调用这一个方法
- */
- public void cleanAllConnector() {
- for (String mac : mGattConnectorMap.keySet()) {
- cleanConnector(mac);
- }
- }
-
- /**
- * 获取已配对蓝牙设备信息
- */
- public Set getBondedDevices() {
- return mBluetoothAdapter.getBondedDevices();
- }
-}
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/BLEClientService.java b/commonbt/src/main/java/com/common/bluetooth/service/ble/BLEClientService.java
similarity index 98%
rename from commonbt/src/main/java/com/common/bluetooth/service/BLEClientService.java
rename to commonbt/src/main/java/com/common/bluetooth/service/ble/BLEClientService.java
index da5b625..76669c7 100644
--- a/commonbt/src/main/java/com/common/bluetooth/service/BLEClientService.java
+++ b/commonbt/src/main/java/com/common/bluetooth/service/ble/BLEClientService.java
@@ -1,4 +1,4 @@
-package com.common.bluetooth.service;
+package com.common.bluetooth.service.ble;
import static com.common.bluetooth.BtConstants.CONNECT_SUCCESS;
@@ -13,8 +13,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.common.bluetooth.BtConstants;
-import com.common.bluetooth.BtUtils;
-import com.common.bluetooth.adapter.BluetoothClientBLEAdapter;
+import com.common.bluetooth.utils.BtUtils;
import com.common.bluetooth.bean.CommonMsg;
import com.common.bluetooth.callback.BLEClientListener;
import com.common.bluetooth.callback.BaseResultCallback;
@@ -29,7 +28,6 @@ import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
-
/**
* BLE客户端服务
*
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/BLEReceiveService.java b/commonbt/src/main/java/com/common/bluetooth/service/ble/BLEReceiveService.java
similarity index 97%
rename from commonbt/src/main/java/com/common/bluetooth/service/BLEReceiveService.java
rename to commonbt/src/main/java/com/common/bluetooth/service/ble/BLEReceiveService.java
index fc62fd0..414dfce 100644
--- a/commonbt/src/main/java/com/common/bluetooth/service/BLEReceiveService.java
+++ b/commonbt/src/main/java/com/common/bluetooth/service/ble/BLEReceiveService.java
@@ -1,4 +1,4 @@
-package com.common.bluetooth.service;
+package com.common.bluetooth.service.ble;
import android.app.Service;
import android.bluetooth.BluetoothDevice;
@@ -18,15 +18,12 @@ import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelUuid;
-import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import com.common.bluetooth.BtConstants;
-import com.common.bluetooth.callback.BleMsgReceiverListener;
-
-import java.nio.charset.StandardCharsets;
+import com.common.bluetooth.callback.MsgReceiverListener;
/**
* BLE接收服务
@@ -51,7 +48,7 @@ public class BLEReceiveService extends Service {
/**
* 蓝牙消息接收监听
*/
- private BleMsgReceiverListener receiverListener;
+ private MsgReceiverListener receiverListener;
/**
* 远端设备
*/
@@ -159,7 +156,7 @@ public class BLEReceiveService extends Service {
}
}
- public void setMsgReceiveListener(BleMsgReceiverListener listener) {
+ public void setMsgReceiveListener(MsgReceiverListener listener) {
receiverListener = listener;
}
diff --git a/commonbt/src/main/java/com/common/bluetooth/adapter/BluetoothClientBLEAdapter.java b/commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothClientBLEAdapter.java
similarity index 97%
rename from commonbt/src/main/java/com/common/bluetooth/adapter/BluetoothClientBLEAdapter.java
rename to commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothClientBLEAdapter.java
index 71ad17a..baccdb0 100644
--- a/commonbt/src/main/java/com/common/bluetooth/adapter/BluetoothClientBLEAdapter.java
+++ b/commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothClientBLEAdapter.java
@@ -1,4 +1,4 @@
-package com.common.bluetooth.adapter;
+package com.common.bluetooth.service.ble;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
@@ -17,8 +17,6 @@ import com.common.bluetooth.exception.BluetoothSearchConflictException;
import com.common.bluetooth.exception.BluetoothWriteException;
import com.common.bluetooth.interfaces.IBluetoothClient;
import com.common.bluetooth.interfaces.IBluetoothSearch;
-import com.common.bluetooth.service.BluetoothLeClient;
-import com.common.bluetooth.service.BluetoothLeConnector;
import java.util.HashSet;
import java.util.Set;
@@ -53,7 +51,7 @@ public class BluetoothClientBLEAdapter implements IBluetoothClient {
}
@Override
- public Observable search(final int millis, final boolean cancel) {
+ public Observable search(final long millis, final boolean cancel) {
return Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(@NonNull final ObservableEmitter emitter) {
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothLeClient.java b/commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothLeClient.java
new file mode 100644
index 0000000..fd2a243
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothLeClient.java
@@ -0,0 +1,79 @@
+package com.common.bluetooth.service.ble;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.common.bluetooth.service.BluetoothCommon;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 蓝牙操作管理类
+ *
+ * @author wangym
+ * @since 2021-10-19
+ */
+public class BluetoothLeClient extends BluetoothCommon {
+ @SuppressLint("StaticFieldLeak")
+ private static volatile BluetoothLeClient mInstance;
+
+ private final static String TAG = "BluetoothLeClient";
+ private final Context mContext;
+ private static Handler mBluetoothWorker;
+
+ private final Map mGattConnectorMap
+ = new ConcurrentHashMap<>();
+
+ private BluetoothLeClient(Context context) {
+ super(context.getApplicationContext());
+ mContext = context.getApplicationContext();
+ HandlerThread thread = new HandlerThread("bluetooth client worker");
+ thread.start();
+ mBluetoothWorker = new Handler(thread.getLooper());
+ }
+
+ public static BluetoothLeClient getInstance(Context context) {
+ if (mInstance == null) {
+ synchronized (BluetoothLeClient.class) {
+ if (mInstance == null) {
+ mInstance = new BluetoothLeClient(context);
+ }
+ }
+ }
+
+ return mInstance;
+ }
+
+ public BluetoothLeConnector getBluetoothLeConnector(String mac) {
+ BluetoothLeConnector result;
+ if ((result = mGattConnectorMap.get(mac)) != null) {
+ return result;
+ }
+
+ result = new BluetoothLeConnector(mContext, getMBluetoothAdapter(), mac, mBluetoothWorker);
+ mGattConnectorMap.put(mac, result);
+ return result;
+ }
+
+ public void cleanConnector(String mac) {
+ BluetoothLeConnector result;
+ if ((result = mGattConnectorMap.get(mac)) != null) {
+ mGattConnectorMap.remove(mac);
+ result.disconnect();
+ result.setOnDataAvailableListener(null);
+ }
+ }
+
+ /**
+ * 在不在需要连接蓝牙设备的时候,
+ * 或者生命周期暂停的时候调用这一个方法
+ */
+ public void cleanAllConnector() {
+ for (String mac : mGattConnectorMap.keySet()) {
+ cleanConnector(mac);
+ }
+ }
+}
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothLeConnector.java b/commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothLeConnector.java
similarity index 99%
rename from commonbt/src/main/java/com/common/bluetooth/service/BluetoothLeConnector.java
rename to commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothLeConnector.java
index fbda5e7..932280f 100644
--- a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothLeConnector.java
+++ b/commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothLeConnector.java
@@ -1,4 +1,4 @@
-package com.common.bluetooth.service;
+package com.common.bluetooth.service.ble;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -23,7 +23,6 @@ import java.util.concurrent.atomic.AtomicLong;
import io.reactivex.rxjava3.functions.Consumer;
-
/**
* Service for managing connection and data communication with a GATT server
* hosted on a given Bluetooth LE device.
@@ -417,8 +416,8 @@ public class BluetoothLeConnector {
try {
action.accept(gattCharacteristic);
- } catch (Throwable e) {
- e.printStackTrace();
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
}
}
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothLeSearcher.java b/commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothLeSearcher.java
similarity index 99%
rename from commonbt/src/main/java/com/common/bluetooth/service/BluetoothLeSearcher.java
rename to commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothLeSearcher.java
index 6819967..fecb3fe 100644
--- a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothLeSearcher.java
+++ b/commonbt/src/main/java/com/common/bluetooth/service/ble/BluetoothLeSearcher.java
@@ -1,4 +1,4 @@
-package com.common.bluetooth.service;
+package com.common.bluetooth.service.ble;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/bt/BTCClientService.java b/commonbt/src/main/java/com/common/bluetooth/service/bt/BTCClientService.java
new file mode 100644
index 0000000..8c3f24c
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/service/bt/BTCClientService.java
@@ -0,0 +1,102 @@
+package com.common.bluetooth.service.bt;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.common.bluetooth.BtConstants;
+import com.common.bluetooth.callback.BtMsgListener;
+
+/**
+ * 经典蓝牙服务端
+ *
+ * @author wangym
+ * @since 2021-10-29
+ */
+public class BTCClientService extends Service {
+ private static final String TAG = "BTCClientService";
+ /**
+ * 检点蓝牙服务端
+ */
+ private BluetoothClassicClient classicClient;
+
+ /**
+ * 消息回调
+ */
+ private final BtMsgListener mMsgListener = new BtMsgListener() {
+ @Override
+ public void socketNotify(int state, @NonNull String msg) {
+ super.socketNotify(state, msg);
+ // 将内容消息透传给外部调用者
+ if (msgListener != null) {
+ msgListener.socketNotify(state, msg);
+ }
+ }
+ };
+
+ /**
+ * 消息回调
+ */
+ private BtMsgListener msgListener = null;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ Log.i(TAG, "initialize BluetoothManager");
+ classicClient = new BluetoothClassicClient(this);
+ classicClient.checkBtDevice(BtConstants.BLUETOOTH_TYPE.CLASSIC);
+ }
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new ClassicClientBinder();
+ }
+
+ public class ClassicClientBinder extends Binder {
+ public BTCClientService getService() {
+ return BTCClientService.this;
+ }
+ }
+
+ public void setMsgReceiveListener(BtMsgListener listener) {
+ msgListener = listener;
+ }
+
+ public void connect(String mac) {
+ if (classicClient == null) {
+ Log.e(TAG, "classicClient not init success");
+ return;
+ }
+ classicClient.setListener(mMsgListener);
+ classicClient.connect(mac);
+ }
+
+ /**
+ * 向客户端发送通知
+ *
+ * @param msg 消息
+ */
+ public void write(byte[] msg) {
+ Log.i(TAG, "write msg = " + new String(msg));
+ if (classicClient != null && msg != null) {
+ Log.i(TAG, "---send msg start---");
+ classicClient.sendMsg(msg);
+ Log.i(TAG, "---send msg end---");
+ } else {
+ Log.e(TAG, "got msg null");
+ }
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ classicClient.close();
+ return super.onUnbind(intent);
+ }
+}
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/bt/BTCReceiverService.java b/commonbt/src/main/java/com/common/bluetooth/service/bt/BTCReceiverService.java
new file mode 100644
index 0000000..9bc8c23
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/service/bt/BTCReceiverService.java
@@ -0,0 +1,108 @@
+package com.common.bluetooth.service.bt;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.common.bluetooth.callback.BtMsgListener;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 经典蓝牙服务端
+ *
+ * @author wangym
+ * @since 2021-10-29
+ */
+public class BTCReceiverService extends Service {
+ private static final String TAG = "BTCReceiverService";
+ /**
+ * 检点蓝牙服务端
+ */
+ private BluetoothClassicServer classicServer;
+
+ /**
+ * 消息回调
+ */
+ private final BtMsgListener mMsgListener = new BtMsgListener() {
+ @Override
+ public void socketNotify(int state, @NonNull String msg) {
+ super.socketNotify(state, msg);
+ // 当客户端断开连接时,需要重新开始监听客户端的连接
+ if (state == BtMsgListener.DISCONNECTED) {
+ if (classicServer != null) {
+ classicServer.listen();
+ }
+ } else if (state == BtMsgListener.MSG) {
+ // 服务端只关心内容消息
+ // 将内容消息透传给外部调用者
+ if (msgListener != null) {
+ msgListener.socketNotify(state, msg);
+ }
+ }
+ }
+ };
+
+ /**
+ * 消息回调
+ */
+ private BtMsgListener msgListener = null;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ Log.i(TAG, "initialize BluetoothManager");
+ classicServer = new BluetoothClassicServer(this);
+ }
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (classicServer != null) {
+ classicServer.setListener(mMsgListener);
+ classicServer.listen();
+ }
+ return new ClassicReceiverBinder();
+ }
+
+ public class ClassicReceiverBinder extends Binder {
+ public BTCReceiverService getService() {
+ return BTCReceiverService.this;
+ }
+ }
+
+ public void setMsgReceiveListener(BtMsgListener listener) {
+ msgListener = listener;
+ }
+
+ /**
+ * 向客户端发送通知
+ *
+ * @param msg 消息
+ */
+ public void write(byte[] msg) {
+ Log.i(TAG, "sendNotify msg = " + new String(msg));
+ if (classicServer != null && msg != null) {
+ Log.i(TAG, "---send msg start---");
+ classicServer.sendMsg(msg);
+ Log.i(TAG, "---send msg end---");
+ } else {
+ Log.e(TAG, "got msg null");
+ }
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ if (classicServer != null) {
+ classicServer.setListener(null);
+ classicServer.close();
+ }
+ return super.onUnbind(intent);
+ }
+}
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicBase.java b/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicBase.java
new file mode 100644
index 0000000..562b9f9
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicBase.java
@@ -0,0 +1,259 @@
+package com.common.bluetooth.service.bt;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSocket;
+import android.content.Context;
+import android.os.Environment;
+import android.util.Log;
+
+import com.common.bluetooth.BtConstants;
+import com.common.bluetooth.callback.BtMsgListener;
+import com.common.bluetooth.service.BluetoothCommon;
+import com.common.bluetooth.utils.BtUtils;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * 客户端和服务端的基类,用于管理socket长连接
+ *
+ * @author wangym
+ * @since 2.21-12-2
+ */
+public class BluetoothClassicBase extends BluetoothCommon {
+ private static final String TAG = "BluetoothClassicBase";
+ private static final String FILE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/bluetooth/";
+ private static final int FLAG_MSG = 0; //消息标记
+ private static final int FLAG_FILE = 1; //文件标记
+
+ protected BluetoothSocket mSocket;
+ private DataOutputStream mOut;
+ private BtMsgListener mListener;
+ /**
+ * 是否在读取中
+ */
+ private final AtomicBoolean isRead = new AtomicBoolean(false);
+ /**
+ * 是否在发送中
+ */
+ private final AtomicBoolean isSending = new AtomicBoolean(false);
+
+ /**
+ * 消息队列
+ */
+ private final LinkedBlockingQueue msgQueue = new LinkedBlockingQueue<>();
+
+ public BluetoothClassicBase(Context context) {
+ super(context);
+ }
+
+ /**
+ * 设置消息的监听
+ *
+ * @param mListener 监听
+ */
+ public void setListener(BtMsgListener mListener) {
+ this.mListener = mListener;
+ }
+
+ /**
+ * 循环读取对方数据(若没有数据,则阻塞等待)
+ */
+ void loopRead(BluetoothSocket socket) {
+ mSocket = socket;
+ try {
+ if (!mSocket.isConnected()) {
+ mSocket.connect();
+ }
+ String mac = mSocket.getRemoteDevice().getAddress();
+ notifyUI(BtMsgListener.CONNECTED, mac);
+ // 将链接成功的MAC地址保存下来
+ BtUtils.INSTANCE.saveConnectMac(getMContext(), mac);
+ mOut = new DataOutputStream(mSocket.getOutputStream());
+ DataInputStream in = new DataInputStream(mSocket.getInputStream());
+ isRead.set(true);
+ while (isRead.get()) { //死循环读取
+ switch (in.readInt()) {
+ case FLAG_MSG: //读取短消息
+ String msg = in.readUTF();
+ Log.d(TAG, "接收短消息:" + msg);
+ notifyUI(BtMsgListener.MSG, msg);
+ break;
+ case FLAG_FILE: //读取文件
+ new File(FILE_PATH).mkdirs();
+ String fileName = in.readUTF(); //文件名
+ long fileLen = in.readLong(); //文件长度
+ // 读取文件内容
+ long len = 0;
+ int r;
+ byte[] b = new byte[4 * 1024];
+ FileOutputStream out = new FileOutputStream(FILE_PATH + fileName);
+ Log.d(TAG, "正在接收文件(" + fileName + "),请稍后...");
+ while ((r = in.read(b)) != -1) {
+ out.write(b, 0, r);
+ len += r;
+ if (len >= fileLen) {
+ break;
+ }
+ }
+ Log.d(TAG, "文件接收完成(存放在:" + FILE_PATH + ")");
+ break;
+ }
+ }
+ } catch (Throwable e) {
+ close();
+ }
+ }
+
+ /**
+ * 发送短消息
+ */
+ public void sendMsg(byte[] msg) {
+ Log.d(TAG, "send msg");
+ if (mSocket == null || !mSocket.isConnected()) {
+ Log.e(TAG, "sendMsg got socket is not connect");
+ return;
+ }
+ msgQueue.add(msg);
+ if (checkSend()) {
+ Log.d(TAG, "sending wait");
+ return;
+ }
+ synchronized (BluetoothClassicBase.class) {
+ isSending.set(true);
+ // 循环发送消息
+ while (true) {
+ if (!doSendMsg()) {
+ break;
+ }
+ }
+ isSending.set(false);
+ }
+ }
+
+ /**
+ * 发送消息
+ */
+ public boolean doSendMsg() {
+ final byte[] msgItem = msgQueue.poll();
+ if (msgItem == null) {
+ Log.d(TAG, "doTranslate Queue is null");
+ return false;
+ }
+ try {
+ mOut.writeInt(FLAG_MSG); //消息标记
+ mOut.writeUTF(new String(msgItem, BtConstants.INSTANCE.getDEFAULT_CHARSET()));
+ mOut.flush();
+ Log.d(TAG, "发送短消息:" + new String(msgItem, BtConstants.INSTANCE.getDEFAULT_CHARSET()));
+ } catch (Throwable e) {
+ close();
+ isSending.set(false);
+ }
+ return true;
+ }
+
+ /**
+ * 发送文件
+ */
+ public void sendFile(final String filePath) {
+ if (checkSend()) return;
+ isSending.set(true);
+ Executors.newCachedThreadPool().execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ FileInputStream in = new FileInputStream(filePath);
+ File file = new File(filePath);
+ mOut.writeInt(FLAG_FILE); //文件标记
+ mOut.writeUTF(file.getName()); //文件名
+ mOut.writeLong(file.length()); //文件长度
+ int r;
+ byte[] b = new byte[4 * 1024];
+ notifyUI(BtMsgListener.MSG, "正在发送文件(" + filePath + "),请稍后...");
+ while ((r = in.read(b)) != -1)
+ mOut.write(b, 0, r);
+ mOut.flush();
+ notifyUI(BtMsgListener.MSG, "文件发送完成.");
+ } catch (Throwable e) {
+ close();
+ }
+ isSending.set(false);
+ }
+ });
+ }
+
+ /**
+ * 关闭Socket连接
+ */
+ public void close() {
+ Log.d(TAG, "close");
+ try {
+ String mac = "";
+ isRead.set(false);
+ if (mSocket != null) {
+ mSocket.close();
+ mac = mSocket.getRemoteDevice().getAddress();
+ }
+ notifyUI(BtMsgListener.DISCONNECTED, mac);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 无回调关闭Socket
+ */
+ public void closeSilence(){
+ Log.d(TAG, "closeSilence");
+ try {
+ isRead.set(false);
+ if (mSocket != null) {
+ mSocket.close();
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 当前设备与指定设备是否连接
+ *
+ * @param mac 设备MAC地址
+ * @return 是否已经和对应设备拦截
+ */
+ public boolean isConnected(String mac) {
+ BluetoothDevice dev = getBtDeviceByMac(mac);
+ boolean connected = (mSocket != null && mSocket.isConnected());
+ if (dev == null) {
+ return connected;
+ }
+ return connected && mSocket.getRemoteDevice().equals(dev);
+ }
+
+ /**
+ * 是否在发送中
+ *
+ * @return 是否发送中
+ */
+ private synchronized boolean checkSend() {
+ return isSending.get();
+ }
+
+ /**
+ * 通知外部接收信息
+ *
+ * @param state 消息类型
+ * @param msg 消息内容
+ */
+ protected void notifyUI(final int state, final String msg) {
+ if (mListener != null) {
+ mListener.socketNotify(state, msg);
+ }
+ }
+}
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicClient.java b/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicClient.java
new file mode 100644
index 0000000..adb25b9
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicClient.java
@@ -0,0 +1,56 @@
+package com.common.bluetooth.service.bt;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSocket;
+import android.content.Context;
+import android.util.Log;
+
+import com.common.bluetooth.BtConstants;
+import com.common.bluetooth.callback.BtMsgListener;
+
+import java.util.concurrent.Executors;
+
+/**
+ * 经典蓝牙客户端,与服务端建立长连接
+ *
+ * @author wangym
+ * @since 2021-12-1
+ */
+public class BluetoothClassicClient extends BluetoothClassicBase {
+ private static final String TAG = "BtClient";
+
+ public BluetoothClassicClient(Context context) {
+ super(context);
+ }
+
+ /**
+ * 与远端设备建立长连接
+ *
+ * @param mac 设备MAC
+ */
+ public void connect(String mac) {
+ Log.d(TAG, "start connect mac:" + mac);
+ BluetoothDevice bluetoothDevice = getBtDeviceByMac(mac);
+ if (bluetoothDevice == null) {
+ Log.e(TAG, "connect got device is null : mac is " + mac);
+ notifyUI(BtMsgListener.DISCONNECTED, mac);
+ return;
+ }
+ if (isConnected(mac)) {
+ Log.i(TAG, "connected, no need to close socket");
+ return;
+ }
+ closeSilence();
+ try {
+// final BluetoothSocket socket = dev.createRfcommSocketToServiceRecord(SPP_UUID); //加密传输,Android系统强制配对,弹窗显示配对码
+ final BluetoothSocket socket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(
+ BtConstants.INSTANCE.getCLASSIC_BT_UUID()); //明文传输(不安全),无需配对
+ // 开启子线程
+ Executors.newCachedThreadPool().execute(() -> {
+ loopRead(socket); //循环读取
+ });
+ } catch (Throwable e) {
+ close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothClassicSearcher.java b/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicSearcher.java
similarity index 96%
rename from commonbt/src/main/java/com/common/bluetooth/service/BluetoothClassicSearcher.java
rename to commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicSearcher.java
index 2688e3e..cced34c 100644
--- a/commonbt/src/main/java/com/common/bluetooth/service/BluetoothClassicSearcher.java
+++ b/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicSearcher.java
@@ -1,4 +1,4 @@
-package com.common.bluetooth.service;
+package com.common.bluetooth.service.bt;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicServer.java b/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicServer.java
new file mode 100644
index 0000000..6769ce2
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClassicServer.java
@@ -0,0 +1,59 @@
+package com.common.bluetooth.service.bt;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSocket;
+import android.content.Context;
+
+import com.common.bluetooth.BtConstants;
+
+import java.util.concurrent.Executors;
+
+/**
+ * 服务端监听和连接线程,只连接一个设备
+ *
+ * @author wangym
+ * @version 2021-12-2
+ */
+public class BluetoothClassicServer extends BluetoothClassicBase {
+ private static final String TAG = BluetoothClassicServer.class.getSimpleName();
+ private BluetoothServerSocket mSSocket;
+
+ BluetoothClassicServer(Context context) {
+ super(context);
+ }
+
+ /**
+ * 监听客户端发起的连接
+ */
+ public void listen() {
+ try {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+// mSSocket = adapter.listenUsingRfcommWithServiceRecord(TAG, SPP_UUID); //加密传输,Android强制执行配对,弹窗显示配对码
+ mSSocket = adapter.listenUsingInsecureRfcommWithServiceRecord(TAG,
+ BtConstants.INSTANCE.getCLASSIC_BT_UUID()); //明文传输(不安全),无需配对
+ // 开启子线程
+ Executors.newCachedThreadPool().execute(() -> {
+ try {
+ BluetoothSocket socket = mSSocket.accept(); // 监听连接
+ mSSocket.close(); // 关闭监听,只连接一个设备
+ loopRead(socket); // 循环读取
+ } catch (Throwable e) {
+ close();
+ }
+ });
+ } catch (Throwable e) {
+ close();
+ }
+ }
+
+ @Override
+ public void close() {
+ try {
+ mSSocket.close();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ super.close();
+ }
+}
\ No newline at end of file
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClientClassicAdapter.kt b/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClientClassicAdapter.kt
new file mode 100644
index 0000000..076f227
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/service/bt/BluetoothClientClassicAdapter.kt
@@ -0,0 +1,98 @@
+package com.common.bluetooth.service.bt
+
+import android.bluetooth.BluetoothDevice
+import com.common.bluetooth.BtConstants
+import com.common.bluetooth.callback.BaseResultCallback
+import com.common.bluetooth.interfaces.IBluetoothClient
+import io.reactivex.rxjava3.core.Observable
+import java.util.UUID
+
+/**
+ * 经典蓝牙适配器
+ *
+ * @author wangym
+ * @since 2021-12-1
+ */
+class BluetoothClientClassicAdapter(private var mClient: BluetoothClassicClient) :
+ IBluetoothClient {
+ val TAG = "BluetoothClientAdapter"
+
+ override fun search(millis: Long, cancel: Boolean): Observable {
+ return Observable.create {
+ mClient.getBluetoothSearcher().startScan(millis, null)
+ it.onComplete()
+ }
+ }
+
+ override fun stopSearch() {
+ mClient.getBluetoothSearcher().stopScan()
+ }
+
+ override fun connect(mac: String): Observable {
+ return Observable.create {
+ if (!mClient.isConnected((mac))) {
+ mClient.connect(mac)
+ }
+ it.onNext(mac)
+ it.onComplete()
+ }
+ }
+
+ override fun disconnect(mac: String) {
+ mClient.close()
+ }
+
+ override fun write(
+ mac: String,
+ service: UUID,
+ characteristic: UUID,
+ values: ByteArray
+ ): Observable? {
+ return Observable.create {
+ if (!mClient.isConnected((mac))) {
+ mClient.sendMsg(values)
+ }
+ it.onNext(mac)
+ it.onComplete()
+ }
+ }
+
+ override fun checkBluetoothDevice(type: BtConstants.BLUETOOTH_TYPE): Boolean {
+ return mClient.checkBtDevice(type)
+ }
+
+ override fun openBluetooth() {
+ mClient.openBt()
+ }
+
+ override fun closeBluetooth(): Boolean {
+ return mClient.closeBt()
+ }
+
+ override fun getBondedDevices(): Set? {
+ return mClient.getBondedDevices()
+ }
+
+ override fun registerNotify(
+ mac: String,
+ service: UUID,
+ characteristic: UUID,
+ callback: BaseResultCallback?
+ ): Observable {
+ return Observable.create {}
+ }
+
+ override fun unRegisterNotify(
+ mac: String,
+ service: UUID,
+ characteristic: UUID
+ ): Observable? {
+ return null
+ }
+
+ override fun clean(mac: String) {
+ }
+
+ override fun cleanAll() {
+ }
+}
\ No newline at end of file
diff --git a/commonbt/src/main/java/com/common/bluetooth/service/bt/BtReceiver.java b/commonbt/src/main/java/com/common/bluetooth/service/bt/BtReceiver.java
new file mode 100644
index 0000000..b1fe75f
--- /dev/null
+++ b/commonbt/src/main/java/com/common/bluetooth/service/bt/BtReceiver.java
@@ -0,0 +1,94 @@
+package com.common.bluetooth.service.bt;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+/**
+ * 监听蓝牙广播-各种状态
+ */
+public class BtReceiver extends BroadcastReceiver {
+ private static final String TAG = BtReceiver.class.getSimpleName();
+ private final Listener mListener;
+
+ public BtReceiver(Context cxt, Listener listener) {
+ mListener = listener;
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙开关状态
+ filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//蓝牙开始搜索
+ filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//蓝牙搜索结束
+
+ filter.addAction(BluetoothDevice.ACTION_FOUND);//蓝牙发现新设备(未配对的设备)
+ filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);//在系统弹出配对框之前(确认/输入配对码)
+ filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//设备配对状态改变
+ filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);//最底层连接建立
+ filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);//最底层连接断开
+
+ filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); //BluetoothAdapter连接状态
+ filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); //BluetoothHeadset连接状态
+ filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); //BluetoothA2dp连接状态
+ cxt.registerReceiver(this, filter);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action == null)
+ return;
+ Log.i(TAG, "===" + action);
+ BluetoothDevice dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (dev != null)
+ Log.i(TAG, "BluetoothDevice: " + dev.getName() + ", " + dev.getAddress());
+ switch (action) {
+ case BluetoothAdapter.ACTION_STATE_CHANGED:
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
+ Log.i(TAG, "STATE: " + state);
+ break;
+ case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
+ break;
+ case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
+ break;
+
+ case BluetoothDevice.ACTION_FOUND:
+ short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MAX_VALUE);
+ Log.i(TAG, "EXTRA_RSSI:" + rssi);
+ mListener.foundDev(dev);
+ break;
+ case BluetoothDevice.ACTION_PAIRING_REQUEST: //在系统弹出配对框之前,实现自动配对,取消系统配对框
+ /*try {
+ abortBroadcast();//终止配对广播,取消系统配对框
+ boolean ret = dev.setPin("1234".getBytes()); //设置PIN配对码(必须是固定的)
+ } catch (Exception e) {
+ e.printStackTrace();
+ }*/
+ break;
+ case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
+ Log.i(TAG, "BOND_STATE: " + intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 0));
+ break;
+ case BluetoothDevice.ACTION_ACL_CONNECTED:
+ break;
+ case BluetoothDevice.ACTION_ACL_DISCONNECTED:
+ break;
+
+ case BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED:
+ Log.i(TAG, "CONN_STATE: " + intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 0));
+ break;
+ case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
+ Log.i(TAG, "CONN_STATE: " + intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 0));
+ break;
+ case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
+ Log.i(TAG, "CONN_STATE: " + intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, 0));
+ break;
+ }
+ }
+
+ public interface Listener {
+ void foundDev(BluetoothDevice dev);
+ }
+}
\ No newline at end of file
diff --git a/commonbt/src/main/java/com/common/bluetooth/BtUtils.kt b/commonbt/src/main/java/com/common/bluetooth/utils/BtUtils.kt
similarity index 99%
rename from commonbt/src/main/java/com/common/bluetooth/BtUtils.kt
rename to commonbt/src/main/java/com/common/bluetooth/utils/BtUtils.kt
index e17ee9f..bc73922 100644
--- a/commonbt/src/main/java/com/common/bluetooth/BtUtils.kt
+++ b/commonbt/src/main/java/com/common/bluetooth/utils/BtUtils.kt
@@ -1,4 +1,4 @@
-package com.common.bluetooth
+package com.common.bluetooth.utils
import android.content.Context
import android.content.SharedPreferences
@@ -113,6 +113,11 @@ object BtUtils {
*/
const val MOD_I_CN = "6"
+ /**
+ * 设置
+ */
+ const val MOD_S = "7"
+
/**
* 中间包
*/
diff --git a/commonbt/src/main/java/com/common/bluetooth/view/BtDeviceListAdapter.java b/commonbt/src/main/java/com/common/bluetooth/view/BtDeviceListAdapter.java
index 1fb62df..ab42f3e 100644
--- a/commonbt/src/main/java/com/common/bluetooth/view/BtDeviceListAdapter.java
+++ b/commonbt/src/main/java/com/common/bluetooth/view/BtDeviceListAdapter.java
@@ -33,13 +33,13 @@ public class BtDeviceListAdapter extends RecyclerView.Adapter
+
+
+
+
\ No newline at end of file