diff options
20 files changed, 1195 insertions, 1013 deletions
diff --git a/api/current.txt b/api/current.txt index cb4a7db50ac6..207a25dc369d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4613,8 +4613,13 @@ package android.bluetooth {      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 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 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_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";      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    } +  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 {      field public static final int ACCEL_SEMICONDUCTOR = 74; // 0x4a      field public static final int ALCATEL = 36; // 0x24 @@ -4837,6 +4850,7 @@ package android.bluetooth {    }    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 createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;      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";    } +  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 {      method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();      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);    } +  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 {      method public abstract java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();      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 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 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 HEALTH = 3; // 0x3      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_NOT_FOREGROUND = 4; // 0x4      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 CONNECTIVITY_SERVICE = "connectivity";      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 addPermissionAsync(android.content.pm.PermissionInfo);      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 int checkPermission(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 deprecated void removePackageFromPreferred(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.ProviderInfo resolveContentProvider(java.lang.String, 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 setUserRestrictions(android.os.Bundle);      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_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_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_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";    } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 734d43503e7b..459e49c7e349 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -19,7 +19,7 @@ package android.app;  import com.android.internal.policy.PolicyManager;  import com.android.internal.util.Preconditions; -import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager;  import android.content.BroadcastReceiver;  import android.content.ComponentName;  import android.content.ContentResolver; @@ -319,7 +319,7 @@ class ContextImpl extends Context {          registerService(BLUETOOTH_SERVICE, new ServiceFetcher() {                  public Object createService(ContextImpl ctx) { -                    return BluetoothAdapter.getDefaultAdapter(); +                    return new BluetoothManager(ctx);                  }});          registerService(CLIPBOARD_SERVICE, new ServiceFetcher() { diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index b00bf0959818..2e9c9e334d68 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -22,7 +22,6 @@ import android.content.Context;  import android.os.Binder;  import android.os.Handler;  import android.os.IBinder; -import android.os.Looper;  import android.os.Message;  import android.os.ParcelUuid;  import android.os.RemoteException; @@ -359,6 +358,8 @@ public final class BluetoothAdapter {      private IBluetooth mService;      private Handler mServiceRecordHandler; +    private BluetoothAdapterCallback mCallback; +    private int mClientIf;      /**       * 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.       *       * <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       * the connection status and to get the proxy object.       * @@ -1166,12 +1168,6 @@ public final class BluetoothAdapter {          } else if (profile == BluetoothProfile.HEALTH) {              BluetoothHealth health = new BluetoothHealth(context, listener);              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 {              return false;          } @@ -1411,4 +1407,230 @@ public final class BluetoothAdapter {              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 +            } +        }; +  } diff --git a/core/java/android/bluetooth/BluetoothAdapterCallback.java b/core/java/android/bluetooth/BluetoothAdapterCallback.java new file mode 100644 index 000000000000..a726bc91895b --- /dev/null +++ b/core/java/android/bluetooth/BluetoothAdapterCallback.java @@ -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) { +    } +} diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 4cc22b4ae909..83e95ca9b940 100755 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -18,6 +18,7 @@ package android.bluetooth;  import android.annotation.SdkConstant;  import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context;  import android.os.IBinder;  import android.os.Parcel;  import android.os.Parcelable; @@ -1126,4 +1127,30 @@ public final class BluetoothDevice implements Parcelable {          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; +    }  } diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index 1e12025497fd..f9ce6eacacea 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -16,8 +16,6 @@  package android.bluetooth; - -import android.bluetooth.BluetoothAdapter;  import android.bluetooth.BluetoothDevice;  import android.bluetooth.BluetoothProfile;  import android.bluetooth.BluetoothProfile.ServiceListener; @@ -39,42 +37,48 @@ import java.util.List;  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.   * - * <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} - * and call {@link #registerApp} to register your application. Gatt capable - * devices can be discovered using the {@link #startScan} function or the - * regular Bluetooth device discovery process. - * @hide + * and call {@link BluetoothDevice#connectGattServer} to get a instance of this class. + * GATT capable devices can be discovered using the Bluetooth device discovery or BLE + * scan process.   */  public final class BluetoothGatt implements BluetoothProfile {      private static final String TAG = "BluetoothGatt";      private static final boolean DBG = true; +    private static final boolean VDBG = true; -    private Context mContext; -    private ServiceListener mServiceListener; -    private BluetoothAdapter mAdapter; +    private final Context mContext;      private IBluetoothGatt mService;      private BluetoothGattCallback mCallback;      private int mClientIf;      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; -    /** 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; -    /** Gatt read operation is not permitted */ +    /** GATT read operation is not permitted */      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;      /** Insufficient authentication for a given operation */ @@ -111,55 +115,6 @@ public final class BluetoothGatt implements BluetoothProfile {      /*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       */      private final IBluetoothGattCallback mBluetoothGattCallback = @@ -171,11 +126,27 @@ public final class BluetoothGatt implements BluetoothProfile {              public void onClientRegistered(int status, int clientIf) {                  if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status                      + " clientIf=" + clientIf); +                if (VDBG) { +                    synchronized(mStateLock) { +                        if (mConnState != CONN_STATE_CONNECTING) { +                            Log.e(TAG, "Bad connection state: " + mConnState); +                        } +                    } +                }                  mClientIf = clientIf; +                if (status != GATT_SUCCESS) { +                    mCallback.onConnectionStateChange(mDevice, GATT_FAILURE, +                                                      BluetoothProfile.STATE_DISCONNECTED); +                    synchronized(mStateLock) { +                        mConnState = CONN_STATE_IDLE; +                    } +                    return; +                }                  try { -                    mCallback.onAppRegistered(status); -                } catch (Exception ex) { -                    Log.w(TAG, "Unhandled exception: " + ex); +                    mService.clientConnect(mClientIf, mDevice.getAddress(), +                                           !mAutoConnect); // autoConnect is inverse of "isDirect" +                } catch (RemoteException e) { +                    Log.e(TAG,"",e);                  }              } @@ -187,13 +158,24 @@ public final class BluetoothGatt implements BluetoothProfile {                                                  boolean connected, String address) {                  if (DBG) Log.d(TAG, "onClientConnectionState() - status=" + status                                   + " clientIf=" + clientIf + " device=" + address); +                if (!address.equals(mDevice.getAddress())) { +                    return; +                } +                int profileState = connected ? BluetoothProfile.STATE_CONNECTED : +                                               BluetoothProfile.STATE_DISCONNECTED;                  try { -                    mCallback.onConnectionStateChange(mAdapter.getRemoteDevice(address), status, -                                                      connected ? BluetoothProfile.STATE_CONNECTED -                                                      : BluetoothProfile.STATE_DISCONNECTED); +                    mCallback.onConnectionStateChange(mDevice, status, profileState);                  } catch (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               */              public void onScanResult(String address, int rssi, byte[] advData) { -                if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); - -                try { -                    mCallback.onScanResult(mAdapter.getRemoteDevice(address), rssi, advData); -                } catch (Exception ex) { -                    Log.w(TAG, "Unhandled exception: " + ex); -                } +                // no op              }              /** @@ -219,8 +195,10 @@ public final class BluetoothGatt implements BluetoothProfile {              public void onGetService(String address, int srvcType,                                       int srvcInstId, ParcelUuid srvcUuid) {                  if (DBG) Log.d(TAG, "onGetService() - Device=" + address + " UUID=" + srvcUuid); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); -                mServices.add(new BluetoothGattService(device, srvcUuid.getUuid(), +                if (!address.equals(mDevice.getAddress())) { +                    return; +                } +                mServices.add(new BluetoothGattService(mDevice, srvcUuid.getUuid(),                                                         srvcInstId, srvcType));              } @@ -236,10 +214,12 @@ public final class BluetoothGatt implements BluetoothProfile {                  if (DBG) Log.d(TAG, "onGetIncludedService() - Device=" + address                      + " UUID=" + srvcUuid + " Included=" + inclSrvcUuid); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); -                BluetoothGattService service = getService(device, +                if (!address.equals(mDevice.getAddress())) { +                    return; +                } +                BluetoothGattService service = getService(mDevice,                          srvcUuid.getUuid(), srvcInstId, srvcType); -                BluetoothGattService includedService = getService(device, +                BluetoothGattService includedService = getService(mDevice,                          inclSrvcUuid.getUuid(), inclSrvcInstId, inclSrvcType);                  if (service != null && includedService != null) { @@ -260,8 +240,10 @@ public final class BluetoothGatt implements BluetoothProfile {                  if (DBG) Log.d(TAG, "onGetCharacteristic() - Device=" + address + " UUID=" +                                 charUuid); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); -                BluetoothGattService service = getService(device, srvcUuid.getUuid(), +                if (!address.equals(mDevice.getAddress())) { +                    return; +                } +                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),                                                            srvcInstId, srvcType);                  if (service != null) {                      service.addCharacteristic(new BluetoothGattCharacteristic( @@ -281,8 +263,10 @@ public final class BluetoothGatt implements BluetoothProfile {                               ParcelUuid descUuid) {                  if (DBG) Log.d(TAG, "onGetDescriptor() - Device=" + address + " UUID=" + descUuid); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); -                BluetoothGattService service = getService(device, srvcUuid.getUuid(), +                if (!address.equals(mDevice.getAddress())) { +                    return; +                } +                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),                                                            srvcInstId, srvcType);                  if (service == null) return; @@ -303,9 +287,11 @@ public final class BluetoothGatt implements BluetoothProfile {               */              public void onSearchComplete(String address, int status) {                  if (DBG) Log.d(TAG, "onSearchComplete() = Device=" + address + " Status=" + status); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); +                if (!address.equals(mDevice.getAddress())) { +                    return; +                }                  try { -                    mCallback.onServicesDiscovered(device, status); +                    mCallback.onServicesDiscovered(mDevice, status);                  } catch (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                              + " UUID=" + charUuid + " Status=" + status); +                if (!address.equals(mDevice.getAddress())) { +                    return; +                }                  if ((status == GATT_INSUFFICIENT_AUTHENTICATION                    || status == GATT_INSUFFICIENT_ENCRYPTION)                    && mAuthRetry == false) { @@ -338,8 +327,7 @@ public final class BluetoothGatt implements BluetoothProfile {                  mAuthRetry = false; -                BluetoothDevice device = mAdapter.getRemoteDevice(address); -                BluetoothGattService service = getService(device, srvcUuid.getUuid(), +                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),                                                            srvcInstId, srvcType);                  if (service == null) return; @@ -367,8 +355,10 @@ public final class BluetoothGatt implements BluetoothProfile {                  if (DBG) Log.d(TAG, "onCharacteristicWrite() - Device=" + address                              + " UUID=" + charUuid + " Status=" + status); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); -                BluetoothGattService service = getService(device, srvcUuid.getUuid(), +                if (!address.equals(mDevice.getAddress())) { +                    return; +                } +                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),                                                            srvcInstId, srvcType);                  if (service == null) return; @@ -411,8 +401,10 @@ public final class BluetoothGatt implements BluetoothProfile {                               byte[] value) {                  if (DBG) Log.d(TAG, "onNotify() - Device=" + address + " UUID=" + charUuid); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); -                BluetoothGattService service = getService(device, srvcUuid.getUuid(), +                if (!address.equals(mDevice.getAddress())) { +                    return; +                } +                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),                                                            srvcInstId, srvcType);                  if (service == null) return; @@ -439,8 +431,10 @@ public final class BluetoothGatt implements BluetoothProfile {                               ParcelUuid descrUuid, byte[] value) {                  if (DBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " UUID=" + charUuid); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); -                BluetoothGattService service = getService(device, srvcUuid.getUuid(), +                if (!address.equals(mDevice.getAddress())) { +                    return; +                } +                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),                                                            srvcInstId, srvcType);                  if (service == null) return; @@ -486,8 +480,10 @@ public final class BluetoothGatt implements BluetoothProfile {                               ParcelUuid descrUuid) {                  if (DBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " UUID=" + charUuid); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); -                BluetoothGattService service = getService(device, srvcUuid.getUuid(), +                if (!address.equals(mDevice.getAddress())) { +                    return; +                } +                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),                                                            srvcInstId, srvcType);                  if (service == null) return; @@ -529,9 +525,11 @@ public final class BluetoothGatt implements BluetoothProfile {              public void onExecuteWrite(String address, int status) {                  if (DBG) Log.d(TAG, "onExecuteWrite() - Device=" + address                      + " status=" + status); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); +                if (!address.equals(mDevice.getAddress())) { +                    return; +                }                  try { -                    mCallback.onReliableWriteCompleted(device, status); +                    mCallback.onReliableWriteCompleted(mDevice, status);                  } catch (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) {                  if (DBG) Log.d(TAG, "onReadRemoteRssi() - Device=" + address +                              " rssi=" + rssi + " status=" + status); -                BluetoothDevice device = mAdapter.getRemoteDevice(address); +                if (!address.equals(mDevice.getAddress())) { +                    return; +                }                  try { -                    mCallback.onReadRemoteRssi(device, rssi, status); +                    mCallback.onReadRemoteRssi(mDevice, rssi, status);                  } catch (Exception ex) {                      Log.w(TAG, "Unhandled exception: " + ex);                  }              }          }; -    /** -     * Create a BluetoothGatt proxy object. -     */ -    /*package*/ BluetoothGatt(Context context, ServiceListener l) { +    /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) {          mContext = context; -        mServiceListener = l; -        mAdapter = BluetoothAdapter.getDefaultAdapter(); +        mService = iGatt; +        mDevice = device;          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"); -            } -        } +        mConnState = CONN_STATE_IDLE;      }      /** @@ -590,24 +569,6 @@ public final class BluetoothGatt implements BluetoothProfile {          if (DBG) Log.d(TAG, "close()");          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 -     * success or failure if the function returns true. +     * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered} +     * 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. +     * @param callback GATT 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 registerApp(BluetoothGattCallback callback) { +    private boolean registerApp(BluetoothGattCallback callback) {          if (DBG) Log.d(TAG, "registerApp()");          if (mService == null) return false; @@ -661,7 +622,7 @@ public final class BluetoothGatt implements BluetoothProfile {      /**       * Unregister the current application and callbacks.       */ -    public void unregisterApp() { +    private void unregisterApp() {          if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);          if (mService == null || mClientIf == 0) return; @@ -675,77 +636,7 @@ public final class BluetoothGatt implements BluetoothProfile {      }      /** -     * Starts a scan for Bluetooth LE devices. -     * -     * <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. +     * Initiate a connection to a Bluetooth GATT capable device.       *       * <p>The connection may not be established right away, but will be       * 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       * connection to a device should be direct (autoConnect set to false) and       * 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.       * @@ -767,18 +658,24 @@ public final class BluetoothGatt implements BluetoothProfile {       *                    device becomes available (true).       * @return true, if the connection attempt was initiated successfully       */ -    public boolean connect(BluetoothDevice device, boolean autoConnect) { -        if (DBG) Log.d(TAG, "connect() - device: " + device.getAddress() + ", auto: " + autoConnect); -        if (mService == null || mClientIf == 0) return false; - -        try { -            mService.clientConnect(mClientIf, device.getAddress(), -                                   autoConnect ? false : true); // autoConnect is inverse of "isDirect" -        } catch (RemoteException e) { -            Log.e(TAG,"",e); +    /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback) { +        if (DBG) Log.d(TAG, "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect); +        synchronized(mStateLock) { +            if (mConnState != CONN_STATE_IDLE) { +                throw new IllegalStateException("Not idle"); +            } +            mConnState = CONN_STATE_CONNECTING; +        } +        if (!registerApp(callback)) { +            synchronized(mStateLock) { +                mConnState = CONN_STATE_IDLE; +            } +            Log.e(TAG, "Failed to register callback");              return false;          } +        // the connection will continue after successful callback registration +        mAutoConnect = autoConnect;          return true;      } @@ -787,18 +684,17 @@ public final class BluetoothGatt implements BluetoothProfile {       * currently in progress.       *       * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. -     * -     * @param device Remote device       */ -    public void cancelConnection(BluetoothDevice device) { -        if (DBG) Log.d(TAG, "cancelOpen() - device: " + device.getAddress()); +    public void disconnect() { +        if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress());          if (mService == null || mClientIf == 0) return;          try { -            mService.clientDisconnect(mClientIf, device.getAddress()); +            mService.clientDisconnect(mClientIf, mDevice.getAddress());          } catch (RemoteException 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.       * -     * @param device Remote device to explore       * @return true, if the remote service discovery has been started       */ -    public boolean discoverServices(BluetoothDevice device) { -        if (DBG) Log.d(TAG, "discoverServices() - device: " + device.getAddress()); +    public boolean discoverServices() { +        if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress());          if (mService == null || mClientIf == 0) return false;          mServices.clear();          try { -            mService.discoverServices(mClientIf, device.getAddress()); +            mService.discoverServices(mClientIf, mDevice.getAddress());          } catch (RemoteException e) {              Log.e(TAG,"",e);              return false; @@ -839,16 +734,15 @@ public final class BluetoothGatt implements BluetoothProfile {       *       * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       * -     * @param device Remote device       * @return List of services on the remote device. Returns an empty list       *         if service discovery has not yet been performed.       */ -    public List<BluetoothGattService> getServices(BluetoothDevice device) { +    public List<BluetoothGattService> getServices() {          List<BluetoothGattService> result =                  new ArrayList<BluetoothGattService>();          for (BluetoothGattService service : mServices) { -            if (service.getDevice().equals(device)) { +            if (service.getDevice().equals(mDevice)) {                  result.add(service);              }          } @@ -868,14 +762,13 @@ public final class BluetoothGatt implements BluetoothProfile {       *       * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       * -     * @param device Remote device       * @param uuid UUID of the requested service       * @return BluetoothGattService if supported, or null if the requested       *         service is not offered by the remote device.       */ -    public BluetoothGattService getService(BluetoothDevice device, UUID uuid) { +    public BluetoothGattService getService(UUID uuid) {          for (BluetoothGattService service : mServices) { -            if (service.getDevice().equals(device) && +            if (service.getDevice().equals(mDevice) &&                  service.getUuid().equals(uuid)) {                  return service;              } @@ -923,8 +816,7 @@ public final class BluetoothGatt implements BluetoothProfile {      }      /** -     * Writes a given characteristic and it's values to the associated remote -     * device. +     * Writes a given characteristic and its values to the associated remote device.       *       * <p>Once the write operation has been completed, the       * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked, @@ -1061,15 +953,14 @@ public final class BluetoothGatt implements BluetoothProfile {       *       * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       * -     * @param device Remote device       * @return true, if the reliable write transaction has been initiated       */ -    public boolean beginReliableWrite(BluetoothDevice device) { -        if (DBG) Log.d(TAG, "beginReliableWrite() - device: " + device.getAddress()); +    public boolean beginReliableWrite() { +        if (DBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress());          if (mService == null || mClientIf == 0) return false;          try { -            mService.beginReliableWrite(mClientIf, device.getAddress()); +            mService.beginReliableWrite(mClientIf, mDevice.getAddress());          } catch (RemoteException e) {              Log.e(TAG,"",e);              return false; @@ -1089,15 +980,14 @@ public final class BluetoothGatt implements BluetoothProfile {       *       * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       * -     * @param device Remote device       * @return true, if the request to execute the transaction has been sent       */ -    public boolean executeReliableWrite(BluetoothDevice device) { -        if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + device.getAddress()); +    public boolean executeReliableWrite() { +        if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());          if (mService == null || mClientIf == 0) return false;          try { -            mService.endReliableWrite(mClientIf, device.getAddress(), true); +            mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);          } catch (RemoteException e) {              Log.e(TAG,"",e);              return false; @@ -1113,15 +1003,13 @@ public final class BluetoothGatt implements BluetoothProfile {       * operations for a given remote device.       *       * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. -     * -     * @param device Remote device       */ -    public void abortReliableWrite(BluetoothDevice device) { -        if (DBG) Log.d(TAG, "abortReliableWrite() - device: " + device.getAddress()); +    public void abortReliableWrite(BluetoothDevice mDevice) { +        if (DBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());          if (mService == null || mClientIf == 0) return;          try { -            mService.endReliableWrite(mClientIf, device.getAddress(), false); +            mService.endReliableWrite(mClientIf, mDevice.getAddress(), false);          } catch (RemoteException e) {              Log.e(TAG,"",e);          } @@ -1172,12 +1060,12 @@ public final class BluetoothGatt implements BluetoothProfile {       * remote device.       * @hide       */ -    public boolean refresh(BluetoothDevice device) { -        if (DBG) Log.d(TAG, "refresh() - device: " + device.getAddress()); +    public boolean refresh() { +        if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());          if (mService == null || mClientIf == 0) return false;          try { -            mService.refreshDevice(mClientIf, device.getAddress()); +            mService.refreshDevice(mClientIf, mDevice.getAddress());          } catch (RemoteException e) {              Log.e(TAG,"",e);              return false; @@ -1194,15 +1082,14 @@ public final class BluetoothGatt implements BluetoothProfile {       *       * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       * -     * @param device Remote device       * @return true, if the RSSI value has been requested successfully       */ -    public boolean readRemoteRssi(BluetoothDevice device) { -        if (DBG) Log.d(TAG, "readRssi() - device: " + device.getAddress()); +    public boolean readRemoteRssi() { +        if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress());          if (mService == null || mClientIf == 0) return false;          try { -            mService.readRemoteRssi(mClientIf, device.getAddress()); +            mService.readRemoteRssi(mClientIf, mDevice.getAddress());          } catch (RemoteException e) {              Log.e(TAG,"",e);              return false; @@ -1212,98 +1099,38 @@ public final class BluetoothGatt implements BluetoothProfile {      }      /** -     * Get the current connection state of the profile. -     * -     * <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. +     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} +     * with {@link BluetoothProfile#GATT} as argument       * -     * @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} +     * @throws UnsupportedOperationException       */      @Override      public int getConnectionState(BluetoothDevice device) { -        if (DBG) Log.d(TAG,"getConnectionState()"); -        if (mService == null) return STATE_DISCONNECTED; - -        List<BluetoothDevice> connectedDevices = getConnectedDevices(); -        for(BluetoothDevice connectedDevice : connectedDevices) { -            if (device.equals(connectedDevice)) { -                return STATE_CONNECTED; -            } -        } - -        return STATE_DISCONNECTED; +        throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");      }      /** -     * Get connected devices for the Gatt profile. -     * -     * <p> Return the set of devices which are in state {@link #STATE_CONNECTED} -     * -     * <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. +     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} +     * with {@link BluetoothProfile#GATT} as argument       * -     * @return List of devices. The list will be empty on error. +     * @throws UnsupportedOperationException       */      @Override      public List<BluetoothDevice> getConnectedDevices() { -        if (DBG) Log.d(TAG,"getConnectedDevices"); - -        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; +        throw new UnsupportedOperationException +            ("Use BluetoothManager#getConnectedDevices instead.");      }      /** -     * 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. +     * Not supported - please use +     * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])} +     * with {@link BluetoothProfile#GATT} as first argument       * -     * <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. +     * @throws UnsupportedOperationException       */      @Override      public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { -        if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates"); - -        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; +        throw new UnsupportedOperationException +            ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");      }  } diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java index afa4539cc619..c9e5fea713d8 100644 --- a/core/java/android/bluetooth/BluetoothGattCallback.java +++ b/core/java/android/bluetooth/BluetoothGattCallback.java @@ -18,34 +18,10 @@ package android.bluetooth;  import android.bluetooth.BluetoothDevice; -import android.util.Log; -  /**   * This abstract class is used to implement {@link BluetoothGatt} callbacks. - * @hide   */  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. @@ -61,8 +37,8 @@ public abstract class BluetoothGattCallback {      }      /** -     * Callback invoked when the list of remote services, characteristics and -     * descriptors for the remote device have been updated. +     * Callback invoked when the list of remote services, characteristics and descriptors +     * for the remote device have been updated, ie new services have been discovered.       *       * @param device Remote device       * @param status {@link BluetoothGatt#GATT_SUCCESS} if the remote device @@ -97,7 +73,7 @@ public abstract class BluetoothGattCallback {       * @param status The result of the write operation       */      public void onCharacteristicWrite(BluetoothGattCharacteristic characteristic, -                               int status) { +                                      int status) {      }      /** @@ -113,23 +89,21 @@ public abstract class BluetoothGattCallback {       * Callback reporting the result of a descriptor read operation.       *       * @param descriptor Descriptor that was read from the associated -     *                       remote device. +     *                   remote device.       * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation       *               was completed successfully       */ -    public void onDescriptorRead(BluetoothGattDescriptor descriptor, -                                     int status) { +    public void onDescriptorRead(BluetoothGattDescriptor descriptor, int status) {      }      /**       * Callback indicating the result of a descriptor write operation.       *       * @param descriptor Descriptor that was writte to the associated -     *                       remote device. +     *                   remote device.       * @param status The result of the write operation       */ -    public void onDescriptorWrite(BluetoothGattDescriptor descriptor, -                               int status) { +    public void onDescriptorWrite(BluetoothGattDescriptor descriptor, int status) {      }      /** @@ -150,7 +124,7 @@ public abstract class BluetoothGattCallback {       *       * @param device Identifies 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) {      } diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java index f44dc5c08bb9..d63d97e22eb3 100644 --- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java +++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java @@ -21,8 +21,7 @@ import java.util.List;  import java.util.UUID;  /** - * Represents a Bluetooth Gatt Characteristic - * @hide + * Represents a Bluetooth GATT Characteristic   */  public class BluetoothGattCharacteristic { @@ -119,7 +118,7 @@ public class BluetoothGattCharacteristic {      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; @@ -219,12 +218,30 @@ public class BluetoothGattCharacteristic {      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       * @hide       */      /*package*/ BluetoothGattCharacteristic(BluetoothGattService service,                                              UUID uuid, int instanceId,                                              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;          mInstance = instanceId;          mProperties = properties; @@ -249,11 +266,16 @@ public class BluetoothGattCharacteristic {      }      /** -     * Add a descriptor to this characteristic -     * @hide +     * Adds a descriptor to this characteristic. +     * <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); +        descriptor.setCharacteristic(this); +        return true;      }      /** @@ -265,8 +287,15 @@ public class BluetoothGattCharacteristic {      }      /** +     * Sets the service associated with this device. +     * @hide +     */ +    /*package*/ void setService(BluetoothGattService service) { +        mService = service; +    } + +    /**       * Returns the UUID of this characteristic -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       *       * @return UUID of this characteristic       */ @@ -280,8 +309,6 @@ public class BluetoothGattCharacteristic {       * <p>If a remote device offers multiple characteristics with the same UUID,       * the instance ID is used to distuinguish between characteristics.       * -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. -     *       * @return Instance ID of this characteristic       */      public int getInstanceId() { @@ -294,8 +321,6 @@ public class BluetoothGattCharacteristic {       * <p>The properties contain a bit mask of property flags indicating       * the features of this characteristic.       * -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. -     *       * @return Properties of this characteristic       */      public int getProperties() { @@ -304,7 +329,6 @@ public class BluetoothGattCharacteristic {      /**       * Returns the permissions for this characteristic. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       *       * @return Permissions of this characteristic       */ @@ -314,7 +338,6 @@ public class BluetoothGattCharacteristic {      /**       * Gets the write type for this characteristic. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       *       * @return Write type for this characteristic       */ @@ -329,11 +352,6 @@ public class BluetoothGattCharacteristic {       * {@link BluetoothGatt#writeCharacteristic} function write this       * 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       *                  of:       *                  {@link #WRITE_TYPE_DEFAULT}, @@ -345,8 +363,15 @@ public class BluetoothGattCharacteristic {      }      /** +     * Set the desired key size. +     * @hide +     */ +    public void setKeySize(int keySize) { +        mKeySize = keySize; +    } + +    /**       * Returns a list of descriptors for this characteristic. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       *       * @return Descriptors for this characteristic       */ @@ -358,9 +383,7 @@ public class BluetoothGattCharacteristic {       * Returns a descriptor with a given UUID out of the list of       * 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.       */      public BluetoothGattDescriptor getDescriptor(UUID uuid) { @@ -376,12 +399,10 @@ public class BluetoothGattCharacteristic {       * Get the stored value for this characteristic.       *       * <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       * operation or if a characteristic update notification has been received.       * -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. -     *       * @return Cached value of the characteristic       */      public byte[] getValue() { @@ -397,8 +418,6 @@ public class BluetoothGattCharacteristic {       * characteristic value at the given offset are interpreted to generate the       * return value.       * -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. -     *       * @param formatType The format type used to interpret the characteristic       *                   value.       * @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.       * <p>See {@link #getValue} for details. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       *       * @param formatType The format type used to interpret the characteristic       *                   value. @@ -462,7 +480,7 @@ public class BluetoothGattCharacteristic {      /**       * Return the stored value of this characteristic.       * <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.       * @return Cached value of the characteristic       */ @@ -481,8 +499,6 @@ public class BluetoothGattCharacteristic {       * {@link BluetoothGatt#writeCharacteristic} to send the value to the       * remote device.       * -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. -     *       * @param value New value for this characteristic       * @return true if the locally stored value has been set, false if the       *              requested value could not be stored locally. @@ -495,7 +511,6 @@ public class BluetoothGattCharacteristic {      /**       * Set the locally stored value of this characteristic.       * <p>See {@link #setValue(byte[])} for details. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       *       * @param value New value for this characteristic       * @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.       * <p>See {@link #setValue(byte[])} for details. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. +     *       * @param mantissa Mantissa for this characteristic       * @param exponent  exponent value for this characteristic       * @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.       * <p>See {@link #setValue(byte[])} for details. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. +     *       * @param value New value for this characteristic       * @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. -     * @hide       */      private int getTypeLen(int formatType) {          return formatType & 0xF; @@ -601,7 +615,6 @@ public class BluetoothGattCharacteristic {      /**       * Convert a signed byte to an unsigned int. -     * @hide       */      private int unsignedByteToInt(byte b) {          return b & 0xFF; @@ -609,7 +622,6 @@ public class BluetoothGattCharacteristic {      /**       * Convert signed bytes to a 16-bit unsigned int. -     * @hide       */      private int unsignedBytesToInt(byte b0, byte b1) {          return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)); @@ -617,7 +629,6 @@ public class BluetoothGattCharacteristic {      /**       * Convert signed bytes to a 32-bit unsigned int. -     * @hide       */      private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) {          return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8)) @@ -626,7 +637,6 @@ public class BluetoothGattCharacteristic {      /**       * Convert signed bytes to a 16-bit short float value. -     * @hide       */      private float bytesToFloat(byte b0, byte b1) {          int mantissa = unsignedToSigned(unsignedByteToInt(b0) @@ -637,7 +647,6 @@ public class BluetoothGattCharacteristic {      /**       * Convert signed bytes to a 32-bit short float value. -     * @hide       */      private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {          int mantissa = unsignedToSigned(unsignedByteToInt(b0) @@ -649,7 +658,6 @@ public class BluetoothGattCharacteristic {      /**       * Convert an unsigned integer value to a two's-complement encoded       * signed value. -     * @hide       */      private int unsignedToSigned(int unsigned, int size) {          if ((unsigned & (1 << size-1)) != 0) { @@ -660,7 +668,6 @@ public class BluetoothGattCharacteristic {      /**       * Convert an integer into the signed bits of a given length. -     * @hide       */      private int intToSignedBits(int i, int size) {          if (i < 0) { diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java index ba1f28afd797..6ba2db704f40 100644 --- a/core/java/android/bluetooth/BluetoothGattDescriptor.java +++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java @@ -19,8 +19,7 @@ package android.bluetooth;  import java.util.UUID;  /** - * Represents a Bluetooth Gatt Descriptor - * @hide + * Represents a Bluetooth GATT Descriptor   */  public class BluetoothGattDescriptor { @@ -109,12 +108,28 @@ public class 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 BluetoothGattDescriptor(UUID uuid, int permissions) { +        initDescriptor(null, uuid, permissions); +    } + +    /** +     * Create a new BluetoothGattDescriptor. +     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. +     *       * @param characteristic The characteristic this descriptor belongs to       * @param uuid The UUID for this descriptor       * @param permissions Permissions for this descriptor       */      /*package*/ BluetoothGattDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,                                      int permissions) { +        initDescriptor(characteristic, uuid, permissions); +    } + +    private void initDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid, +                                int permissions) {          mCharacteristic = characteristic;          mUuid = uuid;          mPermissions = permissions; @@ -129,8 +144,15 @@ public class BluetoothGattDescriptor {      }      /** +     * Set the back-reference to the associated characteristic +     * @hide +     */ +    /*package*/ void setCharacteristic(BluetoothGattCharacteristic characteristic) { +        mCharacteristic = characteristic; +    } + +    /**       * Returns the UUID of this descriptor. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       *       * @return UUID of this descriptor       */ @@ -140,7 +162,6 @@ public class BluetoothGattDescriptor {      /**       * Returns the permissions for this descriptor. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       *       * @return Permissions of this descriptor       */ @@ -152,12 +173,10 @@ public class BluetoothGattDescriptor {       * Returns the stored value for this descriptor       *       * <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       * operation.       * -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. -     *       * @return Cached value of the descriptor       */      public byte[] getValue() { @@ -172,8 +191,6 @@ public class BluetoothGattDescriptor {       * {@link BluetoothGatt#writeDescriptor} to send the value to the       * remote device.       * -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. -     *       * @param value New value for this descriptor       * @return true if the locally stored value has been set, false if the       *              requested value could not be stored locally. diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java index 6b693779153e..d1f4b82f9827 100644 --- a/core/java/android/bluetooth/BluetoothGattServer.java +++ b/core/java/android/bluetooth/BluetoothGattServer.java @@ -38,88 +38,30 @@ import java.util.List;  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   * and characteristics.   *   * <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service   * via IPC.  Use {@link BluetoothAdapter#getProfileProxy} to get the   * BluetoothGatt proxy object. - * @hide   */  public final class BluetoothGattServer implements BluetoothProfile {      private static final String TAG = "BluetoothGattServer";      private static final boolean DBG = true; -    private Context mContext; -    private ServiceListener mServiceListener; +    private final Context mContext;      private BluetoothAdapter mAdapter;      private IBluetoothGatt mService;      private BluetoothGattServerCallback mCallback; -    private int mServerIf; +    private Object mServerIfLock = new Object(); +    private int mServerIf;      private List<BluetoothGattService> mServices; -    /** -     * 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); -                } -            } -        }; +    private static final int CALLBACK_REG_TIMEOUT = 10000;      /**       * Bluetooth GATT interface callbacks @@ -133,11 +75,14 @@ public final class BluetoothGattServer implements BluetoothProfile {              public void onServerRegistered(int status, int serverIf) {                  if (DBG) Log.d(TAG, "onServerRegistered() - status=" + status                      + " serverIf=" + serverIf); -                mServerIf = serverIf; -                try { -                    mCallback.onAppRegistered(status); -                } catch (Exception ex) { -                    Log.w(TAG, "Unhandled exception: " + ex); +                synchronized(mServerIfLock) { +                    if (mCallback != null) { +                        mServerIf = serverIf; +                        mServerIfLock.notify(); +                    } else { +                        // registration timeout +                        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) {                  if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); - -                try { -                    mCallback.onScanResult(mAdapter.getRemoteDevice(address), -                                           rssi, advData); -                } catch (Exception ex) { -                    Log.w(TAG, "Unhandled exception: " + ex); -                } +                // no op              }              /** @@ -209,8 +148,7 @@ public final class BluetoothGattServer implements BluetoothProfile {                  BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);                  if (service == null) return; -                BluetoothGattCharacteristic characteristic = service.getCharacteristic( -                    charUuid); +                BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);                  if (characteristic == null) return;                  try { @@ -340,31 +278,13 @@ public final class BluetoothGattServer implements BluetoothProfile {      /**       * Create a BluetoothGattServer proxy object.       */ -    /*package*/ BluetoothGattServer(Context context, ServiceListener l) { +    /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt) {          mContext = context; -        mServiceListener = l; +        mService = iGatt;          mAdapter = BluetoothAdapter.getDefaultAdapter(); +        mCallback = null; +        mServerIf = 0;          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,82 +292,67 @@ public final class BluetoothGattServer implements BluetoothProfile {       */      /*package*/ void close() {          if (DBG) Log.d(TAG, "close()"); - -        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) { -                try { -                    mService = null; -                    mContext.unbindService(mConnection); -                } catch (Exception re) { -                    Log.e(TAG,"",re); -                } -            } -        } -    } - -    /** -     * Returns a service by UUID, instance and type. -     * @hide -     */ -    /*package*/ BluetoothGattService getService(UUID uuid, int instanceId, int type) { -        for(BluetoothGattService svc : mServices) { -            if (svc.getType() == type && -                svc.getInstanceId() == instanceId && -                svc.getUuid().equals(uuid)) { -                return svc; -            } -        } -        return null; +        unregisterCallback();      }      /** -     * Register an application callback to start using Gatt. +     * 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, if application was successfully registered. +     * @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       */ -    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); +    /*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); -        return true; +        synchronized(mServerIfLock) { +            if (mCallback != null) { +                Log.e(TAG, "App can register callback only once"); +                return false; +            } + +            mCallback = callback; +            try { +                mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback); +            } catch (RemoteException e) { +                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; +            } +        }      }      /**       * Unregister the current application and callbacks.       */ -    public void unregisterApp() { -        if (DBG) Log.d(TAG, "unregisterApp() - mServerIf=" + mServerIf); +    private void unregisterCallback() { +        if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);          if (mService == null || mServerIf == 0) return;          try { @@ -460,77 +365,22 @@ public final class BluetoothGattServer implements BluetoothProfile {      }      /** -     * 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 +     * Returns a service by UUID, instance and type. +     * @hide       */ -    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]); +    /*package*/ BluetoothGattService getService(UUID uuid, int instanceId, int type) { +        for(BluetoothGattService svc : mServices) { +            if (svc.getType() == type && +                svc.getInstanceId() == instanceId && +                svc.getUuid().equals(uuid)) { +                return svc;              } -            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);          } +        return null;      }      /** -     * Initiate a connection to a Bluetooth Gatt capable device. +     * Initiate a connection to a Bluetooth GATT capable device.       *       * <p>The connection may not be established right away, but will be       * 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       * connection to a device should be direct (autoConnect set to false) and       * 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.       * -     * @param device Remote device to connect to       * @param autoConnect Whether to directly connect to the remote device (false)       *                    or to automatically connect as soon as the remote       *                    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.       *       * <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>       *      <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 -     * 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.       *       * <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.       * @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.       * -     * @param service Service to beremoved. +     * @param service Service to be removed.       * @return true, if the service has been removed       */      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.       */      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       * list of services offered by this device. @@ -802,99 +651,40 @@ public final class BluetoothGattServer implements BluetoothProfile {          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 -     * 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} +     * @throws UnsupportedOperationException       */      @Override      public int getConnectionState(BluetoothDevice device) { -        if (DBG) Log.d(TAG,"getConnectionState()"); -        if (mService == null) return STATE_DISCONNECTED; - -        List<BluetoothDevice> connectedDevices = getConnectedDevices(); -        for(BluetoothDevice connectedDevice : connectedDevices) { -            if (device.equals(connectedDevice)) { -                return STATE_CONNECTED; -            } -        } - -        return STATE_DISCONNECTED; +        throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");      }      /** -     * Get connected devices for the Gatt profile. -     * -     * <p> Return the set of devices which are in state {@link #STATE_CONNECTED} +     * 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 -     * 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. +     * @throws UnsupportedOperationException       */      @Override      public List<BluetoothDevice> getConnectedDevices() { -        if (DBG) Log.d(TAG,"getConnectedDevices"); - -        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; +        throw new UnsupportedOperationException +            ("Use BluetoothManager#getConnectedDevices instead.");      }      /** -     * 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. +     * Not supported - please use +     * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])} +     * with {@link BluetoothProfile#GATT} as first argument       * -     * <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. +     * @throws UnsupportedOperationException       */      @Override      public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { -        if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates"); - -        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; +        throw new UnsupportedOperationException +            ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");      }  } diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java index 4f608ff754c2..f9f1d9759515 100644 --- a/core/java/android/bluetooth/BluetoothGattServerCallback.java +++ b/core/java/android/bluetooth/BluetoothGattServerCallback.java @@ -22,30 +22,8 @@ import android.util.Log;  /**   * This abstract class is used to implement {@link BluetoothGattServer} callbacks. - * @hide   */  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. @@ -101,9 +79,9 @@ public abstract class BluetoothGattServerCallback {       * @param value The value the client wants to assign to the characteristic       */      public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, -                            BluetoothGattCharacteristic characteristic, -                            boolean preparedWrite, boolean responseNeeded, -                            int offset, byte[] value) { +                                             BluetoothGattCharacteristic characteristic, +                                             boolean preparedWrite, boolean responseNeeded, +                                             int offset, byte[] value) {      }      /** @@ -118,7 +96,7 @@ public abstract class BluetoothGattServerCallback {       * @param descriptor Descriptor to be read       */      public void onDescriptorReadRequest(BluetoothDevice device, int requestId, -                            int offset, BluetoothGattDescriptor descriptor) { +                                        int offset, BluetoothGattDescriptor descriptor) {      }      /** @@ -137,9 +115,9 @@ public abstract class BluetoothGattServerCallback {       * @param value The value the client wants to assign to the descriptor       */      public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, -                            BluetoothGattDescriptor descriptor, -                            boolean preparedWrite, boolean responseNeeded, -                            int offset,  byte[] value) { +                                         BluetoothGattDescriptor descriptor, +                                         boolean preparedWrite, boolean responseNeeded, +                                         int offset,  byte[] value) {      }      /** diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java index 6a3ce66e8f2a..c3b3cfe23932 100644 --- a/core/java/android/bluetooth/BluetoothGattService.java +++ b/core/java/android/bluetooth/BluetoothGattService.java @@ -22,8 +22,7 @@ import java.util.List;  import java.util.UUID;  /** - * Represents a Bluetooth Gatt Service - * @hide + * Represents a Bluetooth GATT Service   */  public class BluetoothGattService { @@ -81,9 +80,14 @@ public class 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;          mUuid = uuid;          mInstanceId = 0; @@ -115,11 +119,28 @@ public class BluetoothGattService {      }      /** +     * 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. -     * @hide +     * <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       */ -    /*package*/ void addCharacteristic(BluetoothGattCharacteristic characteristic) { +    public boolean addCharacteristic(BluetoothGattCharacteristic characteristic) {          mCharacteristics.add(characteristic); +        characteristic.setService(this); +        return true;      }      /** @@ -136,6 +157,15 @@ public class BluetoothGattService {      }      /** +     * 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.       * @hide       */ @@ -144,6 +174,15 @@ public class BluetoothGattService {      }      /** +     * 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.       * @hide       */ @@ -153,7 +192,6 @@ public class BluetoothGattService {      /**       * Returns the UUID of this service -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       *       * @return UUID of this service       */ @@ -168,8 +206,6 @@ public class BluetoothGattService {       * (ex. multiple battery services for different batteries), the instance       * ID is used to distuinguish services.       * -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. -     *       * @return Instance ID of this service       */      public int getInstanceId() { @@ -178,15 +214,13 @@ public class BluetoothGattService {      /**       * Get the type of this service (primary/secondary) -     * @hide       */      public int getType() {          return mServiceType;      }      /** -     * Get the list of included Gatt services for this service. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. +     * Get the list of included GATT services for this service.       *       * @return List of included services or empty list if no included services       *         were discovered. @@ -197,7 +231,6 @@ public class BluetoothGattService {      /**       * Returns a list of characteristics included in this service. -     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.       *       * @return Characteristics included in this service       */ @@ -217,9 +250,7 @@ public class BluetoothGattService {       * UUID, the first instance of a characteristic with the given UUID       * 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.       */      public BluetoothGattCharacteristic getCharacteristic(UUID uuid) { diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java new file mode 100644 index 000000000000..19083b55dac2 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothManager.java @@ -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; +        } +    } +} diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 9ee202a5896a..43079f44f5ba 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -89,13 +89,11 @@ public interface BluetoothProfile {      /**       * GATT -     * @hide       */      static public final int GATT = 7;      /**       * GATT_SERVER -     * @hide       */      static public final int GATT_SERVER = 8; diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl index ed8777c51526..493d2f8e7741 100755 --- a/core/java/android/bluetooth/IBluetoothManager.aidl +++ b/core/java/android/bluetooth/IBluetoothManager.aidl @@ -17,6 +17,7 @@  package android.bluetooth;  import android.bluetooth.IBluetooth; +import android.bluetooth.IBluetoothGatt;  import android.bluetooth.IBluetoothManagerCallback;  import android.bluetooth.IBluetoothStateChangeCallback; @@ -35,6 +36,7 @@ interface IBluetoothManager      boolean enable();      boolean enableNoAutoConnect();      boolean disable(boolean persist); +    IBluetoothGatt getBluetoothGatt();      String getAddress();      String getName(); diff --git a/core/java/android/bluetooth/MutableBluetoothGattCharacteristic.java b/core/java/android/bluetooth/MutableBluetoothGattCharacteristic.java deleted file mode 100644 index c05abb215009..000000000000 --- a/core/java/android/bluetooth/MutableBluetoothGattCharacteristic.java +++ /dev/null @@ -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; -    } -} diff --git a/core/java/android/bluetooth/MutableBluetoothGattDescriptor.java b/core/java/android/bluetooth/MutableBluetoothGattDescriptor.java deleted file mode 100644 index e45539208791..000000000000 --- a/core/java/android/bluetooth/MutableBluetoothGattDescriptor.java +++ /dev/null @@ -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; -    } -} diff --git a/core/java/android/bluetooth/MutableBluetoothGattService.java b/core/java/android/bluetooth/MutableBluetoothGattService.java deleted file mode 100644 index 927f5ab20b44..000000000000 --- a/core/java/android/bluetooth/MutableBluetoothGattService.java +++ /dev/null @@ -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; -    } -} diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 7dd76cd676f0..ef9b0bf80e00 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2203,7 +2203,6 @@ public abstract class Context {       * {@link android.bluetooth.BluetoothAdapter} for using Bluetooth.       *       * @see #getSystemService -     * @hide       */      public static final String BLUETOOTH_SERVICE = "bluetooth"; diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java index 924b9df3d3e1..ea7b696f68b5 100755 --- a/services/java/com/android/server/BluetoothManagerService.java +++ b/services/java/com/android/server/BluetoothManagerService.java @@ -19,6 +19,7 @@ package com.android.server;  import android.app.ActivityManager;  import android.bluetooth.BluetoothAdapter;  import android.bluetooth.IBluetooth; +import android.bluetooth.IBluetoothGatt;  import android.bluetooth.IBluetoothCallback;  import android.bluetooth.IBluetoothManager;  import android.bluetooth.IBluetoothManagerCallback; @@ -87,6 +88,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub {      // and Airplane mode will have higher priority.      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;      // 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<IBluetoothStateChangeCallback> mStateChangeCallbacks;      private IBluetooth mBluetooth; +    private IBluetoothGatt mBluetoothGatt;      private boolean mBinding;      private boolean mUnbinding;      // 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) {          int n = mStateChangeCallbacks.beginBroadcast();          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) { -            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); +            // 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;              mHandler.sendMessage(msg);          }          public void onServiceDisconnected(ComponentName className) {              // 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); +            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);          }      } @@ -746,13 +775,18 @@ class BluetoothManagerService extends IBluetoothManager.Stub {                  }                  case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:                  { -                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED"); - -                    //Remove timeout -                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); +                    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 +                            mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); +                          mBinding = false;                          mBluetooth = IBluetooth.Stub.asInterface(service); @@ -816,11 +850,19 @@ class BluetoothManagerService extends IBluetoothManager.Stub {                  }                  case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:                  { -                    Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); +                    Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);                      synchronized(mConnection) { -                        // if service is unbinded already, do nothing and return -                        if (mBluetooth == null) return; -                        mBluetooth = null; +                        if (msg.arg1 == SERVICE_IBLUETOOTH) { +                            // if service is unbinded already, do nothing and return +                            if (mBluetooth == null) break; +                            mBluetooth = null; +                        } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { +                            mBluetoothGatt = null; +                            break; +                        } else { +                            Log.e(TAG, "Bad msg.arg1: " + msg.arg1); +                            break; +                        }                      }                      if (mEnable) { @@ -1048,10 +1090,19 @@ class BluetoothManagerService extends IBluetoothManager.Stub {                  boolean isUp = (newState==BluetoothAdapter.STATE_ON);                  sendBluetoothStateCallback(isUp); -                //If Bluetooth is off, send service down event to proxy objects, and unbind -                if (!isUp && canUnbindBluetoothService()) { -                    sendBluetoothServiceDownCallback(); -                    unbindAndFinish(); +                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 (!isUp && canUnbindBluetoothService()) { +                        sendBluetoothServiceDownCallback(); +                        unbindAndFinish(); +                    }                  }              }  |