I'm working on A2DP and GAT bluetooth profile. I need get all available A2DP bluetooth devices around bluetooth application.
However, I didn't scan any low energy bluetooth device or classic bluetooth device by using startDiscovery() or startLeScan() API so far.
I set enough permission in the Android Manifest file as below:
<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_BACKGROUND_LOCATION" />
I also pulled and run Google's origin sample:
https://github.com/android/connectivity-samples/tree/master/BluetoothLeGatt
But, it didn't work
Here is my code by using startDiscovery API
public void searchDevices(OnSearchDeviceListener listener) {
checkNotNull(listener);
if (mBondedList == null) mBondedList = new ArrayList<>();
if (mNewList == null) mNewList = new ArrayList<>();
mOnSearchDeviceListener = listener;
if (mBluetoothAdapter == null) {
mOnSearchDeviceListener.onError(new NullPointerException(DEVICE_HAS_NOT_BLUETOOTH_MODULE));
return;
}
if (mReceiver == null) mReceiver = new Receiver();
// ACTION_FOUND
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
mContext.registerReceiver(mReceiver, filter);
// ACTION_DISCOVERY_FINISHED
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
mContext.registerReceiver(mReceiver, filter);
mNeed2unRegister = true;
mBondedList.clear();
mNewList.clear();
if (mBluetoothAdapter.isDiscovering())
mBluetoothAdapter.cancelDiscovery();
mBluetoothAdapter.startDiscovery();
if (mOnSearchDeviceListener != null)
mOnSearchDeviceListener.onStartDiscovery();
}
I'm not sure, Has the Google updated the bluetooth framework?
If anybody know this issue, please help me.
Thank in advance.
Related
I'm new to the Android platform and I want to create an app that creates a wi-fi hotspot so my microcontroller (esp32-c3) can connect to it. Further, the app should only contain a webview and be able to automatically determinate the IP-adres of the microcontroller so there can be established a Websocket connection to receive sensor data.
After much frustration setting up the IDE, I finally managed to build a simple app and and run it on my phone. My problem is that I always get a failure with reason code 0 (WifiP2pManager.ERROR) after creating a group, which is according to the documentation an internal error. I've tested this on multiple phones (Android 12 and 13) with the same result.
What I noticed is that there are barley examples available covering this topic. Am i making a mistake and is it possible to find out the detailed error message instead of seeing just htis generic error code?
This whole platform is difficult and frustrating. Can someone help me out? It must definitely be possible to create this on my phone, because with the app PdaNet+ I'm able to create a wi-fi direct hotpot that works.
public class MainActivity extends AppCompatActivity implements WifiP2pManager.ChannelListener, WifiP2pManager.ActionListener {
private final IntentFilter intentFilter = new IntentFilter();
private TextView tv1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1 = this.findViewById(R.id.tv1);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
WifiP2pManager.Channel channel = manager.initialize(this, getMainLooper(), this);
manager.createGroup(channel, this);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
tv1.append("\n" + action);
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
tv1.append("\nWifi P2P is enabled");
} else {
tv1.append("\nWifi P2P is disabled");
}
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
tv1.append("\nCall WifiP2pManager.requestPeers() to get a list of current peers");
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
tv1.append("\nRespond to new connection or disconnections");
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
tv1.append("\nRespond to this device's wifi state changing");
}
}
};
registerReceiver(receiver, intentFilter);
}
#Override
public void onSuccess() {
tv1.append("\nGroup created successfully");
}
#Override
public void onFailure(int reason) {
tv1.append("\nFailed to create group (reason "+reason+")");
}
#Override
public void onChannelDisconnected() {
tv1.append("\nonChannelDisconnected");
}
}
Manifest:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
I finally solved the problem: it turned out the location permission was blocked. After giving access, the hotspot could get created.
Through searching around on SO, I found a way to scan wifi networks in the area and to display those results through a TextView. Here is the code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.wifinetworks);
mainText = (TextView) findViewById(R.id.mainText);
mainText.setText("");
mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if(mWifiManager.isWifiEnabled()==false)
{
mWifiManager.setWifiEnabled(true);
}
receiverWifi = new WifiReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(receiverWifi, intentFilter);
mainText.setText("Starting Scan...");
mWifiManager.startScan();
}
public class WifiReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(debugString, "I am in onRecieve");
List<ScanResult> wifiScanList = mWifiManager.getScanResults();
mainText.setText("");
for (int i = 0; i < wifiScanList.size(); i++) {
String info = (wifiScanList.get(i).toString());
mainText.append(info + "\n\n");
}
}
}
The log statement never seems to get called, and I have the following permissions in my manifest file:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
What could be going wrong here? Appreciate any suggestions.
EDIT: I realized that I had not declared my receiver in the manifest so I made a WifiReceiver class (changes are above) and declared it like so:
<receiver android:name="com.example.alexander.bluetoothcontroller.MainActivity$WifiReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
</intent-filter>
</receiver>
However, this still did not change anything unless I am missing something in the declaration. I also added the extra permission that was suggested but still nothing has changed. I did notice this callstack that stood out to me in logcat:
08-09 14:27:17.821 1579-1622/? E/WifiHW: Failed to stop supplicant
08-09 14:27:17.821 1579-1622/? E/wifi: Can not initialize the vendor function pointer table
08-09 14:27:17.821 1579-1622/? E/WifiNative-HAL: Could not start hal
08-09 14:27:17.821 1579-1622/? E/WifiStateMachine: Failed to start HAL
08-09 14:27:17.821 1579-1622/? E/WifiHW: Cannot open "/system/etc/wifi/wpa_supplicant.conf": No such file or directory
08-09 14:27:17.821 1579-1622/? E/WifiHW: Wi-Fi will not be enabled
08-09 14:27:17.821 1579-1622/? E/WifiStateMachine: Failed to start supplicant!
08-09 14:27:17.822 1579-1579/? E/WifiController: WifiControllerWifi turn on failed
Could this be the problem?
EDIT 2:
So I tried checking for permissions at run time but still no change.
private boolean checkAndRequestPermissions() {
int wifi_state = ContextCompat.checkSelfPermission(this, permission.ACCESS_WIFI_STATE);
int change_wifi_state = ContextCompat.checkSelfPermission(this, permission.CHANGE_WIFI_STATE);
int loc = ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION);
int loc2 = ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION);
int internet = ContextCompat.checkSelfPermission(this, permission.INTERNET);
List<String> listPermissionsNeeded = new ArrayList<>();
if (wifi_state != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(permission.ACCESS_WIFI_STATE);
}
if (change_wifi_state != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(permission.CHANGE_WIFI_STATE);
}
if (loc2 != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(android.Manifest.permission.ACCESS_FINE_LOCATION);
}
if (loc != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(android.Manifest.permission.ACCESS_COARSE_LOCATION);
}
if (internet != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(permission.INTERNET);
}
if (!listPermissionsNeeded.isEmpty())
{
ActivityCompat.requestPermissions(this,listPermissionsNeeded.toArray
(new String[listPermissionsNeeded.size()]),REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
I call this method in my onCreate. I'm still getting the call stack message that Controller Wifi failed to turn on as well, which I'm thinking to be the issue more and more.
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
Try to add the missing permission ACCESS_COARSE_LOCATION
Source : https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id
The issue was a mistake on my part, I was using the android emulator to test my app when I should have been using an actual phone.
I have a real android device (Android 4.1.1). Which supports applications like Xender, ShareIt, Zapya etc which uses WiFi Direct to transfer files.
But when I run my application, it says P2P_UNSUPPORTED.
My manifest permissions are....
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
My MainActivity.java is like this..
intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
Receiver receiver=new Receiver();
registerReceiver(receiver,intentFilter);
WifiP2pManager manager=(WifiP2pManager)getSystemService(WIFI_P2P_SERVICE);
channel=manager.initialize(this, Looper.getMainLooper(),null);
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
// Code for when the discovery initiation is successful goes here.
// No services have actually been discovered yet, so this method
// can often be left blank. Code for peer discovery goes in the
// onReceive method, detailed below.
}
#Override
public void onFailure(int reasonCode) {
// Code for when the discovery initiation fails goes here.
// Alert the user that something went wrong.
switch (reasonCode){
case WifiP2pManager.BUSY:Log.e("code","BUSY");break;
case WifiP2pManager.ERROR:Log.e("code","ERROR");break;
case WifiP2pManager.P2P_UNSUPPORTED:Log.e("code","P2P_UNSUPPORTED");break;
}
}
});
In the Log,, I get.
code﹕ P2P_UNSUPPORTED
And my BraodcastReceiver is like this..
#Override
public void onReceive(Context context, Intent intent) {
//Log.e("intent",intent.getAction());
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
Log.e("raw state", ""+state);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
Log.e("state", "ON");
} else if(state == WifiP2pManager.WIFI_P2P_STATE_DISABLED) {
Log.e("state", "DISABLED "+ state);
}
}
And there i get the log as,,
raw state﹕ -1
NOTE : the variable state neither equals WifiP2pManager.WIFI_P2P_STATE_ENABLED nor WifiP2pManager.WIFI_P2P_STATE_DISABLED
It is possible that the applications that you have listed are able to use alternative transports other than Wi-Fi Direct. The P2P_UNSUPPORTED error implies that your device does not have the Wi-Fi Direct feature. You can try confirming this by executing the following: getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT). Alternatively, if your device has Wi-Fi Direct, you can access a Wi-Fi Direct settings activity from the Wi-Fi settings of your device.
What's the difference between Action CONNECTION_STATE_CHANGED and STATE_CHANGED in Android Bluetooth Receiver ?
else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED .equals(action)) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
BluetoothAdapter.STATE_DISCONNECTED);
if (state == BluetoothAdapter.STATE_CONNECTED) {
//nothing
} else {
}
} else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
if (state == BluetoothAdapter.STATE_OFF) {
}
}
According to the docs the difference is the following:
ACTION_CONNECTION_STATE_CHANGED
Intent used to broadcast the change in connection state of the local Bluetooth adapter to a profile of the remote device.
ACTION_STATE_CHANGED
The state of the local Bluetooth adapter has been changed. For example, Bluetooth has been turned on or off.
In other words one Intent is for changes in the connection state and the other one for state changes of the Bluetooth adapter itself.
EDIT:
To detect if a device moves in and out of range you need to use the following intents:
ACTION_ACL_CONNECTED: link to documentation
ACTION_ACL_DISCONNECTED: link to documentation
For both of those you need the normal BLUETOOTH permission and the BLUETOOTH_ADMIN permission:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
The intent filter for your BroadcastReceiver would look something like this:
<intent-filter>
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
</intent-filter>
Here is the general documentation about BluetoothDevice.
I'm trying to have my app's service listen for Bluetooth connection and disconnection attempts, so I can dynamically check/support Bluetooth tethering network communication.
First I have two Samsung S4s (running CyanogenMod 10.2, which is Android 4.3.1 based) which I can pair just fine. If I set one device to Bluetooth tether, when the other connects, a new bt-pan network interface is created and DHCP is used to assign IPs. I confirmed this using iwconfig and ifconfig in shell.
I have the following perms in my app: (there's more, I'm just pointing out the BT perms I added)
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
Here's my Service's onCreate where I set my IntentFilters: (note I've got Toasts here, but I was working with Logging originally)
#Override
public void onCreate() {
super.onCreate();
...
this.mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
mLocalBroadcastManager.registerReceiver(mMessageReceiver, filter);
}
Here's my BroadcastReceiver implementation:
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(BluetoothDevice.ACTION_FOUND)) {
Toast.makeText(getApplicationContext(), "BT found", Toast.LENGTH_SHORT).show();
} else if(action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
Toast.makeText(getApplicationContext(), "BT Connected",
} else if(action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
Toast.makeText(getApplicationContext(), "BT Disconnected", Toast.LENGTH_SHORT).show();
} else
Toast.makeText(getApplicationContext(), "BT Disconnect requested", Toast.LENGTH_SHORT).show();
}
}
}
Now, when I turn Bluetooth off/on, connect/disconnect to a paired device, nothing fires. I've payed around with the devices from both ends. Nothing is broadcast.
Anyone have a suggestion? I really need to receive these bluetooth events. Please don't point to another post/site with the same perms and intent filters. Thanks.
I have a very similar code which works, the only major difference i found was this:
mLocalBroadcastManager.registerReceiver(mMessageReceiver, filter);
i beleive that registerReceiver should be called from the context you want to get intents to.
try calling the method from this. i.e remove the mLocalBroadcastManager like:
registerReceiver(mMessageReceiver, filter);
If you Register the Receiver on the Manifest instead of the Activity, you can receive broadcasts even if you do not have the app opened, you can do this:
<receiver android:name=".BluetoothReceiver" >
<intent-filter>
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<action android:name="android.bluetooth.device.action.BOND_STATE_CHANGED" />
</intent-filter>
</receiver>