com.github.hypfvieh.bluetooth.wrapper.BluetoothDevice Maven / Gradle / Ivy
Show all versions of bluez-dbus Show documentation
package com.github.hypfvieh.bluetooth.wrapper;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.bluez.Device1;
import org.bluez.GattService1;
import org.bluez.exceptions.BluezAlreadyConnectedException;
import org.bluez.exceptions.BluezAlreadyExistsException;
import org.bluez.exceptions.BluezAuthenticationCanceledException;
import org.bluez.exceptions.BluezAuthenticationFailedException;
import org.bluez.exceptions.BluezAuthenticationRejectedException;
import org.bluez.exceptions.BluezAuthenticationTimeoutException;
import org.bluez.exceptions.BluezConnectionAttemptFailedException;
import org.bluez.exceptions.BluezDoesNotExistException;
import org.bluez.exceptions.BluezFailedException;
import org.bluez.exceptions.BluezInProgressException;
import org.bluez.exceptions.BluezInvalidArgumentsException;
import org.bluez.exceptions.BluezNotAvailableException;
import org.bluez.exceptions.BluezNotConnectedException;
import org.bluez.exceptions.BluezNotReadyException;
import org.bluez.exceptions.BluezNotSupportedException;
import org.freedesktop.dbus.connections.impl.DBusConnection;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import org.freedesktop.dbus.interfaces.DBusInterface;
import org.freedesktop.dbus.types.UInt16;
import org.freedesktop.dbus.types.UInt32;
import com.github.hypfvieh.DbusHelper;
/**
* Wrapper class which represents a remote bluetooth device.
* @author hypfvieh
*
*/
public class BluetoothDevice extends AbstractBluetoothObject {
private final Device1 rawdevice;
private final BluetoothAdapter adapter;
private final Map servicesByUuid = new LinkedHashMap<>();
public BluetoothDevice(Device1 _device, BluetoothAdapter _adapter, String _dbusPath, DBusConnection _dbusConnection) {
super(BluetoothDeviceType.DEVICE, _dbusConnection, _dbusPath);
rawdevice = _device;
adapter = _adapter;
}
/**
* {@inheritDoc}
*/
@Override
protected Class extends DBusInterface> getInterfaceClass() {
return Device1.class;
}
/**
* Return the list of available {@link BluetoothGattService}s.
* Will start a query if no list was gathered before.
* To re-scan for services use {@link #refreshGattServices()}.
* @return List, maybe empty but never null
*/
public List getGattServices() {
if (servicesByUuid.isEmpty()) {
refreshGattServices();
}
return new ArrayList<>(servicesByUuid.values());
}
/**
* Re-queries the list of available {@link BluetoothGattService}'s on this device.
*/
public void refreshGattServices() {
servicesByUuid.clear();
Set findNodes = DbusHelper.findNodes(getDbusConnection(), getDbusPath());
Map remoteObjects = getRemoteObjects(findNodes, getDbusPath(), GattService1.class);
for (Entry entry : remoteObjects.entrySet()) {
BluetoothGattService bluetoothGattService = new BluetoothGattService(entry.getValue(), this, entry.getKey(), getDbusConnection());
servicesByUuid.put(bluetoothGattService.getUuid(), bluetoothGattService);
}
}
/**
* Get the given {@link BluetoothGattService} instance by UUID.
* @param _uuid uuid
* @return {@link BluetoothGattService}, maybe null if not found
*/
public BluetoothGattService getGattServiceByUuid(String _uuid) {
if (servicesByUuid.isEmpty()) {
refreshGattServices();
}
return servicesByUuid.get(_uuid);
}
/**
* Get {@link BluetoothAdapter} object where this {@link BluetoothDevice} object belongs to.
* @return adapter
*/
public BluetoothAdapter getAdapter() {
return adapter;
}
/**
* Get the raw {@link Device1} object wrapped by this {@link BluetoothDevice} object.
* @return device
*/
public Device1 getRawDevice() {
return rawdevice;
}
/**
* True if incoming connections are rejected, false otherwise.
* @return maybe null if feature is not supported
*/
public Boolean isBlocked() {
return getTyped("Blocked", Boolean.class);
}
/**
* From bluez Documentation:
*
* If set to true any incoming connections from the
* device will be immediately rejected. Any device
* drivers will also be removed and no new ones will
* be probed as long as the device is blocked
*
* @param _blocked set blocked status
*/
public void setBlocked(Boolean _blocked) {
setTyped("Blocked", _blocked);
}
/**
* True if the remote device is trusted, false otherwise.
* @return maybe null if feature is not supported
*/
public Boolean isTrusted() {
return getTyped("Trusted", Boolean.class);
}
/**
* Set to true to trust the connected device, or to false if you don't.
* Default is false.
* @param _trusted set trusted
*/
public void setTrusted(boolean _trusted) {
setTyped("Trusted", _trusted);
}
/**
* The current name alias for the remote device.
* @return alias name
*/
public String getAlias() {
return getTyped("Alias", String.class);
}
/**
* From bluez Documentation:
*
* The name alias for the remote device. The alias can
* be used to have a different friendly name for the
* remote device.
* In case no alias is set, it will return the remote
* device name. Setting an empty string as alias will
* convert it back to the remote device name.
*
* @param _alias alias name to set
*/
public void setAlias(String _alias) {
setTyped("Alias", _alias);
}
/**
* The Advertising Data Flags of the remote device.
* EXPERIMENTAL
*
* @return byte array maybe null
*/
public byte[] getAdvertisingFlags() {
List> typed = getTyped("AdvertisingFlags", ArrayList.class);
if (typed != null) {
return byteListToByteArray(typed);
}
return null;
}
/**
* From bluez Documentation:
*
* List of 128-bit UUIDs that represents the available
* remote services.
*
* @return string array of UUIDs, maybe null
*/
public String[] getUuids() {
List> typed = getTyped("UUIDs", ArrayList.class);
if (typed != null) {
return typed.toArray(new String[]{});
}
return null;
}
/**
* True if device is connected, false otherwise.
* @return maybe null if feature is not supported
*/
public Boolean isConnected() {
return getTyped("Connected", Boolean.class);
}
/**
* From bluez Documentation:
*
* Set to true if the device only supports the pre-2.1
* pairing mechanism. This property is useful during
* device discovery to anticipate whether legacy or
* simple pairing will occur if pairing is initiated.
* Note that this property can exhibit false-positives
* in the case of Bluetooth 2.1 (or newer) devices that
* have disabled Extended Inquiry Response support.
*
* @return maybe null if feature is not supported
*/
public Boolean isLegacyPairing() {
return getTyped("LegacyPairing", Boolean.class);
}
/**
* True if the device is currently paired with another device. False otherwise.
* @return boolean, maybe null
*/
public Boolean isPaired() {
return getTyped("Paired", Boolean.class);
}
/**
* From bluez Documentation:
*
* Indicate whether or not service discovery has been
* resolved.
*
* @return maybe null if feature is not supported
*/
public Boolean isServiceResolved() {
return getTyped("ServiceResolved", Boolean.class);
}
/**
* From bluez Documentation:
*
* Service advertisement data. Keys are the UUIDs in
* string format followed by its byte array value.
*
* @return map of string/bytearray, maybe null
*/
@SuppressWarnings("unchecked")
public Map getServiceData() {
return getTyped("ServiceData", Map.class);
}
/**
* From bluez Documentation:
*
* Manufacturer specific advertisement data. Keys are
* 16 bits Manufacturer ID followed by its byte array
* value.
*
* @return map of uint16/bytearray, maybe null
*/
@SuppressWarnings("unchecked")
public Map getManufacturerData() {
return getTyped("ManufacturerData", Map.class);
}
/**
* From bluez Documentation:
*
* Received Signal Strength Indicator of the remote
* device (inquiry or advertising).
*
* @return short, maybe null
*/
public Short getRssi() {
return getTyped("RSSI", Short.class);
}
/**
* From bluez Documentation:
*
* Advertised transmitted power level (inquiry or
* advertising).
*
* @return short, maybe null
*/
public Short getTxPower() {
return getTyped("TxPower", Short.class);
}
/**
* Returns the remote devices bluetooth (MAC) address.
* @return mac address, maybe null
*/
public String getAddress() {
return getTyped("Address", String.class);
}
/**
* From bluez Documentation:
*
* Proposed icon name according to the freedesktop.org
* icon naming specification.
*
* @return icon name, maybe null
*/
public String getIcon() {
return getTyped("Icon", String.class);
}
/**
* From bluez Documentation:
*
* Remote Device ID information in modalias format
* used by the kernel and udev.
*
* @return modalias string, maybe null
*/
public String getModAlias() {
return getTyped("Modalias", String.class);
}
/**
* Get the bluetooth device name.
* This may fail if you not connected to the device, or if the device does not support this operation.
* If no name could be retrieved, the alias will be used.
*
* From bluez Documentation:
*
* The Bluetooth remote name. This value can not be
* changed. Use the Alias property instead.
* This value is only present for completeness. It is
* better to always use the Alias property when
* displaying the devices name.
* If the Alias property is unset, it will reflect
* this value which makes it more convenient.
*
* @return name, maybe null
*/
public String getName() {
String name = null;
try {
name = getTyped("Name", String.class);
} catch (DBusExecutionException _ex) {
}
if (name == null) {
name = getAlias();
}
return name;
}
/**
* From bluez Documentation:
*
* External appearance of device, as found on GAP service.
*
* @return integer, maybe null
*/
public Integer getAppearance() {
UInt16 typed = getTyped("Appearance", UInt16.class);
return typed != null ? typed.intValue() : null;
}
/**
* From bluez Documentation:
*
* The Bluetooth class of device of the remote device.
*
* @return integer, maybe null
*/
public Integer getBluetoothClass() {
UInt32 typed = getTyped("Class", UInt32.class);
return typed != null ? typed.intValue() : null;
}
/**
* From bluez Documentation:
*
* This is a generic method to connect any profiles
* the remote device supports that can be connected
* to and have been flagged as auto-connectable on
* our side. If only subset of profiles is already
* connected it will try to connect currently disconnected
* ones.
*
* @return true if connected, false otherwise
*/
public boolean connect() {
try {
rawdevice.Connect();
} catch (BluezNotReadyException _ex) {
} catch (BluezFailedException _ex) {
} catch (BluezAlreadyConnectedException _ex) {
return true;
} catch (BluezInProgressException _ex) {
return false;
}
return isConnected();
}
/**
* From bluez Documentation:
*
* This method gracefully disconnects all connected
* profiles and then terminates low-level ACL connection.
* ACL connection will be terminated even if some profiles
* were not disconnected properly e.g. due to misbehaving
* device.
* This method can be also used to cancel a preceding
* Connect call before a reply to it has been received.
*
* @return true if disconnected false otherwise
*/
public boolean disconnect() {
try {
rawdevice.Disconnect();
return true;
} catch (BluezNotConnectedException _ex) {
}
return !isConnected();
}
/**
* From bluez Documentation:
*
* This method connects a specific profile of this
* device. The UUID provided is the remote service
* UUID for the profile.
*
*
* @param _uuid profile uuid
* @return true if connected to given profile, false otherwise
*/
public boolean connectProfile(String _uuid) {
try {
rawdevice.ConnectProfile(_uuid);
return true;
} catch (BluezFailedException | BluezInProgressException | BluezInvalidArgumentsException
| BluezNotAvailableException | BluezNotReadyException _ex) {
return false;
}
}
/**
* From bluez Documentation:
*
* This method disconnects a specific profile of
* this device. The profile needs to be registered
* client profile.
* There is no connection tracking for a profile, so
* as long as the profile is registered this will always
* succeed.
*
*
* @param _uuid profile uuid
* @return true if profile disconnected, false otherwise
*/
public boolean disconnectProfile(String _uuid) {
try {
rawdevice.DisconnectProfile(_uuid);
} catch (BluezFailedException | BluezInProgressException | BluezInvalidArgumentsException
| BluezNotSupportedException _ex) {
return false;
}
return true;
}
/**
* From bluez Documentation:
*
* This method will connect to the remote device,
* initiate pairing and then retrieve all SDP records
* (or GATT primary services).
* If the application has registered its own agent,
* then that specific agent will be used. Otherwise
* it will use the default agent.
* Only for applications like a pairing wizard it
* would make sense to have its own agent. In almost
* all other cases the default agent will handle
* this just fine.
* In case there is no application agent and also
* no default agent present, this method will fail.
*
* @return true on successful pair, false otherwise
*/
public boolean pair() {
try {
rawdevice.Pair();
return true;
} catch (BluezInvalidArgumentsException | BluezFailedException | BluezAuthenticationFailedException | BluezAlreadyExistsException | BluezAuthenticationCanceledException | BluezAuthenticationRejectedException | BluezAuthenticationTimeoutException | BluezConnectionAttemptFailedException _ex) {
return false;
}
}
/**
* From bluez Documentation:
*
* This method can be used to cancel a pairing
* operation initiated by the Pair method.
*
* @return true if cancel succeeds, false otherwise
*/
public boolean cancelPairing() {
try {
rawdevice.CancelPairing();
return true;
} catch (BluezDoesNotExistException | BluezFailedException _ex) {
return false;
}
}
@Override
public String toString() {
return getClass().getSimpleName() + " [device=" + rawdevice + ", adapter=" + adapter.getDbusPath() + ", getBluetoothType()=" + getBluetoothType().name() + ", getDbusPath()=" + getDbusPath() + "]";
}
}