Android - Bluetooth discovery doesn't find any device - android

I'm currently working on a little app to get started with the services that the Bluetooth Android API can provide.
Edit -> Answer:
It seems that the issue was due to the specific Nexus 5 devices. Seems like their bluetooth receiver doesn't work well. Solution below should work for other devices
Remark:
I’ve read the documentation here: http://developer.android.com/guide/topics/connectivity/bluetooth.html
as well as the following source code of this tutorial http://www.londatiga.net/it/programming/android/how-to-programmatically-scan-or-discover-android-bluetooth-device/ located on github under /lorensiuswlt/AndroBluetooth
I’ve finished almost all the features that interested me (such as check for adapter existence, enable/disable the blueooth, querying paired divices, set the adapter discoverable).
Issue:
Actually no device is found when i launch the .onDiscovery() method, even though devices are found from Settings/Bluetooth on my Nexus 5.
Here is how I handle it:
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
...
protected void onCreate(Bundle savedInstanceState) {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver, filter);
}
The filter is working well as far as i could try, i.e ACTION_STATE_CHANGED (on bluetooth enabling) and the two ACTION_DISCOVERY_***.
The following method is then successfuly called:
public void onDiscovery(View view)
{
mBluetoothAdapter.startDiscovery();
}
And then i have my bluetooth receiver:
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
if (state == BluetoothAdapter.STATE_ON) {
showToast("ACTION_STATE_CHANGED: STATE_ON");
}
}
else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
mDeviceList = new ArrayList<>();
showToast("ACTION_DISCOVERY_STARTED");
mProgressDlg.show();
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action) && !bluetoothSwitchedOFF) {
mProgressDlg.dismiss();
showToast("ACTION_DISCOVERY_FINISHED");
Intent newIntent = new Intent(MainActivity.this, DeviceListActivity.class);
newIntent.putParcelableArrayListExtra("device.list", mDeviceList);
startActivity(newIntent);
}
else if (BluetoothDevice.ACTION_FOUND.equals(action)) {// When discovery finds a device
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
mDeviceList.add(device);
showToast("Device found = " + device.getName());
}
}
};
I don't have any issue coming out the logcat and didn't notice any trouble during the test I did. The only problem is that no device is discovered at the end of the scan, when many discoverable ones are available arround.
I tried to not put too much code in order to not flood the topic. Ask me if you need more.
Thanks for reading me, and thanks in advance for you answers.

What version of Android are you running this on? If it is Android 6.x, I believe you need to add the ACCESS_FINE_LOCATION permission to your manifest. For example:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
I had a similar issue and this fixed it for me.
UPDATE: Adding documentation direct from Google on this:
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
UPDATE 2020: We recently updated our application to target SDK Version 29. In doing this, our application stopped being able to discover Bluetooth devices again. We have been using ACCESS_COARSE_LOCATION since this answer was originally written. Changing to ACCESS_FINE_LOCATION appears to fix the issue. I now recommend developers try ACCESS_FINE_LOCATION if targeting 29+. Answer updated to reflect this.

Bit late to the party but this may come in handy for other people.
You need to do two things
Add <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
or <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
to your AndroidManifest.xml
Make sure you're requesting the permission on runtime as well for Android 6.0 Devices by using something like this
int MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 1;
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);
just before mBluetoothAdapter.startDiscovery();
If you don't do step 2 you won't be able to get any Hardware Identifier info on device with Android >= 6.0
UPDATE/EDIT:
Example with Android Version check and alert dialog as warning
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Only ask for these permissions on runtime when running Android 6.0 or higher
switch (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.ACCESS_COARSE_LOCATION)) {
case PackageManager.PERMISSION_DENIED:
((TextView) new AlertDialog.Builder(this)
.setTitle("Runtime Permissions up ahead")
.setMessage(Html.fromHtml("<p>To find nearby bluetooth devices please click \"Allow\" on the runtime permissions popup.</p>" +
"<p>For more info see here.</p>"))
.setNeutralButton("Okay", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(DeviceListActivity.this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
REQUEST_ACCESS_COARSE_LOCATION);
}
}
})
.show()
.findViewById(android.R.id.message))
.setMovementMethod(LinkMovementMethod.getInstance()); // Make the link clickable. Needs to be called after show(), in order to generate hyperlinks
break;
case PackageManager.PERMISSION_GRANTED:
break;
}
}

As with new android version things are changed a bit
Older android version like android 10 needs FINE_LOCATION where as newer android version like android 12 works with COARSE_LOCATION also. hence my advice is to ask for FINE_LOCATION permission which will work in both. don't ask COAR_LOCATION and FINE_LOCATION simultaneously otherwise it will not work with android 12 and greater if user select coarse location at app start up.

Related

bluetoothAdapter.enable(); shows Bluetooth enable prompt without intent ACTION_REQUEST_ENABLE in some devices

I would like to enable bluetooth with my app without user interaction, the prompt does not appear on my devices - Android 7, 8 & 9, and my friend's Android 10. But it appears in my work colleague's devices (Android 10).
I used the following permissions
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
And used the following Bluetooth Adaptor methods.
bluetoothAdapter.enable();
bluetoothAdapter.disable();
I have no intent ACTION_REQUEST_ENABLE or ACTION_REQUEST_DISABLE in my source code.
Am I missing some permissions or methods?
Or is this an environment problem?
Any advise on how should I handle this would be much appreciated.
Thank you.
bluetoothAdapter.enable() will directly run com.android.settings/.bluetooth.RequestPermissionHelperActivity, and you should listen for ACTION_STATE_CHANGED yourself.
I think use the BluetoothAdapter.ACTION_REQUEST_ENABLE is a better way, which will first run com.android.settings.bluetooth.RequestPermissionActivity and then RequestPermissionHelperActivity. RequestPermissionActivity will listen for ACTION_STATE_CHANGED, while your app only need the result code of Activity.RESULT_OK.
private boolean ensureBluetoothEnabled() {
if(((BluetoothManager) Objects.requireNonNull(getSystemService(Context.BLUETOOTH_SERVICE)))
.getAdapter().isEnabled()) {
return true;
} else {
Intent btIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
btIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, Constants.PACKAGE);
startActivityForResult(btIntent, REQUEST_CODE_BL_OPEN);
return false;
}
}

BLE Scan not working

I am a beginner working on a BLE scanner using Google's sample code: https://github.com/googlesamples/android-BluetoothLeGatt
Currently, the code is not able to detect any devices. This post says that this is because of location services being disabled or not being explicitly asked for on runtime. I have already included the required permissions in my Manifest.
I have added a few lines of code, which I think should work.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setTitle(R.string.title_devices);
mHandler = new Handler();
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
// Quick permission check
int permissionCheck = this.checkSelfPermission("Manifest.permission.ACCESS_FINE_LOCATION");
permissionCheck += this.checkSelfPermission("Manifest.permission.ACCESS_COARSE_LOCATION");
if (permissionCheck != 0) {
this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001); //Any number
}
}
I think the quick permission check I have added should work, but the app still doesn't seem to be detecting any devices.
I have met the same case that you are facing. If you are using android 6.0 or greater than. You must request location permission at runtime. After get Bluetooth Adapter, let's insert a code line as below to request location permission. When your app run, a dialog will be showed to ask whether you agree to shared your location.
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001);
Let response my answer if this is not correct answer for you question, I will delete immediately.
onscannerregistered status =133
This might be because of the below reason.
1)Location Permission not given in Appication.
2)When Connecting to the Devies stop the scan and then connect to devices.
3)Scanning should not happen when we are reading/writing Data to Devices.
Make sure the scan is stopped
4)If Frist scan is started should wait until the scan is finished.Then start the second scan.
5)Scanning multiple times without waiting for the previous scan to finish might result in couldn't find the scan call-back.
Try fast BLE Library it s more effective the Google BLE library available.

How to get available Hotspot network and show on list in android

I am making a android game in which user can play game using hotspot connectivity like the share it app connect the two user using hotspot.I searched on google but they only show list of wifi network but i only want to show the available hotspot in near by.Please help me guys.I am stuck in this from three days.
You need to create a BroadcastReceiver to listen for Wifi scan results:
private final BroadcastReceiver mWifiScanReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context c, Intent intent) {
if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
List<ScanResult> mScanResults = mWifiManager.getScanResults();
// add your logic here
}
}
}
In onCreate() you would assign mWifiManager and initiate a scan:
mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
registerReceiver(mWifiScanReceiver,
new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mWifiManager.startScan();
getScanResults() will return data only if you have appropriate permissions. For this, add one of the following two lines to your AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Also note that in API 23+, permissions must be requested at runtime. (For a lab environment, you can also grant permissions manually in Settings instead—less coding required, but not recommended for an end-user app.)
Note that the code which handles your scan results would run every time a new scan result is available, updating the result.

In Marshmallow broadcast is not working with action android.intent.action.proximity_sensor

In Marshmallow this code is not working with GearVR. Activity.onResume() code
IntentFilter intentFilter = new IntentFilter("android.intent.action.proximity_sensor");
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getType().equals("1"))
{
Log.v(LOGTAG,"headset mounted");
}
else
{
Log.v(LOGTAG,"headset unmounted");
}
}
};
this.registerReceiver(mReceiver, intentFilter);
}
this is used to detect GearVR mounted and unmounted.
It was working in S6 Lollipop.
Probably this is bug in Marshmallow 6.0.1 link.
Any workaround this problem? related links link1 link2
Please share anything that help me in detecting GearVr mount and unmount
Android 6.0 is now using Doze mode to minimize the use of battery. So this Doze mode not allows the system wakups again and again. There should me Minimum of 9 mins gap should be there between two consecutive wakeups. See official documentation for detail.Cleck here

Can I turn on WiFi-Direct from code? on API-16 (Android 4.2.2)

I am developing an application with NFC and wifi direct. I get the MAC address using NFC and the Wifi Direct to transfer data. I call discoverpeers() and could get success. But there is no callback WIFI_P2P_PEERS_CHANGED_ACTION, the callback comes only when I go to settings and the select wifidirect.
This was discussed in the other question
Can I turn on WiFi-Direct from code? on Android API-14 (ICS)
"I'd like to add that WiFi direct on JB and above (at least on AOSP) is not active all the time - it only appears to be. If you look at listeners for WiFi direct, it turns itself off after some time. It turns itself back on if you open the wifi direct menu, however. You might have to have the host do a peer search or initialize itself in order to be able to be found. Likely a battery saving trick. I have also found that it's blocking, since as it accepts a connection, the entire system will lock up and fail to connect sometimes. (The system invitation) – Mgamerz "
Can anyone suggest the solution for the problem WIFI_P2P_PEERS_CHANGED_ACTION callback is not got and can get only when manually go to settings->wifi->tap on wifidirect
I used two devices Samsung galaxy nexus and nexus 7 both running on 4.2.2
There is no available API to enable wifiP2P but you can invoke method "enableP2p" from android settings 4.0.1
WifiP2pManager manager = (WifiP2pManager) getActivity().getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(getActivity(), getActivity().getMainLooper(), null);
try {
Method method1 = manager.getClass().getMethod("enableP2p", Channel.class);
method1.invoke(manager, channel);
//Toast.makeText(getActivity(), "method found",
// Toast.LENGTH_SHORT).show();
} catch (Exception e) {
//Toast.makeText(getActivity(), "method did not found",
// Toast.LENGTH_SHORT).show();
}
To disable wifiP2P use this method
Method method1 = manager.getClass().getMethod("disableP2p", Channel.class);
Not from code. The user has to. That's why the demo has the link to wifi settings in the action bar.
When you call manager.discoverPeers(channel, new WifiP2pManager.ActionListener()
define onFailure and look at the reasonCode. If it's 0, then either the Wifi or WiFi direct is off.
If you look at the WiFi Direct demo app, the WifiDirectBroadcast Reciever, this piece of code looks at whether p2p is enabled specifically
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
// UI update to indicate wifi p2p status.
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
// Wifi Direct mode is enabled
activity.setIsWifiP2pEnabled(true);
} else {
activity.setIsWifiP2pEnabled(false);
activity.resetData();
}
Then when discover peers is called it looks at the variable set by setIsWifiP2pEnabled
thanks user3093354. to continue with your solution, in order to disable the p2p you have to invoke:
Method method1 = manager.getClass().getMethod("disableP2p", Channel.class);
//Try this it may be help you
WifiManager wifiManager = (WifiManager)this.getSystemService(this.WIFI_SERVICE);
wifiManager.setWifiEnabled(true); //True - to enable WIFI connectivity .
//False -disable WIFI connectivity.
//add this permissions in Manifest file :
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
You can load the wifi driver from a command prompt with the desired concurrency level if you are rooted:
/system/bin/insmod /system/lib/modules/wlan.ko con_mode=3
These are the values:
typedef enum
{
VOS_STA_MODE=0,
VOS_STA_SAP_MODE=1,
VOS_P2P_CLIENT_MODE,
VOS_P2P_GO_MODE,
VOS_MONITOR_MODE,
VOS_FTM_MODE = 5,
VOS_IBSS_MODE,
VOS_P2P_DEVICE_MODE,
VOS_MAX_NO_OF_MODE
} tVOS_CON_MODE;
This is for an Atheros card.

Categories

Resources