Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9afa2744 authored by Matthew Xie's avatar Matthew Xie
Browse files

Unhide Bluetooth Low Energy public APIs

Updated API headers. Add BluetoothManager to be retrieved by
context.getSystemService(Context.BLUETOOTH_SERVICE).
LE scan functions are placed in BluetoothAdapter
The GATT API are device driven instead of a profile-driver.
bug 8450158

Change-Id: I424a4cedaac3ef8120a05996500008dd210d2553
parent daef3295
Loading
Loading
Loading
Loading
+230 −8
Original line number Diff line number Diff line
@@ -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
            }
        };

}
+57 −0
Original line number Diff line number Diff line
@@ -16,30 +16,42 @@

package android.bluetooth;

import java.util.UUID;
import android.bluetooth.BluetoothDevice;

/**
 * Mutable variant of a Bluetooth Gatt Descriptor
 * @hide
 * This abstract class is used to implement {@link BluetoothAdapter} callbacks.
 */
public class MutableBluetoothGattDescriptor extends BluetoothGattDescriptor {
public abstract class BluetoothAdapterCallback {

    /**
     * Create a new BluetoothGattDescriptor.
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
     * 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 uuid The UUID for this descriptor
     * @param permissions Permissions for this descriptor
     * @param status Returns {@link #CALLBACK_REGISTERED} if the application
     *               was successfully registered.
     */
    public MutableBluetoothGattDescriptor(UUID uuid, int permissions) {
        super(null, uuid, permissions);
    public void onCallbackRegistration(int status) {
    }

    /**
     * Set the back-reference to the associated characteristic
     * @hide
     * 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.
     */
    /*package*/ void setCharacteristic(BluetoothGattCharacteristic characteristic) {
        mCharacteristic = characteristic;
    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
    }
}
+27 −0
Original line number Diff line number Diff line
@@ -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;
    }
}
+176 −349

File changed.

Preview size limit exceeded, changes collapsed.

+8 −34
Original line number Diff line number Diff line
@@ -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
@@ -117,8 +93,7 @@ public abstract class BluetoothGattCallback {
     * @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) {
    }

    /**
@@ -128,8 +103,7 @@ public abstract class BluetoothGattCallback {
     *                   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) {
    }
Loading