Just updated my android to marshmallow and realized that is not working very well.
I have just created an app that reports the Devices and Services (with UUIDs) availables via classical bluetooth:
I've tested it in:
API 16
API 22
API 23
My manifiest permissions are:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
And if you want the check the code of the app:
I'm running out of ideas, so, any help would be greatly appreciated
Thanks!
To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs. The WifiInfo.getMacAddress()
and the BluetoothAdapter.getAddress()
methods now return a constant value of 02:00:00:00:00:00
.
To access the hardware identifiers of nearby external devices via Bluetooth and Wi-Fi scans, your app must now have the ACCESS_FINE_LOCATION
or ACCESS_COARSE_LOCATION
permissions:
WifiManager.getScanResults();
BluetoothDevice.ACTION_FOUND;
BluetoothLeScanner.startScan();
so this is the update feature, add those three method you can get the UUID
After headaches and hours of research, the answer is create the socket not with CreateInsecureRfcommSocketToServiceRecord
, but instead with CreateRfcommSocketToServiceRecord
and a default UUID like "00001101-0000-1000-8000-00805F9B34FB"
I should imagine you are having the same problem I had, for SDK 23 you have to get the user to confirm they give permission to ACCESS_COARSE_LOCATION. (I assume you are running BLE searches)
have a look at you console log and I am guessing you will find a very add error that looks like this, highlighted in blue.
java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results
at android.os.Parcel.readException(Parcel.java:1627)
at android.os.Parcel.readException(Parcel.java:1579)
at android.bluetooth.IBluetoothGatt$Stub$Proxy.startScan(IBluetoothGatt.java:772)
at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper.onClientRegistered(BluetoothLeScanner.java:324)
at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:56)
at android.os.Binder.execTransact(Binder.java:453)
It appears that you need to get user permission (like an iOS app) so you need to add in some code in you init like this
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_COARSE_LOCATION)){
if (DEBUG) Log.i(TAG, "EXPLANATION NEEDED");
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Warning Permission Needed");
builder.setMessage("If you don't enable the location for this app then we can not connect to the controller");
builder.setPositiveButton("Change", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_LOCATION);
}
}
});
AlertDialog dialog = builder.create();
dialog.show();
}else{
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},REQUEST_LOCATION);
}
}
}
Here you must handle what to do if the user doesn't read the message and clicks deny. so check the return in the below method
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_LOCATION){
if (grantResults[0] != PackageManager.PERMISSION_GRANTED){
// ask the question again as they denied the permission
}
}
}
After all that you it will all suddenly work again if your problem was like mine