Jake Turner
Jake Turner

Reputation: 1

Bluetooth low energy security exception

I'm creating an application to scan for Bluetooth low energy devices and have implemented the scan functionality, however, am getting the error:

fail to start le scan - SecurityException thrown: java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results

I have the required permissions in my manifest, however, am still getting this error. I have done some research and read that SDK versions > 23 require some kind of manual checking for permissions, is this the correct solution to this problem or is there a simpler alternative?

  package com.example.jake.bluetooth;

import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_ENABLE_BT = 1;
    private String ble_not_supported = "BLE not supported";
    private BluetoothManager bluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;
    private Button startScanBtn;
    private boolean mScanning;
    private Handler mHandler;
    private BluetoothAdapter.LeScanCallback mLeScanCallBack;
    private static final long SCAN_PERIOD = 10000;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
        startScanBtn = findViewById(R.id.start_scan);
        mHandler = new Handler();
        mScanning = true;

        mLeScanCallBack = new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi, byte[] bytes) {

            }
        };

        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }

        if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
            Toast.makeText(this, ble_not_supported, Toast.LENGTH_SHORT).show();
            finish();
        }

        startScanBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                scanLeDevice(mScanning);
            }
        });

    }

    private void scanLeDevice(final boolean enable){
        if(enable){
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(mLeScanCallBack);
                }
            },SCAN_PERIOD);

            mScanning = true;
            mBluetoothAdapter.startLeScan(mLeScanCallBack);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallBack);
        }
    }

}

Upvotes: 0

Views: 836

Answers (4)

Dan.R
Dan.R

Reputation: 35

It's 2020, but I respond to this question anyway so maybe it will be helpfull for someone. I encauntered this problem and I resolved it with adding this line of code in onCreate call: requestPermissions(new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);. You're just asking to the user to allow access location. Obvisully PERMISSION_REQUEST_COARSE_LOCATION is defined like: private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;.

Upvotes: 2

Emil
Emil

Reputation: 18482

No it's not enough to just have it in your manifest. You must also explicitly ask the user at runtime. See https://developer.android.com/training/permissions/requesting for more info.

Upvotes: 3

Aboalnaga
Aboalnaga

Reputation: 602

You should uninstall previous build:

Run > Edit Configurations > Application > Before launch section(on the right) Create a gradle-aware Make add :app:uninstallAll

Upvotes: 0

Augusto
Augusto

Reputation: 4243

I've a app to use BLE and this is my AndroidManifest.xml file, all works fine.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.bluetoothlowenergy_gatt_sendreceive">

    <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" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".ServiceActivity"></activity>
    </application>

</manifest>

Upvotes: 1

Related Questions