I need to disable the Bluetooth and the enable it again. I disable that at this way:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
}
but I can not enable that again at this way(nothing happen after running this code):
mBluetoothAdapter.enable();
why?
As this involves tinkering with actual hardware, I think you have to wait a bit before being able to enable it. You could try and see with Thread.sleep(500) or 1000 before enabling...
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
Thread.sleep(500); //code for dealing with InterruptedException not shown
mBluetoothAdapter.enable();
}
However, this is flaky, having magic numbers resolve issues related to events of a hardware device is not nice. Not guarranteed to have well defined behaviour under all circumstances (different devices, different situations, etc...)
If the adapter reports disabled state only when it has been fully disabled, you could try something along these lines:
int retry=0;
while(retry++<5) {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
}
Thread.sleep(100); //again, InterruptedException handling not shown
}
if(retry==5) {
//Ooops, still not successful. Handle situation here.
}
So in words: smaller delay, but a few retries, and check if it has been disabled or not.
This happens if you transfer data via Bluetooth Socket. One socket - use 1 port. You can enable\disable bluetooth whlie all sockets ports(around 30) not be filled. So a question - how to get around of this problem, so a answer - keep track of close\open sockets. May be it helps.
Related
I've made a ListView with devices currently paired to my phone so that I can select one of them and connect to it. To determine which device was selected, I'm storing their MAC Addresses in an array so that I can get a device by its address. When I select a device, the app freezes for a bit then restores with no success of connecting. I cannot find the solution anywhere and I'm stuck. I'm still a beginner and do not understand much. An exception occurs that goes like:
java.io.IOException: read failed, socket might be closed or timeout, read ret: -1
Here is my code.
// If the UUID is incorrect then this one does not work as well
// 00001101-0000-1000-8000-00805f9b34fb
private static final UUID CONNECTION_UUID = UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");
public static boolean connectDevice(final int a) {
try {
BluetoothDevice mBluetoothDevice = btAdapter.getRemoteDevice(deviceAddress[a]);
BluetoothSocket mBluetoothSocket = mBluetoothDevice.createInsecureRfcommSocketToServiceRecord(CONNECTION_UUID);
btAdapter.cancelDiscovery();
mBluetoothSocket.connect();
mmOutputStream = new DataOutputStream(mBluetoothSocket.getOutputStream());
mmInputStream = new DataInputStream(mBluetoothSocket.getInputStream());
mBluetoothSocket.close();
} catch (NullPointerException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
From the CONNECTION_UUID that you provided in your code, I assume that you are connecting with a Bluetooth serial board. I am not sure about the problem yet, however, I thought of writing this answer to provide a probable solution that might solve your issue.
I think in case of the paired devices, you need to initiate the connection with a secure channel. Currently, you are using an insecure channel.
From the documentation...
The communication channel will not have an authenticated link key i.e
it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
devices, the link key will be encrypted, as encryption is mandatory.
For legacy devices (pre Bluetooth 2.1 devices) the link key will be
not be encrypted. Use createRfcommSocketToServiceRecord(UUID) if an
encrypted and authenticated communication channel is desired.
Hence you might consider using createRfcommSocketToServiceRecord() for your case.
Instead of this
BluetoothSocket mBluetoothSocket = mBluetoothDevice.createInsecureRfcommSocketToServiceRecord(CONNECTION_UUID);
Use this...
BluetoothSocket mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(CONNECTION_UUID);
I hope that solves your problem.
From the comment below - The UUID that actually worked here is 00001101-0000-1000-8000-00805f9b34fb
For the past few days i've been trying to show the online/offline status of a user.. For this i have a register activity where they register and their info gets saved in firebase and if they exit an activity i have overriden its onstop method and made the value to set to offline... but if the user suddenly loses internet connection it still shows online.. i cant change it to offline because internet is needed to make a change in the database and the use doesn't have internet... SO how do i set the database value to offline... i googled quite some stuff about this but didnt find anything... Can anyone please help me out please
My code
#Override
protected void onStart() {
super.onStart();
fetchData();
// mDatabaseReference.child("UserData").child(UID).child("Online").setValue("True");
}
#Override
protected void onStop() {
super.onStop();
fetchData();
// mDatabaseReference.child("UserData").child(UID).child("Online").setValue(false);
}
What you're trying to do is known as a presence system. The Firebase Database has a special API to allow this: onDisconnect(). When you attach a handler to onDisconnect(), the write operation you specify will be executed on the server when that server detects that the client has disconnected.
From the documentation on managing presence:
Here is a simple example of writing data upon disconnection by using the onDisconnect primitive:
DatabaseRef presenceRef = FirebaseDatabase.getInstance().getReference("disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnect().setValue("I disconnected!");
In your case this could be as simple as:
protected void onStart() {
super.onStart();
fetchData();
DatabaseReference onlineRef = mDatabaseReference.child("UserData").child(UID).child("Online");
onlineRef.setValue("True");
onlineRef.onDisconnect().setValue("False");
}
Note that this will work in simple cases, but will start to have problems for example when your connection toggles rapidly. In that case it may take the server longer to detect that the client disappears (since this may depends on the socket timing out) than it takes the client to reconnect, resulting in an invalid False.
To handle these situations better, check out the sample presence system in the documentation, which has more elaborate handling of edge cases.
I am using WifiP2pManager class to initiate the discovery of Peers as referred here: http://developer.android.com/training/connect-devices-wirelessly/wifi-direct.html
Part of the code goes as follows:
//Activity Class
#Override
protected void onCreate(Bundle savedInstanceState) {
...
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);
//Separate class here
mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
//register the events to filter on to perform the broadcast receiver
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
myTextView.setText("Success discovery");
}
#Override
public void onFailure(int reasonCode) {
myTextView.setText("Discovery errorcode:" + String.valueOf(reasonCode));
}
});
}
Happens that I get the onSuccess call in my phone (JellyBean based), but a Lenovo A2107A Tablet used for testing running Android 4.1.2 IceCream sandwich just get onFailure where reasonCode equals 2 (Busy):
http://developer.android.com/reference/android/net/wifi/p2p/WifiP2pManager.ActionListener.html
I noticed that in the Wifi Settings of the phone the WifiDirect discovery list option shows up, but in the tablet there is no option to do this, although the OS version 4.x supposedly supports it, programmatically at least (I tested ShareIt App and the tablet can transfer files through WiFi).
A similar question has been made here: Why do I always get BUSY when using WifiP2pManager? but with no accepted answer.
Is there anything I can do to avoid the always busy state while using this API method on the Tablet?. Thanks!
Apparently the Lenovo A2107A tablet returning "Busy" state after calling the WifiP2pManager instance on its discoveryPeers method, doesn't support WiFi Direct/WiFi P2P, in fact there is no option to lookup for P2P peers on it, hence returning the statusCode 2 Busy status in the onFailure callback, even running Android 4.1.2 that in theory does support WifiDirect which is a bit strange.
A couple of helpful projects to understand better the inner workings of this technology are here:
https://github.com/ahmontero/wifi-direct-demo
https://github.com/mayfourth/WiFi-Direct-File-Transfer
Please make sure the Wifi is enabled before discoveryPeers is called.
I got the BUSY when the Wifi is disabled; and success when Wifi is enabled.
In Juice, the enum DetailedState adds a new state named
/** Link has poor connectivity. */
VERIFYING_POOR_LINK
but what is this state stand for?
Having searched for the entire project, I found this:
The subclass VerifyingLinkState in WifiStateMachine.java
class VerifyingLinkState extends State {
#Override
public void enter() {
if (DBG) log(getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK);
mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK);
sendNetworkStateChangeBroadcast(mLastBssid);
}
#Override
public boolean processMessage(Message message) {
switch (message.what) {
case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
//stay here
break;
case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
try {
mNwService.enableIpv6(mInterfaceName);
} catch (RemoteException re) {
loge("Failed to enable IPv6: " + re);
} catch (IllegalStateException e) {
loge("Failed to enable IPv6: " + e);
}
setNetworkDetailedState(DetailedState.CONNECTED);
mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED);
sendNetworkStateChangeBroadcast(mLastBssid);
transitionTo(mConnectedState);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
When it is verifying link state, in the enter() function, it sets the DetailedState to
DetailedState.VERIFYING_POOR_LINK
which will cause the user being confused for getting a state message like the following picture while the connection is really good.
Although this message only stays for a while and then replaced by "Connected" swiftly. But what is this state aim for? what are the risk if I don't set the DetailedState to VERIFYING_POOR_LINK in the enter() function.
VERIFYING_POOR_LINK for certain Samsung Devices are a part of the Smart Network Switch in Wi-Fi which can allow Mobile Data to remain connected over Wi-Fi if poor conditions occur. For Samsung Devices, that's when you would see a detailed state go from CONNECTED to VERIFYING_POOR_LINK.
Most of the logic can be found in: http://androidxref.com/4.3_r2.1/xref/frameworks/base/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
WifiWatchdogStateMachine monitors the connection to a WiFi network. When WiFi
connects at L2 layer, the beacons from access point reach the device and it
can maintain a connection, but the application connectivity can be flaky (due
to bigger packet size exchange).
We now monitor the quality of the last hop on WiFi using packet loss ratio as
an indicator to decide if the link is good enough to switch to Wi-Fi as the uplink.
When WiFi is connected, the WiFi watchdog keeps sampling the RSSI and the
instant packet loss, and record it as per-AP loss-to-rssi statistics. When
the instant packet loss is higher than a threshold, the WiFi watchdog sends a
poor link notification to avoid WiFi connection temporarily.
While WiFi is being avoided, the WiFi watchdog keep watching the RSSI to
bring the WiFi connection back. Once the RSSI is high enough to achieve a
lower packet loss, a good link detection is sent such that the WiFi
connection become available again.
BSSID roaming has been taken into account. When user is moving across
multiple APs, the WiFi watchdog will detect that and keep watching the
currently connected AP.
Power impact should be minimal since much of the measurement relies on passive statistics already being tracked at the driver and the polling is done when screen is turned on and the RSSI is in a certain range.
Although I can't give a for sure (or guaranteed) answer..
I would say that it means that the connection is weak (Less than 30%(?) signal)
Edit:
Android offers the ability to avoid/ignore low-connectivity access points - I'm assuming that this state is suggesting that the connection shouldn't be used.
I don't see any risks in ignoring/neglecting this state.
Edit 2:
In light of recent comments, I have taken this excerpt from the android documentation:
public static final NetworkInfo.DetailedState VERIFYING_POOR_LINK
Added in API level 16 Link has poor connectivity.
It can be found at NetworkInfo.DetailedState
I would like to connect to WiFi network programmatically.
Here is my code:
wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
wifiManager.setWifiEnabled(true);
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"" + ssid + "\"";
config.preSharedKey = "\""+ key +"\"";
int netId = wifiManager.addNetwork(config);
wifiManager.saveConfiguration();
wifiManager.disconnect();
wifiManager.enableNetwork(netId, true);
wifiManager.reconnect();
When I have wifi enabled on my phone, it works as expected, but the problem is, when wifi is disabled. In this case the only result is enabling wifi adapter, but not connecting to the network. It seems like enabling takes to long so it won't get connected. Another strange thing to me is that wifiManager.getConfiguredNetworks() returns null. Do you know how to fix that?
Thank you
It seems like enabling takes to long so it won't get connected.
Yes. This is because enabling of the network is done async, it happens in parallel, and doesn't occur immediately. Here are two possible solutions to your problem:
1) This is the easiest solution, but not the best. Loop as described by another user checking for the scan results to come in. However, you should add a sleep of some sort between every cycle of the loop. I.E. you want to wait for 1ms, so as to not eat up all the CPU resources. I am not sure how to do this in Android off the top of my head. There is another problem with this method. If u are in the GUI thread, you will block all GUI events this way, as you wait for the connection to be established.
2) This is the proper solution. You can register for broadcast events after the network connection has been established. Then you will get an event when it finishes. From this event you can finish performing whatever operations are needed.
Sorry for the rushed answer. I am not an Android pro, so I can't explain the details as to how to do this off the top of my head, but I thought I would at least point you in the right direction.
Actually if you connect WiFi more than one time it will solve your issue.
One other thing I see if my WiFi is enabled and I connect to a specific WiFi network then it's working.
One other thing when I switch from mobile network to a specific WiFi network then it gives an unstable connection ..for this problem I connect WiFi through a specific WiFi network and then forget the network after a 3 second delay I again connect. Then it works properly.
I use this code for connecting to WiFi.
And for delay and for got WiFi network I use this code... .......
{
wifi(SSID,PASS);
final Handler handler = new Handler();
handler.postDelayed(
new Runnable()
{
Override public void run() { forgot(); }
}, 3000);
final Handler handler1 = new Handler();
handler1.postDelayed(
new Runnable()
{
Override public void run() {wifi(SSID,PASS); }
}, 3000);
}