Content
Part # 2 (connecting / disconnecting), you are here.
In the previous article, we looked at device scanning in detail. This article is about connecting , disconnecting, and discovering services .
Connect to device
, , connectGatt()
. β BluetoothGatt
, GATT , . , connectGatt()
. Android , Android-6 :
BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback)
BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport)
β transport = TRANSPORT_AUTO
. BLE . TRANSPORT_AUTO
BLE Bluetooth . , Android . , . connectGatt()
transport = TRANSPORT_LE
:
BluetoothGatt gatt = device.connectGatt(context, false,
bluetoothGattCallback, TRANSPORT_LE);
β context
. β autoconnect
, (false
) (true
). (false
) Android 30 ( ), status_code = 133
. . Android GATT_ERROR
. , . , autoconnect = false
Android ( - , ). β BluetoothGattCallback
(callback) . , . .
Autoconnect = true
autoconnect = true
, Android , . : Bluetooth β . , , . , . BluetoothDevice
connectGatt
autoconnect = true
.
BluetoothDevice device =
bluetoothAdapter.getRemoteDevice("12:34:56:AA:BB:CC");
BluetoothGatt gatt =
device.connectGatt(context, true, bluetoothGattCallback, TRANSPORT_LE);
, , Bluetooth (bonding). , Bluetooth . / Bluetooth ( Airplane ) β , autoconnect = true
, .
Autoconnect (bonded) !
, , , . BluetoothDevice
, getType
, β TYPE_UNKNOWN
, . , - ( ) .
Android-6 , (autoconnect = false
). , Polidea . , .
:
Android (. - Android-8 ).
;
:
, +
autoconnect = false
. AndroidSCAN_MODE_LOW_POWER
, .
connectGatt()
, Bluetooth onConnectionStateChange
, .
β . ( ):
public void onConnectionStateChange(final BluetoothGatt gatt,
final int status,
final int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices();
} else {
gatt.close();
}
}
newState
status
. . , , β discoverServices()
. - close()
, Android Bluetooth. BLE Android, !
connectGatt()
, Bluetooth (client interface: clientIf
).
LogCat:
D/BluetoothGatt: connect() - device: B0:49:5F:01:20:XX, auto: false
D/BluetoothGatt: registerApp()
D/BluetoothGatt: registerApp() β UUID=0e47c0cf-ef13β4afb-9f54β8cf3e9e808d5
D/BluetoothGatt: onClientRegistered() β status=0 clientIf=6
, 6
connectGatt()
. () Android 30 ( GATT_MAX_APPS
), β Android . , Android 5 6 , , Android . , close()
, connectGatt()
. close()
, Bluetooth , .
D/BluetoothGatt: close() D/BluetoothGatt: unregisterApp() β mClientIf=6
close()
! .
(newState)
newState
4 :
STATE_CONNECTED
STATE_DISCONNECTED
STATE_CONNECTING
STATE_DISCONNECTING
. STATE_CONNECTING
, STATE_DISCONNECTING
, . , , , , (. - , ), close()
.
(status)
, status
, . , , . GATT_SUCCESS
, . , - . GATT_SUCCESS
, Β«- Β» status
. , BluetoothGatt
, . 133 (GATT_ERROR
). , β Β« - Β». , GATT_ERROR
.
, newState
status
, onConnectionStateChange
:
public void onConnectionStateChange(final BluetoothGatt gatt,
final int status,
final int newState) {
if(status == GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
// ,
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
// ( )
gatt.close();
} else {
// ,
}
} else {
// ... , !
...
gatt.close();
}
, . , .
bonding (bondState)
, onConnectionStateChange
β bondState
, (bonding) . :
int bondstate = device.getBondState();
bonding BOND_NONE
, BOND_BONDING
or BOND_BONDED
. , .
BOND_NONE
, ,discoverServices()
;
BOND_BONDING
, ,discoverServices()
, BluetoothdiscoverServices()
.discoverServices()
, (bonding);
BOND_BONDED
, Android-8 ,discoverServices()
. 7 . Service Changed Characteristic, BluetoothdiscoverServices()
. 1000-1500 , . , Service Changed Characteristic .
bondState
status
newState
:
if (status == GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
int bondstate = device.getBondState();
// bondState
if(bondstate == BOND_NONE || bondstate == BOND_BONDED) {
// , discoverServices
int delayWhenBonded = 0;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
delayWhenBonded = 1000;
}
final int delay = bondstate == BOND_BONDED ? delayWhenBonded : 0;
discoverServicesRunnable = new Runnable() {
@Override
public void run() {
Log.d(TAG, String.format(Locale.ENGLISH, "discovering services of '%s' with delay of %d ms", getName(), delay));
boolean result = gatt.discoverServices();
if (!result) {
Log.e(TAG, "discoverServices failed to start");
}
discoverServicesRunnable = null;
}
};
bleHandler.postDelayed(discoverServicesRunnable, delay);
} else if (bondstate == BOND_BONDING) {
// Bonding ,
Log.i(TAG, "waiting for bonding to complete");
}
....
, . , «», .
. , . - 19 (
GATT_CONN_TERMINATE_PEER_USER
);
. - 8 (
GATT_CONN_TIMEOUT
);
, . - 133 (
GATT_ERROR
) , ;
Bluetooth . - 133 (
GATT_ERROR
);
bonding
discoverServices
. .
- close()
BluetoothGatt
, . , , , - . UI , - . .
133 (connecting)
- 133 , . , :
,
close()
. ,status=133
;
TRANSPORT_LE
connectGatt()
;
. Bluetooth . (. : / Bluetooth, Airplane - );
advertising .
connectGatt()
autoconnect = false
30 ,status=133
;
/ . ;
133, ! Android , . 133 , close()
, ! , Android close()
. - , β !
(disconnect)
:
disconnect()
;
onConnectionStateChange
;
close()
;
gatt ;
disconnect()
Bluetooth . onConnectionStateChange
Β«disconnectedΒ».
close()
BluetoothGattCallback
Bluetooth .
, BluetoothGatt
.
«»
, , :
disconnect()
close()
-. , Β«disconnectedΒ». , disconnect()
( ), close()
! , Android , .
disconnect()
, close()
. , , disconnect()
( autoconnect = true
). , close()
, .
connectGatt()
, disconnect()
. , onConnectionStateChange
! disconnect()
close()
(. : 50-100).
:
D/BluetoothGatt: cancelOpen() β device: CF:A9:BA:D9:62:9E
, , autoconnect = false
. autoconnect = true
. , β , .
. : autoconnect = false
!
(discovering services)
, discoverServices()
. Bluetooth , . , , . onServicesDiscovered.
, :
// ? -
if (status == GATT_INTERNAL_ERROR) {
Log.e(TAG, "Service discovery failed");
disconnect();
return;
}
( GATT_INTERNAL_ERROR
129), , - ( ). .
, :
final List<BluetoothGattService> services = gatt.getServices();
Log.i(TAG, String.format(Locale.ENGLISH,"discovered %d services for '%s'", services.size(), getName()));
// ( )
...
.
Bluetooth , . , β . Bluetooth. . , , . : , , , . Java:
private boolean clearServicesCache() {
boolean result = false;
try {
Method refreshMethod = bluetoothGatt.getClass().getMethod("refresh");
if(refreshMethod != null) {
result = (boolean) refreshMethod.invoke(bluetoothGatt);
}
} catch (Exception e) {
Log.e(TAG, "ERROR: Could not invoke refresh method");
}
return result;
}
, !
/
, , .
133 , ;
,
onConnectionStateChange
. , Bluetooth. , . β β ;
. , Huawei P8 Lite . (. : !);
/ . , , . (. : 50-100 ).
: .
/ , β , .
Can't wait to work with BLE? Try my Blessed for Android library . It takes all the approaches in this article series and makes it easy to work with BLE in your application.