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

Commit 0afb91d1 authored by Wei Wang's avatar Wei Wang
Browse files

More API modification of BLE APIs (1/2).

Changed include:

1) Add serviceDataUuid to filter so it matches sanRecord and
AdvertiseData.
2) Add raw bytes to ScanRecord and make ScanResult take a ScanRecord
instead of raw bytes.
3) Change from setServiceUuid(List) to addServiceUuid(ParcelUuid).
4) Added include device name
5) Removed service not registered and added ADVERTISE_DATA_TOO_LARGE.
6) Fixed a few comments.

Change-Id: Ibbe07183b1293835c4a84728d1cd2d61e5d627d3
parent 23bde57d
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -23,15 +23,15 @@ public abstract class AdvertiseCallback {

    /**
     * The requested operation was successful.
     *
     * @hide
     */
    public static final int ADVERTISE_SUCCESS = 0;

    /**
     * Failed to start advertising as the advertisement data contains services that are not
     * added to the local Bluetooth GATT server.
     * Failed to start advertising as the advertise data to be broadcasted is larger than 31 bytes.
     */
    public static final int ADVERTISE_FAILED_SERVICE_UNKNOWN = 1;
    public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1;

    /**
     * Failed to start advertising because no advertising instance is available.
@@ -53,7 +53,6 @@ public abstract class AdvertiseCallback {
     */
    public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5;


    /**
     * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertising} indicating
     * that the advertising has been started successfully.
@@ -67,7 +66,8 @@ public abstract class AdvertiseCallback {
    /**
     * Callback when advertising could not be started.
     *
     * @param errorCode Error code (see ADVERTISE_FAILED_* constants) for
     * @param errorCode Error code (see ADVERTISE_FAILED_* constants) for advertising start
     *            failures.
     */
    public void onStartFailure(int errorCode) {
    }
+48 −30
Original line number Diff line number Diff line
@@ -27,10 +27,10 @@ import java.util.Arrays;
import java.util.List;

/**
 * Advertisement data packet container for Bluetooth LE advertising. This represents the data to be
 * Advertise data packet container for Bluetooth LE advertising. This represents the data to be
 * advertised as well as the scan response data for active scans.
 *
 * <p>Use {@link AdvertiseData.Builder} to create an instance of {@link AdvertiseData} to be
 * <p>
 * Use {@link AdvertiseData.Builder} to create an instance of {@link AdvertiseData} to be
 * advertised.
 *
 * @see BluetoothLeAdvertiser
@@ -50,18 +50,21 @@ public final class AdvertiseData implements Parcelable {
    @Nullable
    private final byte[] mServiceData;

    private boolean mIncludeTxPowerLevel;
    private final boolean mIncludeTxPowerLevel;
    private final boolean mIncludeDeviceName;

    private AdvertiseData(List<ParcelUuid> serviceUuids,
            ParcelUuid serviceDataUuid, byte[] serviceData,
            int manufacturerId,
            byte[] manufacturerSpecificData, boolean includeTxPowerLevel) {
            byte[] manufacturerSpecificData, boolean includeTxPowerLevel,
            boolean includeDeviceName) {
        mServiceUuids = serviceUuids;
        mManufacturerId = manufacturerId;
        mManufacturerSpecificData = manufacturerSpecificData;
        mServiceDataUuid = serviceDataUuid;
        mServiceData = serviceData;
        mIncludeTxPowerLevel = includeTxPowerLevel;
        mIncludeDeviceName = includeDeviceName;
    }

    /**
@@ -109,13 +112,20 @@ public final class AdvertiseData implements Parcelable {
        return mIncludeTxPowerLevel;
    }

    /**
     * Whether the device name will be included in the advertisement packet.
     */
    public boolean getIncludeDeviceName() {
        return mIncludeDeviceName;
    }

    @Override
    public String toString() {
        return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mManufacturerId="
                + mManufacturerId + ", mManufacturerSpecificData="
                + Arrays.toString(mManufacturerSpecificData) + ", mServiceDataUuid="
                + mServiceDataUuid + ", mServiceData=" + Arrays.toString(mServiceData)
                + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + "]";
                + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName=" + "]";
    }

    @Override
@@ -153,8 +163,12 @@ public final class AdvertiseData implements Parcelable {
            }
        }
        dest.writeByte((byte) (getIncludeTxPowerLevel() ? 1 : 0));
        dest.writeByte((byte) (getIncludeDeviceName() ? 1 : 0));
    }

    /**
     * @hide
     */
    public static final Parcelable.Creator<AdvertiseData> CREATOR =
            new Creator<AdvertiseData>() {
            @Override
@@ -168,7 +182,9 @@ public final class AdvertiseData implements Parcelable {
                    if (in.readInt() > 0) {
                        List<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
                        in.readList(uuids, ParcelUuid.class.getClassLoader());
                        builder.setServiceUuids(uuids);
                        for (ParcelUuid uuid : uuids) {
                            builder.addServiceUuid(uuid);
                        }
                    }
                    int manufacturerId = in.readInt();
                    int manufacturerDataLength = in.readInt();
@@ -188,6 +204,7 @@ public final class AdvertiseData implements Parcelable {
                        }
                    }
                    builder.setIncludeTxPowerLevel(in.readByte() == 1);
                    builder.setIncludeDeviceName(in.readByte() == 1);
                    return builder.build();
                }
            };
@@ -203,8 +220,7 @@ public final class AdvertiseData implements Parcelable {
        private static final int FLAGS_FIELD_BYTES = 3;

        @Nullable
        private List<ParcelUuid> mServiceUuids;
        private boolean mIncludeTxPowerLevel;
        private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
        private int mManufacturerId;
        @Nullable
        private byte[] mManufacturerSpecificData;
@@ -212,27 +228,25 @@ public final class AdvertiseData implements Parcelable {
        private ParcelUuid mServiceDataUuid;
        @Nullable
        private byte[] mServiceData;
        private boolean mIncludeTxPowerLevel;
        private boolean mIncludeDeviceName;

        /**
         * Set the service UUIDs.
         * Add a service UUID to advertise data.
         *
         * <p><b>Note:</b> The corresponding Bluetooth Gatt services need to already
         * be added on the device (using {@link android.bluetooth.BluetoothGattServer#addService}) prior
         * to advertising them.
         *
         * @param serviceUuids Service UUIDs to be advertised.
         * @param serviceUuid A service UUID to be advertised.
         * @throws IllegalArgumentException If the {@code serviceUuids} are null.
         */
        public Builder setServiceUuids(List<ParcelUuid> serviceUuids) {
            if (serviceUuids == null) {
        public Builder addServiceUuid(ParcelUuid serviceUuid) {
            if (serviceUuid == null) {
                throw new IllegalArgumentException("serivceUuids are null");
            }
            mServiceUuids = serviceUuids;
            mServiceUuids.add(serviceUuid);
            return this;
        }

        /**
         * Add service data to advertisement.
         * Add service data to advertise data.
         *
         * @param serviceDataUuid 16-bit UUID of the service the data is associated with
         * @param serviceData Service data
@@ -251,10 +265,10 @@ public final class AdvertiseData implements Parcelable {

        /**
         * Set manufacturer specific data.
         *
         * <p>Please refer to the Bluetooth Assigned Numbers document provided by the
         * <a href="https://www.bluetooth.org">Bluetooth SIG</a> for a list of existing
         * company identifiers.
         * <p>
         * Please refer to the Bluetooth Assigned Numbers document provided by the <a
         * href="https://www.bluetooth.org">Bluetooth SIG</a> for a list of existing company
         * identifiers.
         *
         * @param manufacturerId Manufacturer ID assigned by Bluetooth SIG.
         * @param manufacturerSpecificData Manufacturer specific data
@@ -275,27 +289,31 @@ public final class AdvertiseData implements Parcelable {
        }

        /**
         * Whether the transmission power level should be included in the advertising packet.
         * Whether the transmission power level should be included in the advertise packet. Tx power
         * level field takes 3 bytes in advertise packet.
         */
        public Builder setIncludeTxPowerLevel(boolean includeTxPowerLevel) {
            mIncludeTxPowerLevel = includeTxPowerLevel;
            return this;
        }

        /**
         * Set whether the device name should be included in advertise packet.
         */
        public Builder setIncludeDeviceName(boolean includeDeviceName) {
            mIncludeDeviceName = includeDeviceName;
            return this;
        }

        /**
         * Build the {@link AdvertiseData}.
         *
         * @throws IllegalArgumentException If the data size is larger than 31 bytes.
         */
        public AdvertiseData build() {
            if (totalBytes() > MAX_ADVERTISING_DATA_BYTES) {
                throw new IllegalArgumentException(
                        "advertisement data size is larger than 31 bytes");
            }
            return new AdvertiseData(mServiceUuids,
                    mServiceDataUuid,
                    mServiceData, mManufacturerId, mManufacturerSpecificData,
                    mIncludeTxPowerLevel);
                    mIncludeTxPowerLevel, mIncludeDeviceName);
        }

        // Compute the size of the advertisement data.
+3 −0
Original line number Diff line number Diff line
@@ -139,6 +139,9 @@ public final class AdvertiseSettings implements Parcelable {
        dest.writeInt(mAdvertiseTimeoutSeconds);
    }

    /**
     * @hide
     */
    public static final Parcelable.Creator<AdvertiseSettings> CREATOR =
            new Creator<AdvertiseSettings>() {
            @Override
+27 −23
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@ public final class BluetoothLeAdvertiser {

    /**
     * Use BluetoothAdapter.getLeAdvertiser() instead.
     *
     * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management
     * @hide
     */
    public BluetoothLeAdvertiser(IBluetoothManager bluetoothManager) {
@@ -66,9 +68,8 @@ public final class BluetoothLeAdvertiser {
    }

    /**
     * Start Bluetooth LE Advertising. On success, the {@code advertiseData} will be
     * broadcasted. Returns immediately, the operation status is delivered through
     * {@code callback}.
     * Start Bluetooth LE Advertising. On success, the {@code advertiseData} will be broadcasted.
     * Returns immediately, the operation status is delivered through {@code callback}.
     * <p>
     * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
     *
@@ -83,9 +84,9 @@ public final class BluetoothLeAdvertiser {

    /**
     * Start Bluetooth LE Advertising. The {@code advertiseData} will be broadcasted if the
     * operation succeeds. The {@code scanResponse} is returned when a scanning device sends
     * an active scan request. This method returns immediately, the operation status is
     * delivered through {@code callback}.
     * operation succeeds. The {@code scanResponse} is returned when a scanning device sends an
     * active scan request. This method returns immediately, the operation status is delivered
     * through {@code callback}.
     * <p>
     * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
     *
@@ -142,11 +143,13 @@ public final class BluetoothLeAdvertiser {
            throw new IllegalArgumentException("callback cannot be null");
        }
        AdvertiseCallbackWrapper wrapper = mLeAdvertisers.get(callback);
        if (wrapper == null) return;
        if (wrapper == null)
            return;

        try {
            IBluetoothGatt gatt = mBluetoothManager.getBluetoothGatt();
            if (gatt != null) gatt.stopMultiAdvertising(wrapper.mLeHandle);
            if (gatt != null)
                gatt.stopMultiAdvertising(wrapper.mClientIf);

            if (wrapper.advertiseStopped()) {
                mLeAdvertisers.remove(callback);
@@ -167,10 +170,10 @@ public final class BluetoothLeAdvertiser {
        private final AdvertiseSettings mSettings;
        private final IBluetoothGatt mBluetoothGatt;

        // mLeHandle 0: not registered
        // mClientIf 0: not registered
        // -1: scan stopped
        // >0: registered and scan started
        private int mLeHandle;
        private int mClientIf;
        private boolean isAdvertising = false;

        public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback,
@@ -182,13 +185,13 @@ public final class BluetoothLeAdvertiser {
            mScanResponse = scanResponse;
            mSettings = settings;
            mBluetoothGatt = bluetoothGatt;
            mLeHandle = 0;
            mClientIf = 0;
        }

        public boolean advertiseStarted() {
            boolean started = false;
            synchronized (this) {
                if (mLeHandle == -1) {
                if (mClientIf == -1) {
                    return false;
                }
                try {
@@ -196,7 +199,7 @@ public final class BluetoothLeAdvertiser {
                } catch (InterruptedException e) {
                    Log.e(TAG, "Callback reg wait interrupted: ", e);
                }
                started = (mLeHandle > 0 && isAdvertising);
                started = (mClientIf > 0 && isAdvertising);
            }
            return started;
        }
@@ -220,18 +223,18 @@ public final class BluetoothLeAdvertiser {
            Log.d(TAG, "onClientRegistered() - status=" + status + " clientIf=" + clientIf);
            synchronized (this) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    mLeHandle = clientIf;
                    mClientIf = clientIf;
                    try {
                        mBluetoothGatt.startMultiAdvertising(mLeHandle, mAdvertisement,
                        mBluetoothGatt.startMultiAdvertising(mClientIf, mAdvertisement,
                                mScanResponse, mSettings);
                    } catch (RemoteException e) {
                        Log.e(TAG, "fail to start le advertise: " + e);
                        mLeHandle = -1;
                        mClientIf = -1;
                        notifyAll();
                    }
                } else {
                    // registration failed
                    mLeHandle = -1;
                    mClientIf = -1;
                    notifyAll();
                }
            }
@@ -342,8 +345,8 @@ public final class BluetoothLeAdvertiser {
                    isAdvertising = !isAdvertising;
                    if (!isAdvertising) {
                        try {
                            mBluetoothGatt.unregisterClient(mLeHandle);
                            mLeHandle = -1;
                            mBluetoothGatt.unregisterClient(mClientIf);
                            mClientIf = -1;
                        } catch (RemoteException e) {
                            Log.e(TAG, "remote exception when unregistering", e);
                        }
@@ -351,7 +354,8 @@ public final class BluetoothLeAdvertiser {
                        mAdvertiseCallback.onStartSuccess(null);
                    }
                } else {
                    if (!isAdvertising) mAdvertiseCallback.onStartFailure(status);
                    if (!isAdvertising)
                        mAdvertiseCallback.onStartFailure(status);
                }
                notifyAll();
            }
+35 −32
Original line number Diff line number Diff line
@@ -36,8 +36,8 @@ import java.util.UUID;

/**
 * This class provides methods to perform scan related operations for Bluetooth LE devices. An
 * application can scan for a particular type of Bluetotoh LE devices using {@link ScanFilter}.
 * It can also request different types of callbacks for delivering the result.
 * application can scan for a particular type of Bluetotoh LE devices using {@link ScanFilter}. It
 * can also request different types of callbacks for delivering the result.
 * <p>
 * Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of
 * {@link BluetoothLeScanner}.
@@ -59,7 +59,8 @@ public final class BluetoothLeScanner {

    /**
     * Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead.
     * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management
     *
     * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management.
     * @hide
     */
    public BluetoothLeScanner(IBluetoothManager bluetoothManager) {
@@ -70,8 +71,8 @@ public final class BluetoothLeScanner {
    }

    /**
     * Start Bluetooth LE scan with default parameters and no filters.
     * The scan results will be delivered through {@code callback}.
     * Start Bluetooth LE scan with default parameters and no filters. The scan results will be
     * delivered through {@code callback}.
     * <p>
     * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
     *
@@ -191,7 +192,7 @@ public final class BluetoothLeScanner {
        // mLeHandle 0: not registered
        // -1: scan stopped
        // > 0: registered and scan started
        private int mLeHandle;
        private int mClientIf;

        public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt,
                List<ScanFilter> filters, ScanSettings settings,
@@ -200,12 +201,12 @@ public final class BluetoothLeScanner {
            mFilters = filters;
            mSettings = settings;
            mScanCallback = scanCallback;
            mLeHandle = 0;
            mClientIf = 0;
        }

        public boolean scanStarted() {
            synchronized (this) {
                if (mLeHandle == -1) {
                if (mClientIf == -1) {
                    return false;
                }
                try {
@@ -214,34 +215,34 @@ public final class BluetoothLeScanner {
                    Log.e(TAG, "Callback reg wait interrupted: " + e);
                }
            }
            return mLeHandle > 0;
            return mClientIf > 0;
        }

        public void stopLeScan() {
            synchronized (this) {
                if (mLeHandle <= 0) {
                    Log.e(TAG, "Error state, mLeHandle: " + mLeHandle);
                if (mClientIf <= 0) {
                    Log.e(TAG, "Error state, mLeHandle: " + mClientIf);
                    return;
                }
                try {
                    mBluetoothGatt.stopScan(mLeHandle, false);
                    mBluetoothGatt.unregisterClient(mLeHandle);
                    mBluetoothGatt.stopScan(mClientIf, false);
                    mBluetoothGatt.unregisterClient(mClientIf);
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to stop scan and unregister", e);
                }
                mLeHandle = -1;
                mClientIf = -1;
                notifyAll();
            }
        }

        void flushPendingBatchResults() {
            synchronized (this) {
                if (mLeHandle <= 0) {
                    Log.e(TAG, "Error state, mLeHandle: " + mLeHandle);
                if (mClientIf <= 0) {
                    Log.e(TAG, "Error state, mLeHandle: " + mClientIf);
                    return;
                }
                try {
                    mBluetoothGatt.flushPendingBatchResults(mLeHandle, false);
                    mBluetoothGatt.flushPendingBatchResults(mClientIf, false);
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to get pending scan results", e);
                }
@@ -257,22 +258,22 @@ public final class BluetoothLeScanner {
                    " clientIf=" + clientIf);

            synchronized (this) {
                if (mLeHandle == -1) {
                if (mClientIf == -1) {
                    if (DBG)
                        Log.d(TAG, "onClientRegistered LE scan canceled");
                }

                if (status == BluetoothGatt.GATT_SUCCESS) {
                    mLeHandle = clientIf;
                    mClientIf = clientIf;
                    try {
                        mBluetoothGatt.startScanWithFilters(mLeHandle, false, mSettings, mFilters);
                        mBluetoothGatt.startScanWithFilters(mClientIf, false, mSettings, mFilters);
                    } catch (RemoteException e) {
                        Log.e(TAG, "fail to start le scan: " + e);
                        mLeHandle = -1;
                        mClientIf = -1;
                    }
                } else {
                    // registration failed
                    mLeHandle = -1;
                    mClientIf = -1;
                }
                notifyAll();
            }
@@ -296,14 +297,14 @@ public final class BluetoothLeScanner {

            // Check null in case the scan has been stopped
            synchronized (this) {
                if (mLeHandle <= 0)
                if (mClientIf <= 0)
                    return;
            }
            BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
                    address);
            long scanNanos = SystemClock.elapsedRealtimeNanos();
            final ScanResult result = new ScanResult(device, advData, rssi,
                    scanNanos);
            final ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(advData),
                    rssi, scanNanos);
            Handler handler = new Handler(Looper.getMainLooper());
            handler.post(new Runnable() {
                    @Override
@@ -433,7 +434,7 @@ public final class BluetoothLeScanner {
            BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
                    address);
            long scanNanos = SystemClock.elapsedRealtimeNanos();
            ScanResult result = new ScanResult(device, advData, rssi,
            ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(advData), rssi,
                    scanNanos);
            if (onFound) {
                mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH, result);
@@ -453,13 +454,15 @@ public final class BluetoothLeScanner {
    }

    private boolean isSettingsConfigAllowedForScan(ScanSettings settings) {
        final int callbackType = settings.getCallbackType();
        if ((  callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES
           || (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES
           && settings.getReportDelaySeconds() > 0))
           && !mBluetoothAdapter.isOffloadedFilteringSupported()) {
            return false;
        if (mBluetoothAdapter.isOffloadedFilteringSupported()) {
            return true;
        }
        final int callbackType = settings.getCallbackType();
        // Only support regular scan if no offloaded filter support.
        if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES
                && settings.getReportDelayMillis() == 0) {
            return true;
        }
        return false;
    }
}
Loading