Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Operation viability check #240

Merged
merged 16 commits into from
Aug 3, 2017
Merged

Operation viability check #240

merged 16 commits into from
Aug 3, 2017

Conversation

mikolak
Copy link
Collaborator

@mikolak mikolak commented Jul 3, 2017

This PR is is connected to #224

I have implemented a mechanism for checking whether the requested characteristic operation can succeed. The check is based upon the properties of the chosen characteristic. End user can opt-out of the 'hard' way of checking (ie. throwing an exception) using new connection setup API.

@mikolak mikolak requested review from dariuszseweryn, uKL and mzgreen July 3, 2017 14:34
@mikolak mikolak self-assigned this Jul 3, 2017
# Conflicts:
#	rxandroidble/src/main/java/com/polidea/rxandroidble/internal/RxBleDeviceImpl.java
#	rxandroidble/src/main/java/com/polidea/rxandroidble/internal/connection/ConnectionModule.java
#	rxandroidble/src/test/groovy/com/polidea/rxandroidble/internal/RxBleDeviceTest.groovy
Copy link
Owner

@dariuszseweryn dariuszseweryn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few thoughts.

}

@Provides
@ConnectionScope
static BluetoothGatt provideBluetoothGatt(BluetoothGattProvider bluetoothGattProvider) {
return bluetoothGattProvider.getBluetoothGatt();
IllegalOperationChecker provideIllegalOperationChecker() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one could be a static function if suppressPropertiesCheck would be passed to it. Play around and find a way that will introduce the lease amount of methods / functions to .dex

You can see how many fields and methods there are by adding the following snippet below apply from: in rxandroidble/build.gradle:

buildscript {
    repositories {
        mavenCentral() // or jcenter()
    }

    dependencies {
        classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.7.0'
    }
}

apply plugin: 'com.getkeepsafe.dexcount'

dexcount {
    format = "list"
    includeClasses = true
    includeFieldCount = false
    includeTotalMethodCount = false
    orderByMethodCount = true
    verbose = false
    maxTreeDepth = Integer.MAX_VALUE
    teamCityIntegration = false
}

@@ -195,6 +204,10 @@ public int getMtu() {
@Override
public Observable<Observable<byte[]>> setupIndication(@NonNull BluetoothGattCharacteristic characteristic,
@NonNull NotificationSetupMode setupMode) {
illegalOperationChecker.checkAnyPropertyMatches(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am actually thinking wether or not it would be better to have something like:

if (illegalOperationChecker.checkAnyPropertyMatches()) {
  return ... // normal stuff
} else {
  return Observable.error(new IllegalOperationException(/* construct */));
}

It would be then consistent no matter how the user would call the function RxBleConnection.setupIndication(UUID) / RxBleConnection.setupIndication(BluetoothGattCharacteristic). Because now calling RxBleConnection.setupIndication(BluetoothGattCharacteristic) will just throw.

It would need a different abstraction though. @uKL any thoughts?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have modified IllegalOperationChecker.checkAnyPropertyMatches() to return Completable.fromCallable() and will upload it shortly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that there should be a model separation. The method should check whether preconditions are correct and the result should be described by the caller.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moreover, the point where the check happens is inconsistent. Sometimes it happens even before the operation is enqueued and sometimes not (when it's required to perform discovery in order to get the characteristic object)

@@ -53,12 +54,20 @@

@Override
public Observable<RxBleConnection> establishConnection(final boolean autoConnect) {
ConnectionSetup options = (new ConnectionSetup.Builder())
.setAutoConnect(autoConnect)
.build();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also have .setSuppressOperationCheck(false) to match the previous behaviour.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree.

return this;
}

public Builder setSupressOperationCheck(boolean suppressOperationCheck) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setSuppressIllegalOperationCheck()? Now it is not too informative in my opinion.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be nice to inform on the nature of the checks. That they are related to permissions.

final ConnectionComponent connectionComponent = connectionComponentBuilder.build();
final ConnectionComponent connectionComponent = connectionComponentBuilder
.connectionModule(new ConnectionModule(options.suppressOperationCheck))
.build();
RxBleRadioOperationConnect operationConnect = connectionComponent.connectOperationBuilder()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be now possible to get rid of the RxBleRadioOperationConnect.Builder as all dependencies could be passed through ConnectionComponent.Builder.

* <p>
* During the disconnect process the library automatically handles order and requirement of device disconnect and gatt close operations.
* <p>
* Autoconnect concept may be misleading at first glance. In cases when the BLE device is available and it is advertising constantly you
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part about autoConnect should go to ConnectionSetup javadoc as it will be the place to set.

…e has ended (was unsubscribed). Enchanced tests.
return this;
}

public Builder setSupressOperationCheck(boolean suppressOperationCheck) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be nice to inform on the nature of the checks. That they are related to permissions.


private boolean autoConnect = false;
private boolean supressOperationCheck = false;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a documentation for public methods. (like in RxBleConnection)

package com.polidea.rxandroidble.exceptions;

/**
*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing JavaDoc?

@@ -53,12 +54,20 @@

@Override
public Observable<RxBleConnection> establishConnection(final boolean autoConnect) {
ConnectionSetup options = (new ConnectionSetup.Builder())
.setAutoConnect(autoConnect)
.build();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree.

@@ -53,12 +55,25 @@

@Override
public Observable<RxBleConnection> establishConnection(final boolean autoConnect) {
ConnectionSetup options = (new ConnectionSetup.Builder())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant backet

@@ -195,6 +204,10 @@ public int getMtu() {
@Override
public Observable<Observable<byte[]>> setupIndication(@NonNull BluetoothGattCharacteristic characteristic,
@NonNull NotificationSetupMode setupMode) {
illegalOperationChecker.checkAnyPropertyMatches(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that there should be a model separation. The method should check whether preconditions are correct and the result should be described by the caller.

@@ -195,6 +204,10 @@ public int getMtu() {
@Override
public Observable<Observable<byte[]>> setupIndication(@NonNull BluetoothGattCharacteristic characteristic,
@NonNull NotificationSetupMode setupMode) {
illegalOperationChecker.checkAnyPropertyMatches(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moreover, the point where the check happens is inconsistent. Sometimes it happens even before the operation is enqueued and sometimes not (when it's required to perform discovery in order to get the characteristic object)

final int characteristicProperties = characteristic.getProperties();

if ((characteristicProperties & neededProperties) == 0) {
int[] possibleProperties = getPossibleProperties();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's more like permited or allowed than possible, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or even supported if I'm reading correctly from the context.

protected abstract void handleMessage(String message);

@NonNull
private String propertiesIntToString(int property, int[] possibleProperties) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More like an util. What do you think about extracting it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. If it's supposed to be testable, then it would need to be instantiated. That would lead to increasing method count and I'm not that convinced that it would be useful anywhere else.

* Method for handling the potential non-match message
* @param message message describing the
*/
protected abstract void handleMessage(String message);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer the checker to return the model with the report, rather than to pass it to a method that needs to be overridden. @dariuszseweryn what do you think? It's easier to test then.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we have a IllegalOperationChecker which is checking and handling the result. We could have IllegalOperationChecker that would work with IllegalOperationHandler which would either log or throw/emit an IllegalOperationException. The checker part would be always the same (could be put directly in RxBleConnectionImpl or injected as a separate object)

Copy link
Owner

@dariuszseweryn dariuszseweryn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And one comment from the previous review was not addressed.

@@ -34,6 +34,10 @@ private ConnectionSetup(boolean autoConnect, boolean suppressOperationCheck) {


/**
* Autoconnect concept may be misleading at first glance. In cases when the BLE device is available and it is advertising constantly
* you won't need to use autoconnect. Use autoconnect for connections where the BLE device is not advertising at
* the moment of #establishConnection call.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{@link com.polidea.rxandroidble.RxBleConnection#establishConnection(ConnectionSetup)} instead of #establishConnection

public final int supportedProperties;
public final int neededProperties;

public BleIllegalOperationException(String message,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) and a javadoc that will tell people not to instantiate this class. Maybe it is worth to expose getters instead of public finals — just a thought.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, getters will increase the method count and all of these fields are immutable anyhow. Can be done, though I'm not sure if it should be.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True though here we have fields in the API and we cannot change that later on if we would decide to pass BluetoothGattCharacteristic in the constructor. But it is just an opinion. @uKL thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the first thought is "Why do I need an int?! It's ugly.". If we'd have an API to read properties more easily.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could annotate the ints with @BluetoothGattCharacteristicProperty to make it more precise what is this int related to. BluetoothGattCharacteristicProperty would then be put on the public API.

@@ -34,21 +34,23 @@ public ConnectionModule(ConnectionSetup connectionSetup) {
@ConnectionScope
IllegalOperationChecker provideIllegalOperationChecker() {
if (suppressOperationCheck) {
return new LoggingIllegalOperationChecker(BluetoothGattCharacteristic.PROPERTY_BROADCAST,
return new IllegalOperationChecker(BluetoothGattCharacteristic.PROPERTY_BROADCAST,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be now optimised. if else only picks a MismatchDataHandler

@@ -79,18 +83,30 @@ public Object call() throws Exception {
propertiesIntToString(neededProperties, possibleProperties),
neededProperties
);
handleMessage(message);
MismatchData mismatchData = new MismatchData(message,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that having a MismatchData here is superfluous and it only adds an allocation. The data could be passed directly to the MismatchDataHandler

* Handler for {@link com.polidea.rxandroidble.internal.util.IllegalOperationChecker.MismatchData} returned by
* {@link IllegalOperationChecker}.
*/
public interface MismatchDataHandler {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just a IllegalOperationHandler? And it can be put just in internal.connection package. Does not look like an util that is used all over the code.

/**
* @param suppressOperationCheck Flag describing the method of operation viability checking. If set to false,
* a {@link com.polidea.rxandroidble.exceptions.BleIllegalOperationException} will be
* thrown everytime properties of the characteristic don't match those required by the operation.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thrown -> emitted

* This exception is thrown when a non-supported operation has been requested upon a characteristic, eg. write operation on a
* characteristic with only read property.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the annotation should be on the constructor only. the class is meant to be used in the API

@Subcomponent.Builder
interface Builder {

Builder connectionModule(ConnectionModule connectionModule);

ConnectionComponent build();
}

@ConnectionScope
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is possible to get rid of the @ConnectionScope here as the operation is used only once and it is not needed to be cached. It is worth checking.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is possible to get rid of caching for other items as well. please check method counts / fields.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think further optimization is out of scope for this pull request. We should have a separate PR for optimizations if you think they are necessary.

@Module
abstract public class ConnectionModuleBinder {

static final String GATT_WRITE_MTU_OVERHEAD = "GATT_WRITE_MTU_OVERHEAD";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should also be with other names in the ConnectionComponent?

public final int supportedProperties;
public final int neededProperties;

public BleIllegalOperationException(String message,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True though here we have fields in the API and we cannot change that later on if we would decide to pass BluetoothGattCharacteristic in the constructor. But it is just an opinion. @uKL thoughts?

* you won't need to use autoconnect. Use autoconnect for connections where the BLE device is not advertising at
* the moment of {@link RxBleDevice#establishConnection(ConnectionSetup)} call.
*
* @param autoConnect Marker related with
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

related to or connected with ;) Flag maybe?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My fault for copy-paste without proof reading, not my grammar mistake. ;) Should I correct it elsewhere as well?

* {@link android.bluetooth.BluetoothDevice#connectGatt(Context, boolean, BluetoothGattCallback)} autoConnect
* flag. In case of auto connect is enabled the observable will wait with the emission of RxBleConnection.
* Without auto connect flag set to true the connection will fail
* with {@link com.polidea.rxandroidble.exceptions.BleGattException} if the device is not in range.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after around 30 seconds timeout

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I correct it elsewhere as well?


def "should throw BleIllegalOperationException if no property matches"() {
when:
objectUnderTest.handleMismatchData(message, mockUuid, supportedProperties, neededProperties)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name suggests a mock for mockUuid but it's null.


void setup() {
mockHandler = Mock IllegalOperationHandler
subscriber = new TestSubscriber()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too many spaces


def "should handle message if no property matches"() {
given:
bluetoothGattCharacteristic.getProperties() >> 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What stands for 0?

Copy link
Collaborator

@uKL uKL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more comments to talk about.

bluetoothGattCharacteristic.getProperties() >> 0

when:
objectUnderTest.checkAnyPropertyMatches(bluetoothGattCharacteristic, BluetoothGattCharacteristic.PROPERTY_READ)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is subscriber used anyhow?

bluetoothGattCharacteristic.getProperties() >> BluetoothGattCharacteristic.PROPERTY_READ

when:
objectUnderTest.checkAnyPropertyMatches(bluetoothGattCharacteristic, BluetoothGattCharacteristic.PROPERTY_READ)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is subscriber used anyhow?

bluetoothGattCharacteristic.getProperties() >> BluetoothGattCharacteristic.PROPERTY_WRITE

when:
objectUnderTest.checkAnyPropertyMatches(bluetoothGattCharacteristic,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is subscriber used anyhow?

Observable<RxBleConnection> establishConnection(RxBleDevice d) {
return establishConnectionCaller.connectionStartClosure.call(d, connectionSetup)
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove empty line

*/
public class IllegalOperationChecker {

private int propertyBroadcast;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make attributes final, just in case.

}

@NonNull
private String propertiesIntToString(int property, int[] possibleProperties) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think generating a message is not in scope of the checker, it should be a separate util class.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, I'll extract it.

@NonNull
private String propertiesIntToString(int property, int[] possibleProperties) {
StringBuilder builder = new StringBuilder();
builder.append(" ");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a space at the beginning?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For prettyness. [ ] looks better than [] if there are no properties and [ READ WRITE ] looks better than [READ WRITE ]. I decided to avoid tracking whether any property has already been matched or not. I admit that I wrote specifically for the message which puts the string in square brackets, so for the purpose of extracting it to a separate parser, maybe the brackets should be added to this function?

return "NOTIFY";
} else {
RxBleLog.e("Unknown property specified");
throw new IllegalArgumentException("Unknown property specified");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it documented that the method may throw IllegalArgumentException? It will be passed to the public API.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just removed the exception in a refactor. ;)

Copy link
Owner

@dariuszseweryn dariuszseweryn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comment to the exception.

public final int supportedProperties;
public final int neededProperties;

public BleIllegalOperationException(String message,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could annotate the ints with @BluetoothGattCharacteristicProperty to make it more precise what is this int related to. BluetoothGattCharacteristicProperty would then be put on the public API.

@@ -0,0 +1,3 @@
package com.polidea.rxandroidble;

public @interface BluetoothGattCharacteristicProperty { }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still needs proper annotations?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...aaaaaand javadoc ;)

@@ -14,5 +16,5 @@
this.messageCreator = messageCreator;
}

public abstract void handleMismatchData(BluetoothGattCharacteristic characteristic, int neededProperties);
public abstract BleIllegalOperationException handleMismatchData(BluetoothGattCharacteristic characteristic, int neededProperties);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mark it with @Nullable

Copy link
Collaborator

@uKL uKL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two more comments regarding the documentation. The rest is acceptable.

@@ -31,11 +31,12 @@

/**
* @param context Android's context.
* @param autoConnect Marker related with
* @param autoConnect Flag related to
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the ConnectionSetup it still says "marker"

* @param characteristic a {@link BluetoothGattCharacteristic} the operation is done on
* @param neededProperties properties required for the operation to be successfully completed
* @return {@link Completable} deferring execution of the check till subscription
* @throws BleIllegalOperationException if there was no match between supported and necessary properties of characteristic and check has
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact it does not throw, it emits BleIllegalOperationException

Copy link
Owner

@dariuszseweryn dariuszseweryn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am good with what was done. 👍

@mikolak mikolak force-pushed the operation_viability branch from bea3b36 to 9a6d7e3 Compare August 1, 2017 08:53
@dariuszseweryn dariuszseweryn merged commit 2685130 into develop Aug 3, 2017
@dariuszseweryn dariuszseweryn deleted the operation_viability branch August 3, 2017 08:59
dariuszseweryn added a commit that referenced this pull request Aug 3, 2017
…lishConnection(SetupOptions)`

(#240 #224) This new function is a perfect extension point to introduce a new public API #239 which will return the new API without changing the Major version number. Till then all new public classes were moved to the `internal` package and should not be publicly available.
dariuszseweryn added a commit that referenced this pull request Aug 3, 2017
…nal package.

(#240 #224) Will become public when new API #239 will be ready.
dariuszseweryn added a commit that referenced this pull request Aug 3, 2017
@uKL
Copy link
Collaborator

uKL commented Mar 20, 2018

Dear @mikolak ,

similar to many open source projects we kindly request to sign our CLA if you'd like to contribute to our project. This license is for your protection as a Contributor as well as the protection of Polidea; it does not change your rights to use your own Contributions for any other purpose.

You can find a link here: https://cla-assistant.io/Polidea/RxAndroidBle

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants