Skip to content

Commit

Permalink
Handle location permission in example on Android (#404)
Browse files Browse the repository at this point in the history
* Add VSC launcher

* Cleanup BLE device model

* Update deprecated methods with new ones

* Add permission_handler

* WIP

* Enable AndroidX and bump Gradle to 3.5 to fix problems with building on Windows

* Ask for location permission before scanning

* Remove empty statement

* Downgrade permission_handler to 4.1.0

* Revert "Downgrade permission_handler to 4.1.0"

This reverts commit 7804437.

* Check with newer Android SDK

* Revert "Check with newer Android SDK"

This reverts commit 6ccb2bb.

* Remove licenses section for Android to check if it will fix native build on Travis

* Specify more licenses

* Add before_install script to install SDK Platform 29

* Add more to before_install

* Move before_script to different section to check how it affects Travis builds

* Try to change build tools from 28 to 29

* Add Build Tools 28 along with 29

* Check how it works without licenses section

* Fixes after review
  • Loading branch information
Łukasz Rejman committed Feb 11, 2020
1 parent a29d53e commit f466a63
Show file tree
Hide file tree
Showing 17 changed files with 124 additions and 158 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Expand Up @@ -21,11 +21,11 @@ _android_job_template: &android_job_template
android:
components:
- tools
- build-tools-28.0.3
- android-28
- android-29
- build-tools-28.0.3
- build-tools-29.0.5
- extra-android-m2repository
licenses:
- 'android-sdk-license-.+'
env:
global:
- GRADLE_OPTS="-Xms128m"
Expand Down
11 changes: 11 additions & 0 deletions .vscode/launch.json
@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Example (debug)",
"request": "launch",
"type": "dart",
"flutterMode": "debug"
}
]
}
2 changes: 1 addition & 1 deletion android/build.gradle
Expand Up @@ -8,7 +8,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.android.tools.build:gradle:3.5.0'
}
}

Expand Down
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
3 changes: 1 addition & 2 deletions example/android/build.gradle
Expand Up @@ -5,15 +5,14 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.android.tools.build:gradle:3.5.0'
}
}

allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}

Expand Down
5 changes: 2 additions & 3 deletions example/android/gradle.properties
@@ -1,5 +1,4 @@
org.gradle.jvmargs=-Xmx1536M

android.useAndroidX=false
android.enableJetifier=false
android.useAndroidX=true
android.enableJetifier=true
android.enableR8=true
2 changes: 1 addition & 1 deletion example/android/gradle/wrapper/gradle-wrapper.properties
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
22 changes: 11 additions & 11 deletions example/lib/device_details/device_details_bloc.dart
Expand Up @@ -24,8 +24,6 @@ class DeviceDetailsBloc {

Observable<List<DebugLog>> get logs => _logsController.stream;

StreamSubscription connectionSubscription;

Stream<BleDevice> get disconnectedDevice => _deviceRepository.pickedDevice
.skipWhile((bleDevice) => bleDevice != null);

Expand All @@ -38,22 +36,25 @@ class DeviceDetailsBloc {
_deviceController = BehaviorSubject<BleDevice>.seeded(device);

_connectionStateController =
BehaviorSubject<PeripheralConnectionState>.seeded(device.isConnected
? PeripheralConnectionState.connected
: PeripheralConnectionState.disconnected);
BehaviorSubject<PeripheralConnectionState>.seeded(
PeripheralConnectionState.disconnected);

_logsController = PublishSubject<List<DebugLog>>();

log = (text) {
var now = DateTime.now();
_logs.insert(0, DebugLog('${now.hour}:${now.minute}:${now.second}.${now.millisecond}', text));
_logs.insert(
0,
DebugLog(
'${now.hour}:${now.minute}:${now.second}.${now.millisecond}',
text,
));
Fimber.d(text);
_logsController.add(_logs);
};

logError = (text) {
_logs.insert(0,
DebugLog(DateTime.now().toString(), "ERROR: $text"));
_logs.insert(0, DebugLog(DateTime.now().toString(), "ERROR: $text"));
Fimber.e(text);
_logsController.add(_logs);
};
Expand Down Expand Up @@ -112,7 +113,6 @@ class DeviceDetailsBloc {
});
}


void readCharacteristicForPeripheral() {
_clearLogs();
_deviceController.stream.listen((bleDevice) async {
Expand Down Expand Up @@ -215,7 +215,8 @@ class DeviceDetailsBloc {
var peripheral = bleDevice.peripheral;

peripheral
.observeConnectionState(emitCurrentValue: true, completeOnDisconnect: true)
.observeConnectionState(
emitCurrentValue: true, completeOnDisconnect: true)
.listen((connectionState) {
log('Observed new connection state: \n$connectionState');
_connectionStateController.add(connectionState);
Expand All @@ -232,7 +233,6 @@ class DeviceDetailsBloc {
}

void dispose() async {
_deviceController.value?.abandon();
await _deviceController.drain();
_deviceController.close();

Expand Down
11 changes: 5 additions & 6 deletions example/lib/device_details/devices_details_bloc_provider.dart
Expand Up @@ -4,22 +4,21 @@ import 'package:flutter_ble_lib/flutter_ble_lib.dart';

import 'device_details_bloc.dart';


class DeviceDetailsBlocProvider extends InheritedWidget {
final DeviceDetailsBloc deviceDetailsBloc;

DeviceDetailsBlocProvider({
Key key,
DeviceDetailsBloc deviceDetailsBloc,
Widget child,
}) : deviceDetailsBloc = deviceDetailsBloc ?? DeviceDetailsBloc(DeviceRepository(), BleManager()),
}) : deviceDetailsBloc = deviceDetailsBloc ??
DeviceDetailsBloc(DeviceRepository(), BleManager()),
super(key: key, child: child);

@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;

static DeviceDetailsBloc of(BuildContext context) =>
(context.inheritFromWidgetOfExactType(DeviceDetailsBlocProvider)
as DeviceDetailsBlocProvider)
.deviceDetailsBloc;
static DeviceDetailsBloc of(BuildContext context) => context
.dependOnInheritedWidgetOfExactType<DeviceDetailsBlocProvider>()
.deviceDetailsBloc;
}
64 changes: 44 additions & 20 deletions example/lib/devices_list/devices_bloc.dart
@@ -1,18 +1,21 @@
import 'dart:async';
import 'dart:io';

import 'package:fimber/fimber.dart';
import 'package:flutter_ble_lib_example/model/ble_device.dart';
import 'package:flutter_ble_lib_example/repository/device_repository.dart';
import 'package:rxdart/rxdart.dart';
import 'package:flutter_ble_lib/flutter_ble_lib.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:rxdart/rxdart.dart';

class DevicesBloc {
final List<BleDevice> bleDevices = <BleDevice>[];

BehaviorSubject<List<BleDevice>> _visibleDevicesController =
BehaviorSubject<List<BleDevice>>.seeded(<BleDevice>[]);

StreamController<BleDevice> _devicePickerController = StreamController<BleDevice>();
StreamController<BleDevice> _devicePickerController =
StreamController<BleDevice>();

StreamSubscription<ScanResult> _scanSubscription;
StreamSubscription _devicePickerSubscription;
Expand All @@ -24,8 +27,10 @@ class DevicesBloc {

DeviceRepository _deviceRepository;
BleManager _bleManager;
PermissionStatus _locationPermissionStatus = PermissionStatus.unknown;

Stream<BleDevice> get pickedDevice => _deviceRepository.pickedDevice.skipWhile((bleDevice) => bleDevice == null);
Stream<BleDevice> get pickedDevice => _deviceRepository.pickedDevice
.skipWhile((bleDevice) => bleDevice == null);

DevicesBloc(this._deviceRepository, this._bleManager);

Expand All @@ -44,34 +49,51 @@ class DevicesBloc {
void init() {
Fimber.d("Init devices bloc");
bleDevices.clear();
_bleManager.createClient(
restoreStateIdentifier: "example-restore-state-identifier",
restoreStateAction: (peripherals) {
peripherals?.forEach((peripheral) {
Fimber.d("Restored peripheral: ${peripheral.name}");
});
}
)
.then((it) => startScan())
.catchError((e) => Fimber.d("Couldn't create BLE client", ex: e));
_bleManager
.createClient(
restoreStateIdentifier: "example-restore-state-identifier",
restoreStateAction: (peripherals) {
peripherals?.forEach((peripheral) {
Fimber.d("Restored peripheral: ${peripheral.name}");
});
})
.catchError((e) => Fimber.d("Couldn't create BLE client", ex: e))
.then((_) => _checkPermissions())
.catchError((e) => Fimber.d("Permission check error", ex: e))
.then((_) => _startScan());

if (_visibleDevicesController.isClosed) {
_visibleDevicesController = BehaviorSubject<List<BleDevice>>.seeded(<BleDevice>[]);
_visibleDevicesController =
BehaviorSubject<List<BleDevice>>.seeded(<BleDevice>[]);
}

if (_devicePickerController.isClosed) {
_devicePickerController = StreamController<BleDevice>();
}


Fimber.d(" listen to _devicePickerController.stream");
_devicePickerSubscription = _devicePickerController.stream.listen(_handlePickedDevice);
_devicePickerSubscription =
_devicePickerController.stream.listen(_handlePickedDevice);
}

Future<void> _checkPermissions() async {
if (Platform.isAndroid) {
var permissionStatus = await PermissionHandler()
.requestPermissions([PermissionGroup.location]);

_locationPermissionStatus = permissionStatus[PermissionGroup.location];

if (_locationPermissionStatus != PermissionStatus.granted) {
return Future.error(Exception("Location permission not granted"));
}
}
}

void startScan() {
void _startScan() {
Fimber.d("Ble client created");
_scanSubscription = _bleManager.startPeripheralScan().listen((ScanResult scanResult) {
var bleDevice = BleDevice.notConnected(scanResult.peripheral.name, scanResult.peripheral.identifier, scanResult.peripheral);
_scanSubscription =
_bleManager.startPeripheralScan().listen((ScanResult scanResult) {
var bleDevice = BleDevice(scanResult);
if (scanResult.advertisementData.localName != null &&
!bleDevices.contains(bleDevice)) {
Fimber.d(
Expand All @@ -87,6 +109,8 @@ class DevicesBloc {
await _bleManager.stopPeripheralScan();
bleDevices.clear();
_visibleDevicesController.add(bleDevices.sublist(0));
startScan();
await _checkPermissions()
.then((_) => _startScan())
.catchError((e) => Fimber.d("Couldn't refresh", ex: e));
}
}
11 changes: 5 additions & 6 deletions example/lib/devices_list/devices_bloc_provider.dart
Expand Up @@ -3,22 +3,21 @@ import 'package:flutter_ble_lib_example/devices_list/devices_bloc.dart';
import 'package:flutter_ble_lib_example/repository/device_repository.dart';
import 'package:flutter_ble_lib/flutter_ble_lib.dart';


class DevicesBlocProvider extends InheritedWidget {
final DevicesBloc devicesBloc;

DevicesBlocProvider({
Key key,
DevicesBloc devicesBloc,
Widget child,
}) : devicesBloc = devicesBloc ?? DevicesBloc(DeviceRepository(), BleManager()),
}) : devicesBloc =
devicesBloc ?? DevicesBloc(DeviceRepository(), BleManager()),
super(key: key, child: child);

@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;

static DevicesBloc of(BuildContext context) =>
(context.inheritFromWidgetOfExactType(DevicesBlocProvider)
as DevicesBlocProvider)
.devicesBloc;
static DevicesBloc of(BuildContext context) => context
.dependOnInheritedWidgetOfExactType<DevicesBlocProvider>()
.devicesBloc;
}
14 changes: 6 additions & 8 deletions example/lib/devices_list/devices_list_view.dart
Expand Up @@ -2,13 +2,12 @@ import 'dart:async';

import 'package:fimber/fimber.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_ble_lib_example/devices_list/hex_painter.dart';

import 'package:flutter_ble_lib_example/model/ble_device.dart';

import 'devices_bloc.dart';
import 'devices_bloc_provider.dart';

import 'hex_painter.dart';

typedef DeviceTapListener = void Function();

Expand Down Expand Up @@ -74,11 +73,10 @@ class DeviceListScreenState extends State<DevicesListScreen> {
body: StreamBuilder<List<BleDevice>>(
initialData: _devicesBloc.visibleDevices.value,
stream: _devicesBloc.visibleDevices,
builder: (context, snapshot) =>
RefreshIndicator(
onRefresh: _devicesBloc.refresh,
child: DevicesList(_devicesBloc, snapshot.data),
),
builder: (context, snapshot) => RefreshIndicator(
onRefresh: _devicesBloc.refresh,
child: DevicesList(_devicesBloc, snapshot.data),
),
),
);
}
Expand Down

0 comments on commit f466a63

Please sign in to comment.