For my thesis I need to measure how long in each stage it takes to connect to a WiFi AP.
I can easily measure everything using SUPPLICANT_STATE_CHANGED_ACTION, but I'm having trouble figuring out how I can measure the time it takes to get the DHCP information.
I just really need to know with a certain precision when the android device gets a new IP. I've tried using CONNECTIVITY_ACTION and inside the BroadcastReceiver checking the IP address, but it's off by at least 1 second, so not too precise.
One more thing if it's relevant: The AP on which I will do the tests won't have internet connection.
Any ideas how this can be done?
Thanks in advance
I managed to solve this problem the following way:
Created a filter with WifiManager.NETWORK_STATE_CHANGED_ACTION
And when there is a new event, I check it the following way:
if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)){
elapseTime = System.currentTimeMillis() - startTime;
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
if (ipAddress != 0 && !wifiConnected) {
wifiConnected = true;
wifiTimeLog = wifiTimeLog + elapseTime + "," + "DHCP Done" + "\n";
state.setText(wifiTimeLog);
}
wifiConnected is a boolean that is set to false before the test. There were some other triggers happening after getting the IP.
Related
TL;DR version
I need to scan and get the BSSID / M.A.C address and Signal Level of the nearby Access Points several times a second. WifiManager.startScan() scans about 3.5 seconds which is a bit slow. (better than 6 seconds for others but still too slow for me).
I'm looking for a way to get results every 200ms or maybe even less.
The more detailed version.
I'm trying to build a location finding app that uses WiFi signals instead of the GPS. So far so good with the exception that i need to get a lot of data in order to have accurate and consistent results.
I need to get the BSSID and the Signal Level from every Access Point I can find and than store this data for later use.
I've tried using the WifiManager and the BroadcastReceiver to scan and get the scan results. The problem with them is that they are really slow. It takes at least 3 seconds for a single scan. In 3 seconds signal level value will change , leading to inaccurate results. I also need to have several thousand scans which will take an awful loooot of time. So far I haven't found an alternative.
My phone is currently running Android 8.0.0
Perhaps if I optimise my code the scan will perform faster?
onCreate method:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sensor);
btnMainActivity = (Button) findViewById(R.id.button_ToMainActivity);
btnGetWifiInfo = (Button) findViewById(R.id.button_GetWifiInfo);
textWifiInfo = findViewById(R.id.textView_wifiInfo);
textWifiNr = findViewById(R.id.textView_wifiNr);
mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
mWifiReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context c, Intent intent) {
getScanResultInfo();
timeDifference = SystemClock.elapsedRealtime() - startTime;
textWifiInfo.setText("Seconds elapsed: "+Double.toString(timeDifference /1000.0));
nrOfScans++;
if (nrOfScans < 10){
mWifiManager.startScan();
}
}
};
getWifiInfo();
toMainActivity();
}
public void getScanResultInfo(){
int level;
List<ScanResult> wifiScanList = mWifiManager.getScanResults();
textWifiNr.setText("Nr of detected APs: "+ wifiScanList.size());
for (ScanResult scanResult : wifiScanList) {
level = WifiManager.calculateSignalLevel(scanResult.level, 5);
Log.d("WIFI","Level is " + level + " out of 5 " + scanResult.level + " on " + scanResult.BSSID + " ");
}
}
And when I press the button the scan starts.
public void getWifiInfo(){
btnGetWifiInfo.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
finePermission = false;
startTime = SystemClock.elapsedRealtime();
nrOfScans = 0;
checkPermissions();
if ( finePermission == true){
((WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE)).startScan();
mWifiManager.startScan();
}
else {
Log.d("WIFI"," Missing Permissions: "+finePermission);
}
}
}
);
}
Thank you in advance for your time!
You can skip passive channel scanning by using the hidden API, startscanActive.
startScanActive is not an exposed API in android reference; so use it at your own risk. If you must use it, refer this - https://github.com/mozilla/MozStumbler/issues/40
Also, note that if the API indeed scans only active channels as the name suggests, you will not be able to get APs present on passive channels in your scan results
Bad news from official Android side
https://android.googlesource.com/platform/frameworks/base/+/478ee74428e04522d6ac0bf10c30ddaaf62028a4
and
https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/4f11976612567e57eefb0b58c7aef1059f52b45c
announce (or propose?) to significantly limit scanResult requests per time from v9 Pie on.
In concrete values, your app should be limited to max 4 scanResult requests in 2 minutes.
This will be a disaster/nightmare for all existing WiFi-Tool apps.
Official reason: safe battery.
Let's unite our voices and let them know we want Android as a Swiss Army knife and not let it become another white brick.
I'm trying to detect mode when we in call. I'm using most popular example with broadcast and telephonyManager.
But there are only 3 states.
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
}
if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
}
if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)){
}
after some tests i found that :
1) when incoming call - than i see state = RINGING
- accept call from this state = OFFHOOK
2) but when im do outgoing call - state = OFFHOOK , and when another "me" on other side accept call - state still = OFFHOOK.
How to correctly detect IN_CALL_MODE (mean im speaking at current time ). ?
Can any help ?
How about using AudioManager??
AudioManager manager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
if(manager.getMode()==AudioManager.MODE_IN_CALL){
return true; // Active call
}
else {
return false;
}
InetAddress localhost = null;
try {
localhost = InetAddress.getLocalHost();
} catch (UnknownHostException ex) {
/* Purposely empty */
}
byte[] ip = localhost.getAddress();
int i = 1;
while (i <= 254) {
ip[3] = (byte) i;
InetAddress address = null;
try {
address = InetAddress.getByAddress(ip);
} catch (UnknownHostException ex) {
/* Purposely empty */
}
String HostName = address.getHostName();
if (!address.getHostAddress().equals(address.getHostName())) {
list.addElement(HostName);
}
i++;
}
(I have problem is long the run time. How I can reduce the run time in this code)
I had a similar issue involving network lookups for IP Addresses. The issue of network latency is just as "that other guy" said...it's driven by the network. How long and how many hops it takes to get to the destination.
The only solution I found was threading out the lookups, InetAddress.getByAddress(ip) in your case. My solution was to setup an ExecutorService with 10 threads. Package each InetAddress.getByAddress(ip) into a Callable. Monitor the Callable for completion. package another one and start it. Have a look at one of my questions on this forum related to this very issue :
ExecutorService - How to set values in a Runnable/Callable and reuse
Be cautious with the ExecutorService (as I found out). The number of threads really depends on the number of CPUs (Power) of your runtime hardware. Too many threads and it'll grind to halt (trust me on this). Too few threads and your time reduction may not get reached.
I've left the department in my Company where I implemented the final solution, so I don't have the code readily available. But the above link provides some basic code on the ExecutorService and using Callable objects.
I made a twitch irc bot.
I have setup a little "system" to turn itself on whenever the stream is going online and should turn off when the stream isnt online anymore.
im using the following code:
if (TwitchStatus.isstreamlive && multistartprepare == false && multistartprepare2 == false){
livemode = true;
multistartprepare = true;
startedAt = DateTime.now();
startup();
}else{
if (TwitchStatus.isstreamlive == false && multistartprepare){
livemode = false;
multistartprepare = false;
multistartprepare2 = false;
TTmsg.cancel();
TTmsg.purge();
}
}
isstreamlive is a boolean which is either true when a stream is live or false when the stream is offline.
isstreamlive gets updated every 5 secons by making a JSON request and holds the right value the whole time.
the problem now is that the startup() Method will activate a timer for a greeting message in the irc chat. Somehow it happens the timer got executed 2 or 3 times when i start my bot so i guess something is wrong with my if else statement.
the booleans multistartprepare and multistartprepare2 are false on start and are there for the bot to start only once a time, til the stream is over and he can get offline.
is there something wrong above? Guess the code gets executed to many times.
greetings and sorry for bad english :D
It might help if you use your livemode variable in the if as well
if (TwitchStatus.isstreamlive &&
!multistartprepare &&
!multistartprepare2 &&
!livemode) {
You might be able work around this by setting up a timeout that prevents your bot from sending the message if it's been sent in the past few seconds.
long lastSent = 0;
...
if (System.currentTimeMillis() - lastSent > 1000*5) { // 5 seconds elapsed
...
// send message
lastSent = System.currentTimeMillis();
}
You might have something wrong with your setup method, or the server might be sending you multiple went-online messages, but it's hard to tell based on the info you have so far.
When I use onSensorChanged() to test my cellphone's accelerometer, finding that it responses to fast. Almost every 1~3ms onSensorChanged() will be activated. I search for some other cellphone's information feeling that it is kind of weird, so I doubt that my code might be wrong. Here is part of my code:
public void onSensorChanged(SensorEvent se_a) { /* 取得x,y,z加速度值 */
xa = se_a.values[0];
ya = se_a.values[1];
za = se_a.values[2];
final String timeStamp_a = new SimpleDateFormat("HHmmssSSS",
Locale.UK).format(new Date());
String tmp_a = "0 " + timeStamp_a + " " + String.valueOf(xa)
+ " " + String.valueOf(ya) + " " + String.valueOf(za) + "\n";
And part of result is like:
0 160106203 9.5385 -0.6895301 1.1109096
0 160106204 9.500193 -0.5746084 1.1109096
0 160106206 9.576807 -0.5746084 1.1875241
0 160106207 9.461885 -0.6895301 1.3024458
My cellphone is LG G2. I set the accelerometer to SENSOR_DELAY_FASTEST. But using some app on google play to test my accelerometer, it shows that in SENSOR_DELAY_FASTEST the frequency is 120Hz, so it is very weird to find that onSensorChanged() response so fast(1~3ms). Where is my code can be wrong? Please help me!
If the update rate is to fast using SENSOR_DELAY_FASTEST you can set another flag which fit your needs.
See the docs for the different rates you can use:
The default data delay (SENSOR_DELAY_NORMAL) is suitable for
monitoring typical screen orientation changes and uses a delay of
200,000 microseconds. You can specify other data delays, such as SENSOR_DELAY_GAME (20,000 microsecond delay), SENSOR_DELAY_UI
(60,000 microsecond delay), or SENSOR_DELAY_FASTEST (0
microsecond!!!! delay). As of Android 3.0 (API Level 11) you can
also specify the delay as an absolute value (in microseconds).
Edit: Have a look at this method SensorManager.registerListener(SensorEventListener, Sensor, int) where you can specify your delay in ms if no flag supports your needs. This is available since API 9. If you want a specific frequenzy provide it as a parameter.