Directly include BLE lib as java files

This commit is contained in:
2019-04-02 10:41:57 +02:00
parent ad95f52f46
commit 2138c42ee0
70 changed files with 11154 additions and 4 deletions

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -29,5 +29,4 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'no.nordicsemi.android:ble:2.1.1'
}

View File

@@ -9,11 +9,11 @@ import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.List;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,206 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
// DO NOT EDIT THIS FILE UNLESS NECESSARY!
/**
* The BleManagerCallbacks should be overridden in your app and all the 'high level' callbacks
* should be added there. See examples in Android nRF Blinky or Android nRF Toolbox.
* <p>
* Keeping this file as is (and {@link BleManager} as well) will allow to quickly update it when
* an update is posted here.
*/
@SuppressWarnings({"DeprecatedIsStillUsed", "unused"})
public interface BleManagerCallbacks {
/**
* Called when the Android device started connecting to given device.
* The {@link #onDeviceConnected(BluetoothDevice)} will be called when the device is connected,
* or {@link #onError(BluetoothDevice, String, int)} in case of error.
*
* @param device the device that got connected.
*/
void onDeviceConnecting(@NonNull final BluetoothDevice device);
/**
* Called when the device has been connected. This does not mean that the application may start
* communication.
* A service discovery will be handled automatically after this call. Service discovery
* may ends up with calling {@link #onServicesDiscovered(BluetoothDevice, boolean)} or
* {@link #onDeviceNotSupported(BluetoothDevice)} if required services have not been found.
*
* @param device the device that got connected.
*/
void onDeviceConnected(@NonNull final BluetoothDevice device);
/**
* Called when user initialized disconnection.
*
* @param device the device that gets disconnecting.
*/
void onDeviceDisconnecting(@NonNull final BluetoothDevice device);
/**
* Called when the device has disconnected (when the callback returned
* {@link BluetoothGattCallback#onConnectionStateChange(BluetoothGatt, int, int)} with state
* DISCONNECTED), but ONLY if the {@link BleManager#shouldAutoConnect()} method returned false
* for this device when it was connecting.
* Otherwise the {@link #onLinkLossOccurred(BluetoothDevice)} method will be called instead.
*
* @param device the device that got disconnected.
*/
void onDeviceDisconnected(@NonNull final BluetoothDevice device);
/**
* This callback is invoked when the Ble Manager lost connection to a device that has been
* connected with autoConnect option (see {@link BleManager#shouldAutoConnect()}.
* Otherwise a {@link #onDeviceDisconnected(BluetoothDevice)} method will be called on such
* event.
*
* @param device the device that got disconnected due to a link loss.
*/
void onLinkLossOccurred(@NonNull final BluetoothDevice device);
/**
* Called when service discovery has finished and primary services has been found.
* This method is not called if the primary, mandatory services were not found during service
* discovery. For example in the Blood Pressure Monitor, a Blood Pressure service is a
* primary service and Intermediate Cuff Pressure service is a optional secondary service.
* Existence of battery service is not notified by this call.
* <p>
* After successful service discovery the service will initialize all services.
* The {@link #onDeviceReady(BluetoothDevice)} method will be called when the initialization
* is complete.
*
* @param device the device which services got disconnected.
* @param optionalServicesFound if <code>true</code> the secondary services were also found
* on the device.
*/
void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound);
/**
* Method called when all initialization requests has been completed.
*
* @param device the device that get ready.
*/
void onDeviceReady(@NonNull final BluetoothDevice device);
/**
* This method should return true if Battery Level notifications should be enabled on the
* target device. If there is no Battery Service, or the Battery Level characteristic does
* not have NOTIFY property, this method will not be called for this device.
* <p>
* This method may return true only if an activity is bound to the service (to display the
* information to the user), always (e.g. if critical battery level is reported using
* notifications) or never, if such information is not important or the manager wants to
* control Battery Level notifications on its own.
*
* @param device the target device.
* @return True to enabled battery level notifications after connecting to the device,
* false otherwise.
* @deprecated Use
* <pre>{@code
* setNotificationCallback(batteryLevelCharacteristic)
* .with(new BatteryLevelDataCallback() {
* onBatteryLevelChanged(int batteryLevel) {
* ...
* }
* });
* }</pre>
* in the {@link BleManager.BleManagerGattCallback#initialize() initialize(BluetoothDevice)}
* instead.
*/
@Deprecated
default boolean shouldEnableBatteryLevelNotifications(@NonNull final BluetoothDevice device) {
return false;
}
/**
* Called when battery value has been received from the device.
*
* @param device the device from which the battery value has changed.
* @param value the battery value in percent.
* @deprecated Use
* <pre>{@code
* setNotificationCallback(batteryLevelCharacteristic)
* .with(new BatteryLevelDataCallback() {
* onBatteryLevelChanged(int batteryLevel) {
* ...
* }
* });
* }</pre>
* in the {@link BleManager.BleManagerGattCallback#initialize() initialize(BluetoothDevice)}
* instead.
*/
@Deprecated
default void onBatteryValueReceived(@NonNull final BluetoothDevice device,
@IntRange(from = 0, to = 100) final int value) {
// do nothing
}
/**
* Called when an {@link BluetoothGatt#GATT_INSUFFICIENT_AUTHENTICATION} error occurred and the
* device bond state is {@link BluetoothDevice#BOND_NONE}.
*
* @param device the device that requires bonding.
*/
void onBondingRequired(@NonNull final BluetoothDevice device);
/**
* Called when the device has been successfully bonded.
*
* @param device the device that got bonded.
*/
void onBonded(@NonNull final BluetoothDevice device);
/**
* Called when the bond state has changed from {@link BluetoothDevice#BOND_BONDING} to
* {@link BluetoothDevice#BOND_NONE}.
*
* @param device the device that failed to bond.
*/
void onBondingFailed(@NonNull final BluetoothDevice device);
/**
* Called when a BLE error has occurred
*
* @param message the error message.
* @param errorCode the error code.
* @param device the device that caused an error.
*/
void onError(@NonNull final BluetoothDevice device,
@NonNull final String message, final int errorCode);
/**
* Called when service discovery has finished but the main services were not found on the device.
*
* @param device the device that failed to connect due to lack of required services.
*/
void onDeviceNotSupported(@NonNull final BluetoothDevice device);
}

View File

@@ -0,0 +1,246 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.content.Context;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.annotation.PhyMask;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
/**
* The connect request is used to connect to a Bluetooth LE device. The request will end when
* the device gets connected, the connection timeouts, or an error occurs.
* <p>
* The {@link #done(SuccessCallback)} callback will be called after the device is ready, that is
* when it is connected, the services were discovered, the required services were found and the
* initialization queue set in {@link BleManager.BleManagerGattCallback#initialize()} is complete
* (without or with errors).
*/
@SuppressWarnings({"WeakerAccess", "unused", "deprecation"})
public class ConnectRequest extends TimeoutableRequest {
@NonNull
private BluetoothDevice device;
@PhyMask
private int preferredPhy;
@IntRange(from = 0)
private int attempt = 0, retries = 0;
@IntRange(from = 0)
private int delay = 0;
private boolean autoConnect = false;
ConnectRequest(@NonNull final Type type, @NonNull final BluetoothDevice device) {
super(type);
this.device = device;
this.preferredPhy = PhyRequest.PHY_LE_1M_MASK;
}
@NonNull
@Override
ConnectRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@NonNull
@Override
public ConnectRequest timeout(@IntRange(from = 0) final long timeout) {
super.timeout(timeout);
return this;
}
/**
* Use to set a completion callback. The callback will be invoked when the operation has
* finished successfully unless {@link #await()} or its variant was used, in which case this
* callback will be ignored.
* <p>
* The done callback will also be called when one or more of initialization requests has
* failed due to a reason other than disconnect event. This is because
* {@link BleManagerCallbacks#onDeviceReady(BluetoothDevice)} is called no matter
* if the requests succeeded, or not. Set failure callbacks to initialization requests
* to get information about failures.
*
* @param callback the callback.
* @return The request.
*/
@NonNull
@Override
public ConnectRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@NonNull
@Override
public ConnectRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public ConnectRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public ConnectRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
/**
* Sets an optional retry count. The BleManager will do that many attempts to connect to the
* device in case of an error. The library will NOT retry if the device is not reachable,
* that is when the 30 sec. timeout occurs. In that case the app should scan before
* connecting, to make sure the target is in range.
*
* @param count how many times should the BleManager retry to connect.
* @return The request.
* @see #retry(int, int)
*/
public ConnectRequest retry(@IntRange(from = 0) final int count) {
this.retries = count;
this.delay = 0;
return this;
}
/**
* Sets an optional retry count and a delay that the process will wait before each connection
* attempt. The library will NOT retry if the device is not reachable, that is when the 30 sec.
* timeout occurs. In that case the app should scan before connecting, to make sure the
* target is in range.
*
* @param count how many times should the BleManager retry to connect.
* @param delay the delay between each connection attempt, in milliseconds.
* The real delay will be 200 ms longer than specified, as
* {@link BluetoothGatt#clone()} is estimated to last
* {@link BleManager#internalConnect(BluetoothDevice, ConnectRequest) 200 ms}.
* @return The request.
* @see #retry(int)
*/
public ConnectRequest retry(@IntRange(from = 0) final int count,
@IntRange(from = 0) final int delay) {
this.retries = count;
this.delay = delay;
return this;
}
/**
* This method replaces the {@link BleManager#shouldAutoConnect()} method.
* <p>
* Sets whether to connect to the remote device just once (false) or to add the address to
* white list of devices that will be automatically connect as soon as they become available
* (true). In the latter case, if Bluetooth adapter is enabled, Android scans periodically
* for devices from the white list and, if an advertising packet is received from such, it tries
* to connect to it. When the connection is lost, the system will keep trying to reconnect to
* it. If method is called with parameter set to true, and the connection to the device is
* lost, the {@link BleManagerCallbacks#onLinkLossOccurred(BluetoothDevice)} callback is
* called instead of {@link BleManagerCallbacks#onDeviceDisconnected(BluetoothDevice)}.
* <p>
* This feature works much better on newer Android phone models and may have issues on older
* phones.
* <p>
* This method should only be used with bonded devices, as otherwise the device may change
* it's address. It will however work also with non-bonded devices with private static address.
* A connection attempt to a non-bonded device with private resolvable address will fail.
* <p>
* The first connection to a device will always be created with autoConnect flag to false
* (see {@link BluetoothDevice#connectGatt(Context, boolean, BluetoothGattCallback)}). This is
* to make it quick as the user most probably waits for a quick response. If autoConnect is
* used (true), the following connections will be done using {@link BluetoothGatt#connect()},
* which forces the autoConnect parameter to true.
*
* @param autoConnect true to use autoConnect feature on the second and following connections.
* The first connection is always done with autoConnect parameter equal to
* false, to make it faster and allow to timeout it the device is unreachable.
* Default value is false.
* @return The request.
*/
public ConnectRequest useAutoConnect(final boolean autoConnect) {
this.autoConnect = autoConnect;
return this;
}
/**
* Sets the preferred PHY used for connection. Th value should be a bitmask composed of
* {@link PhyRequest#PHY_LE_1M_MASK}, {@link PhyRequest#PHY_LE_2M_MASK} or
* {@link PhyRequest#PHY_LE_CODED_MASK}.
* <p>
* Different PHYs are available only on more recent devices with Android 8+.
* Check {@link BluetoothAdapter#isLe2MPhySupported()} and
* {@link BluetoothAdapter#isLeCodedPhySupported()} if required PHYs are supported by this
* Android device. The default PHY is {@link PhyRequest#PHY_LE_1M_MASK}.
*
* @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of
* {@link PhyRequest#PHY_LE_1M_MASK}, {@link PhyRequest#PHY_LE_2M_MASK},
* and {@link PhyRequest#PHY_LE_CODED_MASK}. This option does not take effect
* if {@code autoConnect} is set to true.
* @return The request.
*/
public ConnectRequest usePreferredPhy(@PhyMask final int phy) {
this.preferredPhy = phy;
return this;
}
@NonNull
public BluetoothDevice getDevice() {
return device;
}
@PhyMask
int getPreferredPhy() {
return preferredPhy;
}
boolean canRetry() {
if (retries > 0) {
retries -= 1;
return true;
}
return false;
}
boolean isFirstAttempt() {
return attempt++ == 0;
}
@IntRange(from = 0)
int getRetryDelay() {
return delay;
}
boolean shouldAutoConnect() {
return autoConnect;
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import android.os.Build;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import no.nordicsemi.android.ble.annotation.ConnectionPriority;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.ConnectionPriorityCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
import no.nordicsemi.android.ble.exception.BluetoothDisabledException;
import no.nordicsemi.android.ble.exception.DeviceDisconnectedException;
import no.nordicsemi.android.ble.exception.InvalidRequestException;
import no.nordicsemi.android.ble.exception.RequestFailedException;
@SuppressWarnings({"unused", "WeakerAccess"})
public final class ConnectionPriorityRequest extends SimpleValueRequest<ConnectionPriorityCallback>
implements Operation {
/**
* Connection parameter update - Use the connection parameters recommended by the
* Bluetooth SIG. This is the default value if no connection parameter update
* is requested.
* <p>
* Interval: 30 - 50 ms, latency: 0, supervision timeout: 20 sec.
*/
public static final int CONNECTION_PRIORITY_BALANCED = 0;
/**
* Connection parameter update - Request a high priority, low latency connection.
* An application should only request high priority connection parameters to transfer
* large amounts of data over LE quickly. Once the transfer is complete, the application
* should request {@link #CONNECTION_PRIORITY_BALANCED} connection parameters
* to reduce energy use.
* <p>
* Interval: 11.25 - 15 ms (Android 6+) or 7.5 - 10 ms (Android 4.3 - 5.1),
* latency: 0, supervision timeout: 20 sec.
*/
public static final int CONNECTION_PRIORITY_HIGH = 1;
/**
* Connection parameter update - Request low power, reduced data rate connection parameters.
* <p>
* Interval: 100 - 125 ms, latency: 2, supervision timeout: 20 sec.
*/
public static final int CONNECTION_PRIORITY_LOW_POWER = 2;
private final int value;
ConnectionPriorityRequest(@NonNull final Type type, @ConnectionPriority int priority) {
super(type);
if (priority < 0 || priority > 2)
priority = CONNECTION_PRIORITY_BALANCED;
this.value = priority;
}
@NonNull
@Override
ConnectionPriorityRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@Override
@NonNull
public ConnectionPriorityRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@Override
@NonNull
public ConnectionPriorityRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public ConnectionPriorityRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public ConnectionPriorityRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
@RequiresApi(value = Build.VERSION_CODES.O)
@Override
@NonNull
public ConnectionPriorityRequest with(@NonNull final ConnectionPriorityCallback callback) {
// The BluetoothGattCallback#onConnectionUpdated callback was introduced in Android Oreo.
super.with(callback);
return this;
}
@RequiresApi(value = Build.VERSION_CODES.O)
@NonNull
@Override
public <E extends ConnectionPriorityCallback> E await(@NonNull final Class<E> responseClass)
throws RequestFailedException, DeviceDisconnectedException, BluetoothDisabledException,
InvalidRequestException {
// The BluetoothGattCallback#onConnectionUpdated callback was introduced in Android Oreo.
return super.await(responseClass);
}
@RequiresApi(value = Build.VERSION_CODES.O)
@NonNull
@Override
public <E extends ConnectionPriorityCallback> E await(@NonNull final E response)
throws RequestFailedException, DeviceDisconnectedException, BluetoothDisabledException,
InvalidRequestException {
// The BluetoothGattCallback#onConnectionUpdated callback was introduced in Android Oreo.
return super.await(response);
}
@RequiresApi(api = Build.VERSION_CODES.O)
void notifyConnectionPriorityChanged(@NonNull final BluetoothDevice device,
@IntRange(from = 6, to = 3200) final int interval,
@IntRange(from = 0, to = 499) final int latency,
@IntRange(from = 10, to = 3200) final int timeout) {
if (valueCallback != null)
valueCallback.onConnectionUpdated(device, interval, latency, timeout);
}
@ConnectionPriority
int getRequiredPriority() {
return value;
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
@SuppressWarnings({"WeakerAccess", "unused", "deprecation"})
public class DisconnectRequest extends TimeoutableRequest {
DisconnectRequest(@NonNull final Type type) {
super(type);
}
@NonNull
@Override
DisconnectRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@NonNull
@Override
public DisconnectRequest timeout(@IntRange(from = 0) final long timeout) {
super.timeout(timeout);
return this;
}
@NonNull
@Override
public DisconnectRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@NonNull
@Override
public DisconnectRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public DisconnectRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public DisconnectRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.IntRange;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import no.nordicsemi.android.ble.annotation.ConnectionState;
import no.nordicsemi.android.ble.annotation.PhyValue;
/**
* This class ensures that the BLE callbacks will be called on the main (UI) thread.
* Handler parameter was added to {@link android.bluetooth.BluetoothDevice
* #connectGatt(Context, boolean, BluetoothGattCallback, int, int, Handler)}
* in Android Oreo, before that the behavior was undefined.
*/
abstract class MainThreadBluetoothGattCallback extends BluetoothGattCallback {
private Handler mHandler;
void setHandler(@NonNull final Handler handler) {
mHandler = handler;
}
private void runOnUiThread(@NonNull final Runnable runnable) {
if (Looper.myLooper() != Looper.getMainLooper()) {
mHandler.post(runnable);
} else {
runnable.run();
}
}
abstract void onConnectionStateChangeSafe(@NonNull final BluetoothGatt gatt, final int status,
final int newState);
abstract void onServicesDiscoveredSafe(@NonNull final BluetoothGatt gatt, final int status);
abstract void onCharacteristicReadSafe(@NonNull final BluetoothGatt gatt,
@NonNull final BluetoothGattCharacteristic characteristic,
@Nullable final byte[] data,
final int status);
abstract void onCharacteristicWriteSafe(@NonNull final BluetoothGatt gatt,
@NonNull final BluetoothGattCharacteristic characteristic,
@Nullable final byte[] data,
final int status);
abstract void onCharacteristicChangedSafe(@NonNull final BluetoothGatt gatt,
@NonNull final BluetoothGattCharacteristic characteristic,
@Nullable final byte[] data);
abstract void onDescriptorReadSafe(@NonNull final BluetoothGatt gatt,
@NonNull final BluetoothGattDescriptor descriptor,
@Nullable final byte[] data,
final int status);
abstract void onDescriptorWriteSafe(@NonNull final BluetoothGatt gatt,
@NonNull final BluetoothGattDescriptor descriptor,
@Nullable final byte[] data,
final int status);
abstract void onReadRemoteRssiSafe(@NonNull final BluetoothGatt gatt,
@IntRange(from = -128, to = 20) final int rssi,
final int status);
abstract void onReliableWriteCompletedSafe(@NonNull final BluetoothGatt gatt, final int status);
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
abstract void onMtuChangedSafe(@NonNull final BluetoothGatt gatt,
@IntRange(from = 23, to = 517) final int mtu, final int status);
@RequiresApi(api = Build.VERSION_CODES.O)
abstract void onPhyReadSafe(@NonNull final BluetoothGatt gatt,
@PhyValue final int txPhy, @PhyValue final int rxPhy, final int status);
@RequiresApi(api = Build.VERSION_CODES.O)
abstract void onPhyUpdateSafe(@NonNull final BluetoothGatt gatt,
@PhyValue final int txPhy, @PhyValue final int rxPhy, final int status);
@RequiresApi(api = Build.VERSION_CODES.O)
abstract void onConnectionUpdatedSafe(@NonNull final BluetoothGatt gatt,
@IntRange(from = 6, to = 3200) final int interval,
@IntRange(from = 0, to = 499) final int latency,
@IntRange(from = 10, to = 3200) final int timeout,
final int status);
@Override
public final void onConnectionStateChange(@NonNull final BluetoothGatt gatt, final int status,
@ConnectionState final int newState) {
runOnUiThread(() -> onConnectionStateChangeSafe(gatt, status, newState));
}
@Override
public final void onServicesDiscovered(@NonNull final BluetoothGatt gatt, final int status) {
runOnUiThread(() -> onServicesDiscoveredSafe(gatt, status));
}
@Override
public final void onCharacteristicRead(@NonNull final BluetoothGatt gatt,
@NonNull final BluetoothGattCharacteristic characteristic,
final int status) {
final byte[] data = characteristic.getValue();
runOnUiThread(() -> onCharacteristicReadSafe(gatt, characteristic, data, status));
}
@Override
public final void onCharacteristicWrite(@NonNull final BluetoothGatt gatt,
@NonNull final BluetoothGattCharacteristic characteristic,
final int status) {
final byte[] data = characteristic.getValue();
runOnUiThread(() -> onCharacteristicWriteSafe(gatt, characteristic, data, status));
}
@Override
public final void onCharacteristicChanged(@NonNull final BluetoothGatt gatt,
@NonNull final BluetoothGattCharacteristic characteristic) {
final byte[] data = characteristic.getValue();
runOnUiThread(() -> onCharacteristicChangedSafe(gatt, characteristic, data));
}
@Override
public final void onDescriptorRead(@NonNull final BluetoothGatt gatt,
@NonNull final BluetoothGattDescriptor descriptor,
final int status) {
final byte[] data = descriptor.getValue();
runOnUiThread(() -> onDescriptorReadSafe(gatt, descriptor, data, status));
}
@Override
public final void onDescriptorWrite(@NonNull final BluetoothGatt gatt,
@NonNull final BluetoothGattDescriptor descriptor,
final int status) {
final byte[] data = descriptor.getValue();
runOnUiThread(() -> onDescriptorWriteSafe(gatt, descriptor, data, status));
}
@Override
public final void onReadRemoteRssi(@NonNull final BluetoothGatt gatt,
@IntRange(from = -128, to = 20) final int rssi,
final int status) {
runOnUiThread(() -> onReadRemoteRssiSafe(gatt, rssi, status));
}
@Override
public final void onReliableWriteCompleted(@NonNull final BluetoothGatt gatt, final int status) {
runOnUiThread(() -> onReliableWriteCompletedSafe(gatt, status));
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public final void onMtuChanged(@NonNull final BluetoothGatt gatt,
@IntRange(from = 23, to = 517) final int mtu, final int status) {
runOnUiThread(() -> onMtuChangedSafe(gatt, mtu, status));
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public final void onPhyRead(@NonNull final BluetoothGatt gatt,
@PhyValue final int txPhy, @PhyValue final int rxPhy,
final int status) {
runOnUiThread(() -> onPhyReadSafe(gatt, txPhy, rxPhy, status));
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public final void onPhyUpdate(@NonNull final BluetoothGatt gatt,
@PhyValue final int txPhy, @PhyValue final int rxPhy,
final int status) {
runOnUiThread(() -> onPhyUpdateSafe(gatt, txPhy, rxPhy, status));
}
// This method is hidden in Android Oreo and Pie
// @Override
@SuppressWarnings("unused")
@RequiresApi(api = Build.VERSION_CODES.O)
@Keep
public final void onConnectionUpdated(@NonNull final BluetoothGatt gatt,
@IntRange(from = 6, to = 3200) final int interval,
@IntRange(from = 0, to = 499) final int latency,
@IntRange(from = 10, to = 3200) final int timeout,
final int status) {
runOnUiThread(() -> onConnectionUpdatedSafe(gatt, interval, latency, timeout, status));
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.MtuCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
public final class MtuRequest extends SimpleValueRequest<MtuCallback>implements Operation {
private final int value;
MtuRequest(@NonNull final Type type, @IntRange(from = 23, to = 517) int mtu) {
super(type);
if (mtu < 23)
mtu = 23;
if (mtu > 517)
mtu = 517;
this.value = mtu;
}
@NonNull
@Override
MtuRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@Override
@NonNull
public MtuRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@Override
@NonNull
public MtuRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public MtuRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public MtuRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
@Override
@NonNull
public MtuRequest with(@NonNull final MtuCallback callback) {
super.with(callback);
return this;
}
void notifyMtuChanged(@NonNull final BluetoothDevice device,
@IntRange(from = 23, to = 517) final int mtu) {
if (valueCallback != null)
valueCallback.onMtuChanged(device, mtu);
}
int getRequiredMtu() {
return value;
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
/**
* An operation is a request that can be executed during a pending connection without
* changing connection state. Such requests may be added to {@link RequestQueue}.
*/
@SuppressWarnings("WeakerAccess")
public interface Operation {
// empty
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.annotation.PhyMask;
import no.nordicsemi.android.ble.annotation.PhyOption;
import no.nordicsemi.android.ble.annotation.PhyValue;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.PhyCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
@SuppressWarnings({"WeakerAccess", "unused"})
public final class PhyRequest extends SimpleValueRequest<PhyCallback> implements Operation {
/**
* Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available
* options in a bitmask.
*/
public static final int PHY_LE_1M_MASK = 1;
/**
* Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available
* options in a bitmask.
*/
public static final int PHY_LE_2M_MASK = 2;
/**
* Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many
* available options in a bitmask.
*/
public static final int PHY_LE_CODED_MASK = 4;
/**
* No preferred coding when transmitting on the LE Coded PHY.
*/
public static final int PHY_OPTION_NO_PREFERRED = 0;
/**
* Prefer the S=2 coding to be used when transmitting on the LE Coded PHY.
*/
public static final int PHY_OPTION_S2 = 1;
/**
* Prefer the S=8 coding to be used when transmitting on the LE Coded PHY.
*/
public static final int PHY_OPTION_S8 = 2;
private final int txPhy;
private final int rxPhy;
private final int phyOptions;
PhyRequest(@NonNull final Type type) {
super(type);
this.txPhy = 0;
this.rxPhy = 0;
this.phyOptions = 0;
}
PhyRequest(@NonNull final Type type,
@PhyMask int txPhy, @PhyMask int rxPhy, @PhyOption int phyOptions) {
super(type);
if ((txPhy & ~(PHY_LE_1M_MASK | PHY_LE_2M_MASK | PHY_LE_CODED_MASK)) > 0)
txPhy = PHY_LE_1M_MASK;
if ((rxPhy & ~(PHY_LE_1M_MASK | PHY_LE_2M_MASK | PHY_LE_CODED_MASK)) > 0)
rxPhy = PHY_LE_1M_MASK;
if (phyOptions < PHY_OPTION_NO_PREFERRED || phyOptions > PHY_OPTION_S8)
phyOptions = PHY_OPTION_NO_PREFERRED;
this.txPhy = txPhy;
this.rxPhy = rxPhy;
this.phyOptions = phyOptions;
}
@NonNull
@Override
PhyRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@Override
@NonNull
public PhyRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@Override
@NonNull
public PhyRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public PhyRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public PhyRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
@Override
@NonNull
public PhyRequest with(@NonNull final PhyCallback callback) {
super.with(callback);
return this;
}
void notifyPhyChanged(@NonNull final BluetoothDevice device,
@PhyValue final int txPhy, @PhyValue final int rxPhy) {
if (valueCallback != null)
valueCallback.onPhyChanged(device, txPhy, rxPhy);
}
void notifyLegacyPhy(@NonNull final BluetoothDevice device) {
if (valueCallback != null)
valueCallback.onPhyChanged(device, PhyCallback.PHY_LE_1M, PhyCallback.PHY_LE_1M);
}
@PhyMask
int getPreferredTxPhy() {
return txPhy;
}
@PhyMask
int getPreferredRxPhy() {
return rxPhy;
}
@PhyOption
int getPreferredPhyOptions() {
return phyOptions;
}
}

View File

@@ -0,0 +1,249 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.DataReceivedCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.ReadProgressCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
import no.nordicsemi.android.ble.callback.profile.ProfileReadResponse;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.ble.data.DataFilter;
import no.nordicsemi.android.ble.data.DataMerger;
import no.nordicsemi.android.ble.data.DataStream;
import no.nordicsemi.android.ble.exception.BluetoothDisabledException;
import no.nordicsemi.android.ble.exception.DeviceDisconnectedException;
import no.nordicsemi.android.ble.exception.InvalidDataException;
import no.nordicsemi.android.ble.exception.InvalidRequestException;
import no.nordicsemi.android.ble.exception.RequestFailedException;
@SuppressWarnings({"unused", "WeakerAccess"})
public final class ReadRequest extends SimpleValueRequest<DataReceivedCallback> implements Operation {
private ReadProgressCallback progressCallback;
private DataMerger dataMerger;
private DataStream buffer;
private DataFilter filter;
private int count = 0;
ReadRequest(@NonNull final Type type) {
super(type);
}
ReadRequest(@NonNull final Type type, @Nullable final BluetoothGattCharacteristic characteristic) {
super(type, characteristic);
}
ReadRequest(@NonNull final Type type, @Nullable final BluetoothGattDescriptor descriptor) {
super(type, descriptor);
}
@NonNull
@Override
ReadRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@Override
@NonNull
public ReadRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@Override
@NonNull
public ReadRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public ReadRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public ReadRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
@Override
@NonNull
public ReadRequest with(@NonNull final DataReceivedCallback callback) {
super.with(callback);
return this;
}
/**
* Sets a filter which allows to skip some incoming data.
*
* @param filter the data filter.
* @return The request.
*/
@NonNull
public ReadRequest filter(@NonNull final DataFilter filter) {
this.filter = filter;
return this;
}
/**
* Adds a merger that will be used to merge multiple packets into a single Data.
* The merger may modify each packet if necessary.
*
* @return The request.
*/
@NonNull
public ReadRequest merge(@NonNull final DataMerger merger) {
this.dataMerger = merger;
this.progressCallback = null;
return this;
}
/**
* Adds a merger that will be used to merge multiple packets into a single Data.
* The merger may modify each packet if necessary.
*
* @return The request.
*/
@NonNull
public ReadRequest merge(@NonNull final DataMerger merger,
@NonNull final ReadProgressCallback callback) {
this.dataMerger = merger;
this.progressCallback = callback;
return this;
}
/**
* Same as {@link #await(Class)}, but if the response class extends
* {@link ProfileReadResponse} and the received response is not valid
* ({@link ProfileReadResponse#isValid()} returns false), this method will
* throw an exception.
*
* @param responseClass the response class. This class will be instantiate, therefore it
* has to have a default constructor.
* @return The object with the response.
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link BluetoothGatt#GATT_SUCCESS}.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread.
* @throws IllegalArgumentException thrown when the response class could not be instantiated.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter has been disabled.
* @throws InvalidDataException thrown when the received data were not valid (that is when
* {@link ProfileReadResponse#onDataReceived(BluetoothDevice, Data)}
* failed to parse the data correctly and called
* {@link ProfileReadResponse#onInvalidDataReceived(BluetoothDevice, Data)}).
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
*/
@NonNull
public <E extends ProfileReadResponse> E awaitValid(@NonNull final Class<E> responseClass)
throws RequestFailedException, InvalidDataException, DeviceDisconnectedException,
BluetoothDisabledException, InvalidRequestException {
final E response = await(responseClass);
if (!response.isValid()) {
throw new InvalidDataException(response);
}
return response;
}
/**
* Same as {@link #await(Object)}, but if the response class extends
* {@link ProfileReadResponse} and the received response is not valid
* ({@link ProfileReadResponse#isValid()} returns false), this method will
* throw an exception.
*
* @param response the response object.
* @return The object with the response.
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link BluetoothGatt#GATT_SUCCESS}.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter has been disabled.
* @throws InvalidDataException thrown when the received data were not valid (that is when
* {@link ProfileReadResponse#onDataReceived(BluetoothDevice, Data)}
* failed to parse the data correctly and called
* {@link ProfileReadResponse#onInvalidDataReceived(BluetoothDevice, Data)}).
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
*/
@NonNull
public <E extends ProfileReadResponse> E awaitValid(@NonNull final E response)
throws RequestFailedException, InvalidDataException, DeviceDisconnectedException,
BluetoothDisabledException, InvalidRequestException {
await(response);
if (!response.isValid()) {
throw new InvalidDataException(response);
}
return response;
}
boolean matches(final byte[] packet) {
return filter == null || filter.filter(packet);
}
void notifyValueChanged(@NonNull final BluetoothDevice device, @Nullable final byte[] value) {
// Keep a reference to the value callback, as it may change during execution
final DataReceivedCallback valueCallback = this.valueCallback;
// With no value callback there is no need for any merging
if (valueCallback == null)
return;
if (dataMerger == null) {
valueCallback.onDataReceived(device, new Data(value));
} else {
if (progressCallback != null)
progressCallback.onPacketReceived(device, value, count);
if (buffer == null)
buffer = new DataStream();
if (dataMerger.merge(buffer, value, count++)) {
valueCallback.onDataReceived(device, buffer.toData());
buffer = null;
count = 0;
} // else
// wait for more packets to be merged
}
}
boolean hasMore() {
return count > 0;
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.RssiCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
public final class ReadRssiRequest extends SimpleValueRequest<RssiCallback> implements Operation {
ReadRssiRequest(@NonNull final Type type) {
super(type);
}
@NonNull
@Override
ReadRssiRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@Override
@NonNull
public ReadRssiRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@Override
@NonNull
public ReadRssiRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public ReadRssiRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public ReadRssiRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
@Override
@NonNull
public ReadRssiRequest with(@NonNull final RssiCallback callback) {
super.with(callback);
return this;
}
void notifyRssiRead(@NonNull final BluetoothDevice device,
@IntRange(from = -128, to = 20) final int rssi) {
if (valueCallback != null)
valueCallback.onRssiRead(device, rssi);
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
@SuppressWarnings("unused")
public final class ReliableWriteRequest extends RequestQueue {
private boolean initialized;
private boolean closed;
private boolean cancelled;
@NonNull
@Override
ReliableWriteRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@Override
@NonNull
public ReliableWriteRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@Override
@NonNull
public ReliableWriteRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public ReliableWriteRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public ReliableWriteRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
@NonNull
@Override
public ReliableWriteRequest add(@NonNull final Operation operation) {
super.add(operation);
// Make sure the write request uses splitting, as Long Write is not supported
// in Reliable Write sub-procedure.
if (operation instanceof WriteRequest) {
((WriteRequest) operation).forceSplit();
}
return this;
}
@Override
public void cancelQueue() {
cancelled = true;
super.cancelQueue();
}
/**
* Alias for {@link #cancelQueue()}.
*/
public void abort() {
cancelQueue();
}
@Override
public int size() {
int size = super.size();
// Add Begin Reliable Write
if (!initialized)
size += 1;
// Add Execute or Abort Reliable Write
if (!closed)
size += 1;
return size;
}
@Override
Request getNext() {
if (!initialized) {
initialized = true;
return newBeginReliableWriteRequest();
}
if (super.isEmpty()) {
closed = true;
if (cancelled)
return newAbortReliableWriteRequest();
return newExecuteReliableWriteRequest();
}
return super.getNext();
}
@Override
boolean hasMore() {
// If no operations were added, consider the RW request empty, no requests will be executed.
if (!initialized)
return super.hasMore();
return !closed;
}
}

View File

@@ -0,0 +1,896 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.os.ConditionVariable;
import android.os.Looper;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.annotation.ConnectionPriority;
import no.nordicsemi.android.ble.annotation.PhyMask;
import no.nordicsemi.android.ble.annotation.PhyOption;
import no.nordicsemi.android.ble.annotation.WriteType;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
import no.nordicsemi.android.ble.data.Data;
/**
* On Android, when multiple BLE operations needs to be done, it is required to wait for a proper
* {@link BluetoothGattCallback} callback before calling another operation.
* In order to make BLE operations easier the BleManager allows to enqueue a request containing all
* data necessary for a given operation. Requests are performed one after another until the queue
* is empty.
*/
@SuppressWarnings({"unused", "WeakerAccess", "deprecation", "DeprecatedIsStillUsed"})
public abstract class Request {
enum Type {
SET,
CONNECT,
DISCONNECT,
CREATE_BOND,
REMOVE_BOND,
WRITE,
READ,
WRITE_DESCRIPTOR,
READ_DESCRIPTOR,
BEGIN_RELIABLE_WRITE,
EXECUTE_RELIABLE_WRITE,
ABORT_RELIABLE_WRITE,
ENABLE_NOTIFICATIONS,
ENABLE_INDICATIONS,
DISABLE_NOTIFICATIONS,
DISABLE_INDICATIONS,
WAIT_FOR_NOTIFICATION,
WAIT_FOR_INDICATION,
@Deprecated
READ_BATTERY_LEVEL,
@Deprecated
ENABLE_BATTERY_LEVEL_NOTIFICATIONS,
@Deprecated
DISABLE_BATTERY_LEVEL_NOTIFICATIONS,
ENABLE_SERVICE_CHANGED_INDICATIONS,
REQUEST_MTU,
REQUEST_CONNECTION_PRIORITY,
SET_PREFERRED_PHY,
READ_PHY,
READ_RSSI,
REFRESH_CACHE,
SLEEP,
}
private BleManager manager;
final ConditionVariable syncLock;
final Type type;
final BluetoothGattCharacteristic characteristic;
final BluetoothGattDescriptor descriptor;
BeforeCallback beforeCallback;
SuccessCallback successCallback;
FailCallback failCallback;
InvalidRequestCallback invalidRequestCallback;
BeforeCallback internalBeforeCallback;
SuccessCallback internalSuccessCallback;
FailCallback internalFailCallback;
boolean enqueued;
boolean finished;
Request(@NonNull final Type type) {
this.type = type;
this.characteristic = null;
this.descriptor = null;
this.syncLock = new ConditionVariable(true);
}
Request(@NonNull final Type type, @Nullable final BluetoothGattCharacteristic characteristic) {
this.type = type;
this.characteristic = characteristic;
this.descriptor = null;
this.syncLock = new ConditionVariable(true);
}
Request(@NonNull final Type type, @Nullable final BluetoothGattDescriptor descriptor) {
this.type = type;
this.characteristic = null;
this.descriptor = descriptor;
this.syncLock = new ConditionVariable(true);
}
/**
* Sets the {@link BleManager} instance.
*
* @param manager the manager in which the request will be executed.
*/
@NonNull
Request setManager(@NonNull final BleManager manager) {
this.manager = manager;
return this;
}
/**
* Creates a new connect request. This allows to set a callback to the connect event,
* just like any other request.
*
* @param device the device to connect to.
* @return The new connect request.
*/
@NonNull
static ConnectRequest connect(@NonNull final BluetoothDevice device) {
return new ConnectRequest(Type.CONNECT, device);
}
/**
* Creates a new disconnect request. This allows to set a callback to a disconnect event,
* just like any other request.
*
* @return The new disconnect request.
*/
@NonNull
static DisconnectRequest disconnect() {
return new DisconnectRequest(Type.DISCONNECT);
}
/**
* Creates a new request that will start pairing with the device.
*
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#createBond()} instead.
*/
@Deprecated
@NonNull
public static SimpleRequest createBond() {
return new SimpleRequest(Type.CREATE_BOND);
}
/**
* Creates a new request that will remove the bonding information from the Android device.
* This is done using reflections and may not work on all devices.
* <p>
* The device will disconnect after calling this method. The success callback will be called
* after the device got disconnected, when the {@link BluetoothDevice#getBondState()} changes
* to {@link BluetoothDevice#BOND_NONE}.
*
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#removeBond()} instead.
*/
@Deprecated
@NonNull
public static SimpleRequest removeBond() {
return new SimpleRequest(Type.REMOVE_BOND);
}
/**
* Creates new Read Characteristic request. The request will not be executed if given
* characteristic is null or does not have READ property.
* After the operation is complete a proper callback will be invoked.
*
* @param characteristic characteristic to be read.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#readCharacteristic(BluetoothGattCharacteristic)} instead.
*/
@Deprecated
@NonNull
public static ReadRequest newReadRequest(
@Nullable final BluetoothGattCharacteristic characteristic) {
return new ReadRequest(Type.READ, characteristic);
}
/**
* Creates new Write Characteristic request. The request will not be executed if given
* characteristic is null or does not have WRITE property.
* After the operation is complete a proper callback will be invoked.
*
* @param characteristic characteristic to be written.
* @param value value to be written. The array is copied into another buffer so it's
* safe to reuse the array again.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#writeCharacteristic(BluetoothGattCharacteristic, byte[])} instead.
*/
@Deprecated
@NonNull
public static WriteRequest newWriteRequest(
@Nullable final BluetoothGattCharacteristic characteristic,
@Nullable final byte[] value) {
return new WriteRequest(Type.WRITE, characteristic, value, 0,
value != null ? value.length : 0,
characteristic != null ?
characteristic.getWriteType() :
BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
}
/**
* Creates new Write Characteristic request. The request will not be executed if given
* characteristic is null or does not have WRITE property.
* After the operation is complete a proper callback will be invoked.
*
* @param characteristic characteristic to be written.
* @param value value to be written. The array is copied into another buffer so it's
* safe to reuse the array again.
* @param writeType write type to be used, one of
* {@link BluetoothGattCharacteristic#WRITE_TYPE_DEFAULT},
* {@link BluetoothGattCharacteristic#WRITE_TYPE_NO_RESPONSE}.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#writeCharacteristic(BluetoothGattCharacteristic, Data)} instead.
*/
@Deprecated
@NonNull
public static WriteRequest newWriteRequest(
@Nullable final BluetoothGattCharacteristic characteristic,
@Nullable final byte[] value, @WriteType final int writeType) {
return new WriteRequest(Type.WRITE, characteristic, value, 0,
value != null ? value.length : 0, writeType);
}
/**
* Creates new Write Characteristic request. The request will not be executed if given
* characteristic is null or does not have WRITE property.
* After the operation is complete a proper callback will be invoked.
*
* @param characteristic characteristic to be written.
* @param value value to be written. The array is copied into another buffer so it's
* safe to reuse the array again.
* @param offset the offset from which value has to be copied.
* @param length number of bytes to be copied from the value buffer.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#writeCharacteristic(BluetoothGattCharacteristic, byte[], int, int)}
* instead.
*/
@Deprecated
@NonNull
public static WriteRequest newWriteRequest(
@Nullable final BluetoothGattCharacteristic characteristic,
@Nullable final byte[] value,
@IntRange(from = 0) final int offset, @IntRange(from = 0) final int length) {
return new WriteRequest(Type.WRITE, characteristic, value, offset, length,
characteristic != null ?
characteristic.getWriteType() :
BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
}
/**
* Creates new Write Characteristic request. The request will not be executed if given
* characteristic is null or does not have WRITE property.
* After the operation is complete a proper callback will be invoked.
*
* @param characteristic characteristic to be written.
* @param value value to be written. The array is copied into another buffer so it's
* safe to reuse the array again.
* @param offset the offset from which value has to be copied.
* @param length number of bytes to be copied from the value buffer.
* @param writeType write type to be used, one of
* {@link BluetoothGattCharacteristic#WRITE_TYPE_DEFAULT},
* {@link BluetoothGattCharacteristic#WRITE_TYPE_NO_RESPONSE} or
* {@link BluetoothGattCharacteristic#WRITE_TYPE_SIGNED}.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#writeCharacteristic(BluetoothGattCharacteristic, byte[], int, int)}
* instead.
*/
@Deprecated
@NonNull
public static WriteRequest newWriteRequest(
@Nullable final BluetoothGattCharacteristic characteristic,
@Nullable final byte[] value,
@IntRange(from = 0) final int offset, @IntRange(from = 0) final int length,
@WriteType final int writeType) {
return new WriteRequest(Type.WRITE, characteristic, value, offset, length, writeType);
}
/**
* Creates new Read Descriptor request. The request will not be executed if given descriptor
* is null. After the operation is complete a proper callback will be invoked.
*
* @param descriptor descriptor to be read.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#readDescriptor(BluetoothGattDescriptor)} instead.
*/
@Deprecated
@NonNull
public static ReadRequest newReadRequest(@Nullable final BluetoothGattDescriptor descriptor) {
return new ReadRequest(Type.READ_DESCRIPTOR, descriptor);
}
/**
* Creates new Write Descriptor request. The request will not be executed if given descriptor
* is null. After the operation is complete a proper callback will be invoked.
*
* @param descriptor descriptor to be written.
* @param value value to be written. The array is copied into another buffer so it's safe
* to reuse the array again.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#writeDescriptor(BluetoothGattDescriptor, byte[])} instead.
*/
@Deprecated
@NonNull
public static WriteRequest newWriteRequest(@Nullable final BluetoothGattDescriptor descriptor,
@Nullable final byte[] value) {
return new WriteRequest(Type.WRITE_DESCRIPTOR, descriptor, value, 0,
value != null ? value.length : 0);
}
/**
* Creates new Write Descriptor request. The request will not be executed if given descriptor
* is null. After the operation is complete a proper callback will be invoked.
*
* @param descriptor descriptor to be written.
* @param value value to be written. The array is copied into another buffer so it's safe
* to reuse the array again.
* @param offset the offset from which value has to be copied.
* @param length number of bytes to be copied from the value buffer.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#writeDescriptor(BluetoothGattDescriptor, byte[], int, int)} instead.
*/
@Deprecated
@NonNull
public static WriteRequest newWriteRequest(
@Nullable final BluetoothGattDescriptor descriptor,
@Nullable final byte[] value,
@IntRange(from = 0) final int offset, @IntRange(from = 0) final int length) {
return new WriteRequest(Type.WRITE_DESCRIPTOR, descriptor, value, offset, length);
}
/**
* Creates new Reliable Write request. All operations that need to be executed
* reliably should be enqueued inside the returned request before enqueuing it in the
* BleManager. The library will automatically verify the data sent
*
* @return The new request.
*/
@NonNull
static ReliableWriteRequest newReliableWriteRequest() {
return new ReliableWriteRequest();
}
/**
* Creates new Begin Reliable Write request.
*
* @return The new request.
*/
@NonNull
static SimpleRequest newBeginReliableWriteRequest() {
return new SimpleRequest(Type.BEGIN_RELIABLE_WRITE);
}
/**
* Executes Reliable Write sub-procedure. At lease one Write Request must be performed
* before the Reliable Write is to be executed, otherwise error
* {@link no.nordicsemi.android.ble.error.GattError#GATT_INVALID_OFFSET} will be returned.
*
* @return The new request.
*/
@NonNull
static SimpleRequest newExecuteReliableWriteRequest() {
return new SimpleRequest(Type.EXECUTE_RELIABLE_WRITE);
}
/**
* Aborts Reliable Write sub-procedure. All write requests performed during Reliable Write will
* be cancelled. At lease one Write Request must be performed before the Reliable Write
* is to be executed, otherwise error
* {@link no.nordicsemi.android.ble.error.GattError#GATT_INVALID_OFFSET} will be returned.
*
* @return The new request.
*/
@NonNull
static SimpleRequest newAbortReliableWriteRequest() {
return new SimpleRequest(Type.ABORT_RELIABLE_WRITE);
}
/**
* Creates new Enable Notification request. The request will not be executed if given
* characteristic is null, does not have NOTIFY property or the CCCD.
* After the operation is complete a proper callback will be invoked.
*
* @param characteristic characteristic to have notifications enabled.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#enableNotifications(BluetoothGattCharacteristic)} instead.
*/
@Deprecated
@NonNull
public static WriteRequest newEnableNotificationsRequest(
@Nullable final BluetoothGattCharacteristic characteristic) {
return new WriteRequest(Type.ENABLE_NOTIFICATIONS, characteristic);
}
/**
* Creates new Disable Notification request. The request will not be executed if given
* characteristic is null, does not have NOTIFY property or the CCCD.
* After the operation is complete a proper callback will be invoked.
*
* @param characteristic characteristic to have notifications disabled.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#disableNotifications(BluetoothGattCharacteristic)} instead.
*/
@Deprecated
@NonNull
public static WriteRequest newDisableNotificationsRequest(
@Nullable final BluetoothGattCharacteristic characteristic) {
return new WriteRequest(Type.DISABLE_NOTIFICATIONS, characteristic);
}
/**
* Creates new Enable Indications request. The request will not be executed if given
* characteristic is null, does not have INDICATE property or the CCCD.
* After the operation is complete a proper callback will be invoked.
*
* @param characteristic characteristic to have indications enabled.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#enableIndications(BluetoothGattCharacteristic)} instead.
*/
@Deprecated
@NonNull
public static WriteRequest newEnableIndicationsRequest(
@Nullable final BluetoothGattCharacteristic characteristic) {
return new WriteRequest(Type.ENABLE_INDICATIONS, characteristic);
}
/**
* Creates new Disable Indications request. The request will not be executed if given
* characteristic is null, does not have INDICATE property or the CCCD.
* After the operation is complete a proper callback will be invoked.
*
* @param characteristic characteristic to have indications disabled.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#disableNotifications(BluetoothGattCharacteristic)} instead.
*/
@Deprecated
@NonNull
public static WriteRequest newDisableIndicationsRequest(
@Nullable final BluetoothGattCharacteristic characteristic) {
return new WriteRequest(Type.DISABLE_INDICATIONS, characteristic);
}
/**
* Creates new Wait For Notification request. The request will not be executed if given
* characteristic is null, does not have NOTIFY property or the CCCD.
* After the operation is complete a proper callback will be invoked.
* <p>
* If the notification should be triggered by another operation (for example writing an
* op code), set it with {@link WaitForValueChangedRequest#trigger(Operation)}.
*
* @param characteristic characteristic from which a notification should be received.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#waitForNotification(BluetoothGattCharacteristic)} instead.
*/
@Deprecated
@NonNull
public static WaitForValueChangedRequest newWaitForNotificationRequest(
@Nullable final BluetoothGattCharacteristic characteristic) {
return new WaitForValueChangedRequest(Type.WAIT_FOR_NOTIFICATION, characteristic);
}
/**
* Creates new Wait For Indication request. The request will not be executed if given
* characteristic is null, does not have INDICATE property or the CCCD.
* After the operation is complete a proper callback will be invoked.
* <p>
* If the indication should be triggered by another operation (for example writing an
* op code), set it with {@link WaitForValueChangedRequest#trigger(Operation)}.
*
* @param characteristic characteristic from which a notification should be received.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#waitForIndication(BluetoothGattCharacteristic)} instead.
*/
@Deprecated
@NonNull
public static WaitForValueChangedRequest newWaitForIndicationRequest(
@Nullable final BluetoothGattCharacteristic characteristic) {
return new WaitForValueChangedRequest(Type.WAIT_FOR_INDICATION, characteristic);
}
/**
* Creates new Read Battery Level request. The first found Battery Level characteristic value
* from the first found Battery Service. If any of them is not found, or the characteristic
* does not have the READ property this operation will not execute.
*
* @return The new request.
* @deprecated Use {@link #newReadRequest(BluetoothGattCharacteristic)} with
* BatteryLevelDataCallback from Android BLE Common Library instead.
*/
@NonNull
@Deprecated
public static ReadRequest newReadBatteryLevelRequest() {
return new ReadRequest(Type.READ_BATTERY_LEVEL);
}
/**
* Creates new Enable Notifications on the first found Battery Level characteristic from the
* first found Battery Service. If any of them is not found, or the characteristic does not
* have the NOTIFY property this operation will not execute.
*
* @return The new request.
* @deprecated Use {@link #newEnableNotificationsRequest(BluetoothGattCharacteristic)} with
* BatteryLevelDataCallback from Android BLE Common Library instead.
*/
@NonNull
@Deprecated
public static WriteRequest newEnableBatteryLevelNotificationsRequest() {
return new WriteRequest(Type.ENABLE_BATTERY_LEVEL_NOTIFICATIONS);
}
/**
* Creates new Disable Notifications on the first found Battery Level characteristic from the
* first found Battery Service. If any of them is not found, or the characteristic does not
* have the NOTIFY property this operation will not execute.
*
* @return The new request.
* @deprecated Use {@link #newDisableNotificationsRequest(BluetoothGattCharacteristic)} instead.
*/
@NonNull
@Deprecated
public static WriteRequest newDisableBatteryLevelNotificationsRequest() {
return new WriteRequest(Type.DISABLE_BATTERY_LEVEL_NOTIFICATIONS);
}
/**
* Creates new Enable Indications on Service Changed characteristic. It is a NOOP if such
* characteristic does not exist in the Generic Attribute service.
* It is required to enable those notifications on bonded devices on older Android versions to
* be informed about attributes changes.
* Android 7+ (or 6+) handles this automatically and no action is required.
*
* @return The new request.
*/
@NonNull
static WriteRequest newEnableServiceChangedIndicationsRequest() {
return new WriteRequest(Type.ENABLE_SERVICE_CHANGED_INDICATIONS);
}
/**
* Requests new MTU (Maximum Transfer Unit). This is only supported on Android Lollipop or newer.
* On older platforms the request will enqueue, but will fail to execute and
* {@link #fail(FailCallback)} callback will be called.
* The target device may reject requested value and set a smaller MTU.
*
* @param mtu the new MTU. Acceptable values are &lt;23, 517&gt;.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#requestMtu(int)} instead.
*/
@Deprecated
@NonNull
public static MtuRequest newMtuRequest(@IntRange(from = 23, to = 517) final int mtu) {
return new MtuRequest(Type.REQUEST_MTU, mtu);
}
/**
* Requests the new connection priority. Acceptable values are:
* <ol>
* <li>{@link ConnectionPriorityRequest#CONNECTION_PRIORITY_HIGH}
* - Interval: 11.25 -15 ms (Android 6+) and 7.5 - 10 ms (older), latency: 0,
* supervision timeout: 20 sec,</li>
* <li>{@link ConnectionPriorityRequest#CONNECTION_PRIORITY_BALANCED}
* - Interval: 30 - 50 ms, latency: 0, supervision timeout: 20 sec,</li>
* <li>{@link ConnectionPriorityRequest#CONNECTION_PRIORITY_LOW_POWER}
* - Interval: 100 - 125 ms, latency: 2, supervision timeout: 20 sec.</li>
* </ol>
* Requesting connection priority is available on Android Lollipop or newer. On older
* platforms the request will enqueue, but will fail to execute and {@link #fail(FailCallback)}
* callback will be called.
*
* @param priority one of: {@link ConnectionPriorityRequest#CONNECTION_PRIORITY_HIGH},
* {@link ConnectionPriorityRequest#CONNECTION_PRIORITY_BALANCED},
* {@link ConnectionPriorityRequest#CONNECTION_PRIORITY_LOW_POWER}.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#requestConnectionPriority(int)} instead.
*/
@Deprecated
@NonNull
public static ConnectionPriorityRequest newConnectionPriorityRequest(
@ConnectionPriority final int priority) {
return new ConnectionPriorityRequest(Type.REQUEST_CONNECTION_PRIORITY, priority);
}
/**
* Requests the change of preferred PHY for this connections.
* <p>
* PHY LE 2M and PHY LE Coded are supported only on Android Oreo or newer.
* You may safely request other PHYs on older platforms, but the request will not be executed
* and you will get PHY LE 1M as TX and RX PHY in the callback.
*
* @param txPhy preferred transmitter PHY. Bitwise OR of any of
* {@link PhyRequest#PHY_LE_1M_MASK}, {@link PhyRequest#PHY_LE_2M_MASK},
* and {@link PhyRequest#PHY_LE_CODED_MASK}.
* @param rxPhy preferred receiver PHY. Bitwise OR of any of
* {@link PhyRequest#PHY_LE_1M_MASK}, {@link PhyRequest#PHY_LE_2M_MASK},
* and {@link PhyRequest#PHY_LE_CODED_MASK}.
* @param phyOptions preferred coding to use when transmitting on the LE Coded PHY. Can be one
* of {@link PhyRequest#PHY_OPTION_NO_PREFERRED},
* {@link PhyRequest#PHY_OPTION_S2} or {@link PhyRequest#PHY_OPTION_S8}.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#setPreferredPhy(int, int, int)} instead.
*/
@Deprecated
@NonNull
public static PhyRequest newSetPreferredPhyRequest(@PhyMask final int txPhy,
@PhyMask final int rxPhy,
@PhyOption final int phyOptions) {
return new PhyRequest(Type.SET_PREFERRED_PHY, txPhy, rxPhy, phyOptions);
}
/**
* Reads the current PHY for this connections.
* <p>
* PHY LE 2M and PHY LE Coded are supported only on Android Oreo or newer.
* You may safely read PHY on older platforms, but the request will not be executed
* and you will get PHY LE 1M as TX and RX PHY in the callback.
*
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#readPhy()} instead.
*/
@Deprecated
@NonNull
public static PhyRequest newReadPhyRequest() {
return new PhyRequest(Type.READ_PHY);
}
/**
* Reads the current RSSI (Received Signal Strength Indication).
*
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#readRssi()} instead.
*/
@Deprecated
@NonNull
public static ReadRssiRequest newReadRssiRequest() {
return new ReadRssiRequest(Type.READ_RSSI);
}
/**
* Refreshes the device cache. As the {@link BluetoothGatt#refresh()} method is not in the
* public API (it's hidden, and on Android P it is on a light gray list) it is called
* using reflections and may be removed in some future Android release or on some devices.
* <p>
* There is no callback indicating when the cache has been cleared. This library assumes
* some time and waits. After the delay, it will start service discovery and clear the
* task queue. When the service discovery finishes, the
* {@link BleManager.BleManagerGattCallback#isRequiredServiceSupported(BluetoothGatt)} and
* {@link BleManager.BleManagerGattCallback#isOptionalServiceSupported(BluetoothGatt)} will
* be called and the initialization will be performed as if the device has just connected.
*
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#refreshDeviceCache()} instead.
*/
@Deprecated
@SuppressWarnings("JavadocReference")
@NonNull
public static SimpleRequest newRefreshCacheRequest() {
return new SimpleRequest(Type.REFRESH_CACHE);
}
/**
* Creates new Sleep request that will postpone next request for given number of milliseconds.
*
* @param delay the delay in milliseconds.
* @return The new request.
* @deprecated Access to this method will change to package-only.
* Use {@link BleManager#sleep(long)} instead.
*/
@Deprecated
@NonNull
public static SleepRequest newSleepRequest(@IntRange(from = 0) final long delay) {
return new SleepRequest(Type.SLEEP, delay);
}
/**
* Use to set a completion callback. The callback will be invoked when the operation has
* finished successfully unless the request was executed synchronously, in which case this
* callback will be ignored.
*
* @param callback the callback.
* @return The request.
*/
@NonNull
public Request done(@NonNull final SuccessCallback callback) {
this.successCallback = callback;
return this;
}
/**
* Use to set a callback that will be called in case the request has failed.
* If the target device wasn't set before executing this request
* ({@link BleManager#connect(BluetoothDevice)} was never called), the
* {@link #invalid(InvalidRequestCallback)} will be used instead, as the
* {@link BluetoothDevice} is not known.
* <p>
* This callback will be ignored if request was executed synchronously, in which case
* the error will be returned as an exception.
*
* @param callback the callback.
* @return The request.
*/
@NonNull
public Request fail(@NonNull final FailCallback callback) {
this.failCallback = callback;
return this;
}
/**
* Used to set internal callback what will be executed before the request is executed.
*
* @param callback the callback.
*/
void internalBefore(@NonNull final BeforeCallback callback) {
this.internalBeforeCallback = callback;
}
/**
* Used to set internal success callback. The callback will be notified in case the request
* has completed.
*
* @param callback the callback.
*/
void internalSuccess(@NonNull final SuccessCallback callback) {
this.internalSuccessCallback = callback;
}
/**
* Used to set internal fail callback. The callback will be notified in case the request
* has failed.
*
* @param callback the callback.
*/
void internalFail(@NonNull final FailCallback callback) {
this.internalFailCallback = callback;
}
/**
* Use to set a callback that will be called in case the request was invalid, for example
* called before the device was connected.
* This callback will be ignored if request was executed synchronously, in which case
* the error will be returned as an exception.
*
* @param callback the callback.
* @return The request.
*/
@NonNull
public Request invalid(@NonNull final InvalidRequestCallback callback) {
this.invalidRequestCallback = callback;
return this;
}
/**
* Sets a callback that will be executed before the execution of this operation starts.
*
* @param callback the callback.
* @return The request.
*/
@NonNull
public Request before(@NonNull final BeforeCallback callback) {
this.beforeCallback = callback;
return this;
}
/**
* Enqueues the request for asynchronous execution.
*/
public void enqueue() {
manager.enqueue(this);
}
void notifyStarted(@NonNull final BluetoothDevice device) {
if (beforeCallback != null)
beforeCallback.onRequestStarted(device);
if (internalBeforeCallback != null)
internalBeforeCallback.onRequestStarted(device);
}
void notifySuccess(@NonNull final BluetoothDevice device) {
if (!finished) {
finished = true;
if (successCallback != null)
successCallback.onRequestCompleted(device);
if (internalSuccessCallback != null)
internalSuccessCallback.onRequestCompleted(device);
}
}
void notifyFail(@NonNull final BluetoothDevice device, final int status) {
if (!finished) {
finished = true;
if (failCallback != null)
failCallback.onRequestFailed(device, status);
if (internalFailCallback != null)
internalFailCallback.onRequestFailed(device, status);
}
}
void notifyInvalidRequest() {
if (!finished) {
finished = true;
if (invalidRequestCallback != null)
invalidRequestCallback.onInvalidRequest();
}
}
/**
* Asserts that the synchronous method was not called from the UI thread.
*
* @throws IllegalStateException when called from a UI thread.
*/
static void assertNotMainThread() throws IllegalStateException {
if (Looper.myLooper() == Looper.getMainLooper()) {
throw new IllegalStateException("Cannot execute synchronous operation from the UI thread.");
}
}
final class RequestCallback implements SuccessCallback, FailCallback, InvalidRequestCallback {
final static int REASON_REQUEST_INVALID = -1000000;
int status = BluetoothGatt.GATT_SUCCESS;
@Override
public void onRequestCompleted(@NonNull final BluetoothDevice device) {
syncLock.open();
}
@Override
public void onRequestFailed(@NonNull final BluetoothDevice device, final int status) {
this.status = status;
syncLock.open();
}
@Override
public void onInvalidRequest() {
this.status = REASON_REQUEST_INVALID;
syncLock.open();
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
boolean isSuccess() {
return this.status == BluetoothGatt.GATT_SUCCESS;
}
}
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import java.util.LinkedList;
import java.util.Queue;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
@SuppressWarnings("WeakerAccess")
public class RequestQueue extends SimpleRequest {
/**
* A list of operations that will be executed together.
*/
@NonNull
private final Queue<Request> requests;
RequestQueue() {
super(Type.SET);
requests = new LinkedList<>();
}
@NonNull
@Override
RequestQueue setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@Override
@NonNull
public RequestQueue done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@Override
@NonNull
public RequestQueue fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public RequestQueue invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public RequestQueue before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
/**
* Enqueues a new operation. All operations will be executed sequentially in order they were
* added.
*
* @param operation the new operation to be enqueued.
* @throws IllegalStateException if the operation was enqueued before.
* @throws IllegalArgumentException if the operation is not a {@link Request}.
*/
@NonNull
public RequestQueue add(@NonNull final Operation operation) {
if (operation instanceof Request) {
final Request request = (Request) operation;
// Validate
if (request.enqueued)
throw new IllegalStateException("Request already enqueued");
// Add
requests.add(request);
// Mark
request.enqueued = true;
return this;
} else {
throw new IllegalArgumentException("Operation does not extend Request");
}
}
/**
* Returns number of enqueued operations.
*
* @return the size of the internal operations list.
*/
@IntRange(from = 0)
public int size() {
return requests.size();
}
/**
* Returns whether the set is empty, or not.
*
* @return true if the set is empty. Set gets emptied while it all enqueued operations
* are being executed.
*/
public boolean isEmpty() {
return requests.isEmpty();
}
/**
* Cancels all the enqueued operations that were not executed yet.
* The one currently executed will be finished.
* <p>
* It is safe to call this method in {@link Request#done(SuccessCallback)} or
* {@link Request#fail(FailCallback)} callback;
*/
public void cancelQueue() {
requests.clear();
}
/**
* Returns the next {@link Request} to be enqueued.
*
* @return the next request.
*/
@Nullable
Request getNext() {
try {
return requests.remove();
// poll() may also throw an exception
// See: https://github.com/NordicSemiconductor/Android-BLE-Library/issues/37
} catch (final Exception e) {
return null;
}
}
/**
* Returns whether there are more operations to be executed.
*
* @return true, if not all operations were completed.
*/
boolean hasMore() {
return !requests.isEmpty();
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
import no.nordicsemi.android.ble.exception.BluetoothDisabledException;
import no.nordicsemi.android.ble.exception.DeviceDisconnectedException;
import no.nordicsemi.android.ble.exception.InvalidRequestException;
import no.nordicsemi.android.ble.exception.RequestFailedException;
/**
* A request that requires a {@link android.bluetooth.BluetoothGattCallback callback} or can't
* have timeout for any other reason. This class defines the {@link #await()} method.
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public class SimpleRequest extends Request {
SimpleRequest(@NonNull final Type type) {
super(type);
}
SimpleRequest(@NonNull final Type type,
@Nullable final BluetoothGattCharacteristic characteristic) {
super(type, characteristic);
}
SimpleRequest(@NonNull final Type type,
@Nullable final BluetoothGattDescriptor descriptor) {
super(type, descriptor);
}
/**
* Synchronously waits until the request is done.
* <p>
* Callbacks set using {@link #done(SuccessCallback)} and {@link #fail(FailCallback)}
* will be ignored.
* <p>
* This method may not be called from the main (UI) thread.
*
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link BluetoothGatt#GATT_SUCCESS}.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter has been disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
*/
public final void await() throws RequestFailedException, DeviceDisconnectedException,
BluetoothDisabledException, InvalidRequestException {
assertNotMainThread();
final SuccessCallback sc = successCallback;
final FailCallback fc = failCallback;
try {
syncLock.close();
final RequestCallback callback = new RequestCallback();
done(callback).fail(callback).invalid(callback).enqueue();
syncLock.block();
if (!callback.isSuccess()) {
if (callback.status == FailCallback.REASON_DEVICE_DISCONNECTED) {
throw new DeviceDisconnectedException();
}
if (callback.status == FailCallback.REASON_BLUETOOTH_DISABLED) {
throw new BluetoothDisabledException();
}
if (callback.status == RequestCallback.REASON_REQUEST_INVALID) {
throw new InvalidRequestException(this);
}
throw new RequestFailedException(this, callback.status);
}
} finally {
successCallback = sc;
failCallback = fc;
}
}
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
import no.nordicsemi.android.ble.exception.BluetoothDisabledException;
import no.nordicsemi.android.ble.exception.DeviceDisconnectedException;
import no.nordicsemi.android.ble.exception.InvalidRequestException;
import no.nordicsemi.android.ble.exception.RequestFailedException;
/**
* A value request that requires a {@link android.bluetooth.BluetoothGattCallback callback} or
* can't have timeout for any other reason. This class defines the {@link #await()} methods.
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public abstract class SimpleValueRequest<T> extends SimpleRequest {
T valueCallback;
SimpleValueRequest(@NonNull final Type type) {
super(type);
}
SimpleValueRequest(@NonNull final Type type,
@Nullable final BluetoothGattCharacteristic characteristic) {
super(type, characteristic);
}
SimpleValueRequest(@NonNull final Type type,
@Nullable final BluetoothGattDescriptor descriptor) {
super(type, descriptor);
}
/**
* Sets the value callback. When the request is invoked synchronously, this callback will
* be ignored and the received value will be returned by the <code>await(...)</code> method;
*
* @param callback the callback.
* @return The request.
*/
@NonNull
public SimpleValueRequest<T> with(@NonNull final T callback) {
this.valueCallback = callback;
return this;
}
/**
* Synchronously waits until the request is done. The given response object will be filled
* with the request response.
* <p>
* Callbacks set using {@link #done(SuccessCallback)} and {@link #fail(FailCallback)} and
* {@link #with(T)} will be ignored.
* <p>
* This method may not be called from the main (UI) thread.
*
* @param response the response object.
* @param <E> a response class.
* @return The response with a response.
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link android.bluetooth.BluetoothGatt#GATT_SUCCESS}.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter is disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @see #await(Class)
*/
@NonNull
public <E extends T> E await(@NonNull final E response)
throws RequestFailedException, DeviceDisconnectedException, BluetoothDisabledException,
InvalidRequestException {
assertNotMainThread();
final T vc = valueCallback;
try {
with(response).await();
return response;
} finally {
valueCallback = vc;
}
}
/**
* Synchronously waits until the request is done.
* <p>
* Callbacks set using {@link #done(SuccessCallback)} and {@link #fail(FailCallback)} and
* {@link #with(T)} will be ignored.
* <p>
* This method may not be called from the main (UI) thread.
*
* @param responseClass the response class. This class will be instantiate, therefore it has
* to have a default constructor.
* @return The response with a response.
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link android.bluetooth.BluetoothGatt#GATT_SUCCESS}.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread.
* @throws IllegalArgumentException thrown when the response class could not be instantiated.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter is disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @see #await(Object)
*/
@NonNull
public <E extends T> E await(@NonNull final Class<E> responseClass)
throws RequestFailedException, DeviceDisconnectedException, BluetoothDisabledException,
InvalidRequestException {
assertNotMainThread();
try {
final E response = responseClass.newInstance();
return await(response);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Couldn't instantiate "
+ responseClass.getCanonicalName()
+ " class. Is the default constructor accessible?");
} catch (InstantiationException e) {
throw new IllegalArgumentException("Couldn't instantiate "
+ responseClass.getCanonicalName()
+ " class. Does it have a default constructor with no arguments?");
}
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
@SuppressWarnings({"unused", "WeakerAccess"})
public final class SleepRequest extends SimpleRequest implements Operation {
private long delay;
SleepRequest(@NonNull final Type type, @IntRange(from = 0) final long delay) {
super(type);
this.delay = delay;
}
@NonNull
@Override
SleepRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@NonNull
@Override
public SleepRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@NonNull
@Override
public SleepRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public SleepRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@NonNull
@Override
public SleepRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
long getDelay() {
return delay;
}
}

View File

@@ -0,0 +1,13 @@
package no.nordicsemi.android.ble;
import androidx.annotation.NonNull;
abstract class TimeoutHandler {
/**
* Method called when the request timed out.
*
* @param request the request that timed out.
*/
abstract void onRequestTimeout(@NonNull final TimeoutableRequest request);
}

View File

@@ -0,0 +1,222 @@
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.os.Handler;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
import no.nordicsemi.android.ble.exception.BluetoothDisabledException;
import no.nordicsemi.android.ble.exception.DeviceDisconnectedException;
import no.nordicsemi.android.ble.exception.InvalidRequestException;
import no.nordicsemi.android.ble.exception.RequestFailedException;
@SuppressWarnings("WeakerAccess")
public abstract class TimeoutableRequest extends Request {
private TimeoutHandler timeoutHandler;
private Runnable timeoutCallback;
private Handler handler;
protected long timeout;
TimeoutableRequest(@NonNull final Type type) {
super(type);
}
TimeoutableRequest(@NonNull final Type type, @Nullable final BluetoothGattCharacteristic characteristic) {
super(type, characteristic);
}
TimeoutableRequest(@NonNull final Type type, @Nullable final BluetoothGattDescriptor descriptor) {
super(type, descriptor);
}
@NonNull
@Override
TimeoutableRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
this.handler = manager.mHandler;
this.timeoutHandler = manager;
return this;
}
/**
* Sets the operation timeout.
* When the timeout occurs, the request will fail with {@link FailCallback#REASON_TIMEOUT}.
*
* @param timeout the request timeout in milliseconds, 0 to disable timeout.
* @return the callback.
* @throws IllegalStateException thrown when the request has already been started.
* @throws UnsupportedOperationException thrown when the timeout is not allowed for this request,
* as the callback from the system is required.
*/
@NonNull
public TimeoutableRequest timeout(@IntRange(from = 0) final long timeout) {
if (timeoutCallback != null)
throw new IllegalStateException("Request already started");
this.timeout = timeout;
return this;
}
/**
* Enqueues the request for asynchronous execution.
* <p>
* Use {@link #timeout(long)} to set the maximum time the manager should wait until the device
* is ready. When the timeout occurs, the request will fail with
* {@link FailCallback#REASON_TIMEOUT} and the device will get disconnected.
*/
@Override
public final void enqueue() {
super.enqueue();
}
/**
* Enqueues the request for asynchronous execution.
* <p>
* When the timeout occurs, the request will fail with {@link FailCallback#REASON_TIMEOUT}
* and the device will get disconnected.
*
* @param timeout the request timeout in milliseconds, 0 to disable timeout. This value will
* override one set in {@link #timeout(long)}.
* @deprecated Use {@link #timeout(long)} and {@link #enqueue()} instead.
*/
@Deprecated
public final void enqueue(@IntRange(from = 0) final long timeout) {
timeout(timeout).enqueue();
}
/**
* Synchronously waits until the request is done.
* <p>
* Use {@link #timeout(long)} to set the maximum time the manager should wait until the request
* is ready. When the timeout occurs, the {@link InterruptedException} will be thrown.
* <p>
* Callbacks set using {@link #done(SuccessCallback)} and {@link #fail(FailCallback)}
* will be ignored.
* <p>
* This method may not be called from the main (UI) thread.
*
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link BluetoothGatt#GATT_SUCCESS}.
* @throws InterruptedException thrown if the timeout occurred before the request has
* finished.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter has been disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @see #enqueue()
*/
public final void await() throws RequestFailedException, DeviceDisconnectedException,
BluetoothDisabledException, InvalidRequestException, InterruptedException {
assertNotMainThread();
final SuccessCallback sc = successCallback;
final FailCallback fc = failCallback;
try {
syncLock.close();
final RequestCallback callback = new RequestCallback();
done(callback).fail(callback).invalid(callback).enqueue();
if (!syncLock.block(timeout)) {
throw new InterruptedException();
}
if (!callback.isSuccess()) {
if (callback.status == FailCallback.REASON_DEVICE_DISCONNECTED) {
throw new DeviceDisconnectedException();
}
if (callback.status == FailCallback.REASON_BLUETOOTH_DISABLED) {
throw new BluetoothDisabledException();
}
if (callback.status == RequestCallback.REASON_REQUEST_INVALID) {
throw new InvalidRequestException(this);
}
throw new RequestFailedException(this, callback.status);
}
} finally {
successCallback = sc;
failCallback = fc;
}
}
/**
* Synchronously waits, for as most as the given number of milliseconds, until the request
* is ready.
* <p>
* When the timeout occurs, the {@link InterruptedException} will be thrown.
* <p>
* Callbacks set using {@link #done(SuccessCallback)} and {@link #fail(FailCallback)}
* will be ignored.
* <p>
* This method may not be called from the main (UI) thread.
*
* @param timeout optional timeout in milliseconds, 0 to disable timeout. This will
* override the timeout set using {@link #timeout(long)}.
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link BluetoothGatt#GATT_SUCCESS}.
* @throws InterruptedException thrown if the timeout occurred before the request has
* finished.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter has been disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @deprecated Use {@link #timeout(long)} and {@link #await()} instead.
*/
@Deprecated
public final void await(@IntRange(from = 0) final long timeout) throws RequestFailedException,
InterruptedException, DeviceDisconnectedException, BluetoothDisabledException,
InvalidRequestException {
timeout(timeout).await();
}
@Override
void notifyStarted(@NonNull final BluetoothDevice device) {
if (timeout > 0L) {
timeoutCallback = () -> {
timeoutCallback = null;
if (!finished) {
notifyFail(device, FailCallback.REASON_TIMEOUT);
timeoutHandler.onRequestTimeout(this);
}
};
handler.postDelayed(timeoutCallback, timeout);
}
super.notifyStarted(device);
}
@Override
void notifySuccess(@NonNull final BluetoothDevice device) {
if (!finished) {
handler.removeCallbacks(timeoutCallback);
timeoutCallback = null;
}
super.notifySuccess(device);
}
@Override
void notifyFail(@NonNull final BluetoothDevice device, final int status) {
if (!finished) {
handler.removeCallbacks(timeoutCallback);
timeoutCallback = null;
}
super.notifyFail(device, status);
}
@Override
void notifyInvalidRequest() {
if (!finished) {
handler.removeCallbacks(timeoutCallback);
timeoutCallback = null;
}
super.notifyInvalidRequest();
}
}

View File

@@ -0,0 +1,238 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
import no.nordicsemi.android.ble.exception.BluetoothDisabledException;
import no.nordicsemi.android.ble.exception.DeviceDisconnectedException;
import no.nordicsemi.android.ble.exception.InvalidRequestException;
import no.nordicsemi.android.ble.exception.RequestFailedException;
/**
* A value request that requires a {@link android.bluetooth.BluetoothGattCallback callback} or
* can't have timeout for any other reason. This class defines the {@link #await()} methods.
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public abstract class TimeoutableValueRequest<T> extends TimeoutableRequest {
T valueCallback;
TimeoutableValueRequest(@NonNull final Type type) {
super(type);
}
TimeoutableValueRequest(@NonNull final Type type,
@Nullable final BluetoothGattCharacteristic characteristic) {
super(type, characteristic);
}
TimeoutableValueRequest(@NonNull final Type type,
@Nullable final BluetoothGattDescriptor descriptor) {
super(type, descriptor);
}
@NonNull
@Override
public TimeoutableValueRequest<T> timeout(@IntRange(from = 0) final long timeout) {
super.timeout(timeout);
return this;
}
/**
* Sets the value callback. When the request is invoked synchronously, this callback will
* be ignored and the received value will be returned by the <code>await(...)</code> method;
*
* @param callback the callback.
* @return The request.
*/
@NonNull
public TimeoutableValueRequest<T> with(@NonNull final T callback) {
this.valueCallback = callback;
return this;
}
/**
* Synchronously waits until the request is done.
* <p>
* When the timeout, set with {@link #timeout(long)} occurs, the {@link InterruptedException}
* will be thrown.
* <p>
* Callbacks set using {@link #done(SuccessCallback)} and {@link #fail(FailCallback)} and
* {@link #with(E)} will be ignored.
* <p>
* This method may not be called from the main (UI) thread.
*
* @param response the response object.
* @param <E> a response class.
* @return The response with a response.
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link android.bluetooth.BluetoothGatt#GATT_SUCCESS}.
* @throws InterruptedException thrown if the timeout occurred before the request has
* finished.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread, or when the trigger was already enqueued.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter is disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
*/
@NonNull
public <E extends T> E await(@NonNull final E response)
throws RequestFailedException, DeviceDisconnectedException, BluetoothDisabledException,
InvalidRequestException, InterruptedException {
assertNotMainThread();
final T vc = valueCallback;
try {
with(response).await();
return response;
} finally {
valueCallback = vc;
}
}
/**
* Synchronously waits until the request is done.
* <p>
* Callbacks set using {@link #done(SuccessCallback)} and {@link #fail(FailCallback)} and
* {@link #with(T)} will be ignored.
* <p>
* This method may not be called from the main (UI) thread.
*
* @param responseClass the response class. This class will be instantiate, therefore it has
* to have a default constructor.
* @return The response with a response.
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link android.bluetooth.BluetoothGatt#GATT_SUCCESS}.
* @throws InterruptedException thrown if the timeout occurred before the request has
* finished.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread.
* @throws IllegalArgumentException thrown when the response class could not be instantiated.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter is disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @see #await(Object)
*/
@NonNull
public <E extends T> E await(@NonNull final Class<E> responseClass)
throws RequestFailedException, DeviceDisconnectedException, BluetoothDisabledException,
InvalidRequestException, InterruptedException {
assertNotMainThread();
try {
final E response = responseClass.newInstance();
return await(response);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Couldn't instantiate "
+ responseClass.getCanonicalName()
+ " class. Is the default constructor accessible?");
} catch (InstantiationException e) {
throw new IllegalArgumentException("Couldn't instantiate "
+ responseClass.getCanonicalName()
+ " class. Does it have a default constructor with no arguments?");
}
}
/**
* Synchronously waits until the request is done, for at most given number of milliseconds
* after which the {@link InterruptedException} will be thrown.
* <p>
* Callbacks set using {@link #done(SuccessCallback)}, {@link #fail(FailCallback)} and
* {@link #with(E)} will be ignored.
* <p>
* This method may not be called from the main (UI) thread.
*
* @param responseClass the response class. This class will be instantiate, therefore it has
* to have a default constructor.
* @param timeout optional timeout in milliseconds. This value will override one set
* in {@link #timeout(long)}.
* @param <E> a response class that extends {@link T}.
* @return The object with a response.
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link android.bluetooth.BluetoothGatt#GATT_SUCCESS}.
* @throws InterruptedException thrown if the timeout occurred before the request has
* finished.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread.
* @throws IllegalArgumentException thrown when the response class could not be instantiated.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter is disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @deprecated Use {@link #timeout(long)} and {@link #await(Class)} instead.
*/
@NonNull
@Deprecated
public <E extends T> E await(@NonNull final Class<E> responseClass,
@IntRange(from = 0) final long timeout)
throws RequestFailedException, InterruptedException, DeviceDisconnectedException,
BluetoothDisabledException, InvalidRequestException {
return timeout(timeout).await(responseClass);
}
/**
* Synchronously waits until the request is done, for at most given number of milliseconds
* after which the {@link InterruptedException} will be thrown.
* <p>
* Callbacks set using {@link #done(SuccessCallback)}, {@link #fail(FailCallback)} and
* {@link #with(E)} will be ignored.
* <p>
* This method may not be called from the main (UI) thread.
*
* @param response the response object.
* @param timeout optional timeout in milliseconds.
* @param <E> a response class that extends {@link T}.
* @return The object with a response.
* @throws RequestFailedException thrown when the BLE request finished with status other
* than {@link android.bluetooth.BluetoothGatt#GATT_SUCCESS}.
* @throws InterruptedException thrown if the timeout occurred before the request has
* finished.
* @throws IllegalStateException thrown when you try to call this method from the main
* (UI) thread.
* @throws DeviceDisconnectedException thrown when the device disconnected before the request
* was completed.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter is disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @deprecated Use {@link #timeout(long)} and {@link #await(E)} instead.
*/
@NonNull
@Deprecated
public <E extends T> E await(@NonNull final E response,
@IntRange(from = 0) final long timeout)
throws RequestFailedException, InterruptedException, DeviceDisconnectedException,
BluetoothDisabledException, InvalidRequestException {
return timeout(timeout).await(response);
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.DataReceivedCallback;
import no.nordicsemi.android.ble.callback.ReadProgressCallback;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.ble.data.DataFilter;
import no.nordicsemi.android.ble.data.DataMerger;
import no.nordicsemi.android.ble.data.DataStream;
@SuppressWarnings({"unused", "WeakerAccess", "UnusedReturnValue"})
public class ValueChangedCallback {
private ReadProgressCallback progressCallback;
private DataReceivedCallback valueCallback;
private DataMerger dataMerger;
private DataStream buffer;
private DataFilter filter;
private int count = 0;
ValueChangedCallback() {
// empty
}
/**
* Sets the asynchronous data callback that will be called whenever a notification or
* an indication is received on given characteristic.
*
* @param callback the data callback.
* @return The request.
*/
@NonNull
public ValueChangedCallback with(@NonNull final DataReceivedCallback callback) {
this.valueCallback = callback;
return this;
}
/**
* Sets a filter which allows to skip some incoming data.
*
* @param filter the data filter.
* @return The request.
*/
@NonNull
public ValueChangedCallback filter(@NonNull final DataFilter filter) {
this.filter = filter;
return this;
}
/**
* Adds a merger that will be used to merge multiple packets into a single Data.
* The merger may modify each packet if necessary.
*
* @return The request.
*/
@NonNull
public ValueChangedCallback merge(@NonNull final DataMerger merger) {
this.dataMerger = merger;
this.progressCallback = null;
return this;
}
/**
* Adds a merger that will be used to merge multiple packets into a single Data.
* The merger may modify each packet if necessary.
*
* @return The request.
*/
@NonNull
public ValueChangedCallback merge(@NonNull final DataMerger merger,
@NonNull final ReadProgressCallback callback) {
this.dataMerger = merger;
this.progressCallback = callback;
return this;
}
ValueChangedCallback free() {
valueCallback = null;
dataMerger = null;
progressCallback = null;
buffer = null;
return this;
}
boolean matches(final byte[] packet) {
return filter == null || filter.filter(packet);
}
void notifyValueChanged(@NonNull final BluetoothDevice device, @Nullable final byte[] value) {
// Keep a reference to the value callback, as it may change during execution
final DataReceivedCallback valueCallback = this.valueCallback;
// With no value callback there is no need for any merging
if (valueCallback == null) {
return;
}
if (dataMerger == null) {
valueCallback.onDataReceived(device, new Data(value));
} else {
if (progressCallback != null)
progressCallback.onPacketReceived(device, value, count);
if (buffer == null)
buffer = new DataStream();
if (dataMerger.merge(buffer, value, count++)) {
valueCallback.onDataReceived(device, buffer.toData());
buffer = null;
count = 0;
} // else
// wait for more packets to be merged
}
}
}

View File

@@ -0,0 +1,400 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.DataReceivedCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.ReadProgressCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
import no.nordicsemi.android.ble.callback.profile.ProfileReadResponse;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.ble.data.DataFilter;
import no.nordicsemi.android.ble.data.DataMerger;
import no.nordicsemi.android.ble.data.DataStream;
import no.nordicsemi.android.ble.exception.BluetoothDisabledException;
import no.nordicsemi.android.ble.exception.DeviceDisconnectedException;
import no.nordicsemi.android.ble.exception.InvalidDataException;
import no.nordicsemi.android.ble.exception.InvalidRequestException;
import no.nordicsemi.android.ble.exception.RequestFailedException;
@SuppressWarnings({"unused", "WeakerAccess"})
public final class WaitForValueChangedRequest extends TimeoutableValueRequest<DataReceivedCallback>
implements Operation {
static final int NOT_STARTED = -123456;
static final int STARTED = NOT_STARTED + 1;
private ReadProgressCallback progressCallback;
private DataMerger dataMerger;
private DataStream buffer;
private DataFilter filter;
private Request trigger;
private boolean deviceDisconnected;
private boolean bluetoothDisabled;
private int triggerStatus = BluetoothGatt.GATT_SUCCESS;
private int count = 0;
WaitForValueChangedRequest(@NonNull final Type type,
@Nullable final BluetoothGattCharacteristic characteristic) {
super(type, characteristic);
}
@NonNull
@Override
WaitForValueChangedRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@NonNull
@Override
public WaitForValueChangedRequest timeout(@IntRange(from = 0) final long timeout) {
super.timeout(timeout);
return this;
}
@NonNull
@Override
public WaitForValueChangedRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@NonNull
@Override
public WaitForValueChangedRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public WaitForValueChangedRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public WaitForValueChangedRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
@NonNull
@Override
public WaitForValueChangedRequest with(@NonNull final DataReceivedCallback callback) {
super.with(callback);
return this;
}
/**
* Sets a filter which allows to skip some incoming data.
*
* @param filter the data filter.
* @return The request.
*/
@NonNull
public WaitForValueChangedRequest filter(@NonNull final DataFilter filter) {
this.filter = filter;
return this;
}
/**
* Adds a merger that will be used to merge multiple packets into a single Data.
* The merger may modify each packet if necessary.
*
* @return The request.
*/
@NonNull
public WaitForValueChangedRequest merge(@NonNull final DataMerger merger) {
this.dataMerger = merger;
this.progressCallback = null;
return this;
}
/**
* Adds a merger that will be used to merge multiple packets into a single Data.
* The merger may modify each packet if necessary.
*
* @return The request.
*/
@NonNull
public WaitForValueChangedRequest merge(@NonNull final DataMerger merger,
@NonNull final ReadProgressCallback callback) {
this.dataMerger = merger;
this.progressCallback = callback;
return this;
}
/**
* Sets an optional request that is suppose to trigger the notification or indication.
* This is to ensure that the characteristic value won't change before the callback was set.
*
* @param trigger the operation that triggers the notification, usually a write characteristic
* request that write some OP CODE.
* @return The request.
*/
@NonNull
public WaitForValueChangedRequest trigger(@NonNull final Operation trigger) {
if (trigger instanceof Request) {
this.trigger = (Request) trigger;
this.triggerStatus = NOT_STARTED;
// The trigger will never receive invalid request event.
// If the BluetoothDevice wasn't set, the whole WaitForValueChangedRequest would be invalid.
/*this.trigger.invalid(() -> {
// never called
});*/
this.trigger.internalBefore(device -> triggerStatus = STARTED);
this.trigger.internalSuccess(device -> triggerStatus = BluetoothGatt.GATT_SUCCESS);
this.trigger.internalFail((device, status) -> {
triggerStatus = status;
syncLock.open();
notifyFail(device, status);
});
}
return this;
}
@NonNull
@Override
public <E extends DataReceivedCallback> E await(@NonNull final E response)
throws RequestFailedException, DeviceDisconnectedException, BluetoothDisabledException,
InvalidRequestException, InterruptedException {
assertNotMainThread();
try {
// Ensure the trigger request it enqueued after the callback has been set.
if (trigger != null && trigger.enqueued) {
throw new IllegalStateException("Trigger request already enqueued");
}
super.await(response);
return response;
} catch (final RequestFailedException e) {
if (triggerStatus != BluetoothGatt.GATT_SUCCESS) {
// Trigger will never have invalid request status. The outer request will.
/*if (triggerStatus == RequestCallback.REASON_REQUEST_INVALID) {
throw new InvalidRequestException(trigger);
}*/
throw new RequestFailedException(trigger, triggerStatus);
}
throw e;
}
}
/**
* Similar to {@link #await(Class)}, but if the response class extends
* {@link ProfileReadResponse} and the received response is invalid, an exception is thrown.
* This allows to keep all error handling in one place.
*
* @param response the result object.
* @param <E> a response class that extends {@link ProfileReadResponse}.
* @return Object with a valid response.
* @throws IllegalStateException thrown when you try to call this method from
* the main (UI) thread.
* @throws InterruptedException thrown when the timeout occurred before the
* characteristic value has changed.
* @throws RequestFailedException thrown when the trigger request has failed.
* @throws DeviceDisconnectedException thrown when the device disconnected before the
* notification or indication was received.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter has been disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @throws InvalidDataException thrown when the received data were not valid (that is when
* {@link ProfileReadResponse#onDataReceived(BluetoothDevice, Data)}
* failed to parse the data correctly and called
* {@link ProfileReadResponse#onInvalidDataReceived(BluetoothDevice, Data)}).
*/
@SuppressWarnings("ConstantConditions")
@NonNull
public <E extends ProfileReadResponse> E awaitValid(@NonNull final E response)
throws RequestFailedException, InvalidDataException, DeviceDisconnectedException,
BluetoothDisabledException, InvalidRequestException, InterruptedException {
final E result = await(response);
if (result != null && !result.isValid()) {
throw new InvalidDataException(result);
}
return result;
}
/**
* Similar to {@link #await(DataReceivedCallback)}, but if the response class extends
* {@link ProfileReadResponse} and the received response is invalid, an exception is thrown.
* This allows to keep all error handling in one place.
*
* @param responseClass the result class. This class will be instantiate, therefore it
* has to have a default constructor.
* @param <E> a response class that extends {@link ProfileReadResponse}.
* @return Object with a valid response.
* @throws IllegalStateException thrown when you try to call this method from
* the main (UI) thread.
* @throws InterruptedException thrown when the timeout occurred before the
* characteristic value has changed.
* @throws IllegalArgumentException thrown when the response class could not be instantiated.
* @throws RequestFailedException thrown when the trigger request has failed.
* @throws DeviceDisconnectedException thrown when the device disconnected before the
* notification or indication was received.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter has been disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @throws InvalidDataException thrown when the received data were not valid (that is when
* {@link ProfileReadResponse#onDataReceived(BluetoothDevice, Data)}
* failed to parse the data correctly and called
* {@link ProfileReadResponse#onInvalidDataReceived(BluetoothDevice, Data)}).
*/
@SuppressWarnings("ConstantConditions")
@NonNull
public <E extends ProfileReadResponse> E awaitValid(@NonNull final Class<E> responseClass)
throws RequestFailedException, InvalidDataException, DeviceDisconnectedException,
BluetoothDisabledException, InvalidRequestException, InterruptedException {
final E response = await(responseClass);
if (response != null && !response.isValid()) {
throw new InvalidDataException(response);
}
return response;
}
/**
* Same as {@link #await(Class, long)}, but if received response is not valid, this method will
* thrown an exception.
*
* @param responseClass the result class. This class will be instantiate, therefore it
* has to have a default constructor.
* @param timeout optional timeout in milliseconds.
* @param <E> a response class that extends {@link ProfileReadResponse}.
* @return Object with a valid response.
* @throws IllegalStateException thrown when you try to call this method from
* the main (UI) thread.
* @throws InterruptedException thrown when the timeout occurred before the
* characteristic value has changed.
* @throws IllegalArgumentException thrown when the response class could not be instantiated.
* @throws RequestFailedException thrown when the trigger request has failed.
* @throws DeviceDisconnectedException thrown when the device disconnected before the
* notification or indication was received.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter has been disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @throws InvalidDataException thrown when the received data were not valid (that is when
* {@link ProfileReadResponse#onDataReceived(BluetoothDevice, Data)}
* failed to parse the data correctly and called
* {@link ProfileReadResponse#onInvalidDataReceived(BluetoothDevice, Data)}).
* @deprecated Use {@link #timeout(long)} and {@link #awaitValid(Class)} instead.
*/
@SuppressWarnings("ConstantConditions")
@NonNull
@Deprecated
public <E extends ProfileReadResponse> E awaitValid(@NonNull final Class<E> responseClass,
@IntRange(from = 0) final long timeout)
throws InterruptedException, InvalidDataException, RequestFailedException,
DeviceDisconnectedException, BluetoothDisabledException, InvalidRequestException {
return timeout(timeout).awaitValid(responseClass);
}
/**
* Same as {@link #await(Object, long)}, but if received response is not valid,
* this method will thrown an exception.
*
* @param response the result object.
* @param timeout optional timeout in milliseconds.
* @param <E> a response class that extends {@link ProfileReadResponse}.
* @return Object with a valid response.
* @throws IllegalStateException thrown when you try to call this method from
* the main (UI) thread.
* @throws InterruptedException thrown when the timeout occurred before the
* characteristic value has changed.
* @throws RequestFailedException thrown when the trigger request has failed.
* @throws DeviceDisconnectedException thrown when the device disconnected before the
* notification or indication was received.
* @throws BluetoothDisabledException thrown when the Bluetooth adapter has been disabled.
* @throws InvalidRequestException thrown when the request was called before the device was
* connected at least once (unknown device).
* @throws InvalidDataException thrown when the received data were not valid (that is when
* {@link ProfileReadResponse#onDataReceived(BluetoothDevice, Data)}
* failed to parse the data correctly and called
* {@link ProfileReadResponse#onInvalidDataReceived(BluetoothDevice, Data)}).
* @deprecated Use {@link #timeout(long)} and {@link #awaitValid(E)} instead.
*/
@SuppressWarnings("ConstantConditions")
@NonNull
@Deprecated
public <E extends ProfileReadResponse> E awaitValid(@NonNull final E response,
@IntRange(from = 0) final long timeout)
throws InterruptedException, InvalidDataException, DeviceDisconnectedException,
RequestFailedException, BluetoothDisabledException, InvalidRequestException {
return timeout(timeout).awaitValid(response);
}
boolean matches(final byte[] packet) {
return filter == null || filter.filter(packet);
}
void notifyValueChanged(final BluetoothDevice device, final byte[] value) {
// Keep a reference to the value callback, as it may change during execution
final DataReceivedCallback valueCallback = this.valueCallback;
// With no value callback there is no need for any merging
if (valueCallback == null) {
return;
}
if (dataMerger == null) {
valueCallback.onDataReceived(device, new Data(value));
} else {
if (progressCallback != null)
progressCallback.onPacketReceived(device, value, count);
if (buffer == null)
buffer = new DataStream();
if (dataMerger.merge(buffer, value, count++)) {
valueCallback.onDataReceived(device, buffer.toData());
buffer = null;
count = 0;
} // else
// wait for more packets to be merged
}
}
boolean hasMore() {
return count > 0;
}
@Nullable
Request getTrigger() {
return trigger;
}
boolean isTriggerPending() {
return triggerStatus == NOT_STARTED;
}
boolean isTriggerCompleteOrNull() {
return triggerStatus != STARTED;
}
}

View File

@@ -0,0 +1,282 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import java.util.Arrays;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.annotation.WriteType;
import no.nordicsemi.android.ble.callback.BeforeCallback;
import no.nordicsemi.android.ble.callback.DataSentCallback;
import no.nordicsemi.android.ble.callback.FailCallback;
import no.nordicsemi.android.ble.callback.InvalidRequestCallback;
import no.nordicsemi.android.ble.callback.SuccessCallback;
import no.nordicsemi.android.ble.callback.WriteProgressCallback;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.ble.data.DataSplitter;
import no.nordicsemi.android.ble.data.DefaultMtuSplitter;
@SuppressWarnings({"unused", "WeakerAccess"})
public final class WriteRequest extends SimpleValueRequest<DataSentCallback> implements Operation {
private final static DataSplitter MTU_SPLITTER = new DefaultMtuSplitter();
private WriteProgressCallback progressCallback;
private DataSplitter dataSplitter;
private final byte[] data;
private final int writeType;
private byte[] currentChunk;
private byte[] nextChunk;
private int count = 0;
private boolean complete = false;
WriteRequest(@NonNull final Type type) {
this(type, null);
}
WriteRequest(@NonNull final Type type, @Nullable final BluetoothGattCharacteristic characteristic) {
super(type, characteristic);
// not used:
this.data = null;
this.writeType = 0;
// getData(int) isn't called on enabling and disabling notifications/indications.
this.complete = true;
}
WriteRequest(@NonNull final Type type, @Nullable final BluetoothGattCharacteristic characteristic,
@Nullable final byte[] data,
@IntRange(from = 0) final int offset, @IntRange(from = 0) final int length,
@WriteType final int writeType) {
super(type, characteristic);
this.data = copy(data, offset, length);
this.writeType = writeType;
}
WriteRequest(@NonNull final Type type, @Nullable final BluetoothGattDescriptor descriptor,
@Nullable final byte[] data,
@IntRange(from = 0) final int offset, @IntRange(from = 0) final int length) {
super(type, descriptor);
this.data = copy(data, offset, length);
this.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
}
@NonNull
@Override
WriteRequest setManager(@NonNull final BleManager manager) {
super.setManager(manager);
return this;
}
@Override
@NonNull
public WriteRequest done(@NonNull final SuccessCallback callback) {
super.done(callback);
return this;
}
@Override
@NonNull
public WriteRequest fail(@NonNull final FailCallback callback) {
super.fail(callback);
return this;
}
@NonNull
@Override
public WriteRequest invalid(@NonNull final InvalidRequestCallback callback) {
super.invalid(callback);
return this;
}
@Override
@NonNull
public WriteRequest before(@NonNull final BeforeCallback callback) {
super.before(callback);
return this;
}
@Override
@NonNull
public WriteRequest with(@NonNull final DataSentCallback callback) {
super.with(callback);
return this;
}
/**
* Adds a splitter that will be used to cut given data into multiple packets.
* The splitter may modify each packet if necessary, i.e. add a flag indicating first packet,
* continuation or the last packet.
*
* @param splitter an implementation of a splitter.
* @return The request.
* @see #split()
*/
@NonNull
public WriteRequest split(@NonNull final DataSplitter splitter) {
this.dataSplitter = splitter;
this.progressCallback = null;
return this;
}
/**
* Adds a splitter that will be used to cut given data into multiple packets.
* The splitter may modify each packet if necessary, i.e. add a flag indicating first packet,
* continuation or the last packet.
*
* @param splitter an implementation of a splitter.
* @param callback the progress callback that will be notified each time a packet was sent.
* @return The request.
* @see #split()
*/
@NonNull
public WriteRequest split(@NonNull final DataSplitter splitter,
@NonNull final WriteProgressCallback callback) {
this.dataSplitter = splitter;
this.progressCallback = callback;
return this;
}
/**
* Adds a default MTU splitter that will be used to cut given data into at-most MTU-3
* bytes long packets.
*
* @return The request.
*/
@NonNull
public WriteRequest split() {
this.dataSplitter = MTU_SPLITTER;
this.progressCallback = null;
return this;
}
/**
* Adds a default MTU splitter that will be used to cut given data into at-most MTU-3
* bytes long packets.
*
* @param callback the progress callback that will be notified each time a packet was sent.
* @return The request.
*/
@NonNull
public WriteRequest split(@NonNull final WriteProgressCallback callback) {
this.dataSplitter = MTU_SPLITTER;
this.progressCallback = callback;
return this;
}
/**
* This method makes sure the data sent will be split to at-most MTU-3 bytes long packets.
* This is because Long Write does not work with Reliable Write.
*/
void forceSplit() {
if (dataSplitter == null)
split();
}
/**
* Returns the next chunk to be sent. If data splitter was not set the date returned may
* be longer than MTU. Android will try to send them using Long Write sub-procedure if
* write type is {@link BluetoothGattCharacteristic#WRITE_TYPE_DEFAULT}. Other write types
* will cause the data to be truncated.
*
* @param mtu the current MTU.
* @return The next bytes to be sent.
*/
byte[] getData(@IntRange(from = 23, to = 517) final int mtu) {
if (dataSplitter == null || data == null) {
complete = true;
return currentChunk = data;
}
// Write Request and Write Command require 3 bytes for handler and op code.
// Write Signed requires 12 bytes, as the signature is sent.
final int maxLength = writeType != BluetoothGattCharacteristic.WRITE_TYPE_SIGNED ?
mtu - 3 : mtu - 12;
byte[] chunk = nextChunk;
// Get the first chunk.
if (chunk == null) {
chunk = dataSplitter.chunk(data, count, maxLength);
}
// If there's something to send, check if there are any more packets to be sent later.
if (chunk != null) {
nextChunk = dataSplitter.chunk(data, count + 1, maxLength);
}
// If there's no next packet left, we are done.
if (nextChunk == null) {
complete = true;
}
return currentChunk = chunk;
}
/**
* Method called when packet has been sent and confirmed (when Write With Response was used),
* or added to local outgoing buffer (when Write Without Response was used).
*
* @param device the target device.
* @param data the data received in the
* {@link android.bluetooth.BluetoothGattCallback#onCharacteristicWrite(BluetoothGatt, BluetoothGattCharacteristic, int)}.
* @return True, if the data received are equal to data sent.
*/
boolean notifyPacketSent(@NonNull final BluetoothDevice device, @Nullable final byte[] data) {
if (progressCallback != null)
progressCallback.onPacketSent(device, data, count);
count++;
if (complete && valueCallback != null)
valueCallback.onDataSent(device, new Data(WriteRequest.this.data));
return Arrays.equals(data, currentChunk);
}
/**
* Returns whether there are more bytes to be sent from this Write Request.
* @return True if not all data were sent, false if the request is complete.
*/
boolean hasMore() {
return !complete;
}
/**
* Returns the write type that should be used to send the data.
* @return The write type.
*/
@WriteType
int getWriteType() {
return writeType;
}
private static byte[] copy(@Nullable final byte[] value,
@IntRange(from = 0) final int offset,
@IntRange(from = 0) final int length) {
if (value == null || offset > value.length)
return null;
final int maxLength = Math.min(value.length - offset, length);
final byte[] copy = new byte[maxLength];
System.arraycopy(value, offset, copy, 0, maxLength);
return copy;
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import androidx.annotation.IntDef;
import no.nordicsemi.android.ble.ConnectionPriorityRequest;
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
ConnectionPriorityRequest.CONNECTION_PRIORITY_BALANCED,
ConnectionPriorityRequest.CONNECTION_PRIORITY_HIGH,
ConnectionPriorityRequest.CONNECTION_PRIORITY_LOW_POWER
})
public @interface ConnectionPriority {}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.annotation;
import android.bluetooth.BluetoothProfile;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import androidx.annotation.IntDef;
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
BluetoothProfile.STATE_DISCONNECTED,
BluetoothProfile.STATE_CONNECTING,
BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_DISCONNECTING,
})
public @interface ConnectionState {}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import androidx.annotation.IntDef;
import no.nordicsemi.android.ble.PhyRequest;
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {
PhyRequest.PHY_LE_1M_MASK,
PhyRequest.PHY_LE_2M_MASK,
PhyRequest.PHY_LE_CODED_MASK
})
public @interface PhyMask {}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import androidx.annotation.IntDef;
import no.nordicsemi.android.ble.PhyRequest;
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
PhyRequest.PHY_OPTION_NO_PREFERRED,
PhyRequest.PHY_OPTION_S2,
PhyRequest.PHY_OPTION_S8
})
public @interface PhyOption {}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import androidx.annotation.IntDef;
import no.nordicsemi.android.ble.callback.PhyCallback;
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
PhyCallback.PHY_LE_1M,
PhyCallback.PHY_LE_2M,
PhyCallback.PHY_LE_CODED
})
public @interface PhyValue {}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.annotation;
import android.bluetooth.BluetoothGattCharacteristic;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import androidx.annotation.IntDef;
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT,
BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE,
BluetoothGattCharacteristic.WRITE_TYPE_SIGNED,
})
public @interface WriteType {}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
public interface BeforeCallback {
/**
* A callback invoked when the request is about to start.
*
* @param device the target device.
*/
void onRequestStarted(@NonNull final BluetoothDevice device);
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
/**
* The connection parameters for a Bluetooth LE connection is a set of parameters that determine
* when and how the Central and a Peripheral in a link transmits data.
* It is always the Central that actually sets the connection parameters used, but the Peripheral
* can send a so-called Connection Parameter Update Request, that the Central can then accept or reject.
* <p>
* On Android, requesting connection parameters is available since Android Lollipop using
* {@link android.bluetooth.BluetoothGatt#requestConnectionPriority(int)}. There are 3 options
* available: {@link android.bluetooth.BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER},
* {@link android.bluetooth.BluetoothGatt#CONNECTION_PRIORITY_BALANCED} and
* {@link android.bluetooth.BluetoothGatt#CONNECTION_PRIORITY_HIGH}. See
* {@link no.nordicsemi.android.ble.Request#newConnectionPriorityRequest(int)} for details.
* <p>
* Until Android 8.0 Oreo, there was no callback indicating whether the change has succeeded,
* or not. Also, when a Central or Peripheral requested connection parameters change without
* explicit calling of this method, the application was not aware of it.
* Android Oreo added a hidden callback to {@link android.bluetooth.BluetoothGattCallback}
* notifying about connection parameters change. Those values will be reported with this callback.
*/
public interface ConnectionPriorityCallback {
/**
* Callback indicating the connection parameters were updated. Works on Android 8.0 Oreo or newer.
*
* @param device the target device.
* @param interval Connection interval used on this connection, 1.25ms unit. Valid range is from
* 6 (7.5ms) to 3200 (4000ms).
* @param latency Slave latency for the connection in number of connection events. Valid range
* is from 0 to 499.
* @param timeout Supervision timeout for this connection, in 10ms unit. Valid range is from 10
* (100 ms = 0.1s) to 3200 (32s).
*/
void onConnectionUpdated(@NonNull final BluetoothDevice device,
@IntRange(from = 6, to = 3200) final int interval,
@IntRange(from = 0, to = 499) final int latency,
@IntRange(from = 10, to = 3200) final int timeout);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.ble.data.DataMerger;
public interface DataReceivedCallback {
/**
* Callback received each time the value was read or has changed using
* notifications or indications.
*
* @param device the target device.
* @param data the data received. If the {@link DataMerger} was used,
* this contains the merged result.
*/
void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data);
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.ble.data.DataSplitter;
public interface DataSentCallback {
/**
* Callback received each time the value was written to a characteristic or descriptor.
*
* @param device the target device.
* @param data the data sent. If the {@link DataSplitter} was used, this contains the full data.
*/
void onDataSent(@NonNull final BluetoothDevice device, @NonNull final Data data);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
public interface FailCallback {
int REASON_DEVICE_DISCONNECTED = -1;
int REASON_DEVICE_NOT_SUPPORTED = -2;
int REASON_NULL_ATTRIBUTE = -3;
int REASON_REQUEST_FAILED = -4;
int REASON_TIMEOUT = -5;
int REASON_VALIDATION = -6;
int REASON_BLUETOOTH_DISABLED = -100;
/**
* A callback invoked when the request has failed with status other than
* {@link android.bluetooth.BluetoothGatt#GATT_SUCCESS}.
*
* @param device target device.
* @param status error status code, one of BluetoothGatt#GATT_* constants or
* {@link #REASON_DEVICE_DISCONNECTED}, {@link #REASON_TIMEOUT},
* {@link #REASON_DEVICE_NOT_SUPPORTED} (only for Connect request),
* {@link #REASON_BLUETOOTH_DISABLED}, {@link #REASON_NULL_ATTRIBUTE},
* {@link #REASON_VALIDATION} or {@link #REASON_REQUEST_FAILED} (for other reason).
*/
void onRequestFailed(@NonNull final BluetoothDevice device, final int status);
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
public interface InvalidRequestCallback {
/**
* A callback invoked when the request was invalid, for example when was called before the
* device was connected.
*/
void onInvalidRequest();
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
public interface MtuCallback {
/**
* Method called when the MTU request has finished with success. The MTU value may
* be different than requested one. The maximum packet size is 3 bytes less then MTU.
*
* @param device the target device.
* @param mtu the new MTU (Maximum Transfer Unit).
*/
void onMtuChanged(@NonNull final BluetoothDevice device,
@IntRange(from = 23, to = 517) final int mtu);
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.annotation.PhyValue;
@SuppressWarnings("unused")
public interface PhyCallback {
/**
* Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or
* connection.
*/
int PHY_LE_1M = 1;
/**
* Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or
* connection.
*/
int PHY_LE_2M = 2;
/**
* Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning
* or connection.
*/
int PHY_LE_CODED = 3;
/**
* Method called when the PHY value has changed or was read.
*
* @param device the target device.
* @param txPhy the transmitter PHY in use. One of {@link #PHY_LE_1M},
* {@link #PHY_LE_2M}, and {@link #PHY_LE_CODED}.
* @param rxPhy the receiver PHY in use. One of {@link #PHY_LE_1M},
* {@link #PHY_LE_2M}, and {@link #PHY_LE_CODED}.
*/
void onPhyChanged(@NonNull final BluetoothDevice device,
@PhyValue final int txPhy, @PhyValue final int rxPhy);
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.data.DataMerger;
public interface ReadProgressCallback {
/**
* Callback received each time the value was read or has changed using notifications or
* indications when {@link DataMerger} was used.
*
* @param device the target device.
* @param data the last packet received.
* @param index the index of a packet that will be merged into a single Data.
*/
void onPacketReceived(@NonNull final BluetoothDevice device,
@Nullable final byte[] data, @IntRange(from = 0) final int index);
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
public interface RssiCallback {
/**
* Method called when the RSSI value has been read.
*
* @param device the target device.
* @param rssi the current RSSI value, in dBm.
*/
void onRssiRead(@NonNull final BluetoothDevice device,
@IntRange(from = -128, to = 20) final int rssi);
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
public interface SuccessCallback {
/**
* A callback invoked when the request completed successfully.
*
* @param device the target device.
*/
void onRequestCompleted(@NonNull final BluetoothDevice device);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.data.DataSplitter;
public interface WriteProgressCallback {
/**
* Callback called each time a packet has been sent when {@link DataSplitter} was used.
*
* @param device the target device.
* @param data the last packet sent.
* @param index the index of a packet that the initial Data was cut into.
*/
void onPacketSent(@NonNull final BluetoothDevice device,
@Nullable final byte[] data, @IntRange(from = 0) final int index);
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback.profile;
import android.bluetooth.BluetoothDevice;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.callback.DataReceivedCallback;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.ble.data.DataMerger;
@SuppressWarnings("unused")
public interface ProfileDataCallback extends DataReceivedCallback {
/**
* Callback called when the data received do not conform to required scheme.
* @param device the target device.
* @param data the data received. If the {@link DataMerger} was used, this contains the
* merged result.
*/
default void onInvalidDataReceived(@NonNull final BluetoothDevice device,
@NonNull final Data data) {
// ignore
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.callback.profile;
import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.ble.response.ReadResponse;
/**
* A response type for read requests with basic validation check.
* When read was requested as a synchronous call the {@link #isValid()} can be used to
* check if data were parsed successfully. Parsing method must call super methods on
* both {@link #onDataReceived(BluetoothDevice, Data)} and
* {@link #onInvalidDataReceived(BluetoothDevice, Data)} in order to make getters working properly.
* <p>
* Check out profile data callbacks in the Android BLE Common Library for example of usage.
*/
@SuppressWarnings({"unused", "WeakerAccess"})
public class ProfileReadResponse extends ReadResponse implements ProfileDataCallback, Parcelable {
private boolean valid = true;
public ProfileReadResponse() {
// empty
}
@Override
public void onInvalidDataReceived(@NonNull final BluetoothDevice device,
@NonNull final Data data) {
this.valid = false;
}
/**
* Returns true if {@link #onInvalidDataReceived(BluetoothDevice, Data)} wasn't called.
*
* @return True, if profile data were valid, false if parsing error occurred.
*/
public boolean isValid() {
return valid;
}
// Parcelable
protected ProfileReadResponse(final Parcel in) {
super(in);
valid = in.readByte() != 0;
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
super.writeToParcel(dest, flags);
dest.writeByte((byte) (valid ? 1 : 0));
}
public static final Creator<ProfileReadResponse> CREATOR = new Creator<ProfileReadResponse>() {
@Override
public ProfileReadResponse createFromParcel(final Parcel in) {
return new ProfileReadResponse(in);
}
@Override
public ProfileReadResponse[] newArray(final int size) {
return new ProfileReadResponse[size];
}
};
}

View File

@@ -0,0 +1,470 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.data;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@SuppressWarnings({"WeakerAccess", "unused", "UnusedReturnValue"})
public class Data implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
FORMAT_UINT8,
FORMAT_UINT16,
FORMAT_UINT24,
FORMAT_UINT32,
FORMAT_SINT8,
FORMAT_SINT16,
FORMAT_SINT24,
FORMAT_SINT32,
FORMAT_FLOAT,
FORMAT_SFLOAT
})
public @interface ValueFormat {}
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
FORMAT_UINT8,
FORMAT_UINT16,
FORMAT_UINT24,
FORMAT_UINT32,
FORMAT_SINT8,
FORMAT_SINT16,
FORMAT_SINT24,
FORMAT_SINT32
})
public @interface IntFormat {}
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
FORMAT_UINT32,
FORMAT_SINT32
})
public @interface LongFormat {}
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
FORMAT_FLOAT,
FORMAT_SFLOAT
})
public @interface FloatFormat {}
private static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
/**
* Data value format type uint8
*/
public final static int FORMAT_UINT8 = 0x11;
/**
* Data value format type uint16
*/
public final static int FORMAT_UINT16 = 0x12;
/**
* Data value format type uint24
*/
public final static int FORMAT_UINT24 = 0x13;
/**
* Data value format type uint32
*/
public final static int FORMAT_UINT32 = 0x14;
/**
* Data value format type sint8
*/
public final static int FORMAT_SINT8 = 0x21;
/**
* Data value format type sint16
*/
public final static int FORMAT_SINT16 = 0x22;
/**
* Data value format type sint24
*/
public final static int FORMAT_SINT24 = 0x23;
/**
* Data value format type sint32
*/
public final static int FORMAT_SINT32 = 0x24;
/**
* Data value format type sfloat (16-bit float, IEEE-11073)
*/
public final static int FORMAT_SFLOAT = 0x32;
/**
* Data value format type float (32-bit float, IEEE-11073)
*/
public final static int FORMAT_FLOAT = 0x34;
protected byte[] mValue;
public Data() {
this.mValue = null;
}
public Data(@Nullable final byte[] value) {
this.mValue = value;
}
public static Data from(@NonNull final String value) {
return new Data(value.getBytes()); // UTF-8
}
public static Data from(@NonNull final BluetoothGattCharacteristic characteristic) {
return new Data(characteristic.getValue());
}
public static Data from(@NonNull final BluetoothGattDescriptor descriptor) {
return new Data(descriptor.getValue());
}
public static Data opCode(final byte opCode) {
return new Data(new byte[] { opCode });
}
public static Data opCode(final byte opCode, final byte parameter) {
return new Data(new byte[] { opCode, parameter });
}
/**
* Returns the underlying byte array.
*
* @return Data received.
*/
@Nullable
public byte[] getValue() {
return mValue;
}
/**
* Return the stored value of this characteristic.
* <p>See {@link #getValue} for details.
*
* @param offset Offset at which the string value can be found.
* @return Cached value of the characteristic
*/
@Nullable
public String getStringValue(@IntRange(from = 0) final int offset) {
if (mValue == null || offset > mValue.length)
return null;
final byte[] strBytes = new byte[mValue.length - offset];
for (int i = 0; i != (mValue.length - offset); ++i)
strBytes[i] = mValue[offset+i];
return new String(strBytes);
}
/**
* Returns the size of underlying byte array.
*
* @return Length of the data.
*/
public int size() {
return mValue != null ? mValue.length : 0;
}
@Override
public String toString() {
if (size() == 0)
return "";
final char[] out = new char[mValue.length * 3 - 1];
for (int j = 0; j < mValue.length; j++) {
int v = mValue[j] & 0xFF;
out[j * 3] = HEX_ARRAY[v >>> 4];
out[j * 3 + 1] = HEX_ARRAY[v & 0x0F];
if (j != mValue.length - 1)
out[j * 3 + 2] = '-';
}
return "(0x) " + new String(out);
}
/**
* Returns a byte at the given offset from the byte array.
*
* @param offset Offset at which the byte value can be found.
* @return Cached value or null of offset exceeds value size.
*/
@Nullable
public Byte getByte(@IntRange(from = 0) final int offset) {
if (offset + 1 > size()) return null;
return mValue[offset];
}
/**
* Returns an integer value from the byte array.
* <p>
* <p>The formatType parameter determines how the value
* is to be interpreted. For example, setting formatType to
* {@link #FORMAT_UINT16} specifies that the first two bytes of the
* value at the given offset are interpreted to generate the
* return value.
*
* @param formatType The format type used to interpret the value.
* @param offset Offset at which the integer value can be found.
* @return Cached value or null of offset exceeds value size.
*/
@Nullable
public Integer getIntValue(@IntFormat final int formatType,
@IntRange(from = 0) final int offset) {
if ((offset + getTypeLen(formatType)) > size()) return null;
switch (formatType) {
case FORMAT_UINT8:
return unsignedByteToInt(mValue[offset]);
case FORMAT_UINT16:
return unsignedBytesToInt(mValue[offset], mValue[offset + 1]);
case FORMAT_UINT24:
return unsignedBytesToInt(mValue[offset], mValue[offset + 1],
mValue[offset + 2], (byte) 0);
case FORMAT_UINT32:
return unsignedBytesToInt(mValue[offset], mValue[offset + 1],
mValue[offset + 2], mValue[offset + 3]);
case FORMAT_SINT8:
return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8);
case FORMAT_SINT16:
return unsignedToSigned(unsignedBytesToInt(mValue[offset],
mValue[offset + 1]), 16);
case FORMAT_SINT24:
return unsignedToSigned(unsignedBytesToInt(mValue[offset],
mValue[offset + 1], mValue[offset + 2], (byte) 0), 24);
case FORMAT_SINT32:
return unsignedToSigned(unsignedBytesToInt(mValue[offset],
mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]), 32);
}
return null;
}
/**
* Returns a long value from the byte array.
* <p>Only {@link #FORMAT_UINT32} and {@link #FORMAT_SINT32} are supported.
* <p>The formatType parameter determines how the value
* is to be interpreted. For example, setting formatType to
* {@link #FORMAT_UINT32} specifies that the first four bytes of the
* value at the given offset are interpreted to generate the
* return value.
*
* @param formatType The format type used to interpret the value.
* @param offset Offset at which the integer value can be found.
* @return Cached value or null of offset exceeds value size.
*/
@Nullable
public Long getLongValue(@LongFormat final int formatType,
@IntRange(from = 0) final int offset) {
if ((offset + getTypeLen(formatType)) > size()) return null;
switch (formatType) {
case FORMAT_SINT32:
return unsignedToSigned(unsignedBytesToLong(mValue[offset],
mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]), 32);
case FORMAT_UINT32:
return unsignedBytesToLong(mValue[offset], mValue[offset + 1],
mValue[offset + 2], mValue[offset + 3]);
}
return null;
}
/**
* Returns an float value from the given byte array.
*
* @param formatType The format type used to interpret the value.
* @param offset Offset at which the float value can be found.
* @return Cached value at a given offset or null if the requested offset exceeds the value size.
*/
@Nullable
public Float getFloatValue(@FloatFormat final int formatType,
@IntRange(from = 0) final int offset) {
if ((offset + getTypeLen(formatType)) > size()) return null;
switch (formatType) {
case FORMAT_SFLOAT:
if (mValue[offset + 1] == 0x07 && mValue[offset] == (byte) 0xFE)
return Float.POSITIVE_INFINITY;
if ((mValue[offset + 1] == 0x07 && mValue[offset] == (byte) 0xFF) ||
(mValue[offset + 1] == 0x08 && mValue[offset] == 0x00) ||
(mValue[offset + 1] == 0x08 && mValue[offset] == 0x01))
return Float.NaN;
if (mValue[offset + 1] == 0x08 && mValue[offset] == 0x02)
return Float.NEGATIVE_INFINITY;
return bytesToFloat(mValue[offset], mValue[offset + 1]);
case FORMAT_FLOAT:
if (mValue[offset + 3] == 0x00) {
if (mValue[offset + 2] == 0x7F && mValue[offset + 1] == (byte) 0xFF) {
if (mValue[offset] == (byte) 0xFE)
return Float.POSITIVE_INFINITY;
if (mValue[offset] == (byte) 0xFF)
return Float.NaN;
} else if (mValue[offset + 2] == (byte) 0x80 && mValue[offset + 1] == 0x00) {
if (mValue[offset] == 0x00 || mValue[offset] == 0x01)
return Float.NaN;
if (mValue[offset] == 0x02)
return Float.NEGATIVE_INFINITY;
}
}
return bytesToFloat(mValue[offset], mValue[offset + 1],
mValue[offset + 2], mValue[offset + 3]);
}
return null;
}
/**
* Returns the size of a give value type.
*/
public static int getTypeLen(@ValueFormat final int formatType) {
return formatType & 0xF;
}
/**
* Convert a signed byte to an unsigned int.
*/
private static int unsignedByteToInt(final byte b) {
return b & 0xFF;
}
/**
* Convert a signed byte to an unsigned int.
*/
private static long unsignedByteToLong(final byte b) {
return b & 0xFFL;
}
/**
* Convert signed bytes to a 16-bit unsigned int.
*/
private static int unsignedBytesToInt(final byte b0, final byte b1) {
return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8));
}
/**
* Convert signed bytes to a 32-bit unsigned int.
*/
private static int unsignedBytesToInt(final byte b0, final byte b1, final byte b2, final byte b3) {
return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8))
+ (unsignedByteToInt(b2) << 16) + (unsignedByteToInt(b3) << 24);
}
/**
* Convert signed bytes to a 32-bit unsigned long.
*/
private static long unsignedBytesToLong(final byte b0, final byte b1, final byte b2, final byte b3) {
return (unsignedByteToLong(b0) + (unsignedByteToLong(b1) << 8))
+ (unsignedByteToLong(b2) << 16) + (unsignedByteToLong(b3) << 24);
}
/**
* Convert signed bytes to a 16-bit short float value.
*/
private static float bytesToFloat(final byte b0, final byte b1) {
int mantissa = unsignedToSigned(unsignedByteToInt(b0)
+ ((unsignedByteToInt(b1) & 0x0F) << 8), 12);
int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4);
return (float) (mantissa * Math.pow(10, exponent));
}
/**
* Convert signed bytes to a 32-bit short float value.
*/
private static float bytesToFloat(final byte b0, final byte b1, final byte b2, final byte b3) {
int mantissa = unsignedToSigned(unsignedByteToInt(b0)
+ (unsignedByteToInt(b1) << 8)
+ (unsignedByteToInt(b2) << 16), 24);
return (float) (mantissa * Math.pow(10, b3));
}
/**
* Convert an unsigned integer value to a two's-complement encoded
* signed value.
*/
private static int unsignedToSigned(int unsigned, final int size) {
if ((unsigned & (1 << size - 1)) != 0) {
unsigned = -1 * ((1 << size - 1) - (unsigned & ((1 << size - 1) - 1)));
}
return unsigned;
}
/**
* Convert an unsigned long value to a two's-complement encoded
* signed value.
*/
private static long unsignedToSigned(long unsigned, final int size) {
if ((unsigned & (1 << size - 1)) != 0) {
unsigned = -1 * ((1 << size - 1) - (unsigned & ((1 << size - 1) - 1)));
}
return unsigned;
}
// Parcelable
protected Data(final Parcel in) {
mValue = in.createByteArray();
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeByteArray(mValue);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Data> CREATOR = new Creator<Data>() {
@Override
public Data createFromParcel(final Parcel in) {
return new Data(in);
}
@Override
public Data[] newArray(final int size) {
return new Data[size];
}
};
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.data;
import androidx.annotation.Nullable;
public interface DataFilter {
/**
* This method should return true if the packet matches the filter and should be processed
* by the request.
*
* @param lastPacket the packet received.
* @return True, if packet should be processed, false if it should be ignored.
*/
boolean filter(@Nullable final byte[] lastPacket);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.data;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public interface DataMerger {
/**
* This method should merge the last packet into the output message.
*
* @param output the stream for the output message, initially empty.
* @param lastPacket the data received in the last read/notify/indicate operation.
* @param index an index of the packet, 0-based (if you expect 3 packets, they will be
* called with indexes 0, 1, 2).
* @return True, if the message is complete, false if more data are expected.
*/
boolean merge(@NonNull final DataStream output,
@Nullable final byte[] lastPacket, @IntRange(from = 0) final int index);
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.data;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public interface DataSplitter {
/**
* The implementation should return a index'th byte array from given message,
* with at most maxLength size, or null if no bytes are left to be sent.
*
* @param message the full message to be chunk.
* @param index index of a packet, 0-based.
* @param maxLength maximum length of the returned packet. Equals to MTU-3.
* Use {@link no.nordicsemi.android.ble.BleManager#requestMtu(int)} to request
* higher MTU, or {@link no.nordicsemi.android.ble.BleManager#overrideMtu(int)}
* If the MTU change was initiated by the target device.
* @return The packet to be sent, or null, if the whole message was already split.
*/
@Nullable
byte[] chunk(@NonNull final byte[] message,
@IntRange(from = 0) final int index, @IntRange(from = 20) final int maxLength);
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.data;
import java.io.ByteArrayOutputStream;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@SuppressWarnings("WeakerAccess")
public class DataStream {
private final ByteArrayOutputStream buffer;
public DataStream() {
buffer = new ByteArrayOutputStream();
}
@SuppressWarnings("SimplifiableIfStatement")
public boolean write(@Nullable final byte[] data) {
if (data == null)
return false;
return write(data, 0, data.length);
}
public boolean write(@Nullable final byte[] data,
@IntRange(from = 0) final int offset, @IntRange(from = 0) final int length) {
if (data == null || data.length < offset)
return false;
final int len = Math.min(data.length - offset, length);
buffer.write(data, offset, len);
return true;
}
public boolean write(@Nullable final Data data) {
return data != null && write(data.getValue());
}
@IntRange(from = 0)
public int size() {
return buffer.size();
}
@NonNull
public byte[] toByteArray() {
return buffer.toByteArray();
}
@NonNull
public Data toData() {
return new Data(buffer.toByteArray());
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.data;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* Splits the message into at-most MTU-3 size packets.
*/
public final class DefaultMtuSplitter implements DataSplitter {
@Nullable
@Override
public byte[] chunk(@NonNull final byte[] message,
@IntRange(from = 0) final int index,
@IntRange(from = 20) final int maxLength) {
final int offset = index * maxLength;
final int length = Math.min(maxLength, message.length - offset);
if (length <= 0)
return null;
final byte[] data = new byte[length];
System.arraycopy(message, offset, data, 0, length);
return data;
}
}

View File

@@ -0,0 +1,409 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.data;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@SuppressWarnings({"unused", "SameParameterValue", "WeakerAccess", "UnusedReturnValue"})
public class MutableData extends Data {
// Values required to convert float to IEEE-11073 SFLOAT
private final static int SFLOAT_POSITIVE_INFINITY = 0x07FE;
private final static int SFLOAT_NAN = 0x07FF;
// private final static int SFLOAT_NOT_AT_THIS_RESOLUTION = 0x0800;
// private final static int SFLOAT_RESERVED_VALUE = 0x0801;
private final static int SFLOAT_NEGATIVE_INFINITY = 0x0802;
private final static int SFLOAT_MANTISSA_MAX = 0x07FD;
private final static int SFLOAT_EXPONENT_MAX = 7;
private final static int SFLOAT_EXPONENT_MIN = -8;
private final static float SFLOAT_MAX = 20450000000.0f;
private final static float SFLOAT_MIN = -SFLOAT_MAX;
private final static int SFLOAT_PRECISION = 10000;
// private final static float SFLOAT_EPSILON = 1e-8f;
// Values required to convert float to IEEE-11073 FLOAT
private final static int FLOAT_POSITIVE_INFINITY = 0x007FFFFE;
private final static int FLOAT_NAN = 0x007FFFFF;
// private final static int FLOAT_NOT_AT_THIS_RESOLUTION = 0x00800000;
// private final static int FLOAT_RESERVED_VALUE = 0x00800001;
private final static int FLOAT_NEGATIVE_INFINITY = 0x00800002;
private final static int FLOAT_MANTISSA_MAX = 0x007FFFFD;
private final static int FLOAT_EXPONENT_MAX = 127;
private final static int FLOAT_EXPONENT_MIN = -128;
private final static int FLOAT_PRECISION = 10000000;
// private final static float FLOAT_EPSILON = 1e-128f;
public MutableData() {
super();
}
public MutableData(@Nullable final byte[] data) {
super(data);
}
public static MutableData from(@NonNull final BluetoothGattCharacteristic characteristic) {
return new MutableData(characteristic.getValue());
}
public static MutableData from(@NonNull final BluetoothGattDescriptor descriptor) {
return new MutableData(descriptor.getValue());
}
/**
* Updates the locally stored value of this data.
*
* @param value New value
* @return true if the locally stored value has been set, false if the
* requested value could not be stored locally.
*/
public boolean setValue(@Nullable final byte[] value) {
mValue = value;
return true;
}
/**
* Updates the byte at offset position.
*
* @param value Byte to set
* @param offset The offset
* @return true if the locally stored value has been set, false if the
* requested value could not be stored locally.
*/
public boolean setByte(final int value, @IntRange(from = 0) final int offset) {
final int len = offset + 1;
if (mValue == null) mValue = new byte[len];
if (len > mValue.length) return false;
mValue[offset] = (byte) value;
return true;
}
/**
* Set the locally stored value of this data.
* <p>See {@link #setValue(byte[])} for details.
*
* @param value New value for this data
* @param formatType Integer format type used to transform the value parameter
* @param offset Offset at which the value should be placed
* @return true if the locally stored value has been set
*/
public boolean setValue(int value, @IntFormat int formatType, @IntRange(from = 0) int offset) {
final int len = offset + getTypeLen(formatType);
if (mValue == null) mValue = new byte[len];
if (len > mValue.length) return false;
switch (formatType) {
case FORMAT_SINT8:
value = intToSignedBits(value, 8);
// Fall-through intended
case FORMAT_UINT8:
mValue[offset] = (byte) (value & 0xFF);
break;
case FORMAT_SINT16:
value = intToSignedBits(value, 16);
// Fall-through intended
case FORMAT_UINT16:
mValue[offset++] = (byte) (value & 0xFF);
mValue[offset] = (byte) ((value >> 8) & 0xFF);
break;
case FORMAT_SINT24:
value = intToSignedBits(value, 24);
// Fall-through intended
case FORMAT_UINT24:
mValue[offset++] = (byte) (value & 0xFF);
mValue[offset++] = (byte) ((value >> 8) & 0xFF);
mValue[offset] = (byte) ((value >> 16) & 0xFF);
break;
case FORMAT_SINT32:
value = intToSignedBits(value, 32);
// Fall-through intended
case FORMAT_UINT32:
mValue[offset++] = (byte) (value & 0xFF);
mValue[offset++] = (byte) ((value >> 8) & 0xFF);
mValue[offset++] = (byte) ((value >> 16) & 0xFF);
mValue[offset] = (byte) ((value >> 24) & 0xFF);
break;
default:
return false;
}
return true;
}
/**
* Set the locally stored value of this data.
* <p>See {@link #setValue(byte[])} for details.
*
* @param mantissa Mantissa for this data
* @param exponent Exponent value for this data
* @param formatType Float format type used to transform the value parameter
* @param offset Offset at which the value should be placed
* @return true if the locally stored value has been set
*/
public boolean setValue(int mantissa, int exponent,
@FloatFormat int formatType, @IntRange(from = 0) int offset) {
final int len = offset + getTypeLen(formatType);
if (mValue == null) mValue = new byte[len];
if (len > mValue.length) return false;
switch (formatType) {
case FORMAT_SFLOAT:
mantissa = intToSignedBits(mantissa, 12);
exponent = intToSignedBits(exponent, 4);
mValue[offset++] = (byte) (mantissa & 0xFF);
mValue[offset] = (byte) ((mantissa >> 8) & 0x0F);
mValue[offset] += (byte) ((exponent & 0x0F) << 4);
break;
case FORMAT_FLOAT:
mantissa = intToSignedBits(mantissa, 24);
exponent = intToSignedBits(exponent, 8);
mValue[offset++] = (byte) (mantissa & 0xFF);
mValue[offset++] = (byte) ((mantissa >> 8) & 0xFF);
mValue[offset++] = (byte) ((mantissa >> 16) & 0xFF);
mValue[offset] += (byte) (exponent & 0xFF);
break;
default:
return false;
}
return true;
}
/**
* Set the locally stored value of this data.
* <p>See {@link #setValue(byte[])} for details.
*
* @param value New value for this data. This allows to send {@link #FORMAT_UINT32}.
* @param formatType Integer format type used to transform the value parameter
* @param offset Offset at which the value should be placed
* @return true if the locally stored value has been set
*/
public boolean setValue(long value, @LongFormat int formatType, @IntRange(from = 0) int offset) {
final int len = offset + getTypeLen(formatType);
if (mValue == null) mValue = new byte[len];
if (len > mValue.length) return false;
switch (formatType) {
case FORMAT_SINT32:
value = longToSignedBits(value, 32);
// Fall-through intended
case FORMAT_UINT32:
mValue[offset++] = (byte) (value & 0xFF);
mValue[offset++] = (byte) ((value >> 8) & 0xFF);
mValue[offset++] = (byte) ((value >> 16) & 0xFF);
mValue[offset] = (byte) ((value >> 24) & 0xFF);
break;
default:
return false;
}
return true;
}
/**
* Set the locally stored value of this data.
* <p>See {@link #setValue(byte[])} for details.
*
* @param value Float value to be written
* @param formatType Float format type used to transform the value parameter
* @param offset Offset at which the value should be placed
* @return true if the locally stored value has been set
*/
public boolean setValue(float value,
@FloatFormat int formatType, @IntRange(from = 0) int offset) {
final int len = offset + getTypeLen(formatType);
if (mValue == null) mValue = new byte[len];
if (len > mValue.length) return false;
switch (formatType) {
case FORMAT_SFLOAT:
final int sfloatAsInt = sfloatToInt(value);
mValue[offset++] = (byte) (sfloatAsInt & 0xFF);
mValue[offset] = (byte) ((sfloatAsInt >> 8) & 0xFF);
break;
case FORMAT_FLOAT:
final int floatAsInt = floatToInt(value);
mValue[offset++] = (byte) (floatAsInt & 0xFF);
mValue[offset++] = (byte) ((floatAsInt >> 8) & 0xFF);
mValue[offset++] = (byte) ((floatAsInt >> 16) & 0xFF);
mValue[offset] += (byte) ((floatAsInt >> 24) & 0xFF);
break;
default:
return false;
}
return true;
}
/**
* Converts float to SFLOAT IEEE 11073 format as UINT16, rounding up or down.
* See: https://github.com/signove/antidote/blob/master/src/util/bytelib.c
*
* @param value the value to be converted.
* @return given float as UINT16 in IEEE 11073 format.
*/
private static int sfloatToInt(final float value) {
if (Float.isNaN(value)) {
return SFLOAT_NAN;
} else if (value > SFLOAT_MAX) {
return SFLOAT_POSITIVE_INFINITY;
} else if (value < SFLOAT_MIN) {
return SFLOAT_NEGATIVE_INFINITY;
}
int sign = value >= 0 ? +1 : -1;
float mantissa = Math.abs(value);
int exponent = 0; // Note: 10**x exponent, not 2**x
// scale up if number is too big
while (mantissa > SFLOAT_MANTISSA_MAX) {
mantissa /= 10.0f;
++exponent;
if (exponent > SFLOAT_EXPONENT_MAX) {
// argh, should not happen
if (sign > 0) {
return SFLOAT_POSITIVE_INFINITY;
} else {
return SFLOAT_NEGATIVE_INFINITY;
}
}
}
// scale down if number is too small
while (mantissa < 1) {
mantissa *= 10;
--exponent;
if (exponent < SFLOAT_EXPONENT_MIN) {
// argh, should not happen
return 0;
}
}
// scale down if number needs more precision
double smantissa = Math.round(mantissa * SFLOAT_PRECISION);
double rmantissa = Math.round(mantissa) * SFLOAT_PRECISION;
double mdiff = Math.abs(smantissa - rmantissa);
while (mdiff > 0.5 && exponent > SFLOAT_EXPONENT_MIN &&
(mantissa * 10) <= SFLOAT_MANTISSA_MAX) {
mantissa *= 10;
--exponent;
smantissa = Math.round(mantissa * SFLOAT_PRECISION);
rmantissa = Math.round(mantissa) * SFLOAT_PRECISION;
mdiff = Math.abs(smantissa - rmantissa);
}
int int_mantissa = Math.round(sign * mantissa);
return ((exponent & 0xF) << 12) | (int_mantissa & 0xFFF);
}
/**
* Converts float to FLOAT IEEE 11073 format as UINT32, rounding up or down.
* See: https://github.com/signove/antidote/blob/master/src/util/bytelib.c
*
* @param value the value to be converted.
* @return given float as UINT32 in IEEE 11073 format.
*/
private static int floatToInt(final float value) {
if (Float.isNaN(value)) {
return FLOAT_NAN;
} else if (value == Float.POSITIVE_INFINITY) {
return FLOAT_POSITIVE_INFINITY;
} else if (value == Float.NEGATIVE_INFINITY) {
return FLOAT_NEGATIVE_INFINITY;
}
int sign = value >= 0 ? +1 : -1;
float mantissa = Math.abs(value);
int exponent = 0; // Note: 10**x exponent, not 2**x
// scale up if number is too big
while (mantissa > FLOAT_MANTISSA_MAX) {
mantissa /= 10.0f;
++exponent;
if (exponent > FLOAT_EXPONENT_MAX) {
// argh, should not happen
if (sign > 0) {
return FLOAT_POSITIVE_INFINITY;
} else {
return FLOAT_NEGATIVE_INFINITY;
}
}
}
// scale down if number is too small
while (mantissa < 1) {
mantissa *= 10;
--exponent;
if (exponent < FLOAT_EXPONENT_MIN) {
// argh, should not happen
return 0;
}
}
// scale down if number needs more precision
double smantissa = Math.round(mantissa * FLOAT_PRECISION);
double rmantissa = Math.round(mantissa) * FLOAT_PRECISION;
double mdiff = Math.abs(smantissa - rmantissa);
while (mdiff > 0.5 && exponent > FLOAT_EXPONENT_MIN &&
(mantissa * 10) <= FLOAT_MANTISSA_MAX) {
mantissa *= 10;
--exponent;
smantissa = Math.round(mantissa * FLOAT_PRECISION);
rmantissa = Math.round(mantissa) * FLOAT_PRECISION;
mdiff = Math.abs(smantissa - rmantissa);
}
int int_mantissa = Math.round(sign * mantissa);
return (exponent << 24) | (int_mantissa & 0xFFFFFF);
}
/**
* Convert an integer into the signed bits of a given length.
*/
private static int intToSignedBits(int i, int size) {
if (i < 0) {
i = (1 << size - 1) + (i & ((1 << size - 1) - 1));
}
return i;
}
/**
* Convert a long into the signed bits of a given length.
*/
private static long longToSignedBits(long i, int size) {
if (i < 0) {
i = (1L << size - 1) + (i & ((1L << size - 1) - 1));
}
return i;
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.error;
import android.bluetooth.BluetoothGatt;
/**
* Parses the GATT and HCI errors to human readable strings.
* <p>
* See: <a href="https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/stack/include/gatt_api.h">gatt_api.h</a> for details.<br>
* See also: <a href="https://android.googlesource.com/platform/external/libnfc-nci/+/master/src/include/hcidefs.h#447">hcidefs.h</a> for other possible HCI errors.
*/
@SuppressWarnings("WeakerAccess")
public class GattError {
public static final int GATT_SUCCESS = BluetoothGatt.GATT_SUCCESS;
public static final int GATT_CONN_L2C_FAILURE = 0x01;
public static final int GATT_CONN_TIMEOUT = 0x08;
public static final int GATT_CONN_TERMINATE_PEER_USER = 0x13;
public static final int GATT_CONN_TERMINATE_LOCAL_HOST = 0x16;
public static final int GATT_CONN_FAIL_ESTABLISH = 0x3E;
public static final int GATT_CONN_LMP_TIMEOUT = 0x22;
public static final int GATT_CONN_CANCEL = 0x0100;
public static final int GATT_ERROR = 0x0085; // Device not reachable
public static final int GATT_INVALID_HANDLE = 0x0001;
public static final int GATT_READ_NOT_PERMIT = 0x0002;
public static final int GATT_WRITE_NOT_PERMIT = 0x0003;
public static final int GATT_INVALID_PDU = 0x0004;
public static final int GATT_INSUF_AUTHENTICATION = 0x0005;
public static final int GATT_REQ_NOT_SUPPORTED = 0x0006;
public static final int GATT_INVALID_OFFSET = 0x0007;
public static final int GATT_INSUF_AUTHORIZATION = 0x0008;
public static final int GATT_PREPARE_Q_FULL = 0x0009;
public static final int GATT_NOT_FOUND = 0x000a;
public static final int GATT_NOT_LONG = 0x000b;
public static final int GATT_INSUF_KEY_SIZE = 0x000c;
public static final int GATT_INVALID_ATTR_LEN = 0x000d;
public static final int GATT_ERR_UNLIKELY = 0x000e;
public static final int GATT_INSUF_ENCRYPTION = 0x000f;
public static final int GATT_UNSUPPORT_GRP_TYPE = 0x0010;
public static final int GATT_INSUF_RESOURCE = 0x0011;
public static final int GATT_CONTROLLER_BUSY = 0x003A;
public static final int GATT_UNACCEPT_CONN_INTERVAL = 0x003B;
public static final int GATT_ILLEGAL_PARAMETER = 0x0087;
public static final int GATT_NO_RESOURCES = 0x0080;
public static final int GATT_INTERNAL_ERROR = 0x0081;
public static final int GATT_WRONG_STATE = 0x0082;
public static final int GATT_DB_FULL = 0x0083;
public static final int GATT_BUSY = 0x0084;
public static final int GATT_CMD_STARTED = 0x0086;
public static final int GATT_PENDING = 0x0088;
public static final int GATT_AUTH_FAIL = 0x0089;
public static final int GATT_MORE = 0x008a;
public static final int GATT_INVALID_CFG = 0x008b;
public static final int GATT_SERVICE_STARTED = 0x008c;
public static final int GATT_ENCRYPTED_NO_MITM = 0x008d;
public static final int GATT_NOT_ENCRYPTED = 0x008e;
public static final int GATT_CONGESTED = 0x008f;
public static final int GATT_CCCD_CFG_ERROR = 0x00FD;
public static final int GATT_PROCEDURE_IN_PROGRESS = 0x00FE;
public static final int GATT_VALUE_OUT_OF_RANGE = 0x00FF;
public static final int TOO_MANY_OPEN_CONNECTIONS = 0x0101;
/**
* Converts the connection status given by the
* {@link android.bluetooth.BluetoothGattCallback#onConnectionStateChange(BluetoothGatt, int, int)}
* to error name.
*
* @param error the status number.
* @return The error name as stated in the links in {@link GattError} documentation.
*/
public static String parseConnectionError(final int error) {
switch (error) {
case GATT_SUCCESS:
return "SUCCESS";
case GATT_CONN_L2C_FAILURE:
return "GATT CONN L2C FAILURE";
case GATT_CONN_TIMEOUT:
return "GATT CONN TIMEOUT";
case GATT_CONN_TERMINATE_PEER_USER:
return "GATT CONN TERMINATE PEER USER";
case GATT_CONN_TERMINATE_LOCAL_HOST:
return "GATT CONN TERMINATE LOCAL HOST";
case GATT_CONN_FAIL_ESTABLISH:
return "GATT CONN FAIL ESTABLISH";
case GATT_CONN_LMP_TIMEOUT:
return "GATT CONN LMP TIMEOUT";
case GATT_CONN_CANCEL:
return "GATT CONN CANCEL ";
case GATT_ERROR:
return "GATT ERROR"; // Device not reachable
default:
return "UNKNOWN (" + error + ")";
}
}
/**
* Converts the Bluetooth communication status given by other BluetoothGattCallbacks to error
* name. It also parses the DFU errors.
*
* @param error the status number.
* @return The error name as stated in the links in {@link GattError} documentation.
*/
public static String parse(final int error) {
switch (error) {
case GATT_INVALID_HANDLE:
return "GATT INVALID HANDLE";
case GATT_READ_NOT_PERMIT:
return "GATT READ NOT PERMIT";
case GATT_WRITE_NOT_PERMIT:
return "GATT WRITE NOT PERMIT";
case GATT_INVALID_PDU:
return "GATT INVALID PDU";
case GATT_INSUF_AUTHENTICATION:
return "GATT INSUF AUTHENTICATION";
case GATT_REQ_NOT_SUPPORTED:
return "GATT REQ NOT SUPPORTED";
case GATT_INVALID_OFFSET:
return "GATT INVALID OFFSET";
case GATT_INSUF_AUTHORIZATION:
return "GATT INSUF AUTHORIZATION";
case GATT_PREPARE_Q_FULL:
return "GATT PREPARE Q FULL";
case GATT_NOT_FOUND:
return "GATT NOT FOUND";
case GATT_NOT_LONG:
return "GATT NOT LONG";
case GATT_INSUF_KEY_SIZE:
return "GATT INSUF KEY SIZE";
case GATT_INVALID_ATTR_LEN:
return "GATT INVALID ATTR LEN";
case GATT_ERR_UNLIKELY:
return "GATT ERR UNLIKELY";
case GATT_INSUF_ENCRYPTION:
return "GATT INSUF ENCRYPTION";
case GATT_UNSUPPORT_GRP_TYPE:
return "GATT UNSUPPORT GRP TYPE";
case GATT_INSUF_RESOURCE:
return "GATT INSUF RESOURCE";
case GATT_CONN_LMP_TIMEOUT:
return "GATT CONN LMP TIMEOUT";
case GATT_CONTROLLER_BUSY:
return "GATT CONTROLLER BUSY";
case GATT_UNACCEPT_CONN_INTERVAL:
return "GATT UNACCEPT CONN INTERVAL";
case GATT_ILLEGAL_PARAMETER:
return "GATT ILLEGAL PARAMETER";
case GATT_NO_RESOURCES:
return "GATT NO RESOURCES";
case GATT_INTERNAL_ERROR:
return "GATT INTERNAL ERROR";
case GATT_WRONG_STATE:
return "GATT WRONG STATE";
case GATT_DB_FULL:
return "GATT DB FULL";
case GATT_BUSY:
return "GATT BUSY";
case GATT_ERROR:
return "GATT ERROR";
case GATT_CMD_STARTED:
return "GATT CMD STARTED";
case GATT_PENDING:
return "GATT PENDING";
case GATT_AUTH_FAIL:
return "GATT AUTH FAIL";
case GATT_MORE:
return "GATT MORE";
case GATT_INVALID_CFG:
return "GATT INVALID CFG";
case GATT_SERVICE_STARTED:
return "GATT SERVICE STARTED";
case GATT_ENCRYPTED_NO_MITM:
return "GATT ENCRYPTED NO MITM";
case GATT_NOT_ENCRYPTED:
return "GATT NOT ENCRYPTED";
case GATT_CONGESTED:
return "GATT CONGESTED";
case GATT_CCCD_CFG_ERROR:
return "GATT CCCD CFG ERROR";
case GATT_PROCEDURE_IN_PROGRESS:
return "GATT PROCEDURE IN PROGRESS";
case GATT_VALUE_OUT_OF_RANGE:
return "GATT VALUE OUT OF RANGE";
case TOO_MANY_OPEN_CONNECTIONS:
return "TOO MANY OPEN CONNECTIONS";
default:
return "UNKNOWN (" + error + ")";
}
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.exception;
public class BluetoothDisabledException extends ConnectionException {
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.exception;
@SuppressWarnings("WeakerAccess")
public class ConnectionException extends Exception {
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.exception;
public class DeviceDisconnectedException extends ConnectionException {
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.exception;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.callback.profile.ProfileReadResponse;
@SuppressWarnings("unused")
public final class InvalidDataException extends Exception {
private final ProfileReadResponse response;
public InvalidDataException(@NonNull final ProfileReadResponse response) {
this.response = response;
}
public ProfileReadResponse getResponse() {
return response;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.exception;
import no.nordicsemi.android.ble.Request;
@SuppressWarnings({"WeakerAccess", "unused"})
public final class InvalidRequestException extends Exception {
private final Request request;
public InvalidRequestException(final Request request) {
super("Invalid request");
this.request = request;
}
/**
* Returns the invalid request.
* @return The invalid request.
*/
public Request getRequest() {
return request;
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.exception;
import no.nordicsemi.android.ble.Request;
@SuppressWarnings({"WeakerAccess", "unused"})
public final class RequestFailedException extends Exception {
private final Request request;
private final int status;
public RequestFailedException(final Request request, final int status) {
super("Request failed with status " + status);
this.request = request;
this.status = status;
}
/**
* Returns the request status. One of {{@link android.bluetooth.BluetoothGatt}} GATT_*
* or {@link no.nordicsemi.android.ble.callback.FailCallback} REASON_* codes.
*
* @return Error code.
*/
public int getStatus() {
return status;
}
/**
* Returns the request that failed.
* @return The request that failed.
*/
public Request getRequest() {
return request;
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.response;
import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.ConnectionPriorityCallback;
/**
* The synchronous response type for connection priority requests.
*
* @see ConnectionPriorityCallback
*/
@SuppressWarnings({"unused", "WeakerAccess"})
public class ConnectionPriorityResponse implements ConnectionPriorityCallback, Parcelable {
private BluetoothDevice device;
@IntRange(from = 6, to = 3200)
private int interval;
@IntRange(from = 0, to = 499)
private int latency;
@IntRange(from = 10, to = 3200)
private int supervisionTimeout;
@Override
public void onConnectionUpdated(@NonNull final BluetoothDevice device,
@IntRange(from = 6, to = 3200) final int interval,
@IntRange(from = 0, to = 499) final int latency,
@IntRange(from = 10, to = 3200) final int timeout) {
this.device = device;
this.interval = interval;
this.latency = latency;
this.supervisionTimeout = timeout;
}
@Nullable
public BluetoothDevice getBluetoothDevice() {
return device;
}
/**
* The connection interval determines how often the Central will ask for data from the Peripheral.
* When the Peripheral requests an update, it supplies a maximum and a minimum wanted interval.
* The connection interval must be between 7.5 ms and 4 s.
*
* @return Connection interval used on this connection, 1.25ms unit.
* Valid range is from 6 (7.5ms) to 3200 (4000ms).
*/
@IntRange(from = 6, to = 3200)
public int getConnectionInterval() {
return interval;
}
/**
* By setting a non-zero slave latency, the Peripheral can choose to not answer when
* the Central asks for data up to the slave latency number of times.
* However, if the Peripheral has data to send, it can choose to send data at any time.
* This enables a peripheral to stay sleeping for a longer time, if it doesn't have data to send,
* but still send data fast if needed. The text book example of such device is for example
* keyboard and mice, which want to be sleeping for as long as possible when there is
* no data to send, but still have low latency (and for the mouse: low connection interval)
* when needed.
*
* @return Slave latency for the connection in number of connection events.
* Valid range is from 0 to 499.
*/
@IntRange(from = 0, to = 499)
public int getSlaveLatency() {
return latency;
}
/**
* This timeout determines the timeout from the last data exchange till a link is considered lost.
* A Central will not start trying to reconnect before the timeout has passed,
* so if you have a device which goes in and out of range often, and you need to notice when
* that happens, it might make sense to have a short timeout.
*
* @return Supervision timeout for this connection, in 10ms unit.
* Valid range is from 10 (100 ms = 0.1s) to 3200 (32s).
*/
@IntRange(from = 10, to = 3200)
public int getSupervisionTimeout() {
return supervisionTimeout;
}
// Parcelable
protected ConnectionPriorityResponse(final Parcel in) {
device = in.readParcelable(BluetoothDevice.class.getClassLoader());
interval = in.readInt();
latency = in.readInt();
supervisionTimeout = in.readInt();
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeParcelable(device, flags);
dest.writeInt(interval);
dest.writeInt(latency);
dest.writeInt(supervisionTimeout);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<ConnectionPriorityResponse> CREATOR = new Creator<ConnectionPriorityResponse>() {
@Override
public ConnectionPriorityResponse createFromParcel(final Parcel in) {
return new ConnectionPriorityResponse(in);
}
@Override
public ConnectionPriorityResponse[] newArray(final int size) {
return new ConnectionPriorityResponse[size];
}
};
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.response;
import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.MtuCallback;
@SuppressWarnings({"unused", "WeakerAccess"})
public class MtuResult implements MtuCallback, Parcelable {
private BluetoothDevice device;
@IntRange(from = 23, to = 517)
private int mtu;
@Override
public void onMtuChanged(@NonNull final BluetoothDevice device,
@IntRange(from = 23, to = 517) final int mtu) {
this.device = device;
this.mtu = mtu;
}
@Nullable
public BluetoothDevice getBluetoothDevice() {
return device;
}
/**
* Returns the agreed MTU. The maximum packet size is 3 bytes less then MTU.
*
* @return The MTU.
*/
@IntRange(from = 23, to = 517)
public int getMtu() {
return mtu;
}
// Parcelable
protected MtuResult(final Parcel in) {
device = in.readParcelable(BluetoothDevice.class.getClassLoader());
mtu = in.readInt();
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeParcelable(device, flags);
dest.writeInt(mtu);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<MtuResult> CREATOR = new Creator<MtuResult>() {
@Override
public MtuResult createFromParcel(final Parcel in) {
return new MtuResult(in);
}
@Override
public MtuResult[] newArray(final int size) {
return new MtuResult[size];
}
};
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.response;
import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.annotation.PhyValue;
import no.nordicsemi.android.ble.callback.PhyCallback;
@SuppressWarnings({"unused", "WeakerAccess"})
public class PhyResult implements PhyCallback, Parcelable {
private BluetoothDevice device;
@PhyValue
private int txPhy;
@PhyValue
private int rxPhy;
@Override
public void onPhyChanged(@NonNull final BluetoothDevice device,
@PhyValue final int txPhy, @PhyValue final int rxPhy) {
this.device = device;
this.txPhy = txPhy;
this.rxPhy = rxPhy;
}
@Nullable
public BluetoothDevice getBluetoothDevice() {
return device;
}
@PhyValue
public int getTxPhy() {
return txPhy;
}
@PhyValue
public int getRxPhy() {
return rxPhy;
}
// Parcelable
protected PhyResult(final Parcel in) {
device = in.readParcelable(BluetoothDevice.class.getClassLoader());
txPhy = in.readInt();
rxPhy = in.readInt();
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeParcelable(device, flags);
dest.writeInt(txPhy);
dest.writeInt(rxPhy);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<PhyResult> CREATOR = new Creator<PhyResult>() {
@Override
public PhyResult createFromParcel(final Parcel in) {
return new PhyResult(in);
}
@Override
public PhyResult[] newArray(final int size) {
return new PhyResult[size];
}
};
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.response;
import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.DataReceivedCallback;
import no.nordicsemi.android.ble.data.Data;
/**
* Generic read response class that returns the data received and the device from which data
* were read.
* Overriding class must call super on {@link #onDataReceived(BluetoothDevice, Data)} in
* order to make getters work properly.
*/
@SuppressWarnings({"unused", "WeakerAccess"})
public class ReadResponse implements DataReceivedCallback, Parcelable {
private BluetoothDevice device;
private Data data;
public ReadResponse() {
// empty
}
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
this.device = device;
this.data = data;
}
@Nullable
public BluetoothDevice getBluetoothDevice() {
return device;
}
@Nullable
public Data getRawData() {
return data;
}
// Parcelable
protected ReadResponse(final Parcel in) {
device = in.readParcelable(BluetoothDevice.class.getClassLoader());
data = in.readParcelable(Data.class.getClassLoader());
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeParcelable(device, flags);
dest.writeParcelable(data, flags);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<ReadResponse> CREATOR = new Creator<ReadResponse>() {
@Override
public ReadResponse createFromParcel(final Parcel in) {
return new ReadResponse(in);
}
@Override
public ReadResponse[] newArray(final int size) {
return new ReadResponse[size];
}
};
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.response;
import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.RssiCallback;
@SuppressWarnings({"unused", "WeakerAccess"})
public class RssiResult implements RssiCallback, Parcelable {
private BluetoothDevice device;
@IntRange(from = -128, to = 20)
private int rssi;
@Override
public void onRssiRead(@NonNull final BluetoothDevice device,
@IntRange(from = -128, to = 20) final int rssi) {
this.device = device;
this.rssi = rssi;
}
@Nullable
public BluetoothDevice getBluetoothDevice() {
return device;
}
@IntRange(from = -128, to = 20)
public int getRssi() {
return rssi;
}
// Parcelable
protected RssiResult(final Parcel in) {
device = in.readParcelable(BluetoothDevice.class.getClassLoader());
rssi = in.readInt();
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeParcelable(device, flags);
dest.writeInt(rssi);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<RssiResult> CREATOR = new Creator<RssiResult>() {
@Override
public RssiResult createFromParcel(final Parcel in) {
return new RssiResult(in);
}
@Override
public RssiResult[] newArray(final int size) {
return new RssiResult[size];
}
};
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.response;
import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import no.nordicsemi.android.ble.callback.DataSentCallback;
import no.nordicsemi.android.ble.data.Data;
/**
* Generic write response class that returns the target device and the data that were sent.
* Overriding class must call super on {@link #onDataSent(BluetoothDevice, Data)} in
* order to make getters work properly.
*/
@SuppressWarnings({"unused", "WeakerAccess"})
public class WriteResponse implements DataSentCallback, Parcelable {
private BluetoothDevice device;
private Data data;
@Override
public void onDataSent(@NonNull final BluetoothDevice device, @NonNull final Data data) {
this.device = device;
this.data = data;
}
@Nullable
public BluetoothDevice getBluetoothDevice() {
return device;
}
@Nullable
public Data getRawData() {
return data;
}
// Parcelable
protected WriteResponse(final Parcel in) {
device = in.readParcelable(BluetoothDevice.class.getClassLoader());
data = in.readParcelable(Data.class.getClassLoader());
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
dest.writeParcelable(device, flags);
dest.writeParcelable(data, flags);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<WriteResponse> CREATOR = new Creator<WriteResponse>() {
@Override
public WriteResponse createFromParcel(final Parcel in) {
return new WriteResponse(in);
}
@Override
public WriteResponse[] newArray(final int size) {
return new WriteResponse[size];
}
};
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.utils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
@SuppressWarnings("unused")
public interface ILogger {
/**
* Logs the given message with given log priority into the all managed devices' log session.
*
* @param priority the log priority.
* @param message the message to be logged.
*/
void log(final int priority, @NonNull final String message);
/**
* Logs the given message with given log priority into the all managed devices' log session.
*
* @param priority the log priority.
* @param messageRes string resource id.
* @param params additional (optional) parameters used to fill the message.
*/
void log(final int priority, @StringRes final int messageRes, @Nullable final Object... params);
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.ble.utils;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
@SuppressWarnings({"WeakerAccess", "unused"})
public class ParserUtils {
protected final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String parse(final BluetoothGattCharacteristic characteristic) {
return parse(characteristic.getValue());
}
public static String parse(final BluetoothGattDescriptor descriptor) {
return parse(descriptor.getValue());
}
public static String parse(final byte[] data) {
if (data == null || data.length == 0)
return "";
final char[] out = new char[data.length * 3 - 1];
for (int j = 0; j < data.length; j++) {
int v = data[j] & 0xFF;
out[j * 3] = HEX_ARRAY[v >>> 4];
out[j * 3 + 1] = HEX_ARRAY[v & 0x0F];
if (j != data.length - 1)
out[j * 3 + 2] = '-';
}
return "(0x) " + new String(out);
}
}

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -15,4 +15,4 @@
android:text="Button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -13,3 +13,6 @@ org.gradle.jvmargs=-Xmx1536m
# org.gradle.parallel=true
android.enableJetifier=true
android.useAndroidX=true