Skip to content

Commit

Permalink
Added runtime permission ACCESS_COARSE_LOCATION for Android when scan…
Browse files Browse the repository at this point in the history
…ning. Fixes #28
  • Loading branch information
pauldemarco committed Apr 2, 2018
1 parent a7698f2 commit 83b127a
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 15 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,9 @@ device.onValueChanged(characteristic).listen((value) {
| onValueChanged | :white_check_mark: | :white_check_mark: | Notifies when the characteristic's value has changed. |
| state | :white_check_mark: | :white_check_mark: | Gets the current state of the Bluetooth Device. |
| onStateChanged | :white_check_mark: | :white_check_mark: | Notifies of state changes for the Bluetooth Device. |


## Troubleshooting
### Scanning for service UUID's doesn't return any results
Make sure the device is advertising which service UUID's it supports. This is found in the advertisement
packet as **UUID 16 bit complete list** or **UUID 128 bit complete list**.
3 changes: 2 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ android {

defaultConfig {
minSdkVersion 19
targetSdkVersion 26
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
Expand All @@ -39,6 +39,7 @@ android {
dependencies {
// Required for local unit tests (JUnit 4 framework)
testImplementation 'junit:junit:4.12'
implementation 'com.android.support:support-v4:27.1.0'
//compile files('/home/paul/flutter/bin/cache/artifacts/engine/android-arm/flutter.jar')
}
sourceSets {
Expand Down
2 changes: 1 addition & 1 deletion android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
package="com.pauldemarco.flutterblue">
<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"/>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package com.pauldemarco.flutterblue;

import android.Manifest;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
Expand All @@ -22,8 +23,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.ParcelUuid;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;

import com.google.protobuf.ByteString;
Expand All @@ -43,14 +47,16 @@
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener;


/**
* FlutterBluePlugin
*/
public class FlutterBluePlugin implements MethodCallHandler {
public class FlutterBluePlugin implements MethodCallHandler, RequestPermissionsResultListener {
private static final String TAG = "FlutterBluePlugin";
private static final String NAMESPACE = "plugins.pauldemarco.com/flutter_blue";
private static final int REQUEST_COARSE_LOCATION_PERMISSIONS = 1452;
static final private UUID CCCD_ID = UUID.fromString("000002902-0000-1000-8000-00805f9b34fb");
private final Registrar registrar;
private final MethodChannel channel;
Expand All @@ -63,11 +69,16 @@ public class FlutterBluePlugin implements MethodCallHandler {
private BluetoothAdapter mBluetoothAdapter;
private final Map<String, BluetoothGatt> mGattServers = new HashMap<>();

// Pending call and result for startScan, in the case where permissions are needed
private MethodCall pendingCall;
private Result pendingResult;

/**
* Plugin registration.
*/
public static void registerWith(Registrar registrar) {
final FlutterBluePlugin instance = new FlutterBluePlugin(registrar);
registrar.addRequestPermissionsResultListener(instance);
}

FlutterBluePlugin(Registrar r){
Expand Down Expand Up @@ -138,17 +149,19 @@ public void onMethodCall(MethodCall call, Result result) {

case "startScan":
{
// TODO: Request permission.
byte[] data = call.arguments();
Protos.ScanSettings request;
try {
request = Protos.ScanSettings.newBuilder().mergeFrom(data).build();
} catch (InvalidProtocolBufferException e) {
result.error("RuntimeException", e.getMessage(), e);
if (ContextCompat.checkSelfPermission(registrar.activity(), Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
registrar.activity(),
new String[] {
Manifest.permission.ACCESS_COARSE_LOCATION
},
REQUEST_COARSE_LOCATION_PERMISSIONS);
pendingCall = call;
pendingResult = result;
break;
}
startScan(request);
result.success(null);
startScan(call, result);
break;
}

Expand Down Expand Up @@ -473,6 +486,23 @@ public void onMethodCall(MethodCall call, Result result) {
}
}

@Override
public boolean onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_COARSE_LOCATION_PERMISSIONS) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startScan(pendingCall, pendingResult);
} else {
pendingResult.error(
"no_permissions", "flutter_blue plugin requires location permissions for scanning", null);
pendingResult = null;
pendingCall = null;
}
return true;
}
return false;
}

private BluetoothGatt locateGatt(String remoteId) throws Exception {
BluetoothGatt gattServer = mGattServers.get(remoteId);
if(gattServer == null) {
Expand Down Expand Up @@ -556,12 +586,21 @@ public void onCancel(Object o) {
}
};

private void startScan(Protos.ScanSettings settings) {
private void startScan(MethodCall call, Result result) {
byte[] data = call.arguments();
Protos.ScanSettings settings;
try {
settings = Protos.ScanSettings.newBuilder().mergeFrom(data).build();
} catch (InvalidProtocolBufferException e) {
result.error("RuntimeException", e.getMessage(), e);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
startScan21(settings);
} else {
startScan18(settings);
}
result.success(null);
}

private void stopScan() {
Expand Down
2 changes: 1 addition & 1 deletion example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.pauldemarco.flutterblueexample"
minSdkVersion 19
targetSdkVersion 27
targetSdkVersion 21
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
Expand Down
2 changes: 1 addition & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class _FlutterBlueAppState extends State<FlutterBlueApp> {
_scanSubscription = _flutterBlue.scan(
timeout: const Duration(seconds: 5),
withServices: [
new Guid('0000180f-0000-1000-8000-00805f9b34fb')
new Guid('0000180F-0000-1000-8000-00805F9B34FB')
]).listen((scanResult) {
setState(() {
scanResults[scanResult.device.id] = scanResult;
Expand Down

0 comments on commit 83b127a

Please sign in to comment.