I am trying to detect whether a bluetooth device is currently connected to an Android device using API 14 or better. It seems like I should be able to use the BluetoothSocket.isConnected() method, but no matter what I've done, so far I just get false back for anything, connected or not.
AndroidManifest includes these lines:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Locale 4.x supports API 14 or greater. -->
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" />
<uses-feature android:name="android.hardware.bluetooth" />
And the code in question:
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
for (BluetoothDevice device : pairedDevices) {
Log.i(Constants.LOG_TAG, String.format(Locale.US, "Device: %s connected: %b", device.getName(), isConnected(device))); //$NON-NLS-1$z
}
}
private boolean isConnected(BluetoothDevice device) {
BluetoothSocket socket = null;
// Get a BluetoothSocket for a connection with the given BluetoothDevice
UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
try {
socket = device.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
Log.e(Constants.LOG_TAG, e.getMessage()); //$NON-NLS-1$z
return false;
}
Log.i(Constants.LOG_TAG, socket.toString()); //$NON-NLS-1$z
return socket.isConnected();
}
No errors are thrown, it simply returns "false" 100% of the time. Is there something that I'm not doing right?
I believe that jkane001 already solved his problem, so I hope this answer will help someone else.
First of all after socket creation
socket = device.createRfcommSocketToServiceRecord(SPP_UUID);
you shall init connection by
socket.connect();
After that you'll be able to check connection state using socket.isConnected()
Since connect() method is not blocking, so immediately after socket may be not connected yet. I suggest to use something like this
while(!socket.isConnected() && trial++ < 3){
try {
Thread.sleep(300);
} catch (Exception e) {}
}
By the way, I found that on some android devices isConnected() always returns false. In such case just try to write something to socket and check if there is no exception.
Apparently there are devices and/or Android versions where isConnected() is implemented (i.e. the function exists and you can call it), but worse than useless because it always returns false. I have an Alcatel phone in on my desk running Android 4.2.2 which exhibits this behavior.
My code was assuming it was disconnected, and so killed my connection thread and this was driving me crazy for a long time. However, I removed the isConnected() call and assumed it was connected, and everything works fine! I haven't found a better way to check for a valid connection other than waiting for an error and declaring the connection dead. The blocked read() in the thread eventually does fail.
We have reports from the field that sound similar, and 2 of the 2 problem devices for which we know the version are also on 4.2.2. Haven't yet deployed the fix, so not sure if it fixed those cases yet.
First off, why are you using reflection?! That's a red flag to me. The APIs allow you to talk to another device via bluetooth, see this link so you should not use reflection.
A socket will always return not connected before its connect method is called. It seems that your code obtains the socket but never tries to make a connection with it. You first need to call this method.
Related
my onCreate() looks like:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(new IpAddressCallable()).start();
int n=100;
for(int i=1;i<=n&&!gotWifiUpOrFail;i++)
try {
Thread.sleep(100);
} catch(InterruptedException e) {
System.out.println("5 caught: "+e);
}
initialize();
}
i need to wait to force a wifi conection since the tablets come up in a: "no internet access detected won't automatically reconnect" mode (apparently since 5.1 or so).
the initialization buids the gui and does a: setContentView(relativeLayout), so i can not run this from another thread.
is this sane way to wait for something like this?
Don't you normally use intents or receivers for this sort of thing? I thought hard-coded wait loops were frowned upon. Maybe these will help:
How to detect when WIFI Connection has been established in Android?
Wifi Connect-Disconnect Listener
CONNECTIVITY_ACTION intent received twice when Wifi connected
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.
So im trying to get this little piece of code to run
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket,
// because mmServerSocket is final
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("Server", MY_UUID);
} catch (IOException e) { }
mmServerSocket = tmp;
}
But when i continue from the line where tmp should be assigned it is still null. Bluetooth is activated and everything but it simply wont set tmp to anything when i get to it. Any ideas why not? And btw. does this method not work on a 2.2 android machine since it crashes at that line on my 2.2 machine but not on my 4.1.2 device.
If any more information is needed to be able to answer please just ask for it and ill give it to the best of my ability.
Found out i hadn't given permission to the app to use bluetooth so solved.
I am completely new to Android development and ran into the same problem. Here is more help if other people run into this:
Because this is happening on the server side, be sure discoverability is enabled before starting the accept-connection thread. This can by starting the thread in the onActivityResult() method when the proper resultCode is received.
I need to find a way to (using an Android application) programmatically connect and disconnect an Android device from a host.
I am using a Galaxy Nexus. My goal is to keep everything as close to stock as possible, though I have already enabled verbose debug messages in the kernel and in order to view them have enabled root access on the phone to access /proc/kmsg (and the shell command dmesg).
I am certain that there is a way to leverage root access to do what I need to do, but all of my attempts have lead to nix.
Mess with /proc/bus/usb
Mess with /dev/bus/usb
Change between MTP/PTP (unable to do programatically)
Making the Android USB gadget driver into a module <- ???
I am going to try to figure out how to do the last object on the list, as then I would be able to rmmod and insmod the resulting *.ko in my application and that would connect and disconnect the phone. I am unsure of the feasibility of this option though.
Solution came when close to a deadline, so I am almost sure it is not the best way of doing things, but it met my requirements.
Build Modded kernel (to allow hooking of particular function)
Modify kernel config to support Kprobes (set CONFIG_KPROBES to Y)
Remove "static" keyword from android_setup() definition (driver/usb/gadget/android.c)
Build that kernel
Build kernel module (which gives the actual functionality of connecting and disconnecting)
Use Kallsyms to dynamically pull the absolute address of android_setup()
Using kprobes, hook android_setup()
Set up two timers to execute every time android_setup() is called
First timer set for 2 seconds from now, Second set for 2.005 seconds from now
Both timers take a pointer to the struct usb_gadget as their data
In respective callback functions, call usb_gadget_connect() and usb_gadget_disconnect(), which forces physical disconnect followed by reconnect on the Samsung Galaxy Nexus
Build Application
Gotta have a rooted device
Simply make a shell call with SU privilege - "insmod module_name." Until you call rmmod, the module will force the device into an enumeration cycle, disconnecting and reconnecting continuously.
If you are interested in repeating these results, read the document posted here and feel free to send me any questions.
https://docs.google.com/uc?export=download&id=0B9WchRkSOWwJbi10MGhLWUljT2s
You can try to enable/disable some secured settings like Settings.Secure.USB_MASS_STORAGE_ENABLED or Settings.Secure.ADB_ENABLED (depending on what you call "connect" !)
This code should work (disabling USB mass storage):
Settings.Secure.putInt(getContentResolver(),Settings.Secure.USB_MASS_STORAGE_ENABLED, 0);
Settings.Secure.putInt(getContentResolver(),Settings.Secure.USB_MASS_STORAGE_ENABLED, 0);
InternetControl.java
public class InternetControl {
public static void EnableInternet(Context context)
{
try {
Log.i("Reached Enable", "I am here");
setMobileDataEnabled(context,true);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static void DisableInternet(Context context)
{
try {
Log.i("Reached Disable", "I am here");
setMobileDataEnabled(context,false);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
private static void setMobileDataEnabled(Context context , boolean enabled) throws Exception{
final ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final Class connClass = Class.forName(conman.getClass().getName());
final Field iConnectivityManagerField = connClass.getDeclaredField("mService");
iConnectivityManagerField.setAccessible(true);
final Object iConnectivityManager = iConnectivityManagerField.get(conn);
final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
final Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
setMobileDataEnabledMethod.setAccessible(true);
setMobileDataEnabledMethod.invoke(iConnectivityManager, enabled);
}
}
Manifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
Enable or Disable function are static so you can call by using
classname.functionname();
I'm writing an Android app which receives information from a Bluetooth device. Our client has suggested that the Bluetooth device (which they produce) will change its name depending on certain conditions - for the simplest example its name will sometimes be "xxx-ON" and sometimes "xxx-OFF". My app is just supposed to seek this BT transmitter (I use BluetoothAdapter.startDiscovery() ) and do different things depending on the name it finds. I am NOT pairing with the Bluetooth device (though I suppose it might be possible, the app is supposed to eventually work with multiple Android devices and multiple BT transmitters so I'm not sure it would be a good idea).
My code works fine to detect BT devices and find their names. Also, if the device goes off, I can detect the next time I seek, that it is not there. But it seems that if it is there and it changes name, I pick up the old name - presumably it is cached somewhere. Even if the bluetooth device goes off, and we notice that, the next time I detect it, I still see the old name.
I found this issue in Google Code: here but it was unclear to me even how to use the workaround given ("try to connect"). Has anyone done this and had any luck? Can you share code?
Is there a simple way to just delete the cached names and search again so I always find the newest names? Even a non-simple way would be good (I am writing for a rooted device).
Thanks
I would suggest 'fetchUuidsWithSdp()'. It's significance is that, unlike the similar getUuids() method, fetchUuidsWithSdp causes the device to update cached information about the remote device. And I believe this includes the remote name as well as the SPD.
Note that both the methods I mentioned are hidden prior to 4.0.3, so your code would look l ike this:
public static void startServiceDiscovery( BluetoothDevice device ) {
// Need to use reflection prior to API 15
Class cl = null;
try {
cl = Class.forName("android.bluetooth.BluetoothDevice");
} catch( ClassNotFoundException exc ) {
Log.e(CTAG, "android.bluetooth.BluetoothDevice not found." );
}
if (null != cl) {
Class[] param = {};
Method method = null;
try {
method = cl.getMethod("fetchUuidsWithSdp", param);
} catch( NoSuchMethodException exc ) {
Log.e(CTAG, "fetchUuidsWithSdp not found." );
}
if (null != method) {
Object[] args = {};
try {
method.invoke(device, args);
} catch (Exception exc) {
Log.e(CTAG, "Failed to invoke fetchUuidsWithSdp method." );
}
}
}
}
You'll then need to listen for the BluetoothDevice.ACTION_NAME_CHANGED intent, and extract BluetoothDevice.EXTRA_NAME from it.
Let me know if that helps.