I hope someone can give me an advice with regard to this problem. I've been trying to solve it without any luck, I´ve seen also that this is a real problem and there is a lot of discussions out there.
This is a simple app, that has only a button. The button will make the device to work as a beacon while is pressed, and it will stop sending data when the button is released. At the beginning, the app will check if Bluetooth and BLE are supported suggested in this question.
The app crashes when the device does not have the Bluetooth turned on and asks the user to turn it on. But it doesn´t crash when the device has the Bluetooth already turned on.
Doing further analysis, I saw that the following code snippet is executed showing me the message that The device does not support BLE.
if (mBluetoothAdapter.isEnabled()==false) {
mBluetoothAdapter.enable();
Toast.makeText(getApplicationContext(),"Enabling Bluetooth", Toast.LENGTH_SHORT).show();
Log.e("BLE_code", "State: " + mBluetoothAdapter.getState());
}
if(!mBluetoothAdapter.isMultipleAdvertisementSupported()){
Toast.makeText(getApplicationContext(),"Device does not support BLE", Toast.LENGTH_SHORT).show();
}
I also searched on this website to see if the device does support BLE (I'm working with a Samsung Galaxy S7), it might not be there, but I have tried the app that is suggested to check if the device allows BLE in peripheral mode and it can be discovered. (On the google store there are plenty apps that work as beacons).
There are also more people struggling with the same issue right here, here and some other questions. It might be a little bit old, but still valid.
You can find the full code below to test.
EDITED:
MainActivity.java
package com.ble_app.aecheverri.ble_app;
import android.bluetooth.le.AdvertiseSettings;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.content.Intent;
import android.util.Log;
import java.nio.charset.Charset;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.os.ParcelUuid;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseCallback;
import android.widget.EditText;
import java.util.UUID;
import android.content.Context;
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter;
private final static int REQUEST_ENABLE_BT = 1;
private Button btn;
private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.BLE_CHECK_button);
final EditText edit = (EditText) findViewById(R.id.Data_Sent);
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
mBluetoothAdapter.setName("APEX");
//Check if bluetooth is on, otherwise, turn it on!
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
Log.e("BLE_code", "State: " + mBluetoothAdapter.getBluetoothLeAdvertiser());
//getBluetoothLeScanner
if (mBluetoothAdapter.isEnabled()==false) {
mBluetoothAdapter.enable();
Toast.makeText(getApplicationContext(),"Enabling Bluetooth", Toast.LENGTH_SHORT).show();
Log.e("BLE_code", "State: " + mBluetoothAdapter.getState());
}
if(!mBluetoothAdapter.isMultipleAdvertisementSupported()){
Toast.makeText(getApplicationContext(),"Device does not support BLE", Toast.LENGTH_SHORT).show();
}
final BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
//Set the advertise settings and the power of the signal
final AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
.setConnectable(false)
.build();
final AdvertiseCallback advertisingCallback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
}
@Override
public void onStartFailure(int errorCode) {
Log.e("BLE_code", "Advertising onStartFailure: " + errorCode);
super.onStartFailure(errorCode);
}
};
//BLE Button
btn.setOnTouchListener(new View.OnTouchListener() {
private Handler mHandler;
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction())
{
case MotionEvent.ACTION_DOWN:
Log.e( "BLE_code","Button is being pressed");
Log.e("BLE_code", "State ble: " + mBluetoothAdapter.getState());
ParcelUuid pUuid = new ParcelUuid(UUID.fromString(getString(R.string.ble_uuid)));
AdvertiseData data = new AdvertiseData.Builder()
.setIncludeDeviceName( true )
.addServiceUuid( pUuid )
.addServiceData(pUuid,edit.getText().toString().getBytes(Charset.forName("UTF-8")))
.build();
Log.e( "BLE_code", "Sent Data: " + edit.getText().toString());
String macAddress = android.provider.Settings.Secure.getString(getContentResolver(),"bluetooth_address");
Toast.makeText(getApplicationContext(),"Device: " + macAddress, Toast.LENGTH_SHORT).show();
mBluetoothLeAdvertiser.startAdvertising(settings, data, advertisingCallback);
//advertiser.startAdvertising( settings, data, advertisingCallback );
if (mHandler!=null) return true;
mHandler = new Handler();
mHandler.postDelayed(btn_pressed,10);
break;
case MotionEvent.ACTION_UP:
if(mHandler==null) return true;
mHandler.removeCallbacks(btn_pressed);
mHandler = null;
advertiser.stopAdvertising(advertisingCallback);
Toast.makeText(getApplicationContext(),"Stoping Advertising", Toast.LENGTH_SHORT).show();
Log.e( "BLE_code","Button was released");
break;
}
return false;
}
Runnable btn_pressed = new Runnable() {
public void run(){
Log.e( "BLE_code","Button while pressed");
mHandler.postDelayed(this,10);
}
};
});
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.ble_app.aecheverri.ble_app.MainActivity">
<Button
android:id="@+id/BLE_CHECK_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="195dp"
android:text="Authenticate"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.474" />
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline"
app:layout_constraintGuide_begin="20dp"
android:orientation="vertical" />
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline2"
android:orientation="vertical"
app:layout_constraintGuide_end="340dp" />
<EditText
android:id="@+id/Data_Sent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text"
android:text="Data"
android:layout_marginTop="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/BLE_CHECK_button"
app:layout_constraintVertical_bias="0.683"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.503" />
</android.support.constraint.ConstraintLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ble_app.aecheverri.ble_app">
<!-- Declare this required feature if you want to make the app available to BLE-capable
devices only. If you want to make your app available to devices that don't support BLE,
you should omit this in the manifest. Instead, determine BLE capability by using
PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) -->
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS"/>
<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" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<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>
</application>
</manifest>
strings.xml
<resources>
<string name="app_name">BLE_app</string>
<string name="ble_uuid">00000218-0000-1000-8000-00805f9b34fb</string>
</resources>
Log errors
08-17 13:55:25.533 13469-13469/com.ble_app.aecheverri.ble_app E/BoostFramework: BoostFramework() : Exception_1 = java.lang.ClassNotFoundException: Didn't find class "com.qualcomm.qti.Performance" on path: DexPathList[[],nativeLibraryDirectories=[/system/lib64, /vendor/lib64]]
08-17 13:55:25.566 13469-13469/com.ble_app.aecheverri.ble_app E/InputEventReceiver: Exception dispatching input event.
08-17 13:55:25.567 13469-13469/com.ble_app.aecheverri.ble_app E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
08-17 13:55:25.569 13469-13469/com.ble_app.aecheverri.ble_app E/MessageQueue-JNI: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.bluetooth.le.BluetoothLeAdvertiser.startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback)' on a null object reference
at com.ble_app.aecheverri.ble_app.MainActivity$2.onTouch(MainActivity.java:101)
at android.view.View.dispatchTouchEvent(View.java:10727)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:509)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1863)
at android.app.Activity.dispatchTouchEvent(Activity.java:3226)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:471)
at android.view.View.dispatchPointerEvent(View.java:10960)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5075)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4927)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4458)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4511)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4477)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4610)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4485)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4667)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4458)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4511)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4477)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4485)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4458)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6960)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6899)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6860)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7070)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
08-17 13:55:25.571 13469-13469/com.ble_app.aecheverri.ble_app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ble_app.aecheverri.ble_app, PID: 13469
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.bluetooth.le.BluetoothLeAdvertiser.startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback)' on a null object reference
at com.ble_app.aecheverri.ble_app.MainActivity$2.onTouch(MainActivity.java:101)
at android.view.View.dispatchTouchEvent(View.java:10727)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2865)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2492)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:509)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1863)
at android.app.Activity.dispatchTouchEvent(Activity.java:3226)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:471)
at android.view.View.dispatchPointerEvent(View.java:10960)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5075)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4927)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4458)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4511)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4477)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4610)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4485)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4667)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4458)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4511)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4477)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4485)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4458)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6960)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6899)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6860)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7070)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)