@Override public final void onServicesDiscovered(final BluetoothGatt gatt, final int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Logger.i(mLogSession, "Services Discovered"); if (isRequiredServiceSupported(gatt)) { Logger.v(mLogSession, "Primary service found"); final boolean optionalServicesFound = isOptionalServiceSupported(gatt); if (optionalServicesFound) Logger.v(mLogSession, "Secondary service found"); // Notify the parent activity mCallbacks.onServicesDiscovered(optionalServicesFound); // Obtain the queue of initialization requests mInitInProgress = true; mInitQueue = initGatt(gatt); // When the device is bonded and has Service Changed characteristic, the indications must // be enabled first. // In case this method returns true we have to continue in the onDescriptorWrite callback if (ensureServiceChangedEnabled(gatt)) return; // We have discovered services, let's start by reading the battery level value. If the // characteristic is not readable, try to enable notifications. // If there is no Battery service, proceed with the initialization queue. if (!readBatteryLevel()) nextRequest(); } else { Logger.w(mLogSession, "Device is not supported"); mCallbacks.onDeviceNotSupported(); disconnect(); } } else { DebugLogger.e(TAG, "onServicesDiscovered error " + status); onError(ERROR_DISCOVERY_SERVICE, status); } }
/** * This method tries to enable notifications on the Battery Level characteristic. * * @param enable <code>true</code> to enable battery notifications, false to disable * @return true if request has been sent */ public boolean setBatteryNotifications(final boolean enable) { final BluetoothGatt gatt = mBluetoothGatt; if (gatt == null) { return false; } final BluetoothGattService batteryService = gatt.getService(BATTERY_SERVICE); if (batteryService == null) return false; final BluetoothGattCharacteristic batteryLevelCharacteristic = batteryService.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC); if (batteryLevelCharacteristic == null) return false; // Check characteristic property final int properties = batteryLevelCharacteristic.getProperties(); if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) == 0) return false; gatt.setCharacteristicNotification(batteryLevelCharacteristic, enable); final BluetoothGattDescriptor descriptor = batteryLevelCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); if (descriptor != null) { if (enable) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); Logger.a(mLogSession, "Enabling battery level notifications..."); Logger.v(mLogSession, "Enabling notifications for " + BATTERY_LEVEL_CHARACTERISTIC); Logger.d( mLogSession, "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID + ", value=0x01-00)"); } else { descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); Logger.a(mLogSession, "Disabling battery level notifications..."); Logger.v(mLogSession, "Disabling notifications for " + BATTERY_LEVEL_CHARACTERISTIC); Logger.d( mLogSession, "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID + ", value=0x00-00)"); } return gatt.writeDescriptor(descriptor); } return false; }
/** * Sends the read request to the given characteristic. * * @param characteristic the characteristic to read * @return true if request has been sent */ protected final boolean readCharacteristic(final BluetoothGattCharacteristic characteristic) { final BluetoothGatt gatt = mBluetoothGatt; if (gatt == null || characteristic == null) return false; // Check characteristic property final int properties = characteristic.getProperties(); if ((properties & BluetoothGattCharacteristic.PROPERTY_READ) == 0) return false; Logger.v(mLogSession, "Reading characteristic " + characteristic.getUuid()); Logger.d(mLogSession, "gatt.readCharacteristic(" + characteristic.getUuid() + ")"); return gatt.readCharacteristic(characteristic); }
/** * Disconnects from the device. Does nothing if not connected. * * @return true if device is to be disconnected. False if it was already disconnected. */ public boolean disconnect() { mUserDisconnected = true; if (mConnected && mBluetoothGatt != null) { Logger.v(mLogSession, "Disconnecting..."); mCallbacks.onDeviceDisconnecting(); Logger.d(mLogSession, "gatt.disconnect()"); mBluetoothGatt.disconnect(); return true; } return false; }
/** * Writes the characteristic value to the given characteristic. * * @param characteristic the characteristic to write to * @return true if request has been sent */ protected final boolean writeCharacteristic(final BluetoothGattCharacteristic characteristic) { final BluetoothGatt gatt = mBluetoothGatt; if (gatt == null || characteristic == null) return false; // Check characteristic property final int properties = characteristic.getProperties(); if ((properties & (BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)) == 0) return false; Logger.v(mLogSession, "Writing characteristic " + characteristic.getUuid()); Logger.d(mLogSession, "gatt.writeCharacteristic(" + characteristic.getUuid() + ")"); return gatt.writeCharacteristic(characteristic); }
/** * Connects to the Bluetooth Smart device * * @param device a device to connect to */ public void connect(final BluetoothDevice device) { if (mConnected) return; if (mBluetoothGatt != null) { Logger.d(mLogSession, "gatt.close()"); mBluetoothGatt.close(); mBluetoothGatt = null; } final boolean autoConnect = shouldAutoConnect(); mUserDisconnected = !autoConnect; // We will receive Linkloss events only when the device is connected with // autoConnect=true Logger.v(mLogSession, "Connecting..."); Logger.d(mLogSession, "gatt = device.connectGatt(autoConnect = " + autoConnect + ")"); mBluetoothGatt = device.connectGatt(mContext, autoConnect, getGattCallback()); }
@Override public void onReceive(final Context context, final Intent intent) { final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1); // Skip other devices if (mBluetoothGatt == null || !device.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) return; Logger.d( mLogSession, "[Broadcast] Action received: " + BluetoothDevice.ACTION_BOND_STATE_CHANGED + ", bond state changed to: " + bondStateToString(bondState) + " (" + bondState + ")"); DebugLogger.i( TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState); switch (bondState) { case BluetoothDevice.BOND_BONDING: mCallbacks.onBondingRequired(); break; case BluetoothDevice.BOND_BONDED: Logger.i(mLogSession, "Device bonded"); mCallbacks.onBonded(); // Start initializing again. // In fact, bonding forces additional, internal service discovery (at least on Nexus // devices), so this method may safely be used to start this process again. Logger.v(mLogSession, "Discovering Services..."); Logger.d(mLogSession, "gatt.discoverServices()"); mBluetoothGatt.discoverServices(); break; } }
/** * Enables indications on given characteristic * * @return true is the request has been sent, false if one of the arguments was <code>null</code> * or the characteristic does not have the CCCD. */ protected final boolean enableIndications(final BluetoothGattCharacteristic characteristic) { final BluetoothGatt gatt = mBluetoothGatt; if (gatt == null || characteristic == null) return false; // Check characteristic property final int properties = characteristic.getProperties(); if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) == 0) return false; gatt.setCharacteristicNotification(characteristic, true); final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); if (descriptor != null) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); Logger.v(mLogSession, "Enabling indications for " + characteristic.getUuid()); Logger.d( mLogSession, "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID + ", value=0x02-00)"); return gatt.writeDescriptor(descriptor); } return false; }