Merge "Unhide Bluetooth Low Energy public APIs" into jb-mr2-dev

This commit is contained in:
Matthew Xie
2013-03-28 23:04:47 +00:00
committed by Android (Google) Code Review
20 changed files with 1207 additions and 1025 deletions

View File

@ -4613,8 +4613,13 @@ package android.bluetooth {
method public boolean isEnabled(); method public boolean isEnabled();
method public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException; method public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
method public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException; method public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
method public boolean registerCallback(android.bluetooth.BluetoothAdapterCallback);
method public boolean setName(java.lang.String); method public boolean setName(java.lang.String);
method public boolean startDiscovery(); method public boolean startDiscovery();
method public boolean startLeScan();
method public boolean startLeScan(java.util.UUID[]);
method public void stopLeScan();
method public boolean unRegisterCallback(android.bluetooth.BluetoothAdapterCallback);
field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED"; field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
@ -4645,6 +4650,14 @@ package android.bluetooth {
field public static final int STATE_TURNING_ON = 11; // 0xb field public static final int STATE_TURNING_ON = 11; // 0xb
} }
public abstract class BluetoothAdapterCallback {
ctor public BluetoothAdapterCallback();
method public void onCallbackRegistration(int);
method public void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
field public static final int CALLBACK_REGISTERED = 0; // 0x0
field public static final int CALLBACK_REGISTRATION_FAILURE = 1; // 0x1
}
public class BluetoothAssignedNumbers { public class BluetoothAssignedNumbers {
field public static final int ACCEL_SEMICONDUCTOR = 74; // 0x4a field public static final int ACCEL_SEMICONDUCTOR = 74; // 0x4a
field public static final int ALCATEL = 36; // 0x24 field public static final int ALCATEL = 36; // 0x24
@ -4837,6 +4850,7 @@ package android.bluetooth {
} }
public final class BluetoothDevice implements android.os.Parcelable { public final class BluetoothDevice implements android.os.Parcelable {
method public android.bluetooth.BluetoothGatt connectGattServer(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException; method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException; method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public int describeContents(); method public int describeContents();
@ -4869,6 +4883,159 @@ package android.bluetooth {
field public static final java.lang.String EXTRA_UUID = "android.bluetooth.device.extra.UUID"; field public static final java.lang.String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
} }
public final class BluetoothGatt implements android.bluetooth.BluetoothProfile {
method public void abortReliableWrite(android.bluetooth.BluetoothDevice);
method public boolean beginReliableWrite();
method public void disconnect();
method public boolean discoverServices();
method public boolean executeReliableWrite();
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public int getConnectionState(android.bluetooth.BluetoothDevice);
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
method public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
method public boolean readDescriptor(android.bluetooth.BluetoothGattDescriptor);
method public boolean readRemoteRssi();
method public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
method public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
method public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
field public static final int GATT_FAILURE = 0; // 0x0
field public static final int GATT_INSUFFICIENT_AUTHENTICATION = 5; // 0x5
field public static final int GATT_INSUFFICIENT_ENCRYPTION = 15; // 0xf
field public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 13; // 0xd
field public static final int GATT_INVALID_OFFSET = 7; // 0x7
field public static final int GATT_READ_NOT_PERMITTED = 2; // 0x2
field public static final int GATT_REQUEST_NOT_SUPPORTED = 6; // 0x6
field public static final int GATT_SUCCESS = 0; // 0x0
field public static final int GATT_WRITE_NOT_PERMITTED = 3; // 0x3
}
public abstract class BluetoothGattCallback {
ctor public BluetoothGattCallback();
method public void onCharacteristicChanged(android.bluetooth.BluetoothGattCharacteristic);
method public void onCharacteristicRead(android.bluetooth.BluetoothGattCharacteristic, int);
method public void onCharacteristicWrite(android.bluetooth.BluetoothGattCharacteristic, int);
method public void onConnectionStateChange(android.bluetooth.BluetoothDevice, int, int);
method public void onDescriptorRead(android.bluetooth.BluetoothGattDescriptor, int);
method public void onDescriptorWrite(android.bluetooth.BluetoothGattDescriptor, int);
method public void onReadRemoteRssi(android.bluetooth.BluetoothDevice, int, int);
method public void onReliableWriteCompleted(android.bluetooth.BluetoothDevice, int);
method public void onServicesDiscovered(android.bluetooth.BluetoothDevice, int);
}
public class BluetoothGattCharacteristic {
ctor public BluetoothGattCharacteristic(java.util.UUID, int, int);
method public boolean addDescriptor(android.bluetooth.BluetoothGattDescriptor);
method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
method public java.lang.Float getFloatValue(int, int);
method public int getInstanceId();
method public java.lang.Integer getIntValue(int, int);
method public int getPermissions();
method public int getProperties();
method public android.bluetooth.BluetoothGattService getService();
method public java.lang.String getStringValue(int);
method public java.util.UUID getUuid();
method public byte[] getValue();
method public int getWriteType();
method public boolean setValue(byte[]);
method public boolean setValue(int, int, int);
method public boolean setValue(int, int, int, int);
method public boolean setValue(java.lang.String);
method public void setWriteType(int);
field public static final int FORMAT_FLOAT = 52; // 0x34
field public static final int FORMAT_SFLOAT = 50; // 0x32
field public static final int FORMAT_SINT16 = 34; // 0x22
field public static final int FORMAT_SINT32 = 36; // 0x24
field public static final int FORMAT_SINT8 = 33; // 0x21
field public static final int FORMAT_UINT16 = 18; // 0x12
field public static final int FORMAT_UINT32 = 20; // 0x14
field public static final int FORMAT_UINT8 = 17; // 0x11
field public static final int PERMISSION_READ = 1; // 0x1
field public static final int PERMISSION_READ_ENCRYPTED = 2; // 0x2
field public static final int PERMISSION_READ_ENCRYPTED_MITM = 4; // 0x4
field public static final int PERMISSION_WRITE = 16; // 0x10
field public static final int PERMISSION_WRITE_ENCRYPTED = 32; // 0x20
field public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 64; // 0x40
field public static final int PERMISSION_WRITE_SIGNED = 128; // 0x80
field public static final int PERMISSION_WRITE_SIGNED_MITM = 256; // 0x100
field public static final int PROPERTY_BROADCAST = 1; // 0x1
field public static final int PROPERTY_EXTENDED_PROPS = 128; // 0x80
field public static final int PROPERTY_INDICATE = 32; // 0x20
field public static final int PROPERTY_NOTIFY = 16; // 0x10
field public static final int PROPERTY_READ = 2; // 0x2
field public static final int PROPERTY_SIGNED_WRITE = 64; // 0x40
field public static final int PROPERTY_WRITE = 8; // 0x8
field public static final int PROPERTY_WRITE_NO_RESPONSE = 4; // 0x4
field public static final int WRITE_TYPE_DEFAULT = 2; // 0x2
field public static final int WRITE_TYPE_NO_RESPONSE = 1; // 0x1
field public static final int WRITE_TYPE_SIGNED = 4; // 0x4
field protected java.util.List mDescriptors;
}
public class BluetoothGattDescriptor {
ctor public BluetoothGattDescriptor(java.util.UUID, int);
method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
method public int getPermissions();
method public java.util.UUID getUuid();
method public byte[] getValue();
method public boolean setValue(byte[]);
field public static final byte[] DISABLE_NOTIFICATION_VALUE;
field public static final byte[] ENABLE_INDICATION_VALUE;
field public static final byte[] ENABLE_NOTIFICATION_VALUE;
field public static final int PERMISSION_READ = 1; // 0x1
field public static final int PERMISSION_READ_ENCRYPTED = 2; // 0x2
field public static final int PERMISSION_READ_ENCRYPTED_MITM = 4; // 0x4
field public static final int PERMISSION_WRITE = 16; // 0x10
field public static final int PERMISSION_WRITE_ENCRYPTED = 32; // 0x20
field public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 64; // 0x40
field public static final int PERMISSION_WRITE_SIGNED = 128; // 0x80
field public static final int PERMISSION_WRITE_SIGNED_MITM = 256; // 0x100
}
public final class BluetoothGattServer implements android.bluetooth.BluetoothProfile {
method public boolean addService(android.bluetooth.BluetoothGattService);
method public void cancelConnection(android.bluetooth.BluetoothDevice);
method public void clearServices();
method public boolean connect(android.bluetooth.BluetoothDevice, boolean);
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public int getConnectionState(android.bluetooth.BluetoothDevice);
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
method public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
method public boolean removeService(android.bluetooth.BluetoothGattService);
method public boolean sendResponse(android.bluetooth.BluetoothDevice, int, int, int, byte[]);
}
public abstract class BluetoothGattServerCallback {
ctor public BluetoothGattServerCallback();
method public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice, int, int, android.bluetooth.BluetoothGattCharacteristic);
method public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice, int, android.bluetooth.BluetoothGattCharacteristic, boolean, boolean, int, byte[]);
method public void onConnectionStateChange(android.bluetooth.BluetoothDevice, int, int);
method public void onDescriptorReadRequest(android.bluetooth.BluetoothDevice, int, int, android.bluetooth.BluetoothGattDescriptor);
method public void onDescriptorWriteRequest(android.bluetooth.BluetoothDevice, int, android.bluetooth.BluetoothGattDescriptor, boolean, boolean, int, byte[]);
method public void onExecuteWrite(android.bluetooth.BluetoothDevice, int, boolean);
method public void onServiceAdded(int, android.bluetooth.BluetoothGattService);
}
public class BluetoothGattService {
ctor public BluetoothGattService(java.util.UUID, int);
method public boolean addCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
method public boolean addService(android.bluetooth.BluetoothGattService);
method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattCharacteristic> getCharacteristics();
method public java.util.List<android.bluetooth.BluetoothGattService> getIncludedServices();
method public int getInstanceId();
method public int getType();
method public java.util.UUID getUuid();
field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0
field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1
field protected java.util.List mCharacteristics;
field protected java.util.List mIncludedServices;
}
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile { public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public int getConnectionState(android.bluetooth.BluetoothDevice); method public int getConnectionState(android.bluetooth.BluetoothDevice);
@ -4931,6 +5098,14 @@ package android.bluetooth {
method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int); method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
} }
public final class BluetoothManager {
method public android.bluetooth.BluetoothAdapter getAdapter();
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
method public int getConnectionState(android.bluetooth.BluetoothDevice, int);
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int, int[]);
method public android.bluetooth.BluetoothGattServer openGattServer(android.content.Context, android.bluetooth.BluetoothGattServerCallback);
}
public abstract interface BluetoothProfile { public abstract interface BluetoothProfile {
method public abstract java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); method public abstract java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public abstract int getConnectionState(android.bluetooth.BluetoothDevice); method public abstract int getConnectionState(android.bluetooth.BluetoothDevice);
@ -4938,6 +5113,8 @@ package android.bluetooth {
field public static final int A2DP = 2; // 0x2 field public static final int A2DP = 2; // 0x2
field public static final java.lang.String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE"; field public static final java.lang.String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE";
field public static final java.lang.String EXTRA_STATE = "android.bluetooth.profile.extra.STATE"; field public static final java.lang.String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
field public static final int GATT = 7; // 0x7
field public static final int GATT_SERVER = 8; // 0x8
field public static final int HEADSET = 1; // 0x1 field public static final int HEADSET = 1; // 0x1
field public static final int HEALTH = 3; // 0x3 field public static final int HEALTH = 3; // 0x3
field public static final int STATE_CONNECTED = 2; // 0x2 field public static final int STATE_CONNECTED = 2; // 0x2
@ -5495,6 +5672,7 @@ package android.content {
field public static final int BIND_IMPORTANT = 64; // 0x40 field public static final int BIND_IMPORTANT = 64; // 0x40
field public static final int BIND_NOT_FOREGROUND = 4; // 0x4 field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20 field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20
field public static final java.lang.String BLUETOOTH_SERVICE = "bluetooth";
field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard"; field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity"; field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2 field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@ -6658,6 +6836,7 @@ package android.content.pm {
method public abstract boolean addPermission(android.content.pm.PermissionInfo); method public abstract boolean addPermission(android.content.pm.PermissionInfo);
method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo); method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo);
method public abstract deprecated void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName); method public abstract deprecated void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
method public android.content.Intent buildPermissionRequestIntent(java.lang.String...);
method public abstract java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]); method public abstract java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
method public abstract int checkPermission(java.lang.String, java.lang.String); method public abstract int checkPermission(java.lang.String, java.lang.String);
method public abstract int checkSignatures(java.lang.String, java.lang.String); method public abstract int checkSignatures(java.lang.String, java.lang.String);
@ -6717,7 +6896,6 @@ package android.content.pm {
method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract deprecated void removePackageFromPreferred(java.lang.String); method public abstract deprecated void removePackageFromPreferred(java.lang.String);
method public abstract void removePermission(java.lang.String); method public abstract void removePermission(java.lang.String);
method public android.content.Intent buildPermissionRequestIntent(java.lang.String...);
method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int); method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
method public abstract android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int); method public abstract android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int); method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
@ -16810,13 +16988,13 @@ package android.os {
method public void setUserRestriction(java.lang.String, boolean); method public void setUserRestriction(java.lang.String, boolean);
method public void setUserRestrictions(android.os.Bundle); method public void setUserRestrictions(android.os.Bundle);
method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle); method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi"; field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps"; field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts"; field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location"; field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps"; field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer"; field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
} }

View File

@ -19,7 +19,7 @@ package android.app;
import com.android.internal.policy.PolicyManager; import com.android.internal.policy.PolicyManager;
import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.ContentResolver; import android.content.ContentResolver;
@ -319,7 +319,7 @@ class ContextImpl extends Context {
registerService(BLUETOOTH_SERVICE, new ServiceFetcher() { registerService(BLUETOOTH_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) { public Object createService(ContextImpl ctx) {
return BluetoothAdapter.getDefaultAdapter(); return new BluetoothManager(ctx);
}}); }});
registerService(CLIPBOARD_SERVICE, new ServiceFetcher() { registerService(CLIPBOARD_SERVICE, new ServiceFetcher() {

View File

@ -22,7 +22,6 @@ import android.content.Context;
import android.os.Binder; import android.os.Binder;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.ParcelUuid; import android.os.ParcelUuid;
import android.os.RemoteException; import android.os.RemoteException;
@ -359,6 +358,8 @@ public final class BluetoothAdapter {
private IBluetooth mService; private IBluetooth mService;
private Handler mServiceRecordHandler; private Handler mServiceRecordHandler;
private BluetoothAdapterCallback mCallback;
private int mClientIf;
/** /**
* Get a handle to the default local Bluetooth adapter. * Get a handle to the default local Bluetooth adapter.
@ -1137,7 +1138,8 @@ public final class BluetoothAdapter {
* Get the profile proxy object associated with the profile. * Get the profile proxy object associated with the profile.
* *
* <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
* or {@link BluetoothProfile#A2DP}. Clients must implement * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or
* {@link BluetoothProfile#GATT_SERVER}. Clients must implement
* {@link BluetoothProfile.ServiceListener} to get notified of * {@link BluetoothProfile.ServiceListener} to get notified of
* the connection status and to get the proxy object. * the connection status and to get the proxy object.
* *
@ -1166,12 +1168,6 @@ public final class BluetoothAdapter {
} else if (profile == BluetoothProfile.HEALTH) { } else if (profile == BluetoothProfile.HEALTH) {
BluetoothHealth health = new BluetoothHealth(context, listener); BluetoothHealth health = new BluetoothHealth(context, listener);
return true; return true;
} else if (profile == BluetoothProfile.GATT) {
BluetoothGatt gatt = new BluetoothGatt(context, listener);
return true;
} else if (profile == BluetoothProfile.GATT_SERVER) {
BluetoothGattServer gattServer = new BluetoothGattServer(context, listener);
return true;
} else { } else {
return false; return false;
} }
@ -1411,4 +1407,230 @@ public final class BluetoothAdapter {
mProxyServiceStateCallbacks.remove(cb); mProxyServiceStateCallbacks.remove(cb);
} }
} }
/**
* Register an callback to receive async results, such as LE scan result.
*
* <p>This is an asynchronous call. The callback
* {@link BluetoothAdapterCallback#onCallbackRegistration}
* is used to notify success or failure if the function returns true.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param callback BluetootAdapter callback handler that will receive asynchronous callbacks.
* @return If true, the callback will be called to notify success or failure,
* false on immediate error
*/
public boolean registerCallback(BluetoothAdapterCallback callback) {
try {
IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
mCallback = callback;
UUID uuid = UUID.randomUUID();
if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
iGatt.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
return true;
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
}
/**
* Unregister the registered callback.
*/
public boolean unRegisterCallback(BluetoothAdapterCallback callback) {
if (callback != mCallback) return false;
try {
IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
iGatt.unregisterClient(mClientIf);
return true;
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
}
/**
* Starts a scan for Bluetooth LE devices.
*
* <p>Results of the scan are reported using the
* {@link BluetoothAdapterCallback#onLeScan} callback.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return true, if the scan was started successfully
*/
public boolean startLeScan() {
if (DBG) Log.d(TAG, "startLeScan()");
if (mClientIf == 0) return false;
try {
IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
iGatt.startScan(mClientIf, false);
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
return true;
}
/**
* Starts a scan for Bluetooth LE devices, looking for devices that
* advertise given services.
*
* <p>Devices which advertise all specified services are reported using the
* {@link BluetoothAdapterCallback#onLeScan} callback.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param serviceUuids Array of services to look for
* @return true, if the scan was started successfully
*/
public boolean startLeScan(UUID[] serviceUuids) {
if (DBG) Log.d(TAG, "startLeScan() - with UUIDs");
if (mClientIf == 0) return false;
try {
IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
for(int i = 0; i != uuids.length; ++i) {
uuids[i] = new ParcelUuid(serviceUuids[i]);
}
iGatt.startScanWithUuids(mClientIf, false, uuids);
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
return true;
}
/**
* Stops an ongoing Bluetooth LE device scan.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*/
public void stopLeScan() {
if (DBG) Log.d(TAG, "stopScan()");
if (mClientIf == 0) return;
try {
IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
iGatt.stopScan(mClientIf, false);
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
}
/**
* Bluetooth GATT interface callbacks
*/
private final IBluetoothGattCallback mBluetoothGattCallback =
new IBluetoothGattCallback.Stub() {
/**
* Application interface registered - app is ready to go
*/
public void onClientRegistered(int status, int clientIf) {
if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
+ " clientIf=" + clientIf);
mClientIf = clientIf;
mCallback.onCallbackRegistration(status == BluetoothGatt.GATT_SUCCESS ?
BluetoothAdapterCallback.CALLBACK_REGISTERED :
BluetoothAdapterCallback.CALLBACK_REGISTRATION_FAILURE);
}
public void onClientConnectionState(int status, int clientIf,
boolean connected, String address) {
// no op
}
/**
* Callback reporting an LE scan result.
* @hide
*/
public void onScanResult(String address, int rssi, byte[] advData) {
if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
try {
mCallback.onLeScan(getRemoteDevice(address), rssi, advData);
} catch (Exception ex) {
Log.w(TAG, "Unhandled exception: " + ex);
}
}
public void onGetService(String address, int srvcType,
int srvcInstId, ParcelUuid srvcUuid) {
// no op
}
public void onGetIncludedService(String address, int srvcType,
int srvcInstId, ParcelUuid srvcUuid,
int inclSrvcType, int inclSrvcInstId,
ParcelUuid inclSrvcUuid) {
// no op
}
public void onGetCharacteristic(String address, int srvcType,
int srvcInstId, ParcelUuid srvcUuid,
int charInstId, ParcelUuid charUuid,
int charProps) {
// no op
}
public void onGetDescriptor(String address, int srvcType,
int srvcInstId, ParcelUuid srvcUuid,
int charInstId, ParcelUuid charUuid,
ParcelUuid descUuid) {
// no op
}
public void onSearchComplete(String address, int status) {
// no op
}
public void onCharacteristicRead(String address, int status, int srvcType,
int srvcInstId, ParcelUuid srvcUuid,
int charInstId, ParcelUuid charUuid, byte[] value) {
// no op
}
public void onCharacteristicWrite(String address, int status, int srvcType,
int srvcInstId, ParcelUuid srvcUuid,
int charInstId, ParcelUuid charUuid) {
// no op
}
public void onNotify(String address, int srvcType,
int srvcInstId, ParcelUuid srvcUuid,
int charInstId, ParcelUuid charUuid,
byte[] value) {
// no op
}
public void onDescriptorRead(String address, int status, int srvcType,
int srvcInstId, ParcelUuid srvcUuid,
int charInstId, ParcelUuid charUuid,
ParcelUuid descrUuid, byte[] value) {
// no op
}
public void onDescriptorWrite(String address, int status, int srvcType,
int srvcInstId, ParcelUuid srvcUuid,
int charInstId, ParcelUuid charUuid,
ParcelUuid descrUuid) {
// no op
}
public void onExecuteWrite(String address, int status) {
// no op
}
public void onReadRemoteRssi(String address, int rssi, int status) {
// no op
}
};
} }

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2013 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 android.bluetooth;
import android.bluetooth.BluetoothDevice;
/**
* This abstract class is used to implement {@link BluetoothAdapter} callbacks.
*/
public abstract class BluetoothAdapterCallback {
/**
* Indicates the callback has been registered successfully
*/
public static final int CALLBACK_REGISTERED = 0;
/**
* Indicates the callback registration has failed
*/
public static final int CALLBACK_REGISTRATION_FAILURE = 1;
/**
* Callback to inform change in registration state of the application.
*
* @param status Returns {@link #CALLBACK_REGISTERED} if the application
* was successfully registered.
*/
public void onCallbackRegistration(int status) {
}
/**
* Callback reporting an LE device found during a device scan initiated
* by the {@link BluetoothAdapter#startLeScan} function.
*
* @param device Identifies the remote device
* @param rssi The RSSI value for the remote device as reported by the
* Bluetooth hardware. 0 if no RSSI value is available.
* @param scanRecord The content of the advertisement record offered by
* the remote device.
*/
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
}
}

View File

@ -18,6 +18,7 @@ package android.bluetooth;
import android.annotation.SdkConstant; import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.os.IBinder; import android.os.IBinder;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
@ -1126,4 +1127,30 @@ public final class BluetoothDevice implements Parcelable {
return pinBytes; return pinBytes;
} }
/**
* Connect to GATT Server hosted by this device. Caller acts as GATT client.
* The callback is used to deliver results to Caller, such as connection status as well
* as any further GATT client operations.
* The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
* GATT client operations.
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @param autoConnect Whether to directly connect to the remote device (false)
* or to automatically connect as soon as the remote
* device becomes available (true).
* @throws IllegalArgumentException if callback is null
*/
public BluetoothGatt connectGattServer(Context context, boolean autoConnect,
BluetoothGattCallback callback) {
// TODO(Bluetooth) check whether platform support BLE
// Do the check here or in GattServer?
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager managerService = adapter.getBluetoothManager();
try {
IBluetoothGatt iGatt = managerService.getBluetoothGatt();
BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this);
gatt.connect(autoConnect, callback);
return gatt;
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
} }

View File

@ -16,8 +16,6 @@
package android.bluetooth; package android.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener; import android.bluetooth.BluetoothProfile.ServiceListener;
@ -39,42 +37,48 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* Public API for the Bluetooth Gatt Profile. * Public API for the Bluetooth GATT Profile.
* *
* <p>This class provides Bluetooth Gatt functionality to enable communication * <p>This class provides Bluetooth GATT functionality to enable communication
* with Bluetooth Smart or Smart Ready devices. * with Bluetooth Smart or Smart Ready devices.
* *
* <p>BluetoothGatt is a proxy object for controlling the Bluetooth Service
* via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
* BluetoothGatt proxy object.
*
* <p>To connect to a remote peripheral device, create a {@link BluetoothGattCallback} * <p>To connect to a remote peripheral device, create a {@link BluetoothGattCallback}
* and call {@link #registerApp} to register your application. Gatt capable * and call {@link BluetoothDevice#connectGattServer} to get a instance of this class.
* devices can be discovered using the {@link #startScan} function or the * GATT capable devices can be discovered using the Bluetooth device discovery or BLE
* regular Bluetooth device discovery process. * scan process.
* @hide
*/ */
public final class BluetoothGatt implements BluetoothProfile { public final class BluetoothGatt implements BluetoothProfile {
private static final String TAG = "BluetoothGatt"; private static final String TAG = "BluetoothGatt";
private static final boolean DBG = true; private static final boolean DBG = true;
private static final boolean VDBG = true;
private Context mContext; private final Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter;
private IBluetoothGatt mService; private IBluetoothGatt mService;
private BluetoothGattCallback mCallback; private BluetoothGattCallback mCallback;
private int mClientIf; private int mClientIf;
private boolean mAuthRetry = false; private boolean mAuthRetry = false;
private BluetoothDevice mDevice;
private boolean mAutoConnect;
private int mConnState;
private final Object mStateLock = new Object();
private static final int CONN_STATE_IDLE = 0;
private static final int CONN_STATE_CONNECTING = 1;
private static final int CONN_STATE_CONNECTED = 2;
private static final int CONN_STATE_DISCONNECTING = 3;
private List<BluetoothGattService> mServices; private List<BluetoothGattService> mServices;
/** A Gatt operation completed successfully */ /** A GATT operation failed */
public static final int GATT_FAILURE = 0;
/** A GATT operation completed successfully */
public static final int GATT_SUCCESS = 0; public static final int GATT_SUCCESS = 0;
/** Gatt read operation is not permitted */ /** GATT read operation is not permitted */
public static final int GATT_READ_NOT_PERMITTED = 0x2; public static final int GATT_READ_NOT_PERMITTED = 0x2;
/** Gatt write operation is not permitted */ /** GATT write operation is not permitted */
public static final int GATT_WRITE_NOT_PERMITTED = 0x3; public static final int GATT_WRITE_NOT_PERMITTED = 0x3;
/** Insufficient authentication for a given operation */ /** Insufficient authentication for a given operation */
@ -110,55 +114,6 @@ public final class BluetoothGatt implements BluetoothProfile {
*/ */
/*package*/ static final int AUTHENTICATION_MITM = 2; /*package*/ static final int AUTHENTICATION_MITM = 2;
/**
* Bluetooth state change handlers
*/
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
public void onBluetoothStateChange(boolean up) {
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
if (!up) {
if (DBG) Log.d(TAG,"Unbinding service...");
synchronized (mConnection) {
mService = null;
mContext.unbindService(mConnection);
}
} else {
synchronized (mConnection) {
if (mService == null) {
if (DBG) Log.d(TAG,"Binding service...");
if (!mContext.bindService(new Intent(IBluetoothGatt.class.getName()),
mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth GATT Service");
}
}
}
}
}
};
/**
* Service binder handling
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothGatt.Stub.asInterface(service);
ServiceListener serviceListener = mServiceListener;
if (serviceListener != null) {
serviceListener.onServiceConnected(BluetoothProfile.GATT, BluetoothGatt.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
ServiceListener serviceListener = mServiceListener;
if (serviceListener != null) {
serviceListener.onServiceDisconnected(BluetoothProfile.GATT);
}
}
};
/** /**
* Bluetooth GATT interface callbacks * Bluetooth GATT interface callbacks
*/ */
@ -171,11 +126,27 @@ public final class BluetoothGatt implements BluetoothProfile {
public void onClientRegistered(int status, int clientIf) { public void onClientRegistered(int status, int clientIf) {
if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
+ " clientIf=" + clientIf); + " clientIf=" + clientIf);
if (VDBG) {
synchronized(mStateLock) {
if (mConnState != CONN_STATE_CONNECTING) {
Log.e(TAG, "Bad connection state: " + mConnState);
}
}
}
mClientIf = clientIf; mClientIf = clientIf;
if (status != GATT_SUCCESS) {
mCallback.onConnectionStateChange(mDevice, GATT_FAILURE,
BluetoothProfile.STATE_DISCONNECTED);
synchronized(mStateLock) {
mConnState = CONN_STATE_IDLE;
}
return;
}
try { try {
mCallback.onAppRegistered(status); mService.clientConnect(mClientIf, mDevice.getAddress(),
} catch (Exception ex) { !mAutoConnect); // autoConnect is inverse of "isDirect"
Log.w(TAG, "Unhandled exception: " + ex); } catch (RemoteException e) {
Log.e(TAG,"",e);
} }
} }
@ -187,13 +158,24 @@ public final class BluetoothGatt implements BluetoothProfile {
boolean connected, String address) { boolean connected, String address) {
if (DBG) Log.d(TAG, "onClientConnectionState() - status=" + status if (DBG) Log.d(TAG, "onClientConnectionState() - status=" + status
+ " clientIf=" + clientIf + " device=" + address); + " clientIf=" + clientIf + " device=" + address);
if (!address.equals(mDevice.getAddress())) {
return;
}
int profileState = connected ? BluetoothProfile.STATE_CONNECTED :
BluetoothProfile.STATE_DISCONNECTED;
try { try {
mCallback.onConnectionStateChange(mAdapter.getRemoteDevice(address), status, mCallback.onConnectionStateChange(mDevice, status, profileState);
connected ? BluetoothProfile.STATE_CONNECTED
: BluetoothProfile.STATE_DISCONNECTED);
} catch (Exception ex) { } catch (Exception ex) {
Log.w(TAG, "Unhandled exception: " + ex); Log.w(TAG, "Unhandled exception: " + ex);
} }
synchronized(mStateLock) {
if (connected) {
mConnState = CONN_STATE_CONNECTED;
} else {
mConnState = CONN_STATE_IDLE;
}
}
} }
/** /**
@ -201,13 +183,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @hide * @hide
*/ */
public void onScanResult(String address, int rssi, byte[] advData) { public void onScanResult(String address, int rssi, byte[] advData) {
if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); // no op
try {
mCallback.onScanResult(mAdapter.getRemoteDevice(address), rssi, advData);
} catch (Exception ex) {
Log.w(TAG, "Unhandled exception: " + ex);
}
} }
/** /**
@ -219,8 +195,10 @@ public final class BluetoothGatt implements BluetoothProfile {
public void onGetService(String address, int srvcType, public void onGetService(String address, int srvcType,
int srvcInstId, ParcelUuid srvcUuid) { int srvcInstId, ParcelUuid srvcUuid) {
if (DBG) Log.d(TAG, "onGetService() - Device=" + address + " UUID=" + srvcUuid); if (DBG) Log.d(TAG, "onGetService() - Device=" + address + " UUID=" + srvcUuid);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
mServices.add(new BluetoothGattService(device, srvcUuid.getUuid(), return;
}
mServices.add(new BluetoothGattService(mDevice, srvcUuid.getUuid(),
srvcInstId, srvcType)); srvcInstId, srvcType));
} }
@ -236,10 +214,12 @@ public final class BluetoothGatt implements BluetoothProfile {
if (DBG) Log.d(TAG, "onGetIncludedService() - Device=" + address if (DBG) Log.d(TAG, "onGetIncludedService() - Device=" + address
+ " UUID=" + srvcUuid + " Included=" + inclSrvcUuid); + " UUID=" + srvcUuid + " Included=" + inclSrvcUuid);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
BluetoothGattService service = getService(device, return;
}
BluetoothGattService service = getService(mDevice,
srvcUuid.getUuid(), srvcInstId, srvcType); srvcUuid.getUuid(), srvcInstId, srvcType);
BluetoothGattService includedService = getService(device, BluetoothGattService includedService = getService(mDevice,
inclSrvcUuid.getUuid(), inclSrvcInstId, inclSrvcType); inclSrvcUuid.getUuid(), inclSrvcInstId, inclSrvcType);
if (service != null && includedService != null) { if (service != null && includedService != null) {
@ -260,8 +240,10 @@ public final class BluetoothGatt implements BluetoothProfile {
if (DBG) Log.d(TAG, "onGetCharacteristic() - Device=" + address + " UUID=" + if (DBG) Log.d(TAG, "onGetCharacteristic() - Device=" + address + " UUID=" +
charUuid); charUuid);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
BluetoothGattService service = getService(device, srvcUuid.getUuid(), return;
}
BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
srvcInstId, srvcType); srvcInstId, srvcType);
if (service != null) { if (service != null) {
service.addCharacteristic(new BluetoothGattCharacteristic( service.addCharacteristic(new BluetoothGattCharacteristic(
@ -281,8 +263,10 @@ public final class BluetoothGatt implements BluetoothProfile {
ParcelUuid descUuid) { ParcelUuid descUuid) {
if (DBG) Log.d(TAG, "onGetDescriptor() - Device=" + address + " UUID=" + descUuid); if (DBG) Log.d(TAG, "onGetDescriptor() - Device=" + address + " UUID=" + descUuid);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
BluetoothGattService service = getService(device, srvcUuid.getUuid(), return;
}
BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
srvcInstId, srvcType); srvcInstId, srvcType);
if (service == null) return; if (service == null) return;
@ -303,9 +287,11 @@ public final class BluetoothGatt implements BluetoothProfile {
*/ */
public void onSearchComplete(String address, int status) { public void onSearchComplete(String address, int status) {
if (DBG) Log.d(TAG, "onSearchComplete() = Device=" + address + " Status=" + status); if (DBG) Log.d(TAG, "onSearchComplete() = Device=" + address + " Status=" + status);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
return;
}
try { try {
mCallback.onServicesDiscovered(device, status); mCallback.onServicesDiscovered(mDevice, status);
} catch (Exception ex) { } catch (Exception ex) {
Log.w(TAG, "Unhandled exception: " + ex); Log.w(TAG, "Unhandled exception: " + ex);
} }
@ -322,6 +308,9 @@ public final class BluetoothGatt implements BluetoothProfile {
if (DBG) Log.d(TAG, "onCharacteristicRead() - Device=" + address if (DBG) Log.d(TAG, "onCharacteristicRead() - Device=" + address
+ " UUID=" + charUuid + " Status=" + status); + " UUID=" + charUuid + " Status=" + status);
if (!address.equals(mDevice.getAddress())) {
return;
}
if ((status == GATT_INSUFFICIENT_AUTHENTICATION if ((status == GATT_INSUFFICIENT_AUTHENTICATION
|| status == GATT_INSUFFICIENT_ENCRYPTION) || status == GATT_INSUFFICIENT_ENCRYPTION)
&& mAuthRetry == false) { && mAuthRetry == false) {
@ -338,8 +327,7 @@ public final class BluetoothGatt implements BluetoothProfile {
mAuthRetry = false; mAuthRetry = false;
BluetoothDevice device = mAdapter.getRemoteDevice(address); BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
BluetoothGattService service = getService(device, srvcUuid.getUuid(),
srvcInstId, srvcType); srvcInstId, srvcType);
if (service == null) return; if (service == null) return;
@ -367,8 +355,10 @@ public final class BluetoothGatt implements BluetoothProfile {
if (DBG) Log.d(TAG, "onCharacteristicWrite() - Device=" + address if (DBG) Log.d(TAG, "onCharacteristicWrite() - Device=" + address
+ " UUID=" + charUuid + " Status=" + status); + " UUID=" + charUuid + " Status=" + status);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
BluetoothGattService service = getService(device, srvcUuid.getUuid(), return;
}
BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
srvcInstId, srvcType); srvcInstId, srvcType);
if (service == null) return; if (service == null) return;
@ -411,8 +401,10 @@ public final class BluetoothGatt implements BluetoothProfile {
byte[] value) { byte[] value) {
if (DBG) Log.d(TAG, "onNotify() - Device=" + address + " UUID=" + charUuid); if (DBG) Log.d(TAG, "onNotify() - Device=" + address + " UUID=" + charUuid);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
BluetoothGattService service = getService(device, srvcUuid.getUuid(), return;
}
BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
srvcInstId, srvcType); srvcInstId, srvcType);
if (service == null) return; if (service == null) return;
@ -439,8 +431,10 @@ public final class BluetoothGatt implements BluetoothProfile {
ParcelUuid descrUuid, byte[] value) { ParcelUuid descrUuid, byte[] value) {
if (DBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " UUID=" + charUuid); if (DBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " UUID=" + charUuid);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
BluetoothGattService service = getService(device, srvcUuid.getUuid(), return;
}
BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
srvcInstId, srvcType); srvcInstId, srvcType);
if (service == null) return; if (service == null) return;
@ -486,8 +480,10 @@ public final class BluetoothGatt implements BluetoothProfile {
ParcelUuid descrUuid) { ParcelUuid descrUuid) {
if (DBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " UUID=" + charUuid); if (DBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " UUID=" + charUuid);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
BluetoothGattService service = getService(device, srvcUuid.getUuid(), return;
}
BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
srvcInstId, srvcType); srvcInstId, srvcType);
if (service == null) return; if (service == null) return;
@ -529,9 +525,11 @@ public final class BluetoothGatt implements BluetoothProfile {
public void onExecuteWrite(String address, int status) { public void onExecuteWrite(String address, int status) {
if (DBG) Log.d(TAG, "onExecuteWrite() - Device=" + address if (DBG) Log.d(TAG, "onExecuteWrite() - Device=" + address
+ " status=" + status); + " status=" + status);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
return;
}
try { try {
mCallback.onReliableWriteCompleted(device, status); mCallback.onReliableWriteCompleted(mDevice, status);
} catch (Exception ex) { } catch (Exception ex) {
Log.w(TAG, "Unhandled exception: " + ex); Log.w(TAG, "Unhandled exception: " + ex);
} }
@ -544,43 +542,24 @@ public final class BluetoothGatt implements BluetoothProfile {
public void onReadRemoteRssi(String address, int rssi, int status) { public void onReadRemoteRssi(String address, int rssi, int status) {
if (DBG) Log.d(TAG, "onReadRemoteRssi() - Device=" + address + if (DBG) Log.d(TAG, "onReadRemoteRssi() - Device=" + address +
" rssi=" + rssi + " status=" + status); " rssi=" + rssi + " status=" + status);
BluetoothDevice device = mAdapter.getRemoteDevice(address); if (!address.equals(mDevice.getAddress())) {
return;
}
try { try {
mCallback.onReadRemoteRssi(device, rssi, status); mCallback.onReadRemoteRssi(mDevice, rssi, status);
} catch (Exception ex) { } catch (Exception ex) {
Log.w(TAG, "Unhandled exception: " + ex); Log.w(TAG, "Unhandled exception: " + ex);
} }
} }
}; };
/** /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) {
* Create a BluetoothGatt proxy object.
*/
/*package*/ BluetoothGatt(Context context, ServiceListener l) {
mContext = context; mContext = context;
mServiceListener = l; mService = iGatt;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mDevice = device;
mServices = new ArrayList<BluetoothGattService>(); mServices = new ArrayList<BluetoothGattService>();
IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE); mConnState = CONN_STATE_IDLE;
if (b != null) {
IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException re) {
Log.e(TAG, "Unable to register BluetoothStateChangeCallback", re);
}
} else {
Log.e(TAG, "Unable to get BluetoothManager interface.");
throw new RuntimeException("BluetoothManager inactive");
}
//Bind to the service only if the Bluetooth is ON
if(mAdapter.isEnabled()){
if (!context.bindService(new Intent(IBluetoothGatt.class.getName()), mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth Gatt Service");
}
}
} }
/** /**
@ -590,24 +569,6 @@ public final class BluetoothGatt implements BluetoothProfile {
if (DBG) Log.d(TAG, "close()"); if (DBG) Log.d(TAG, "close()");
unregisterApp(); unregisterApp();
mServiceListener = null;
IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
if (b != null) {
IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException re) {
Log.e(TAG, "Unable to unregister BluetoothStateChangeCallback", re);
}
}
synchronized (mConnection) {
if (mService != null) {
mService = null;
mContext.unbindService(mConnection);
}
}
} }
/** /**
@ -629,18 +590,18 @@ public final class BluetoothGatt implements BluetoothProfile {
/** /**
* Register an application callback to start using Gatt. * Register an application callback to start using GATT.
* *
* <p>This is an asynchronous call. The callback is used to notify * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
* success or failure if the function returns true. * is used to notify success or failure if the function returns true.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param callback Gatt callback handler that will receive asynchronous * @param callback GATT callback handler that will receive asynchronous callbacks.
* callbacks. * @return If true, the callback will be called to notify success or failure,
* @return true, if application was successfully registered. * false on immediate error
*/ */
public boolean registerApp(BluetoothGattCallback callback) { private boolean registerApp(BluetoothGattCallback callback) {
if (DBG) Log.d(TAG, "registerApp()"); if (DBG) Log.d(TAG, "registerApp()");
if (mService == null) return false; if (mService == null) return false;
@ -661,7 +622,7 @@ public final class BluetoothGatt implements BluetoothProfile {
/** /**
* Unregister the current application and callbacks. * Unregister the current application and callbacks.
*/ */
public void unregisterApp() { private void unregisterApp() {
if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf); if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);
if (mService == null || mClientIf == 0) return; if (mService == null || mClientIf == 0) return;
@ -675,77 +636,7 @@ public final class BluetoothGatt implements BluetoothProfile {
} }
/** /**
* Starts a scan for Bluetooth LE devices. * Initiate a connection to a Bluetooth GATT capable device.
*
* <p>Results of the scan are reported using the
* {@link BluetoothGattCallback#onScanResult} callback.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return true, if the scan was started successfully
*/
public boolean startScan() {
if (DBG) Log.d(TAG, "startScan()");
if (mService == null || mClientIf == 0) return false;
try {
mService.startScan(mClientIf, false);
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
return true;
}
/**
* Starts a scan for Bluetooth LE devices, looking for devices that
* advertise given services.
*
* <p>Devices which advertise all specified services are reported using the
* {@link BluetoothGattCallback#onScanResult} callback.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param serviceUuids Array of services to look for
* @return true, if the scan was started successfully
*/
public boolean startScan(UUID[] serviceUuids) {
if (DBG) Log.d(TAG, "startScan() - with UUIDs");
if (mService == null || mClientIf == 0) return false;
try {
ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
for(int i = 0; i != uuids.length; ++i) {
uuids[i] = new ParcelUuid(serviceUuids[i]);
}
mService.startScanWithUuids(mClientIf, false, uuids);
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
return true;
}
/**
* Stops an ongoing Bluetooth LE device scan.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*/
public void stopScan() {
if (DBG) Log.d(TAG, "stopScan()");
if (mService == null || mClientIf == 0) return;
try {
mService.stopScan(mClientIf, false);
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
}
/**
* Initiate a connection to a Bluetooth Gatt capable device.
* *
* <p>The connection may not be established right away, but will be * <p>The connection may not be established right away, but will be
* completed when the remote device is available. A * completed when the remote device is available. A
@ -757,7 +648,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* when the remote device is in range/available. Generally, the first ever * when the remote device is in range/available. Generally, the first ever
* connection to a device should be direct (autoConnect set to false) and * connection to a device should be direct (autoConnect set to false) and
* subsequent connections to known devices should be invoked with the * subsequent connections to known devices should be invoked with the
* autoConnect parameter set to false. * autoConnect parameter set to true.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
@ -767,18 +658,24 @@ public final class BluetoothGatt implements BluetoothProfile {
* device becomes available (true). * device becomes available (true).
* @return true, if the connection attempt was initiated successfully * @return true, if the connection attempt was initiated successfully
*/ */
public boolean connect(BluetoothDevice device, boolean autoConnect) { /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback) {
if (DBG) Log.d(TAG, "connect() - device: " + device.getAddress() + ", auto: " + autoConnect); if (DBG) Log.d(TAG, "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
if (mService == null || mClientIf == 0) return false; synchronized(mStateLock) {
if (mConnState != CONN_STATE_IDLE) {
try { throw new IllegalStateException("Not idle");
mService.clientConnect(mClientIf, device.getAddress(), }
autoConnect ? false : true); // autoConnect is inverse of "isDirect" mConnState = CONN_STATE_CONNECTING;
} catch (RemoteException e) { }
Log.e(TAG,"",e); if (!registerApp(callback)) {
synchronized(mStateLock) {
mConnState = CONN_STATE_IDLE;
}
Log.e(TAG, "Failed to register callback");
return false; return false;
} }
// the connection will continue after successful callback registration
mAutoConnect = autoConnect;
return true; return true;
} }
@ -787,18 +684,17 @@ public final class BluetoothGatt implements BluetoothProfile {
* currently in progress. * currently in progress.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device Remote device
*/ */
public void cancelConnection(BluetoothDevice device) { public void disconnect() {
if (DBG) Log.d(TAG, "cancelOpen() - device: " + device.getAddress()); if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return; if (mService == null || mClientIf == 0) return;
try { try {
mService.clientDisconnect(mClientIf, device.getAddress()); mService.clientDisconnect(mClientIf, mDevice.getAddress());
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG,"",e); Log.e(TAG,"",e);
} }
// TBD deregister after conneciton is torn down
} }
/** /**
@ -812,17 +708,16 @@ public final class BluetoothGatt implements BluetoothProfile {
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param device Remote device to explore
* @return true, if the remote service discovery has been started * @return true, if the remote service discovery has been started
*/ */
public boolean discoverServices(BluetoothDevice device) { public boolean discoverServices() {
if (DBG) Log.d(TAG, "discoverServices() - device: " + device.getAddress()); if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false; if (mService == null || mClientIf == 0) return false;
mServices.clear(); mServices.clear();
try { try {
mService.discoverServices(mClientIf, device.getAddress()); mService.discoverServices(mClientIf, mDevice.getAddress());
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG,"",e); Log.e(TAG,"",e);
return false; return false;
@ -839,16 +734,15 @@ public final class BluetoothGatt implements BluetoothProfile {
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param device Remote device
* @return List of services on the remote device. Returns an empty list * @return List of services on the remote device. Returns an empty list
* if service discovery has not yet been performed. * if service discovery has not yet been performed.
*/ */
public List<BluetoothGattService> getServices(BluetoothDevice device) { public List<BluetoothGattService> getServices() {
List<BluetoothGattService> result = List<BluetoothGattService> result =
new ArrayList<BluetoothGattService>(); new ArrayList<BluetoothGattService>();
for (BluetoothGattService service : mServices) { for (BluetoothGattService service : mServices) {
if (service.getDevice().equals(device)) { if (service.getDevice().equals(mDevice)) {
result.add(service); result.add(service);
} }
} }
@ -868,14 +762,13 @@ public final class BluetoothGatt implements BluetoothProfile {
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param device Remote device
* @param uuid UUID of the requested service * @param uuid UUID of the requested service
* @return BluetoothGattService if supported, or null if the requested * @return BluetoothGattService if supported, or null if the requested
* service is not offered by the remote device. * service is not offered by the remote device.
*/ */
public BluetoothGattService getService(BluetoothDevice device, UUID uuid) { public BluetoothGattService getService(UUID uuid) {
for (BluetoothGattService service : mServices) { for (BluetoothGattService service : mServices) {
if (service.getDevice().equals(device) && if (service.getDevice().equals(mDevice) &&
service.getUuid().equals(uuid)) { service.getUuid().equals(uuid)) {
return service; return service;
} }
@ -923,8 +816,7 @@ public final class BluetoothGatt implements BluetoothProfile {
} }
/** /**
* Writes a given characteristic and it's values to the associated remote * Writes a given characteristic and its values to the associated remote device.
* device.
* *
* <p>Once the write operation has been completed, the * <p>Once the write operation has been completed, the
* {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked, * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
@ -1061,15 +953,14 @@ public final class BluetoothGatt implements BluetoothProfile {
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param device Remote device
* @return true, if the reliable write transaction has been initiated * @return true, if the reliable write transaction has been initiated
*/ */
public boolean beginReliableWrite(BluetoothDevice device) { public boolean beginReliableWrite() {
if (DBG) Log.d(TAG, "beginReliableWrite() - device: " + device.getAddress()); if (DBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false; if (mService == null || mClientIf == 0) return false;
try { try {
mService.beginReliableWrite(mClientIf, device.getAddress()); mService.beginReliableWrite(mClientIf, mDevice.getAddress());
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG,"",e); Log.e(TAG,"",e);
return false; return false;
@ -1089,15 +980,14 @@ public final class BluetoothGatt implements BluetoothProfile {
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param device Remote device
* @return true, if the request to execute the transaction has been sent * @return true, if the request to execute the transaction has been sent
*/ */
public boolean executeReliableWrite(BluetoothDevice device) { public boolean executeReliableWrite() {
if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + device.getAddress()); if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false; if (mService == null || mClientIf == 0) return false;
try { try {
mService.endReliableWrite(mClientIf, device.getAddress(), true); mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG,"",e); Log.e(TAG,"",e);
return false; return false;
@ -1113,15 +1003,13 @@ public final class BluetoothGatt implements BluetoothProfile {
* operations for a given remote device. * operations for a given remote device.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device Remote device
*/ */
public void abortReliableWrite(BluetoothDevice device) { public void abortReliableWrite(BluetoothDevice mDevice) {
if (DBG) Log.d(TAG, "abortReliableWrite() - device: " + device.getAddress()); if (DBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return; if (mService == null || mClientIf == 0) return;
try { try {
mService.endReliableWrite(mClientIf, device.getAddress(), false); mService.endReliableWrite(mClientIf, mDevice.getAddress(), false);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG,"",e); Log.e(TAG,"",e);
} }
@ -1172,12 +1060,12 @@ public final class BluetoothGatt implements BluetoothProfile {
* remote device. * remote device.
* @hide * @hide
*/ */
public boolean refresh(BluetoothDevice device) { public boolean refresh() {
if (DBG) Log.d(TAG, "refresh() - device: " + device.getAddress()); if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false; if (mService == null || mClientIf == 0) return false;
try { try {
mService.refreshDevice(mClientIf, device.getAddress()); mService.refreshDevice(mClientIf, mDevice.getAddress());
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG,"",e); Log.e(TAG,"",e);
return false; return false;
@ -1194,15 +1082,14 @@ public final class BluetoothGatt implements BluetoothProfile {
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param device Remote device
* @return true, if the RSSI value has been requested successfully * @return true, if the RSSI value has been requested successfully
*/ */
public boolean readRemoteRssi(BluetoothDevice device) { public boolean readRemoteRssi() {
if (DBG) Log.d(TAG, "readRssi() - device: " + device.getAddress()); if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false; if (mService == null || mClientIf == 0) return false;
try { try {
mService.readRemoteRssi(mClientIf, device.getAddress()); mService.readRemoteRssi(mClientIf, mDevice.getAddress());
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG,"",e); Log.e(TAG,"",e);
return false; return false;
@ -1212,98 +1099,38 @@ public final class BluetoothGatt implements BluetoothProfile {
} }
/** /**
* Get the current connection state of the profile. * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
* with {@link BluetoothProfile#GATT} as argument
* *
* <p>This is not specific to any application configuration but represents * @throws UnsupportedOperationException
* the connection state of the local Bluetooth adapter for this profile.
* This can be used by applications like status bar which would just like
* to know the state of the local adapter.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device Remote bluetooth device.
* @return State of the profile connection. One of
* {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
*/ */
@Override @Override
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (DBG) Log.d(TAG,"getConnectionState()"); throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
if (mService == null) return STATE_DISCONNECTED;
List<BluetoothDevice> connectedDevices = getConnectedDevices();
for(BluetoothDevice connectedDevice : connectedDevices) {
if (device.equals(connectedDevice)) {
return STATE_CONNECTED;
}
}
return STATE_DISCONNECTED;
} }
/** /**
* Get connected devices for the Gatt profile. * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
* with {@link BluetoothProfile#GATT} as argument
* *
* <p> Return the set of devices which are in state {@link #STATE_CONNECTED} * @throws UnsupportedOperationException
*
* <p>This is not specific to any application configuration but represents
* the connection state of the local Bluetooth adapter for this profile.
* This can be used by applications like status bar which would just like
* to know the state of the local adapter.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return List of devices. The list will be empty on error.
*/ */
@Override @Override
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (DBG) Log.d(TAG,"getConnectedDevices"); throw new UnsupportedOperationException
("Use BluetoothManager#getConnectedDevices instead.");
List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
if (mService == null) return connectedDevices;
try {
connectedDevices = mService.getDevicesMatchingConnectionStates(
new int[] { BluetoothProfile.STATE_CONNECTED });
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
return connectedDevices;
} }
/** /**
* Get a list of devices that match any of the given connection * Not supported - please use
* states. * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
* with {@link BluetoothProfile#GATT} as first argument
* *
* <p> If none of the devices match any of the given states, * @throws UnsupportedOperationException
* an empty list will be returned.
*
* <p>This is not specific to any application configuration but represents
* the connection state of the local Bluetooth adapter for this profile.
* This can be used by applications like status bar which would just like
* to know the state of the local adapter.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param states Array of states. States can be one of
* {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
* @return List of devices. The list will be empty on error.
*/ */
@Override @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates"); throw new UnsupportedOperationException
("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
if (mService == null) return devices;
try {
devices = mService.getDevicesMatchingConnectionStates(states);
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
return devices;
} }
} }

View File

@ -18,34 +18,10 @@ package android.bluetooth;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.util.Log;
/** /**
* This abstract class is used to implement {@link BluetoothGatt} callbacks. * This abstract class is used to implement {@link BluetoothGatt} callbacks.
* @hide
*/ */
public abstract class BluetoothGattCallback { public abstract class BluetoothGattCallback {
/**
* Callback to inform change in registration state of the application.
*
* @param status Returns {@link BluetoothGatt#GATT_SUCCESS} if the application
* was successfully registered.
*/
public void onAppRegistered(int status) {
}
/**
* Callback reporting an LE device found during a device scan initiated
* by the {@link BluetoothGatt#startScan} function.
*
* @param device Identifies the remote device
* @param rssi The RSSI value for the remote device as reported by the
* Bluetooth hardware. 0 if no RSSI value is available.
* @param scanRecord The content of the advertisement record offered by
* the remote device.
*/
public void onScanResult(BluetoothDevice device, int rssi, byte[] scanRecord) {
}
/** /**
* Callback indicating when a remote device has been connected or disconnected. * Callback indicating when a remote device has been connected or disconnected.
@ -61,8 +37,8 @@ public abstract class BluetoothGattCallback {
} }
/** /**
* Callback invoked when the list of remote services, characteristics and * Callback invoked when the list of remote services, characteristics and descriptors
* descriptors for the remote device have been updated. * for the remote device have been updated, ie new services have been discovered.
* *
* @param device Remote device * @param device Remote device
* @param status {@link BluetoothGatt#GATT_SUCCESS} if the remote device * @param status {@link BluetoothGatt#GATT_SUCCESS} if the remote device
@ -117,8 +93,7 @@ public abstract class BluetoothGattCallback {
* @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation
* was completed successfully * was completed successfully
*/ */
public void onDescriptorRead(BluetoothGattDescriptor descriptor, public void onDescriptorRead(BluetoothGattDescriptor descriptor, int status) {
int status) {
} }
/** /**
@ -128,8 +103,7 @@ public abstract class BluetoothGattCallback {
* remote device. * remote device.
* @param status The result of the write operation * @param status The result of the write operation
*/ */
public void onDescriptorWrite(BluetoothGattDescriptor descriptor, public void onDescriptorWrite(BluetoothGattDescriptor descriptor, int status) {
int status) {
} }
/** /**
@ -150,7 +124,7 @@ public abstract class BluetoothGattCallback {
* *
* @param device Identifies the remote device * @param device Identifies the remote device
* @param rssi The RSSI value for the remote device * @param rssi The RSSI value for the remote device
* @param status 0 if the RSSI was read successfully * @param status {@link BluetoothGatt#GATT_SUCCESS} if the RSSI was read successfully
*/ */
public void onReadRemoteRssi(BluetoothDevice device, int rssi, int status) { public void onReadRemoteRssi(BluetoothDevice device, int rssi, int status) {
} }

View File

@ -21,8 +21,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* Represents a Bluetooth Gatt Characteristic * Represents a Bluetooth GATT Characteristic
* @hide
*/ */
public class BluetoothGattCharacteristic { public class BluetoothGattCharacteristic {
@ -119,7 +118,7 @@ public class BluetoothGattCharacteristic {
public static final int WRITE_TYPE_NO_RESPONSE = 0x01; public static final int WRITE_TYPE_NO_RESPONSE = 0x01;
/** /**
* Write characteristic including and authenticated signature * Write characteristic including authentication signature
*/ */
public static final int WRITE_TYPE_SIGNED = 0x04; public static final int WRITE_TYPE_SIGNED = 0x04;
@ -218,6 +217,18 @@ public class BluetoothGattCharacteristic {
*/ */
protected List<BluetoothGattDescriptor> mDescriptors; protected List<BluetoothGattDescriptor> mDescriptors;
/**
* Create a new BluetoothGattCharacteristic.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this characteristic
* @param properties Properties of this characteristic
* @param permissions Permissions for this characteristic
*/
public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) {
initCharacteristic(null, uuid, 0, properties, permissions);
}
/** /**
* Create a new BluetoothGattCharacteristic * Create a new BluetoothGattCharacteristic
* @hide * @hide
@ -225,6 +236,12 @@ public class BluetoothGattCharacteristic {
/*package*/ BluetoothGattCharacteristic(BluetoothGattService service, /*package*/ BluetoothGattCharacteristic(BluetoothGattService service,
UUID uuid, int instanceId, UUID uuid, int instanceId,
int properties, int permissions) { int properties, int permissions) {
initCharacteristic(service, uuid, instanceId, properties, permissions);
}
private void initCharacteristic(BluetoothGattService service,
UUID uuid, int instanceId,
int properties, int permissions) {
mUuid = uuid; mUuid = uuid;
mInstance = instanceId; mInstance = instanceId;
mProperties = properties; mProperties = properties;
@ -249,11 +266,16 @@ public class BluetoothGattCharacteristic {
} }
/** /**
* Add a descriptor to this characteristic * Adds a descriptor to this characteristic.
* @hide * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param descriptor Descriptor to be added to this characteristic.
* @return true, if the descriptor was added to the characteristic
*/ */
/*package*/ void addDescriptor(BluetoothGattDescriptor descriptor) { public boolean addDescriptor(BluetoothGattDescriptor descriptor) {
mDescriptors.add(descriptor); mDescriptors.add(descriptor);
descriptor.setCharacteristic(this);
return true;
} }
/** /**
@ -264,9 +286,16 @@ public class BluetoothGattCharacteristic {
return mService; return mService;
} }
/**
* Sets the service associated with this device.
* @hide
*/
/*package*/ void setService(BluetoothGattService service) {
mService = service;
}
/** /**
* Returns the UUID of this characteristic * Returns the UUID of this characteristic
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @return UUID of this characteristic * @return UUID of this characteristic
*/ */
@ -280,8 +309,6 @@ public class BluetoothGattCharacteristic {
* <p>If a remote device offers multiple characteristics with the same UUID, * <p>If a remote device offers multiple characteristics with the same UUID,
* the instance ID is used to distuinguish between characteristics. * the instance ID is used to distuinguish between characteristics.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return Instance ID of this characteristic * @return Instance ID of this characteristic
*/ */
public int getInstanceId() { public int getInstanceId() {
@ -294,8 +321,6 @@ public class BluetoothGattCharacteristic {
* <p>The properties contain a bit mask of property flags indicating * <p>The properties contain a bit mask of property flags indicating
* the features of this characteristic. * the features of this characteristic.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return Properties of this characteristic * @return Properties of this characteristic
*/ */
public int getProperties() { public int getProperties() {
@ -304,7 +329,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Returns the permissions for this characteristic. * Returns the permissions for this characteristic.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @return Permissions of this characteristic * @return Permissions of this characteristic
*/ */
@ -314,7 +338,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Gets the write type for this characteristic. * Gets the write type for this characteristic.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @return Write type for this characteristic * @return Write type for this characteristic
*/ */
@ -329,11 +352,6 @@ public class BluetoothGattCharacteristic {
* {@link BluetoothGatt#writeCharacteristic} function write this * {@link BluetoothGatt#writeCharacteristic} function write this
* characteristic. * characteristic.
* *
* <p>The default write type for a characteristic is
* {@link #WRITE_TYPE_DEFAULT}.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param writeType The write type to for this characteristic. Can be one * @param writeType The write type to for this characteristic. Can be one
* of: * of:
* {@link #WRITE_TYPE_DEFAULT}, * {@link #WRITE_TYPE_DEFAULT},
@ -344,9 +362,16 @@ public class BluetoothGattCharacteristic {
mWriteType = writeType; mWriteType = writeType;
} }
/**
* Set the desired key size.
* @hide
*/
public void setKeySize(int keySize) {
mKeySize = keySize;
}
/** /**
* Returns a list of descriptors for this characteristic. * Returns a list of descriptors for this characteristic.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @return Descriptors for this characteristic * @return Descriptors for this characteristic
*/ */
@ -358,9 +383,7 @@ public class BluetoothGattCharacteristic {
* Returns a descriptor with a given UUID out of the list of * Returns a descriptor with a given UUID out of the list of
* descriptors for this characteristic. * descriptors for this characteristic.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * @return GATT descriptor object or null if no descriptor with the
*
* @return Gatt descriptor object or null if no descriptor with the
* given UUID was found. * given UUID was found.
*/ */
public BluetoothGattDescriptor getDescriptor(UUID uuid) { public BluetoothGattDescriptor getDescriptor(UUID uuid) {
@ -376,12 +399,10 @@ public class BluetoothGattCharacteristic {
* Get the stored value for this characteristic. * Get the stored value for this characteristic.
* *
* <p>This function returns the stored value for this characteristic as * <p>This function returns the stored value for this characteristic as
* retrieved by calling {@link BluetoothGatt#readCharacteristic}. To cached * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached
* value of the characteristic is updated as a result of a read characteristic * value of the characteristic is updated as a result of a read characteristic
* operation or if a characteristic update notification has been received. * operation or if a characteristic update notification has been received.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return Cached value of the characteristic * @return Cached value of the characteristic
*/ */
public byte[] getValue() { public byte[] getValue() {
@ -397,8 +418,6 @@ public class BluetoothGattCharacteristic {
* characteristic value at the given offset are interpreted to generate the * characteristic value at the given offset are interpreted to generate the
* return value. * return value.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param formatType The format type used to interpret the characteristic * @param formatType The format type used to interpret the characteristic
* value. * value.
* @param offset Offset at which the integer value can be found. * @param offset Offset at which the integer value can be found.
@ -436,7 +455,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Return the stored value of this characteristic. * Return the stored value of this characteristic.
* <p>See {@link #getValue} for details. * <p>See {@link #getValue} for details.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param formatType The format type used to interpret the characteristic * @param formatType The format type used to interpret the characteristic
* value. * value.
@ -462,7 +480,7 @@ public class BluetoothGattCharacteristic {
/** /**
* Return the stored value of this characteristic. * Return the stored value of this characteristic.
* <p>See {@link #getValue} for details. * <p>See {@link #getValue} for details.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. *
* @param offset Offset at which the string value can be found. * @param offset Offset at which the string value can be found.
* @return Cached value of the characteristic * @return Cached value of the characteristic
*/ */
@ -481,8 +499,6 @@ public class BluetoothGattCharacteristic {
* {@link BluetoothGatt#writeCharacteristic} to send the value to the * {@link BluetoothGatt#writeCharacteristic} to send the value to the
* remote device. * remote device.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param value New value for this characteristic * @param value New value for this characteristic
* @return true if the locally stored value has been set, false if the * @return true if the locally stored value has been set, false if the
* requested value could not be stored locally. * requested value could not be stored locally.
@ -495,7 +511,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Set the locally stored value of this characteristic. * Set the locally stored value of this characteristic.
* <p>See {@link #setValue(byte[])} for details. * <p>See {@link #setValue(byte[])} for details.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param value New value for this characteristic * @param value New value for this characteristic
* @param formatType Integer format type used to transform the value parameter * @param formatType Integer format type used to transform the value parameter
@ -542,7 +557,7 @@ public class BluetoothGattCharacteristic {
/** /**
* Set the locally stored value of this characteristic. * Set the locally stored value of this characteristic.
* <p>See {@link #setValue(byte[])} for details. * <p>See {@link #setValue(byte[])} for details.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. *
* @param mantissa Mantissa for this characteristic * @param mantissa Mantissa for this characteristic
* @param exponent exponent value for this characteristic * @param exponent exponent value for this characteristic
* @param formatType Float format type used to transform the value parameter * @param formatType Float format type used to transform the value parameter
@ -582,7 +597,7 @@ public class BluetoothGattCharacteristic {
/** /**
* Set the locally stored value of this characteristic. * Set the locally stored value of this characteristic.
* <p>See {@link #setValue(byte[])} for details. * <p>See {@link #setValue(byte[])} for details.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. *
* @param value New value for this characteristic * @param value New value for this characteristic
* @return true if the locally stored value has been set * @return true if the locally stored value has been set
*/ */
@ -593,7 +608,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Returns the size of a give value type. * Returns the size of a give value type.
* @hide
*/ */
private int getTypeLen(int formatType) { private int getTypeLen(int formatType) {
return formatType & 0xF; return formatType & 0xF;
@ -601,7 +615,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Convert a signed byte to an unsigned int. * Convert a signed byte to an unsigned int.
* @hide
*/ */
private int unsignedByteToInt(byte b) { private int unsignedByteToInt(byte b) {
return b & 0xFF; return b & 0xFF;
@ -609,7 +622,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Convert signed bytes to a 16-bit unsigned int. * Convert signed bytes to a 16-bit unsigned int.
* @hide
*/ */
private int unsignedBytesToInt(byte b0, byte b1) { private int unsignedBytesToInt(byte b0, byte b1) {
return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)); return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8));
@ -617,7 +629,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Convert signed bytes to a 32-bit unsigned int. * Convert signed bytes to a 32-bit unsigned int.
* @hide
*/ */
private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) { private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) {
return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)) return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8))
@ -626,7 +637,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Convert signed bytes to a 16-bit short float value. * Convert signed bytes to a 16-bit short float value.
* @hide
*/ */
private float bytesToFloat(byte b0, byte b1) { private float bytesToFloat(byte b0, byte b1) {
int mantissa = unsignedToSigned(unsignedByteToInt(b0) int mantissa = unsignedToSigned(unsignedByteToInt(b0)
@ -637,7 +647,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Convert signed bytes to a 32-bit short float value. * Convert signed bytes to a 32-bit short float value.
* @hide
*/ */
private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) { private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
int mantissa = unsignedToSigned(unsignedByteToInt(b0) int mantissa = unsignedToSigned(unsignedByteToInt(b0)
@ -649,7 +658,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Convert an unsigned integer value to a two's-complement encoded * Convert an unsigned integer value to a two's-complement encoded
* signed value. * signed value.
* @hide
*/ */
private int unsignedToSigned(int unsigned, int size) { private int unsignedToSigned(int unsigned, int size) {
if ((unsigned & (1 << size-1)) != 0) { if ((unsigned & (1 << size-1)) != 0) {
@ -660,7 +668,6 @@ public class BluetoothGattCharacteristic {
/** /**
* Convert an integer into the signed bits of a given length. * Convert an integer into the signed bits of a given length.
* @hide
*/ */
private int intToSignedBits(int i, int size) { private int intToSignedBits(int i, int size) {
if (i < 0) { if (i < 0) {

View File

@ -19,8 +19,7 @@ package android.bluetooth;
import java.util.UUID; import java.util.UUID;
/** /**
* Represents a Bluetooth Gatt Descriptor * Represents a Bluetooth GATT Descriptor
* @hide
*/ */
public class BluetoothGattDescriptor { public class BluetoothGattDescriptor {
@ -105,6 +104,17 @@ public class BluetoothGattDescriptor {
*/ */
protected byte[] mValue; protected byte[] mValue;
/**
* Create a new BluetoothGattDescriptor.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this descriptor
* @param permissions Permissions for this descriptor
*/
public BluetoothGattDescriptor(UUID uuid, int permissions) {
initDescriptor(null, uuid, permissions);
}
/** /**
* Create a new BluetoothGattDescriptor. * Create a new BluetoothGattDescriptor.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
@ -115,6 +125,11 @@ public class BluetoothGattDescriptor {
*/ */
/*package*/ BluetoothGattDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid, /*package*/ BluetoothGattDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
int permissions) { int permissions) {
initDescriptor(characteristic, uuid, permissions);
}
private void initDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
int permissions) {
mCharacteristic = characteristic; mCharacteristic = characteristic;
mUuid = uuid; mUuid = uuid;
mPermissions = permissions; mPermissions = permissions;
@ -128,9 +143,16 @@ public class BluetoothGattDescriptor {
return mCharacteristic; return mCharacteristic;
} }
/**
* Set the back-reference to the associated characteristic
* @hide
*/
/*package*/ void setCharacteristic(BluetoothGattCharacteristic characteristic) {
mCharacteristic = characteristic;
}
/** /**
* Returns the UUID of this descriptor. * Returns the UUID of this descriptor.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @return UUID of this descriptor * @return UUID of this descriptor
*/ */
@ -140,7 +162,6 @@ public class BluetoothGattDescriptor {
/** /**
* Returns the permissions for this descriptor. * Returns the permissions for this descriptor.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @return Permissions of this descriptor * @return Permissions of this descriptor
*/ */
@ -152,12 +173,10 @@ public class BluetoothGattDescriptor {
* Returns the stored value for this descriptor * Returns the stored value for this descriptor
* *
* <p>This function returns the stored value for this descriptor as * <p>This function returns the stored value for this descriptor as
* retrieved by calling {@link BluetoothGatt#readDescriptor}. To cached * retrieved by calling {@link BluetoothGatt#readDescriptor}. The cached
* value of the descriptor is updated as a result of a descriptor read * value of the descriptor is updated as a result of a descriptor read
* operation. * operation.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return Cached value of the descriptor * @return Cached value of the descriptor
*/ */
public byte[] getValue() { public byte[] getValue() {
@ -172,8 +191,6 @@ public class BluetoothGattDescriptor {
* {@link BluetoothGatt#writeDescriptor} to send the value to the * {@link BluetoothGatt#writeDescriptor} to send the value to the
* remote device. * remote device.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param value New value for this descriptor * @param value New value for this descriptor
* @return true if the locally stored value has been set, false if the * @return true if the locally stored value has been set, false if the
* requested value could not be stored locally. * requested value could not be stored locally.

View File

@ -38,88 +38,30 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* Public API for the Bluetooth Gatt Profile server role. * Public API for the Bluetooth GATT Profile server role.
* *
* <p>This class provides Bluetooth Gatt server role functionality, * <p>This class provides Bluetooth GATT server role functionality,
* allowing applications to create and advertise Bluetooth Smart services * allowing applications to create and advertise Bluetooth Smart services
* and characteristics. * and characteristics.
* *
* <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service * <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service
* via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the * via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
* BluetoothGatt proxy object. * BluetoothGatt proxy object.
* @hide
*/ */
public final class BluetoothGattServer implements BluetoothProfile { public final class BluetoothGattServer implements BluetoothProfile {
private static final String TAG = "BluetoothGattServer"; private static final String TAG = "BluetoothGattServer";
private static final boolean DBG = true; private static final boolean DBG = true;
private Context mContext; private final Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter;
private IBluetoothGatt mService; private IBluetoothGatt mService;
private BluetoothGattServerCallback mCallback; private BluetoothGattServerCallback mCallback;
private int mServerIf;
private Object mServerIfLock = new Object();
private int mServerIf;
private List<BluetoothGattService> mServices; private List<BluetoothGattService> mServices;
/** private static final int CALLBACK_REG_TIMEOUT = 10000;
* Bluetooth state change handlers
*/
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
public void onBluetoothStateChange(boolean up) {
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
if (!up) {
if (DBG) Log.d(TAG,"Unbinding service...");
synchronized (mConnection) {
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG,"",re);
}
}
} else {
synchronized (mConnection) {
try {
if (mService == null) {
if (DBG) Log.d(TAG,"Binding service...");
if (!mContext.bindService(new
Intent(IBluetoothGatt.class.getName()),
mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth GATT Service");
}
}
} catch (Exception re) {
Log.e(TAG,"",re);
}
}
}
}
};
/**
* Service binder handling
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothGatt.Stub.asInterface(service);
ServiceListener serviceListner = mServiceListener;
if (serviceListner != null) {
serviceListner.onServiceConnected(BluetoothProfile.GATT_SERVER,
BluetoothGattServer.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
ServiceListener serviceListner = mServiceListener;
if (serviceListner != null) {
serviceListner.onServiceDisconnected(BluetoothProfile.GATT_SERVER);
}
}
};
/** /**
* Bluetooth GATT interface callbacks * Bluetooth GATT interface callbacks
@ -133,11 +75,14 @@ public final class BluetoothGattServer implements BluetoothProfile {
public void onServerRegistered(int status, int serverIf) { public void onServerRegistered(int status, int serverIf) {
if (DBG) Log.d(TAG, "onServerRegistered() - status=" + status if (DBG) Log.d(TAG, "onServerRegistered() - status=" + status
+ " serverIf=" + serverIf); + " serverIf=" + serverIf);
synchronized(mServerIfLock) {
if (mCallback != null) {
mServerIf = serverIf; mServerIf = serverIf;
try { mServerIfLock.notify();
mCallback.onAppRegistered(status); } else {
} catch (Exception ex) { // registration timeout
Log.w(TAG, "Unhandled exception: " + ex); Log.e(TAG, "onServerRegistered: mCallback is null");
}
} }
} }
@ -147,13 +92,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
*/ */
public void onScanResult(String address, int rssi, byte[] advData) { public void onScanResult(String address, int rssi, byte[] advData) {
if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
// no op
try {
mCallback.onScanResult(mAdapter.getRemoteDevice(address),
rssi, advData);
} catch (Exception ex) {
Log.w(TAG, "Unhandled exception: " + ex);
}
} }
/** /**
@ -209,8 +148,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType); BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
if (service == null) return; if (service == null) return;
BluetoothGattCharacteristic characteristic = service.getCharacteristic( BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
charUuid);
if (characteristic == null) return; if (characteristic == null) return;
try { try {
@ -340,31 +278,13 @@ public final class BluetoothGattServer implements BluetoothProfile {
/** /**
* Create a BluetoothGattServer proxy object. * Create a BluetoothGattServer proxy object.
*/ */
/*package*/ BluetoothGattServer(Context context, ServiceListener l) { /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt) {
mContext = context; mContext = context;
mServiceListener = l; mService = iGatt;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
mCallback = null;
mServerIf = 0;
mServices = new ArrayList<BluetoothGattService>(); mServices = new ArrayList<BluetoothGattService>();
IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
if (b != null) {
IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException re) {
Log.e(TAG, "Unable to register BluetoothStateChangeCallback", re);
}
} else {
Log.e(TAG, "Unable to get BluetoothManager interface.");
throw new RuntimeException("BluetoothManager inactive");
}
//Bind to the service only if the Bluetooth is ON
if(mAdapter.isEnabled()){
if (!context.bindService(new Intent(IBluetoothGatt.class.getName()), mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth Gatt Service");
}
}
} }
/** /**
@ -372,29 +292,75 @@ public final class BluetoothGattServer implements BluetoothProfile {
*/ */
/*package*/ void close() { /*package*/ void close() {
if (DBG) Log.d(TAG, "close()"); if (DBG) Log.d(TAG, "close()");
unregisterCallback();
}
unregisterApp(); /**
mServiceListener = null; * Register an application callback to start using GattServer.
*
* <p>This is an asynchronous call. The callback is used to notify
* success or failure if the function returns true.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param callback GATT callback handler that will receive asynchronous
* callbacks.
* @return true, the callback will be called to notify success or failure,
* false on immediate error
*/
/*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
if (DBG) Log.d(TAG, "registerCallback()");
if (mService == null) {
Log.e(TAG, "GATT service not available");
return false;
}
UUID uuid = UUID.randomUUID();
if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE); synchronized(mServerIfLock) {
if (b != null) { if (mCallback != null) {
IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b); Log.e(TAG, "App can register callback only once");
return false;
}
mCallback = callback;
try { try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
} catch (RemoteException re) { } catch (RemoteException e) {
Log.e(TAG, "Unable to unregister BluetoothStateChangeCallback", re); Log.e(TAG,"",e);
mCallback = null;
return false;
}
try {
mServerIfLock.wait(CALLBACK_REG_TIMEOUT);
} catch (InterruptedException e) {
Log.e(TAG, "" + e);
mCallback = null;
}
if (mServerIf == 0) {
mCallback = null;
return false;
} else {
return true;
}
} }
} }
synchronized (mConnection) { /**
if (mService != null) { * Unregister the current application and callbacks.
*/
private void unregisterCallback() {
if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);
if (mService == null || mServerIf == 0) return;
try { try {
mService = null; mCallback = null;
mContext.unbindService(mConnection); mService.unregisterServer(mServerIf);
} catch (Exception re) { mServerIf = 0;
Log.e(TAG,"",re); } catch (RemoteException e) {
} Log.e(TAG,"",e);
}
} }
} }
@ -414,123 +380,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
} }
/** /**
* Register an application callback to start using Gatt. * Initiate a connection to a Bluetooth GATT capable device.
*
* <p>This is an asynchronous call. The callback is used to notify
* success or failure if the function returns true.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param callback Gatt callback handler that will receive asynchronous
* callbacks.
* @return true, if application was successfully registered.
*/
public boolean registerApp(BluetoothGattServerCallback callback) {
if (DBG) Log.d(TAG, "registerApp()");
if (mService == null) return false;
mCallback = callback;
UUID uuid = UUID.randomUUID();
if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
try {
mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
return true;
}
/**
* Unregister the current application and callbacks.
*/
public void unregisterApp() {
if (DBG) Log.d(TAG, "unregisterApp() - mServerIf=" + mServerIf);
if (mService == null || mServerIf == 0) return;
try {
mCallback = null;
mService.unregisterServer(mServerIf);
mServerIf = 0;
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
}
/**
* Starts a scan for Bluetooth LE devices.
*
* <p>Results of the scan are reported using the
* {@link BluetoothGattServerCallback#onScanResult} callback.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return true, if the scan was started successfully
*/
public boolean startScan() {
if (DBG) Log.d(TAG, "startScan()");
if (mService == null || mServerIf == 0) return false;
try {
mService.startScan(mServerIf, true);
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
return true;
}
/**
* Starts a scan for Bluetooth LE devices, looking for devices that
* advertise given services.
*
* <p>Devices which advertise all specified services are reported using the
* {@link BluetoothGattServerCallback#onScanResult} callback.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param serviceUuids Array of services to look for
* @return true, if the scan was started successfully
*/
public boolean startScan(UUID[] serviceUuids) {
if (DBG) Log.d(TAG, "startScan() - with UUIDs");
if (mService == null || mServerIf == 0) return false;
try {
ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
for(int i = 0; i != uuids.length; ++i) {
uuids[i] = new ParcelUuid(serviceUuids[i]);
}
mService.startScanWithUuids(mServerIf, true, uuids);
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
}
return true;
}
/**
* Stops an ongoing Bluetooth LE device scan.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*/
public void stopScan() {
if (DBG) Log.d(TAG, "stopScan()");
if (mService == null || mServerIf == 0) return;
try {
mService.stopScan(mServerIf, true);
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
}
/**
* Initiate a connection to a Bluetooth Gatt capable device.
* *
* <p>The connection may not be established right away, but will be * <p>The connection may not be established right away, but will be
* completed when the remote device is available. A * completed when the remote device is available. A
@ -542,11 +392,10 @@ public final class BluetoothGattServer implements BluetoothProfile {
* when the remote device is in range/available. Generally, the first ever * when the remote device is in range/available. Generally, the first ever
* connection to a device should be direct (autoConnect set to false) and * connection to a device should be direct (autoConnect set to false) and
* subsequent connections to known devices should be invoked with the * subsequent connections to known devices should be invoked with the
* autoConnect parameter set to false. * autoConnect parameter set to true.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param device Remote device to connect to
* @param autoConnect Whether to directly connect to the remote device (false) * @param autoConnect Whether to directly connect to the remote device (false)
* or to automatically connect as soon as the remote * or to automatically connect as soon as the remote
* device becomes available (true). * device becomes available (true).
@ -590,7 +439,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* Send a response to a read or write request to a remote device. * Send a response to a read or write request to a remote device.
* *
* <p>This function must be invoked in when a remote read/write request * <p>This function must be invoked in when a remote read/write request
* is received by one of these callback methots: * is received by one of these callback methods:
* *
* <ul> * <ul>
* <li>{@link BluetoothGattServerCallback#onCharacteristicReadRequest} * <li>{@link BluetoothGattServerCallback#onCharacteristicReadRequest}
@ -662,17 +511,17 @@ public final class BluetoothGattServer implements BluetoothProfile {
} }
/** /**
* Add a service to the list of services to be advertised. * Add a service to the list of services to be hosted.
* *
* <p>Once a service has been addded to the the list, the service and it's * <p>Once a service has been addded to the the list, the service and it's
* included characteristics will be advertised by the local device. * included characteristics will be provided by the local device.
* *
* <p>If the local device is already advertising services when this function * <p>If the local device has already exposed services when this function
* is called, a service update notification will be sent to all clients. * is called, a service update notification will be sent to all clients.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param service Service to be added to the list of services advertised * @param service Service to be added to the list of services provided
* by this device. * by this device.
* @return true, if the service has been added successfully * @return true, if the service has been added successfully
*/ */
@ -721,11 +570,11 @@ public final class BluetoothGattServer implements BluetoothProfile {
} }
/** /**
* Removes a service from the list of services to be advertised. * Removes a service from the list of services to be provided.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @param service Service to beremoved. * @param service Service to be removed.
* @return true, if the service has been removed * @return true, if the service has been removed
*/ */
public boolean removeService(BluetoothGattService service) { public boolean removeService(BluetoothGattService service) {
@ -749,7 +598,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
} }
/** /**
* Remove all services from the list of advertised services. * Remove all services from the list of provided services.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*/ */
public void clearServices() { public void clearServices() {
@ -765,7 +614,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
} }
/** /**
* Returns a list of GATT services offered bu this device. * Returns a list of GATT services offered by this device.
* *
* <p>An application must call {@link #addService} to add a serice to the * <p>An application must call {@link #addService} to add a serice to the
* list of services offered by this device. * list of services offered by this device.
@ -802,99 +651,40 @@ public final class BluetoothGattServer implements BluetoothProfile {
return null; return null;
} }
/** /**
* Get the current connection state of the profile. * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
* with {@link BluetoothProfile#GATT} as argument
* *
* <p>This is not specific to any application configuration but represents * @throws UnsupportedOperationException
* the connection state of the local Bluetooth adapter for this profile.
* This can be used by applications like status bar which would just like
* to know the state of the local adapter.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device Remote bluetooth device.
* @return State of the profile connection. One of
* {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
*/ */
@Override @Override
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (DBG) Log.d(TAG,"getConnectionState()"); throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
if (mService == null) return STATE_DISCONNECTED;
List<BluetoothDevice> connectedDevices = getConnectedDevices();
for(BluetoothDevice connectedDevice : connectedDevices) {
if (device.equals(connectedDevice)) {
return STATE_CONNECTED;
}
}
return STATE_DISCONNECTED;
} }
/** /**
* Get connected devices for the Gatt profile. * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
* with {@link BluetoothProfile#GATT} as argument
* *
* <p> Return the set of devices which are in state {@link #STATE_CONNECTED} * @throws UnsupportedOperationException
*
* <p>This is not specific to any application configuration but represents
* the connection state of the local Bluetooth adapter for this profile.
* This can be used by applications like status bar which would just like
* to know the state of the local adapter.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return List of devices. The list will be empty on error.
*/ */
@Override @Override
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (DBG) Log.d(TAG,"getConnectedDevices"); throw new UnsupportedOperationException
("Use BluetoothManager#getConnectedDevices instead.");
List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
if (mService == null) return connectedDevices;
try {
connectedDevices = mService.getDevicesMatchingConnectionStates(
new int[] { BluetoothProfile.STATE_CONNECTED });
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
return connectedDevices;
} }
/** /**
* Get a list of devices that match any of the given connection * Not supported - please use
* states. * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
* with {@link BluetoothProfile#GATT} as first argument
* *
* <p> If none of the devices match any of the given states, * @throws UnsupportedOperationException
* an empty list will be returned.
*
* <p>This is not specific to any application configuration but represents
* the connection state of the local Bluetooth adapter for this profile.
* This can be used by applications like status bar which would just like
* to know the state of the local adapter.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param states Array of states. States can be one of
* {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
* @return List of devices. The list will be empty on error.
*/ */
@Override @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates"); throw new UnsupportedOperationException
("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
if (mService == null) return devices;
try {
devices = mService.getDevicesMatchingConnectionStates(states);
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
return devices;
} }
} }

View File

@ -22,30 +22,8 @@ import android.util.Log;
/** /**
* This abstract class is used to implement {@link BluetoothGattServer} callbacks. * This abstract class is used to implement {@link BluetoothGattServer} callbacks.
* @hide
*/ */
public abstract class BluetoothGattServerCallback { public abstract class BluetoothGattServerCallback {
/**
* Callback to inform change in registration state of the application.
*
* @param status Returns {@link BluetoothGatt#GATT_SUCCESS} if the application
* was successfully registered.
*/
public void onAppRegistered(int status) {
}
/**
* Callback reporting an LE device found during a device scan initiated
* by the {@link BluetoothGattServer#startScan} function.
*
* @param device Identifies the remote device
* @param rssi The RSSI value for the remote device as reported by the
* Bluetooth hardware. 0 if no RSSI value is available.
* @param scanRecord The content of the advertisement record offered by
* the remote device.
*/
public void onScanResult(BluetoothDevice device, int rssi, byte[] scanRecord) {
}
/** /**
* Callback indicating when a remote device has been connected or disconnected. * Callback indicating when a remote device has been connected or disconnected.

View File

@ -22,8 +22,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* Represents a Bluetooth Gatt Service * Represents a Bluetooth GATT Service
* @hide
*/ */
public class BluetoothGattService { public class BluetoothGattService {
@ -81,9 +80,14 @@ public class BluetoothGattService {
/** /**
* Create a new BluetoothGattService. * Create a new BluetoothGattService.
* @hide * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this service
* @param serviceType The type of this service,
* {@link BluetoothGattService#SERVICE_TYPE_PRIMARY} or
* {@link BluetoothGattService#SERVICE_TYPE_SECONDARY}
*/ */
/*package*/ BluetoothGattService(UUID uuid, int serviceType) { public BluetoothGattService(UUID uuid, int serviceType) {
mDevice = null; mDevice = null;
mUuid = uuid; mUuid = uuid;
mInstanceId = 0; mInstanceId = 0;
@ -115,11 +119,28 @@ public class BluetoothGattService {
} }
/** /**
* Add a characteristic to this service. * Add an included service to this service.
* @hide * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param service The service to be added
* @return true, if the included service was added to the service
*/ */
/*package*/ void addCharacteristic(BluetoothGattCharacteristic characteristic) { public boolean addService(BluetoothGattService service) {
mIncludedServices.add(service);
return true;
}
/**
* Add a characteristic to this service.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic The characteristics to be added
* @return true, if the characteristic was added to the service
*/
public boolean addCharacteristic(BluetoothGattCharacteristic characteristic) {
mCharacteristics.add(characteristic); mCharacteristics.add(characteristic);
characteristic.setService(this);
return true;
} }
/** /**
@ -135,6 +156,15 @@ public class BluetoothGattService {
return null; return null;
} }
/**
* Force the instance ID.
* This is needed for conformance testing only.
* @hide
*/
public void setInstanceId(int instanceId) {
mInstanceId = instanceId;
}
/** /**
* Get the handle count override (conformance testing. * Get the handle count override (conformance testing.
* @hide * @hide
@ -143,6 +173,15 @@ public class BluetoothGattService {
return mHandles; return mHandles;
} }
/**
* Force the number of handles to reserve for this service.
* This is needed for conformance testing only.
* @hide
*/
public void setHandles(int handles) {
mHandles = handles;
}
/** /**
* Add an included service to the internal map. * Add an included service to the internal map.
* @hide * @hide
@ -153,7 +192,6 @@ public class BluetoothGattService {
/** /**
* Returns the UUID of this service * Returns the UUID of this service
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @return UUID of this service * @return UUID of this service
*/ */
@ -168,8 +206,6 @@ public class BluetoothGattService {
* (ex. multiple battery services for different batteries), the instance * (ex. multiple battery services for different batteries), the instance
* ID is used to distuinguish services. * ID is used to distuinguish services.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return Instance ID of this service * @return Instance ID of this service
*/ */
public int getInstanceId() { public int getInstanceId() {
@ -178,15 +214,13 @@ public class BluetoothGattService {
/** /**
* Get the type of this service (primary/secondary) * Get the type of this service (primary/secondary)
* @hide
*/ */
public int getType() { public int getType() {
return mServiceType; return mServiceType;
} }
/** /**
* Get the list of included Gatt services for this service. * Get the list of included GATT services for this service.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @return List of included services or empty list if no included services * @return List of included services or empty list if no included services
* were discovered. * were discovered.
@ -197,7 +231,6 @@ public class BluetoothGattService {
/** /**
* Returns a list of characteristics included in this service. * Returns a list of characteristics included in this service.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
* *
* @return Characteristics included in this service * @return Characteristics included in this service
*/ */
@ -217,9 +250,7 @@ public class BluetoothGattService {
* UUID, the first instance of a characteristic with the given UUID * UUID, the first instance of a characteristic with the given UUID
* is returned. * is returned.
* *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * @return GATT characteristic object or null if no characteristic with the
*
* @return Gatt characteristic object or null if no characteristic with the
* given UUID was found. * given UUID was found.
*/ */
public BluetoothGattCharacteristic getCharacteristic(UUID uuid) { public BluetoothGattCharacteristic getCharacteristic(UUID uuid) {

View File

@ -0,0 +1,219 @@
/*
* Copyright (C) 2013 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 android.bluetooth;
import android.content.Context;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
/**
* High level manager used to obtain an instance of an {@link BluetoothAdapter}
* and to conduct overall Bluetooth Management.
* <p>
* Use {@link android.content.Context#getSystemService(java.lang.String)}
* with {@link Context#BLUETOOTH_SERVICE} to create an {@link BluetoothManager},
* then call {@link #getAdapter} to obtain the {@link BluetoothAdapter}.
* <p>
* Alternately, you can just call the static helper
* {@link BluetoothAdapter#getDefaultAdapter()}.
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about using BLUETOOTH, read the
* <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.</p>
* </div>
*
* @see Context#getSystemService
* @see BluetoothAdapter#getDefaultAdapter()
*/
public final class BluetoothManager {
private static final String TAG = "BluetoothManager";
private static final boolean DBG = true;
private static final boolean VDBG = true;
private final BluetoothAdapter mAdapter;
/**
* @hide
*/
public BluetoothManager(Context context) {
context = context.getApplicationContext();
if (context == null) {
throw new IllegalArgumentException(
"context not associated with any application (using a mock context?)");
}
// Legacy api - getDefaultAdapter does not take in the context
mAdapter = BluetoothAdapter.getDefaultAdapter();
}
/**
* Get the default BLUETOOTH Adapter for this device.
*
* @return the default BLUETOOTH Adapter
*/
public BluetoothAdapter getAdapter() {
return mAdapter;
}
/**
* Get the current connection state of the profile to the remote device.
*
* <p>This is not specific to any application configuration but represents
* the connection state of the local Bluetooth adapter for certain profile.
* This can be used by applications like status bar which would just like
* to know the state of Bluetooth.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device Remote bluetooth device.
* @param profile GATT or GATT_SERVER
* @return State of the profile connection. One of
* {@link BluetoothProfile#STATE_CONNECTED}, {@link BluetoothProfile#STATE_CONNECTING},
* {@link BluetoothProfile#STATE_DISCONNECTED},
* {@link BluetoothProfile#STATE_DISCONNECTING}
*/
public int getConnectionState(BluetoothDevice device, int profile) {
if (DBG) Log.d(TAG,"getConnectionState()");
List<BluetoothDevice> connectedDevices = getConnectedDevices(profile);
for(BluetoothDevice connectedDevice : connectedDevices) {
if (device.equals(connectedDevice)) {
return BluetoothProfile.STATE_CONNECTED;
}
}
return BluetoothProfile.STATE_DISCONNECTED;
}
/**
* Get connected devices for the specified profile.
*
* <p> Return the set of devices which are in state {@link BluetoothProfile#STATE_CONNECTED}
*
* <p>This is not specific to any application configuration but represents
* the connection state of Bluetooth for this profile.
* This can be used by applications like status bar which would just like
* to know the state of Bluetooth.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param profile GATT or GATT_SERVER
* @return List of devices. The list will be empty on error.
*/
public List<BluetoothDevice> getConnectedDevices(int profile) {
if (DBG) Log.d(TAG,"getConnectedDevices");
if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
throw new IllegalArgumentException("Profile not supported: " + profile);
}
List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
try {
IBluetoothManager managerService = mAdapter.getBluetoothManager();
IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
if (iGatt == null) return connectedDevices;
connectedDevices = iGatt.getDevicesMatchingConnectionStates(
new int[] { BluetoothProfile.STATE_CONNECTED });
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
return connectedDevices;
}
/**
*
* Get a list of devices that match any of the given connection
* states.
*
* <p> If none of the devices match any of the given states,
* an empty list will be returned.
*
* <p>This is not specific to any application configuration but represents
* the connection state of the local Bluetooth adapter for this profile.
* This can be used by applications like status bar which would just like
* to know the state of the local adapter.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param profile GATT or GATT_SERVER
* @param states Array of states. States can be one of
* {@link BluetoothProfile#STATE_CONNECTED}, {@link BluetoothProfile#STATE_CONNECTING},
* {@link BluetoothProfile#STATE_DISCONNECTED},
* {@link BluetoothProfile#STATE_DISCONNECTING},
* @return List of devices. The list will be empty on error.
*/
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int profile, int[] states) {
if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates");
if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
throw new IllegalArgumentException("Profile not supported: " + profile);
}
List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
try {
IBluetoothManager managerService = mAdapter.getBluetoothManager();
IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
if (iGatt == null) return devices;
devices = iGatt.getDevicesMatchingConnectionStates(states);
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
return devices;
}
/**
* Open a GATT Server
* The callback is used to deliver results to Caller, such as connection status as well
* as the results of any other GATT server operations.
* The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
* to conduct GATT server operations.
* @param context App context
* @param callback GATT server callback handler that will receive asynchronous callbacks.
* @return BluetoothGattServer instance
*/
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback) {
if (context == null || callback == null) {
throw new IllegalArgumentException("null parameter: " + context + " " + callback);
}
// TODO(Bluetooth) check whether platform support BLE
// Do the check here or in GattServer?
try {
IBluetoothManager managerService = mAdapter.getBluetoothManager();
IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
if (iGatt == null) {
Log.e(TAG, "Fail to get GATT Server connection");
return null;
}
BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt);
Boolean regStatus = mGattServer.registerCallback(callback);
return regStatus? mGattServer : null;
} catch (RemoteException e) {
Log.e(TAG,"",e);
return null;
}
}
}

View File

@ -89,13 +89,11 @@ public interface BluetoothProfile {
/** /**
* GATT * GATT
* @hide
*/ */
static public final int GATT = 7; static public final int GATT = 7;
/** /**
* GATT_SERVER * GATT_SERVER
* @hide
*/ */
static public final int GATT_SERVER = 8; static public final int GATT_SERVER = 8;

View File

@ -17,6 +17,7 @@
package android.bluetooth; package android.bluetooth;
import android.bluetooth.IBluetooth; import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothManagerCallback;
import android.bluetooth.IBluetoothStateChangeCallback; import android.bluetooth.IBluetoothStateChangeCallback;
@ -35,6 +36,7 @@ interface IBluetoothManager
boolean enable(); boolean enable();
boolean enableNoAutoConnect(); boolean enableNoAutoConnect();
boolean disable(boolean persist); boolean disable(boolean persist);
IBluetoothGatt getBluetoothGatt();
String getAddress(); String getAddress();
String getName(); String getName();

View File

@ -1,67 +0,0 @@
/*
* Copyright (C) 2013 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 android.bluetooth;
import java.util.ArrayList;
import java.util.IllegalFormatConversionException;
import java.util.List;
import java.util.UUID;
/**
* Mutable variant of a Bluetooth Gatt Characteristic
* @hide
*/
public class MutableBluetoothGattCharacteristic extends BluetoothGattCharacteristic {
/**
* Create a new MutableBluetoothGattCharacteristic.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this characteristic
* @param properties Properties of this characteristic
* @param permissions Permissions for this characteristic
*/
public MutableBluetoothGattCharacteristic(UUID uuid, int properties, int permissions) {
super(null, uuid, 0, properties, permissions);
}
/**
* Adds a descriptor to this characteristic.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param descriptor Descriptor to be added to this characteristic.
*/
public void addDescriptor(MutableBluetoothGattDescriptor descriptor) {
mDescriptors.add(descriptor);
descriptor.setCharacteristic(this);
}
/**
* Set the desired key size.
* @hide
*/
public void setKeySize(int keySize) {
mKeySize = keySize;
}
/**
* Sets the service associated with this device.
* @hide
*/
/*package*/ void setService(BluetoothGattService service) {
mService = service;
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright (C) 2013 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 android.bluetooth;
import java.util.UUID;
/**
* Mutable variant of a Bluetooth Gatt Descriptor
* @hide
*/
public class MutableBluetoothGattDescriptor extends BluetoothGattDescriptor {
/**
* Create a new BluetoothGattDescriptor.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this descriptor
* @param permissions Permissions for this descriptor
*/
public MutableBluetoothGattDescriptor(UUID uuid, int permissions) {
super(null, uuid, permissions);
}
/**
* Set the back-reference to the associated characteristic
* @hide
*/
/*package*/ void setCharacteristic(BluetoothGattCharacteristic characteristic) {
mCharacteristic = characteristic;
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright (C) 2013 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 android.bluetooth;
import android.bluetooth.BluetoothDevice;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* Represents a Bluetooth Gatt Service
* @hide
*/
public class MutableBluetoothGattService extends BluetoothGattService {
/**
* Create a new MutableBluetoothGattService.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this service
* @param serviceType The type of this service (primary/secondary)
*/
public MutableBluetoothGattService(UUID uuid, int serviceType) {
super(uuid, serviceType);
}
/**
* Add an included service to this service.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param service The service to be added
* @return true, if the included service was added to the service
*/
public boolean addService(BluetoothGattService service) {
mIncludedServices.add(service);
return true;
}
/**
* Add a characteristic to this service.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic The characteristics to be added
* @return true, if the characteristic was added to the service
*/
public boolean addCharacteristic(MutableBluetoothGattCharacteristic characteristic) {
mCharacteristics.add(characteristic);
characteristic.setService(this);
return true;
}
/**
* Force the instance ID.
* This is needed for conformance testing only.
* @hide
*/
public void setInstanceId(int instanceId) {
mInstanceId = instanceId;
}
/**
* Force the number of handles to reserve for this service.
* This is needed for conformance testing only.
* @hide
*/
public void setHandles(int handles) {
mHandles = handles;
}
}

View File

@ -2203,7 +2203,6 @@ public abstract class Context {
* {@link android.bluetooth.BluetoothAdapter} for using Bluetooth. * {@link android.bluetooth.BluetoothAdapter} for using Bluetooth.
* *
* @see #getSystemService * @see #getSystemService
* @hide
*/ */
public static final String BLUETOOTH_SERVICE = "bluetooth"; public static final String BLUETOOTH_SERVICE = "bluetooth";

View File

@ -19,6 +19,7 @@ package com.android.server;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetooth; import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothManager; import android.bluetooth.IBluetoothManager;
import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothManagerCallback;
@ -87,6 +88,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// and Airplane mode will have higher priority. // and Airplane mode will have higher priority.
private static final int BLUETOOTH_ON_AIRPLANE=2; private static final int BLUETOOTH_ON_AIRPLANE=2;
private static final int SERVICE_IBLUETOOTH = 1;
private static final int SERVICE_IBLUETOOTHGATT = 2;
private final Context mContext; private final Context mContext;
// Locks are not provided for mName and mAddress. // Locks are not provided for mName and mAddress.
@ -97,6 +101,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks; private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
private IBluetooth mBluetooth; private IBluetooth mBluetooth;
private IBluetoothGatt mBluetoothGatt;
private boolean mBinding; private boolean mBinding;
private boolean mUnbinding; private boolean mUnbinding;
// used inside handler thread // used inside handler thread
@ -463,6 +468,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
} }
} }
public IBluetoothGatt getBluetoothGatt() {
// sync protection
return mBluetoothGatt;
}
private void sendBluetoothStateCallback(boolean isUp) { private void sendBluetoothStateCallback(boolean isUp) {
int n = mStateChangeCallbacks.beginBroadcast(); int n = mStateChangeCallbacks.beginBroadcast();
if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
@ -575,16 +585,35 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
} }
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService"); if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
// TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
msg.arg1 = SERVICE_IBLUETOOTH;
// } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
} else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
} else {
Log.e(TAG, "Unknown service connected: " + className.getClassName());
return;
}
msg.obj = service; msg.obj = service;
mHandler.sendMessage(msg); mHandler.sendMessage(msg);
} }
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
// Called if we unexpected disconnected. // Called if we unexpected disconnected.
if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService"); if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
className.getClassName());
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
msg.arg1 = SERVICE_IBLUETOOTH;
} else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
} else {
Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
return;
}
mHandler.sendMessage(msg); mHandler.sendMessage(msg);
} }
} }
@ -746,13 +775,18 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
} }
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
{ {
if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED"); if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
IBinder service = (IBinder) msg.obj;
synchronized(mConnection) {
if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
break;
} // else must be SERVICE_IBLUETOOTH
//Remove timeout //Remove timeout
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
IBinder service = (IBinder) msg.obj;
synchronized(mConnection) {
mBinding = false; mBinding = false;
mBluetooth = IBluetooth.Stub.asInterface(service); mBluetooth = IBluetooth.Stub.asInterface(service);
@ -816,11 +850,19 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
} }
case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
{ {
Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
synchronized(mConnection) { synchronized(mConnection) {
if (msg.arg1 == SERVICE_IBLUETOOTH) {
// if service is unbinded already, do nothing and return // if service is unbinded already, do nothing and return
if (mBluetooth == null) return; if (mBluetooth == null) break;
mBluetooth = null; mBluetooth = null;
} else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
mBluetoothGatt = null;
break;
} else {
Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
break;
}
} }
if (mEnable) { if (mEnable) {
@ -1048,12 +1090,21 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
boolean isUp = (newState==BluetoothAdapter.STATE_ON); boolean isUp = (newState==BluetoothAdapter.STATE_ON);
sendBluetoothStateCallback(isUp); sendBluetoothStateCallback(isUp);
if (isUp) {
// connect to GattService
Intent i = new Intent(IBluetoothGatt.class.getName());
if (!mContext.bindServiceAsUser(i, mConnection, Context.BIND_AUTO_CREATE,
UserHandle.CURRENT)) {
Log.e(TAG, "Fail to bind to: " + IBluetoothGatt.class.getName());
}
} else {
//If Bluetooth is off, send service down event to proxy objects, and unbind //If Bluetooth is off, send service down event to proxy objects, and unbind
if (!isUp && canUnbindBluetoothService()) { if (!isUp && canUnbindBluetoothService()) {
sendBluetoothServiceDownCallback(); sendBluetoothServiceDownCallback();
unbindAndFinish(); unbindAndFinish();
} }
} }
}
//Send broadcast message to everyone else //Send broadcast message to everyone else
Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);