Connect to BLE device through service

This commit is contained in:
Robert Marshall 2021-07-31 09:51:46 +01:00
parent 192f65dd93
commit f1a0f48628
4 changed files with 269 additions and 110 deletions

117
.idea/codeStyles/Project.xml generated Normal file
View file

@ -0,0 +1,117 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>

View file

@ -21,10 +21,13 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".LightsService">
</service>
</application>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
</manifest>

View file

@ -0,0 +1,67 @@
package uk.robware.vanlights;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import java.util.UUID;
public class LightsService extends Service {
private final IBinder binder = new LightsBinder();
public class LightsBinder extends Binder {
LightsService getService() {
return LightsService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
private Handler handler = new Handler();
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice _device = bluetoothAdapter.getRemoteDevice("9C:9C:1F:E3:C0:26");
private BluetoothGattCharacteristic _characteristic;
private BluetoothGatt _gatt;
BluetoothGattCallback gattCallback=new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (status!=133) {
gatt.discoverServices();
_gatt = gatt;
}else{
handler.postDelayed(()->connect(), 500);
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
BluetoothGattService service = gatt.getService(UUID.fromString("4fafc201-1fb5-459e-8fcc-c5c9c331914b"));
_characteristic = service.getCharacteristic(UUID.fromString("beb5483e-36e1-4688-b7f5-ea07361b26a8"));
}
};
public void connect(){
_device.connectGatt(this, false, gattCallback);
}
public void disconnect() {
_gatt.disconnect();
}
public void write(String value){
_characteristic.setValue(value);
_gatt.writeCharacteristic(_characteristic);
}
}

View file

@ -1,89 +1,77 @@
package uk.robware.vanlights;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private static final int ACCESS_COARSE_LOCATION_REQUEST = 2;
private Handler handler = new Handler();
private ScanCallback leScanCallback=new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
Log.i("NAME", device.getName());
if (device.getName()=="Van Lights"){
Log.i("asdasd", "asdasd");
}
}
private boolean hasPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (getApplicationContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
}, ACCESS_COARSE_LOCATION_REQUEST);
return false;
}
}
return true;
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
// Ignore for now
}
private LightsService _lightsService;
private boolean _lightsBound;
private ServiceConnection _serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LightsService.LightsBinder binder = (LightsService.LightsBinder) service;
_lightsService = binder.getService();
_lightsBound = true;
connect();
Log.d("MAIN", "Lights service connected");
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
// Ignore for now
}
};
@Override
public void onServiceDisconnected(ComponentName arg0) {
_lightsBound = false;
Log.d("MAIN", "Lights service disconnected");
}
};
private void connect() {
if (!_lightsBound) return;
_lightsService.connect();
}
private void disconnect() {
if (!_lightsBound) return;
_lightsService.disconnect();
}
private void write(String message) {
if (!_lightsBound) return;
_lightsService.write(message);
}
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = bluetoothAdapter.getRemoteDevice("9C:9C:1F:E3:C0:26");
private BluetoothGattCharacteristic _characteristic;
private BluetoothGatt _gatt;
BluetoothGattCallback gattCallback=new BluetoothGattCallback() {
@Override
protected void onCreate(Bundle savedInstanceState) {
hasPermissions();
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
gatt.discoverServices();
_gatt=gatt;
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
BluetoothGattService service = gatt.getService(UUID.fromString("4fafc201-1fb5-459e-8fcc-c5c9c331914b"));
_characteristic = service.getCharacteristic(UUID.fromString("beb5483e-36e1-4688-b7f5-ea07361b26a8"));
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
//Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
//getApplicationContext().startActivity(enableBtIntent);
hasPermissions();
//scanLeDevice();
device.connectGatt(this, true, gattCallback);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.seating_on_button).setOnClickListener(view -> write("seating on"));
findViewById(R.id.seating_off_button).setOnClickListener(view -> write("seating off"));
@ -93,52 +81,36 @@ public class MainActivity extends AppCompatActivity {
findViewById(R.id.all_on_button).setOnClickListener(view -> write("all on"));
findViewById(R.id.all_off_button).setOnClickListener(view -> write("all off"));
}
}
private static final int ACCESS_COARSE_LOCATION_REQUEST = 2;
private boolean hasPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (getApplicationContext().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[] { Manifest.permission.ACCESS_COARSE_LOCATION }, ACCESS_COARSE_LOCATION_REQUEST);
return false;
}
}
return true;
}
@Override
protected void onStart() {
super.onStart();
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
Intent intent = new Intent(this, LightsService.class);
bindService(intent, _serviceConnection, Context.BIND_AUTO_CREATE);
connect();
}
private void scanLeDevice() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
@Override
protected void onStop() {
super.onStop();
disconnect();
unbindService(_serviceConnection);
_lightsBound = false;
}
List<ScanFilter> filters = Collections.singletonList(new ScanFilter.Builder()
//.setServiceUuid(ParcelUuid.fromString("4fafc201-1fb5-459e-8fcc-c5c9c331914b"))
.setDeviceName("Van Lights")
.build());
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
.setReportDelay(0L)
.build();
@Override
protected void onResume() {
super.onResume();
connect();
}
bluetoothLeScanner.startScan(leScanCallback);
Log.i("BLE", "Scanning");
// Stops scanning after a predefined scan period.
handler.postDelayed(() -> {
bluetoothLeScanner.stopScan(leScanCallback);
Log.i("BLE", "Stop scanning");
}, SCAN_PERIOD);
}
private void write(String value){
_characteristic.setValue(value);
_gatt.writeCharacteristic(_characteristic);
}
@Override
protected void onPause() {
super.onPause();
disconnect();
}
}