Wait for Bluetooth enabled - android

I have an app used for Bluetooth control of an embedded system using the SPP protocol that has worked fine until Marshmallow. If Bluetooth is enabled when I start the app everything is good. I use startActivityForResult() to prompt the user to allow Bluetooth to be enabled if it's not already. It used to block until a result was given but under Marshmallow it blows through it and crashes immediately with a null pointer exception. I added a "hack" in onResume() to keep it from doing this by returning if not enabled, but am wondering if this is poor practice?
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btAdapter = BluetoothAdapter.getDefaultAdapter();
if (btAdapter == null) {
Toast.makeText(getApplicationContext(), "No bluetooth detected", Toast.LENGTH_SHORT).show();
finish();
} else {
if (!btAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, ENABLE_BT_REQUEST_CODE);
}
}
}
#Override
public void onResume() {
super.onResume();
/* This keeps from crashing immediately if BT not enabled */
if (!btAdapter.isEnabled()) {
return;
};
if (btAdapter.isDiscovering()) {
btAdapter.cancelDiscovery();
}
// Rest of code .......
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Check Result from turnOnBT()
if (requestCode == ENABLE_BT_REQUEST_CODE) {
if (resultCode == RESULT_CANCELED) {
Toast.makeText(getApplicationContext(), "Bluetooth must be enabled to continue", Toast.LENGTH_SHORT).show();
finish();
}
}
}

Related

No devices found upon starting bluetooth scan

I'm currently working on an android app to control Bluetooth devices but no available devices show up even though I can find them from the built-in settings>bluetooth menu.
I initially followed the android starter sample out of the box, but couldn't make it work. I then came across several similar posts and tried those as well, but still couldn't make it work. This is my code so far: ```
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_LOCATION_BT = 3;
private static final int REQUEST_ENABLE_BT = 2;
private BluetoothAdapter bluetoothAdapter;
private ArrayList<String> deviceList;
private ActivityMainBinding binding;
private ArrayAdapter<String> listAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
requiredSetup();
setupListView();
}
private void setupListView() {
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
deviceList = new ArrayList<>();
if (pairedDevices.size() > 0) {
// There are paired devices. Get the name and address of each paired device.
for (BluetoothDevice device : pairedDevices) {
deviceList.add(device.getName());
//String deviceHardwareAddress = device.getAddress(); // MAC address
}
}
listAdapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, deviceList);
binding.listView.setAdapter(listAdapter);
}
private void requiredSetup() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.ACCESS_BACKGROUND_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
MainActivity.this,
new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
REQUEST_LOCATION_BT);
}
}
// checking if device supports bluetooth
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
// Device doesn't support Bluetooth
Toast.makeText(this, "Device doesnt support bluetooth", Toast.LENGTH_SHORT).show();
return;
}
// enabling bluetooth if disabled
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT && resultCode == RESULT_OK) {
Toast.makeText(this, "Bluetooth enabled", Toast.LENGTH_SHORT).show();
} else if (requestCode == REQUEST_ENABLE_BT && resultCode == RESULT_CANCELED) {
Toast.makeText(this, "App requires bluetooth to function", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults) {
if (requestCode == REQUEST_LOCATION_BT) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, yay! Start the Bluetooth device scan.
startScan();
} else {
// Alert the user that this application requires the location permission to perform the scan.
Toast.makeText(this, "Requires location permission to work", Toast.LENGTH_SHORT).show();
}
}
}
/**
* initializes device discovery. The list of devices are sent to the broadcast receiver
* The discovery process usually involves an inquiry scan of about 12 seconds,
* followed by a page scan of each device found to retrieve its Bluetooth name.
*/
private void startScan() {
// If we're already discovering, stop it
if (bluetoothAdapter.isDiscovering()) {
Toast.makeText(this, "stopping discovery", Toast.LENGTH_SHORT).show();
bluetoothAdapter.cancelDiscovery();
} else {
try {
// Register for broadcasts when a device is discovered
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
// Request discover from BluetoothAdapter
bluetoothAdapter.startDiscovery();
binding.progressBar.setVisibility(View.VISIBLE);
} catch (IllegalArgumentException e) {
e.printStackTrace();
Toast.makeText(this, "receivers not registered", Toast.LENGTH_SHORT).show();
}
}
}
/**
* #param view the button view that is pressed and the scanning begins
*/
public void searchDevices(View view) {
// checking if location permissions enabled
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_LOCATION_BT);
} else {
startScan();
}
}
/**
* The BroadcastReceiver that listens for discovered devices and changes the title when
* discovery is finished
*/
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Toast.makeText(getApplicationContext(), "reeiver working", Toast.LENGTH_SHORT).show();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// If it's already paired, skip it, because it's been listed already
if (device != null && device.getBondState() != BluetoothDevice.BOND_BONDED) {
listAdapter.add(device.getName() + "\n" + device.getAddress());
Log.i("NEW DEVICE", device.getName());
listAdapter.notifyDataSetChanged();
}
// When discovery is finished, change the Activity title
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//setProgressBarIndeterminateVisibility(false);
//setTitle(R.string.select_device);
binding.progressBar.setVisibility(View.INVISIBLE);
if (listAdapter.getCount() == 0) {
Toast.makeText(context, "no devices found", Toast.LENGTH_SHORT).show();
}
} else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
Toast.makeText(context, "Bluetooth state changed", Toast.LENGTH_SHORT).show();
} else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
Toast.makeText(context, "Discovery started", Toast.LENGTH_SHORT).show();
}
}
};
#Override
protected void onDestroy() {
super.onDestroy();
// Make sure we're not doing discovery anymore
if (bluetoothAdapter != null) {
bluetoothAdapter.cancelDiscovery();
}
// Unregister broadcast listeners
this.unregisterReceiver(mReceiver);
}}
This is my manifest permissions:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
This is my repository. It would be very helpful if anyone could shed some light here.
It seems like the code was just fine. The problem was with the target SDK version. Upon changing the version from 30 to 28, it worked. Thanks to MatejC's answer.

how to wait till bluetooth turn on in android

I need to turn on Bluetooth in an android device programmatically and wait till it on to proceed to next line of code.
My code is as below
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
ctx.startActivity(enableBtIntent);
}
When doing like this, the code continue to execute from next line without waiting for bluetooth completely on. Is there any way to solve this? Can I add a look to check if bluetooth is on?
You can register a BroadcastReceiver to listen for state changes on the BluetoothAdapter.
First create a BroadcastReceiver that will listen for state changes
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
final int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR);
switch (bluetoothState) {
case BluetoothAdapter.STATE_ON:
//Bluethooth is on, now you can perform your tasks
break;
}
}
}
};
Then register the BroadcastReceiver with your Activity when it is created so that it can start receiving events.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Set a filter to only receive bluetooth state changed events.
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mReceiver, filter);
}
Remember to unregister the listener when the Activity is destroyed.
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
You can use startActivityForResult() and check for whether resultCode is RESULT_OK in onActivityResult() with bluetooth permission in your Manifest file like..
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, 0);
}
onActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
// bluetooth enabled
}else{
// show error
}
}
ACTION_REQUEST_ENABLE
Use this code
Permissions on your menifest file
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
and code
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent , 0);
} else
{
Toast.makeText(getApplicationContext(),"Already on", Toast.LENGTH_LONG).show();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
Toast.makeText(getApplicationContext(),"Turned on",Toast.LENGTH_LONG).show();
}
if(resultCode == RESULT_CANCELED){
}
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//do your things
}

How to stop repeated request to enable bluetooth

Whenever I start/resume my android phone app, it will prompt me to enable my bluetooth twice, regardless what I choose on the first prompt message. What is wrong with my code?
public class MainActivity extends AppCompatActivity {
// BLE management
private static BluetoothManager btManager;
private static BluetoothAdapter btAdapter;
// Set the enable bluetooth code
private final static int REQUEST_ENABLE_BT = 0;
// String for LogCat documentation
private final static String DEBUG_TAG= "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
btAdapter = btManager.getAdapter();
if (btAdapter != null) {
if (!btAdapter.isEnabled()) {
// Request Bluetooth Adapter to be turned on
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
}
else
{
Log.i(DEBUG_TAG, "No bluetooth available");
}
Button launchReminderButton = (Button) findViewById(R.id.button);
launchReminderButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Launch Reminder
// Used Context's startActivity() method
// Create an intent stating which Activity you would like to
// start
Intent reminder = new Intent(MainActivity.this, Reminder.class);
// Launch the Activity using the intent
startActivity(reminder);
}
}
);
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onResume() {
super.onResume();
// check for Bluetooth enabled on each resume
if(btAdapter != null && !btAdapter.isEnabled()){
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onStop() {
super.onStop();
}
#Override
public void onRestart() {
super.onRestart();
}
#Override
public void onDestroy() {
super.onDestroy();
btAdapter = null;
}
#Override
protected void onActivityResult(int request_enable_bt, int result_enable_bt, Intent data)
{
super.onActivityResult(request_enable_bt, result_enable_bt, data);
if(result_enable_bt == RESULT_OK) {
Toast.makeText(this, "Turned On", Toast.LENGTH_SHORT).show();
}
else if (result_enable_bt == RESULT_CANCELED)
{
Toast.makeText(this, "Didn't Turn On", Toast.LENGTH_SHORT).show();
finish();
}
}
Thanks.
Pay attention to the following code,the key is finish() you used here:
#Override
protected void onActivityResult(int request_enable_bt,
int result_enable_bt, Intent data)
{
super.onActivityResult(request_enable_bt, result_enable_bt, data);
if (result_enable_bt == RESULT_OK)
{
Toast.makeText(this, "Turned On", Toast.LENGTH_SHORT).show();
}
else if (result_enable_bt == RESULT_CANCELED)
{
Toast.makeText(this, "Didn't Turn On", Toast.LENGTH_SHORT).show();
finish();
}
}
When you start your app,the system will remind you to turn on your Bluetooth,because your request Bluetooth on in onCreate method.When you deny the request, and the method onActivityResult call back,you will run the following code:
else if (result_enable_bt == RESULT_CANCELED)
{
Toast.makeText(this, "Didn't Turn On", Toast.LENGTH_SHORT).show();
finish();
}
The finish() will finish your Activity,every time when you click your app,when you click deny first time,and then you click deny second time.Every time you got this: onCreate -> onResume.So you get the request to enable your Bluetooth twice!

OnActivityResult for 2 different activites

I am trying to initialize/ turn on the NFC and the BT modules in same activity.
I need them both to be enabled before I continue the task.
I do understand that OnResultActivity is Async so I am trying to figure out what would be the best way to achieve it?
Here's most of the code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initBT();
initNFC();
Intent nextIntent;
if(SaveSharedPreference.getUserName(MainActivity.this).length() == 0)
{
nextIntent = new Intent(MainActivity.this, LoginActivity.class);
}
else
{
nextIntent = new Intent(MainActivity.this, MainMenuActivity.class);
}
startActivity(nextIntent);
finish();
}
private void initBT() {
if(BTModule.GetInstance().initBT().equals(Constants.eBluetoothStatus.BT_DISABLED)){
Intent enableBtIntent = new Intent(BTModule.GetAdapter().ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
private void initNFC(){
mNFCState = NFCModule.initNFC(this);
if(mNFCState == eNFCStatus.NFC_NOT_SUPPORTED){
Toast.makeText(this, "NFC is not suppoeted for this device", Toast.LENGTH_LONG).show();
}
else if(mNFCState == eNFCStatus.NFC_DISABLED){
Intent nfcIntent;
if(android.os.Build.VERSION.SDK_INT >= 16){
nfcIntent = new Intent(android.provider.Settings.ACTION_NFC_SETTINGS);
}
else{
nfcIntent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
}
startActivity(nfcIntent);
Toast.makeText(this, "Please enable NFC", Toast.LENGTH_LONG);
}
else{
Toast.makeText(this, "NFC is up and running", Toast.LENGTH_LONG).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == eBluetoothStatus.BT_OK.ordinal()){
Toast.makeText(this, "BT is up and running", Toast.LENGTH_LONG).show();
return;
}
}
}
As I am a newbie please feel free to correct me if I am wrong with anything :)
thanks!!
Use startActivityForResult instead of startActivity in initNFC method. Also define 2 boolean variables like isNfcEnabled and isBtEnabled. In onActivityResult method check those booleans. If both of them are enable, do whatever you want.

Android: force bluetooth

Is there a way to force bluetooth on?
all I've found so far is this (using the estimote sdk, which I'm working with):
// Check if device supports Bluetooth Low Energy.
if (!beaconManager.hasBluetooth()) {
Toast.makeText(this, "Device does not have Bluetooth Low Energy", Toast.LENGTH_LONG).show();
return;
}
// If Bluetooth is not enabled, let user enable it.
if (!beaconManager.isBluetoothEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
else {
connectToBlueTooth();
}
And then in the onActivityResult:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == Activity.RESULT_OK) {
connectToBlueTooth();
}
else {
Toast.makeText(this, "Bluetooth not enabled", Toast.LENGTH_LONG).show();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
But this asks to the user if he wants to turn on bluetooth... but is there a way to turn it on without asking the user?
And, if there is no way to do it, how can I use this technique outside of an activity?
Thanks
Try BluetoothAdapter like this:
BluetoothAdapter.getDefaultAdapter().enable();

Categories

Resources