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

Add get bluetooth device class #206

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ rootProject.allprojects {
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 30
compileSdkVersion 33
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
Expand Down
11 changes: 8 additions & 3 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.github.edufolly.flutterbluetoothserial">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-sdk
android:targetSdkVersion="33" />
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothClass;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
Expand All @@ -16,6 +17,7 @@
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.os.Build;
import android.util.Log;
import android.util.SparseArray;
import android.os.AsyncTask;
Expand Down Expand Up @@ -268,20 +270,21 @@ public void onReceive(Context context, Intent intent) {
switch (action) {
case BluetoothDevice.ACTION_FOUND:
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//final BluetoothClass deviceClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS); // @TODO . !BluetoothClass!
// final BluetoothClass deviceClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS); // @TODO . !BluetoothClass!
//final String extraName = intent.getStringExtra(BluetoothDevice.EXTRA_NAME); // @TODO ? !EXTRA_NAME!
final int deviceRSSI = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);

Map<String, Object> discoveryResult = new HashMap<>();
discoveryResult.put("address", device.getAddress());
discoveryResult.put("name", device.getName());
discoveryResult.put("type", device.getType());
//discoveryResult.put("class", deviceClass); // @TODO . it isn't my priority for now !BluetoothClass!
// discoveryResult.put("class", deviceClass); // @TODO . it isn't my priority for now !BluetoothClass!
discoveryResult.put("isConnected", checkIsDeviceConnected(device));
discoveryResult.put("bondState", device.getBondState());
discoveryResult.put("rssi", deviceRSSI);
discoveryResult.put("deviceClass", device.getBluetoothClass().getDeviceClass());

Log.d(TAG, "Discovered " + device.getAddress());
Log.d(TAG, "Discovered " + device.getAddress() + " (deviceClass: " + device.getBluetoothClass().getDeviceClass() + ")");
if (discoverySink != null) {
discoverySink.success(discoveryResult);
}
Expand Down Expand Up @@ -444,15 +447,35 @@ private interface EnsurePermissionsCallback {
EnsurePermissionsCallback pendingPermissionsEnsureCallbacks = null;

private void ensurePermissions(EnsurePermissionsCallback callbacks) {
if (
boolean permissionGranted = (
ContextCompat.checkSelfPermission(activity,
Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(activity,
== PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(activity,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
== PackageManager.PERMISSION_GRANTED);

String[] requestString = new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION};

Log.e(TAG,"request permission");

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
Log.e(TAG,"request scan permission");
permissionGranted = (
ContextCompat.checkSelfPermission(activity,
Manifest.permission.BLUETOOTH_SCAN)
== PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(activity,
Manifest.permission.BLUETOOTH_CONNECT)
== PackageManager.PERMISSION_GRANTED);
requestString = new String[]{Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT};
}

if (!permissionGranted) {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
requestString,
REQUEST_COARSE_LOCATION_PERMISSIONS);

pendingPermissionsEnsureCallbacks = callbacks;
Expand Down Expand Up @@ -481,7 +504,6 @@ static private boolean checkIsDeviceConnected(BluetoothDevice device) {
}
}


/// Helper wrapper class for `BluetoothConnection`
private class BluetoothConnectionWrapper extends BluetoothConnection {
private final int id;
Expand Down Expand Up @@ -549,6 +571,7 @@ protected void onDisconnected(boolean byRemote) {

private class FlutterBluetoothSerialMethodCallHandler implements MethodCallHandler {
/// Provides access to the plugin methods
@SuppressLint("MissingPermission")
@Override
public void onMethodCall(MethodCall call, Result result) {
if (bluetoothAdapter == null) {
Expand Down Expand Up @@ -580,18 +603,32 @@ public void onMethodCall(MethodCall call, Result result) {

case "requestEnable":
if (!bluetoothAdapter.isEnabled()) {
pendingResultForActivityResult = result;
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
ActivityCompat.startActivityForResult(activity, intent, REQUEST_ENABLE_BLUETOOTH, null);
ensurePermissions(granted -> {
if (!granted) {
result.error("no_permissions", "Enabling bluetooth requires bluetooth permission", null);
return;
}

pendingResultForActivityResult = result;
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
ActivityCompat.startActivityForResult(activity, intent, REQUEST_ENABLE_BLUETOOTH, null);
});
} else {
result.success(true);
}
break;

case "requestDisable":
if (bluetoothAdapter.isEnabled()) {
ensurePermissions(granted -> {
if (!granted) {
result.error("no_permissions", "Enabling bluetooth requires bluetooth permission", null);
return;
}

bluetoothAdapter.disable();
result.success(true);
});
} else {
result.success(false);
}
Expand All @@ -606,7 +643,11 @@ public void onMethodCall(MethodCall call, Result result) {
break;

case "getAddress": {
String address = bluetoothAdapter.getAddress();
String address = "02:00:00:00:00:00";

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
address = bluetoothAdapter.getAddress();
}

if (address.equals("02:00:00:00:00:00")) {
Log.w(TAG, "Local Bluetooth MAC address is hidden by system, trying other options...");
Expand Down Expand Up @@ -907,6 +948,8 @@ public void onReceive(Context context, Intent intent) {
entry.put("type", device.getType());
entry.put("isConnected", checkIsDeviceConnected(device));
entry.put("bondState", BluetoothDevice.BOND_BONDED);
entry.put("deviceClass", device.getBluetoothClass().getDeviceClass());
Log.d(TAG, "Discovered " + device.getAddress() + " (deviceClass: " + device.getBluetoothClass().getDeviceClass() + ")");
list.add(entry);
}

Expand All @@ -919,6 +962,7 @@ public void onReceive(Context context, Intent intent) {
break;

case "startDiscovery":
Log.d(TAG,"Starting discovery 22");
ensurePermissions(granted -> {
if (!granted) {
result.error("no_permissions", "discovering other devices requires location access permission", null);
Expand Down Expand Up @@ -1067,4 +1111,4 @@ public void onReceive(Context context, Intent intent) {
}

}
}
}
4 changes: 2 additions & 2 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
compileSdkVersion 30
compileSdkVersion 33
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "io.github.edufolly.flutterbluetoothserialexample"
minSdkVersion 19
targetSdkVersion 30
targetSdkVersion 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
1 change: 1 addition & 0 deletions example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
Expand Down
2 changes: 1 addition & 1 deletion example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ subprojects {
project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
10 changes: 8 additions & 2 deletions example/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
android.enableJetifier=true
org.gradle.jvmargs=-Xmx1536M \
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED \
--add-opens=java.base/java.lang=ALL-UNNAMED \
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED \
--add-opens=java.base/java.io=ALL-UNNAMED \
--add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M
android.enableJetifier=true
android.enableR8=true
2 changes: 1 addition & 1 deletion example/android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
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-6.7.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
26 changes: 24 additions & 2 deletions example/lib/BluetoothDeviceListEntry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ class BluetoothDeviceListEntry extends ListTile {
onTap: onTap,
onLongPress: onLongPress,
enabled: enabled,
leading:
Icon(Icons.devices), // @TODO . !BluetoothClass! class aware icon
leading: Icon(getIcon(device.deviceClass)), // @TODO . !BluetoothClass! class aware icon
title: Text(device.name ?? ""),
subtitle: Text(device.address.toString()),
trailing: Row(
Expand Down Expand Up @@ -44,6 +43,29 @@ class BluetoothDeviceListEntry extends ListTile {
),
);

static IconData getIcon(BluetoothDeviceClass deviceClass) {
switch (deviceClass) {
case BluetoothDeviceClass.PERIPHERAL_KEYBOARD:
return Icons.keyboard;
case BluetoothDeviceClass.AUDIO_VIDEO_WEARABLE_HEADSET:
return Icons.headphones;
case BluetoothDeviceClass.AUDIO_VIDEO_HEADPHONES:
return Icons.headphones;
case BluetoothDeviceClass.AUDIO_VIDEO_HANDSFREE:
return Icons.headphones;
case BluetoothDeviceClass.AUDIO_VIDEO_LOUDSPEAKER:
return Icons.speaker;
case BluetoothDeviceClass.PHONE_SMART:
return Icons.smartphone;
case BluetoothDeviceClass.COMPUTER_DESKTOP:
return Icons.computer;
case BluetoothDeviceClass.COMPUTER_LAPTOP:
return Icons.laptop;
default:
return Icons.devices;
}
}

static TextStyle _computeTextStyle(int rssi) {
/**/ if (rssi >= -35)
return TextStyle(color: Colors.greenAccent[700]);
Expand Down
3 changes: 1 addition & 2 deletions example/lib/SelectBondedDevicePage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class SelectBondedDevicePage extends StatefulWidget {
}

enum _DeviceAvailability {
no,
maybe,
yes,
}
Expand All @@ -27,7 +26,7 @@ class _DeviceWithAvailability {
_DeviceAvailability availability;
int? rssi;

_DeviceWithAvailability(this.device, this.availability, [this.rssi]);
_DeviceWithAvailability(this.device, this.availability);
}

class _SelectBondedDevicePage extends State<SelectBondedDevicePage> {
Expand Down
6 changes: 3 additions & 3 deletions example/lib/helpers/LineChart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ class LineChart extends StatelessWidget {
values: values,
valuesLabels: valuesLabels,
horizontalLabelsTextStyle:
horizontalLabelsTextStyle ?? Theme.of(context).textTheme.caption,
horizontalLabelsTextStyle ?? Theme.of(context).textTheme.bodySmall,
verticalLabelsTextStyle:
verticalLabelsTextStyle ?? Theme.of(context).textTheme.caption,
verticalLabelsTextStyle ?? Theme.of(context).textTheme.bodySmall,
horizontalLinesPaint: horizontalLinesPaint,
verticalLinesPaint: verticalLinesPaint,
additionalMinimalHorizontalLabelsInterval:
Expand Down Expand Up @@ -510,7 +510,7 @@ class _LineChartPainter extends CustomPainter {
Iterator<double> argument = arguments.iterator;
while (value.moveNext()) {
argument.moveNext();
if (value.current == null || value.current == double.nan) continue;
if (value.current == null) continue;

if (argument.current < argumentsOffset) continue;
final double xOffset = padding.left +
Expand Down
2 changes: 0 additions & 2 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
name: flutter_bluetooth_serial_example
version: 0.4.0
description: Demonstrates how to use the `flutter_bluetooth_serial` plugin.
authors:
- Patryk Ludwikowski <patryk.ludwikowski.7@gmail.com>
homepage: https://github.com/edufolly/flutter_bluetooth_serial/tree/master/example/

environment:
Expand Down
1 change: 1 addition & 0 deletions lib/BluetoothConnection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class BluetoothConnection {
//

/// This ID identifies real full `BluetoothConenction` object on platform side code.
// ignore: unused_field
final int? _id;

final EventChannel _readChannel;
Expand Down
Loading