diff --git a/.gitignore b/.gitignore index 3100593..a32f62f 100644 --- a/.gitignore +++ b/.gitignore @@ -35,11 +35,13 @@ captures/ # Intellij *.iml -.idea/workspace.xml -.idea/tasks.xml -.idea/gradle.xml -.idea/dictionaries -.idea/libraries +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/captures # Keystore files *.jks diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..30aa626 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..2996d53 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..703e5d4 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..39b92ed --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,33 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + defaultConfig { + applicationId "com.example.nrftest" + minSdkVersion 28 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + 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' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/com/example/nrftest/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/nrftest/ExampleInstrumentedTest.java new file mode 100644 index 0000000..a2a84ce --- /dev/null +++ b/app/src/androidTest/java/com/example/nrftest/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.nrftest; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.example.nrftest", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e726950 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/nrftest/DecaCallbacks.java b/app/src/main/java/com/example/nrftest/DecaCallbacks.java new file mode 100644 index 0000000..90049d2 --- /dev/null +++ b/app/src/main/java/com/example/nrftest/DecaCallbacks.java @@ -0,0 +1,70 @@ +package com.example.nrftest; + +import android.bluetooth.BluetoothDevice; +import android.util.Log; + +import androidx.annotation.NonNull; + +public class DecaCallbacks implements DecaManagerCallbacks { + static final String TAG = "DecaCallbacks"; + + @Override + public void onDeviceConnecting(@NonNull BluetoothDevice device) { + Log.d(TAG, "onDeviceConnecting"); + } + + @Override + public void onDeviceConnected(@NonNull BluetoothDevice device) { + Log.d(TAG, "onDeviceConnected"); + } + + @Override + public void onDeviceDisconnecting(@NonNull BluetoothDevice device) { + Log.d(TAG, "onDeviceDisconnecting"); + } + + @Override + public void onDeviceDisconnected(@NonNull BluetoothDevice device) { + Log.d(TAG, "onDeviceDisconnected"); + } + + @Override + public void onLinkLossOccurred(@NonNull BluetoothDevice device) { + Log.d(TAG, "onLinkLossOccurred"); + } + + @Override + public void onServicesDiscovered(@NonNull BluetoothDevice device, boolean optionalServicesFound) { + Log.d(TAG, "onServicesDiscovered"); + } + + @Override + public void onDeviceReady(@NonNull BluetoothDevice device) { + Log.d(TAG, "onDeviceReady"); + } + + @Override + public void onBondingRequired(@NonNull BluetoothDevice device) { + Log.d(TAG, "onBondingRequired"); + } + + @Override + public void onBonded(@NonNull BluetoothDevice device) { + Log.d(TAG, "onBonded"); + } + + @Override + public void onBondingFailed(@NonNull BluetoothDevice device) { + Log.d(TAG, "onBondingFailed"); + } + + @Override + public void onError(@NonNull BluetoothDevice device, @NonNull String message, int errorCode) { + Log.d(TAG, "onError: " + message); + } + + @Override + public void onDeviceNotSupported(@NonNull BluetoothDevice device) { + Log.d(TAG, "onDeviceNotSupported"); + } +} diff --git a/app/src/main/java/com/example/nrftest/DecaManager.java b/app/src/main/java/com/example/nrftest/DecaManager.java new file mode 100644 index 0000000..47fab9e --- /dev/null +++ b/app/src/main/java/com/example/nrftest/DecaManager.java @@ -0,0 +1,98 @@ +package com.example.nrftest; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattService; +import android.content.Context; +import android.util.Log; + +import java.util.UUID; + +import androidx.annotation.NonNull; +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.callback.profile.ProfileDataCallback; +import no.nordicsemi.android.ble.data.Data; + +public class DecaManager extends BleManager { + private static final String TAG = "DecaManager"; + + /** Decawave Service UUID. */ + public final static UUID LBS_UUID_SERVICE = UUID.fromString("680c21d9-c946-4c1f-9c11-baa1c21329e7"); + /** */ + public final static UUID LBS_UUID_LOCATION_DATA_CHAR = UUID.fromString("003bbdf2-c634-4b3d-ab56-7ec889b89a37"); + + + + private BluetoothGattCharacteristic _locationDataCharacteristic; + + + + public DecaManager(@NonNull final Context context) + { + super(context); + } + + + @NonNull + @Override + protected BleManagerGattCallback getGattCallback() { + return mGattCallback; + } + + + /** + * BluetoothGatt callbacks object. + */ + private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() { + @Override + protected void initialize() { + + requestMtu(512).enqueue(); + + setNotificationCallback(_locationDataCharacteristic).with(mButtonCallback); +// readCharacteristic(mLedCharacteristic).with(mLedCallback).enqueue(); +// readCharacteristic(mButtonCharacteristic).with(mButtonCallback).enqueue(); + enableNotifications(_locationDataCharacteristic).enqueue(); + } + + @Override + public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { + final BluetoothGattService service = gatt.getService(LBS_UUID_SERVICE); + if (service != null) { + _locationDataCharacteristic = service.getCharacteristic(LBS_UUID_LOCATION_DATA_CHAR); + } + +// boolean writeRequest = false; +// if (mLedCharacteristic != null) { +// final int rxProperties = mLedCharacteristic.getProperties(); +// writeRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0; +// } +// +// mSupported = mButtonCharacteristic != null && mLedCharacteristic != null && writeRequest; +// return mSupported; + + return _locationDataCharacteristic != null; + } + + @Override + protected void onDeviceDisconnected() { + _locationDataCharacteristic = null; + } + }; + + + + private final ProfileDataCallback mButtonCallback = new ProfileDataCallback() { + @Override + public void onDataReceived(@NonNull BluetoothDevice device, @NonNull Data data) { + Log.d(TAG, "onDataReceived: length=" + data.size() + " data=" + data); + } + + @Override + public void onInvalidDataReceived(@NonNull final BluetoothDevice device, + @NonNull final Data data) { + Log.w(TAG, "Invalid data received: " + data); + } + }; +} diff --git a/app/src/main/java/com/example/nrftest/DecaManagerCallbacks.java b/app/src/main/java/com/example/nrftest/DecaManagerCallbacks.java new file mode 100644 index 0000000..dbedd0e --- /dev/null +++ b/app/src/main/java/com/example/nrftest/DecaManagerCallbacks.java @@ -0,0 +1,7 @@ +package com.example.nrftest; + +import no.nordicsemi.android.ble.BleManagerCallbacks; + +public interface DecaManagerCallbacks extends BleManagerCallbacks +{ +} diff --git a/app/src/main/java/com/example/nrftest/MainActivity.java b/app/src/main/java/com/example/nrftest/MainActivity.java new file mode 100644 index 0000000..b1682f7 --- /dev/null +++ b/app/src/main/java/com/example/nrftest/MainActivity.java @@ -0,0 +1,113 @@ +package com.example.nrftest; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanCallback; +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 java.util.List; + +import static android.widget.Toast.LENGTH_LONG; +import static android.widget.Toast.LENGTH_SHORT; + +public class MainActivity extends AppCompatActivity { + + DecaManager manager; + + BluetoothManager bluetoothManager; + BluetoothAdapter bluetoothAdapter; + BluetoothLeScanner leScanner; + BluetoothDevice device; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + manager = new DecaManager(getApplicationContext()); + manager.setGattCallbacks(new DecaCallbacks()); + + Button clickButton = (Button) findViewById(R.id.button2); + clickButton.setOnClickListener( new View.OnClickListener() { + @Override + public void onClick(View v) { + DoScan(); + } + }); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + device = null; + leScanner = null; + bluetoothAdapter = null; + } + + private void DoScan() { + bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + bluetoothAdapter = bluetoothManager.getAdapter(); + + if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) { + Intent enableBtIntent = + new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, 42); + } + + // Scanning settings + final ScanSettings settings = new ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .setReportDelay(500) + //.setUseHardwareBatchingIfSupported(false) + .build(); + + leScanner = bluetoothAdapter.getBluetoothLeScanner(); + leScanner.startScan(null, settings, scanCallback); + } + + ScanCallback scanCallback = new ScanCallback() { + @Override + public void onScanResult(int callbackType, ScanResult result) { + + Toast.makeText(getApplicationContext(), "On scan result", LENGTH_SHORT).show(); + + if (result.getDevice().getAddress().equals("D1:6C:7A:99:57:71")) { + device = result.getDevice(); + + leScanner.stopScan(scanCallback); + + manager.connect(device) + .retry(3, 100) + .useAutoConnect(false) + .enqueue(); + } + } + + @Override + public void onBatchScanResults(List results) { + + for (int i = 0; i < results.size(); i++) { + onScanResult(0, results.get(i)); + } + } + + @Override + public void onScanFailed(int errorCode) { + super.onScanFailed(errorCode); + + + Toast.makeText(getApplicationContext(), "Scan failed with code: " + errorCode, LENGTH_LONG).show(); + } + }; +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..1f6bb29 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..0d025f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..f5d42d7 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,18 @@ + + + +