I am writing an application that relies on the Android device (for my current testing purposes an HTC Evo 4G and several original Motorola Droids) being discoverable via bluetooth for 300 seconds.
I am targeting Android version 2.0.1, so according to the API I should be able to prompt the user to enable discoverability for a maximum of 300 seconds. On both my Droids and my Evo the prompt window has 300 seconds listed, but they both end after 120 seconds.
The code I used to prompt the user is here:
private void makeDiscoverable() {
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
I am certain that this code runs. However, I later have a handler for when my discoverability status changes (in this case ends, I assume) that reads like this:
if (isDiscoverableChange(action)) {
int discoverState = intent.getIntExtra(
BluetoothAdapter.EXTRA_SCAN_MODE, Short.MIN_VALUE);
if (isDiscoverableState(discoverState)) {
setItOrder();
setUpScanAndDisplay();
} else {
discoverScheduler.cancel();
itScheduler.cancel();
}
}
private boolean isDiscoverableChange(String action) {
return BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action);
}
private boolean isDiscoverableState(int state) {
return state == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
}
I tried commenting out the portion that runs when discoverability mode ends, just in case it was cancelling everything prematurely, but discoverability really does end after 120 seconds.
Is this a hardware issue, or am I doing something wrong here?
It appears to be a bug:
Issue 15486: Bluetooth Adapter.EXTRA DISCOVERABLE not obeyed
http://code.google.com/p/android/issues/detail?id=15486
Issue 13361: BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION intent Extra does not extend 120 sec discovery interval
http://code.google.com/p/android/issues/detail?id=13361
First reported Dec 22, 2010, still listed as 'new' status, so I wouldn't expect this to be fixed.
There is bluetooth DiscoverableTimeout value besides Android timeout.
Usually, DiscoverableTimeout is set in file /system/etc/bluetooth/main.conf to 120 .
You should write
DiscoverableTimeout = 0
in /system/etc/bluetooth/main.conf to disable bluetooth timeout. This will allow you to extend Android timeout over than 120 sec.
Related
I have an dashcam which automatically starts and stops recording based on charging (start on charging and stop when it stops charging)
So I have something like this at the BroadcastReceiver.onReceive
Intent.ACTION_POWER_CONNECTED -> {
startRecording()
}
Intent.ACTION_POWER_DISCONNECTED -> {
stopRecording()
}
Some users reported that recording stops when their device becomes fully charged though it is still plugged to a power source via USB.
So it seems BatteryManager sends the event that the power is not connected.
What can I do in this case to know for sure that it is still plugged to a source power?
Mb should I use the following solution?
Intent.ACTION_BATTERY_CHANGED -> {
val plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0
// conditionally it looks like this: if (plugged) startRec() else stopRec()
}
I am trying to scan all visible wifi APs using wifimanger class. My question is that my code is working good when the (wifiscan-results) called repeatedly every 5 sec using recursive (Runnable) service. But when the time is reduced to be 1 sec or less, such that I register (wifimanger.statrscan) every 1 sec to receive the (wifiscan-results) every 1 sec, the output give null and gives values only every 4 second at least. Could you tell me why this happens. My aim to scan all visible wifi APs every one second or less, repeatedly, Is this possible?
Runnable function code:
public void Running() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
tv1.setText("counter : " + time1);
time1++;
Scan_number++;
mwifiManager.startScan();
periodic_recieving_wifi_signals();
Running();
}
}, 1000);}
broadcastreciever code:
public void periodic_recieving_wifi_signals() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION);
} else {
//flag1 = false;
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//tv2.setText("Each scan period is : " + results);
results = mwifiManager.getScanResults();
size = results.size();// number of the elements in the list
}
}, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}}
You almost certainly cannot get a WiFi scan every second ... the process simply takes too long.
I don't know all the technical details, and while some of the specific details may vary according to which version of WiFi you are using, looking at Wi-Fi / WLAN Channels, Frequencies, Bands & Bandwidths we can see that basic 2.4GHz 802.11 WiFi has 14 channels defined and 5GHz WiFi has 25 channels (not all channels are permitted in all locations).
To perform a scan, the radio in your phone has to tune to each channel in turn to see "what's out there". Seeing what (if anything) is on a particular channel will involve an exchange of messages, and will take a finite amount of time1 (it will have to wait "long enough" to tell the difference between a slow-to-respond device and "nothing there").
As you noted in a comment, if all of this is taking four seconds or so, you won't be able to perform a scan faster than about once every five seconds.
1 Thanks to John Hanley for supplying some numbers. By default, access points transmit their "I am here" beacons every 102.4ms. Thus some minimum scan-times are:
2.4GHz: 14 x 102.4ms = 1,433ms
5GHz: 25 x 102.4ms = 2,560ms
(Both figures may be slightly less in some locations, depending on the number or channels allowed to be used).
In practice, you would want to listen on each channel for longer than 102.4ms, otherwise you run the risk of not-quite-getting-a-beacon as you switch to a channel, and then switching from that channel just as (or before) the next beacon is sent. There may also be a small delay for the radio to stabilise to each new frequency.
This article: "SSID Overhead Calculator" from the Revolution WiFi website (as well as confirming the 102.4ms figure) also shows the dangers of having too many access-points (APs) and/or too many SSIDs... it doesn't take many of each before the time spent sending out these "beacon" frames takes a significant chunk out of your WiFi throughput. For example: 4 SSIDs on one AP (or 4 single-SSID APs on the same channel, or 2 double-SSID APs on the same channel) will each use about one-eighth of that channel's airtime just with "I am here" beacons!
The problem I'm having is that my count is totally off, from any pedometers, fitbit, or the Samsung Step Counter.
It appears to shut down, and not add any steps after awhile.
If I enter that I'm starting at 3000 for example, it calculates an offset and it stores as a shared preference. It tries to remain registered for the the Sensor. I also store the current steps, so that if the activity that is listening for Step Broadcasts is resumed, it will request for the steps to be output.
I have tried making the service provide notifications and be a foreground service, but the accuracy does not improve, and it uses a ton of power, I have tried a wakelock, with similiar results, not accurate, and uses too much power.
As it stands, my app does not show up in the power usage statistics, so it is hardly using power at all. The hardware sensor should be capturing steps from the accelerometers, and when it does wake up, it should output the newest steps. When it does update, it is closer to the value that I set as the step count.
I am using the Step Counter which was made available in kitkat or above, on some devices. The following code registers for the sensor.
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
if (null != sensor)
{
sensorManager.registerListener(this, sensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
This is within the OnCreate Method of a Service, that I have constructed.
The Service is created as sticky. And uses a broadcast receiver to receive starting steps from an activity, to compute an offset. It also broadcasts the steps that have happened. Here is more of the code.
class MyBroadCastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_REQUEST_STEPS))
{
SendStepBroadcast(currentSteps);
}
else if (intent.getAction().equals(ACTION_SET_STEPS))
{
setSteps = intent.getFloatExtra(
STEPS_OCCURRED, -1);
SendStepBroadcast(setSteps);
}
}
}
#Override
public void onSensorChanged(SensorEvent event) {
if (setSteps > -1) {
offset = setSteps - event.values[0] + 1;
SharedPreferences prefs = getSharedPreferences("com.halfwaythere",
MODE_PRIVATE);
prefs.edit().putFloat("offset", offset).apply();
setSteps = -1;
}
currentSteps = event.values[0] + offset;
SharedPreferences prefs = getSharedPreferences("com.halfwaythere",
MODE_PRIVATE);
prefs.edit().putFloat("currentSteps", currentSteps).apply();
SendStepBroadcast(currentSteps);
}
private void SendStepBroadcast(float steps) {
Intent broadcastSteps = new Intent();
broadcastSteps.setAction(ACTION_STEPS_OCCURRED);
broadcastSteps.putExtra(STEPS_OCCURRED, steps);
this.sendBroadcast(broadcastSteps);
}
In the Activity the following code is used to start the service:
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, StepService.class);
startService(intent);
}
My most recent set of attempts to fix this, I tried the following:
Use android:process=":background" to start the service in it's own process. I will try this tomorrow in a field test, and see how it works.
I tried setting the count to zero, and found out my code would not allow, so in the above code I used > -1. Since -1 shouldn't be a valid step count.
All of the code above has test wrapped around it, and I've tried to find any edge cases, and have looked over stack overflow for pedometer problems with Step Counter on Samsung Galaxy S4. Or anything about best practices.
Thanks, and if you need any additional info, please let me know.
From my research:
When the screen is locked, the Hardware Sensor waits before outputting steps. It does count steps, but once you press the button on the side it wakes up, and it receives a SensorEvent.
Service was occasionally having Start Command being called. Was very important that I only register once, so I added a boolean that would be flipped once the initialization was called, and flip off after that. Service was paused, but not killed, and Start Command would run upon it being awoken.
Setting Service to Foreground, seems to be getting closer to the value from other pedometers. Uses more battery, but is keeping it going more, so that makes sense.
Did not require wakelock, it was only on for several milliseconds, but that did not cause the hardware sensor to send results.
Will have my Service run till goal is achieved, or offer the option to stop tracking at half way point. I really just wanted something to tell me that I would get my goal if I turned around, anything else will be equivalent to extra steps.
So I will apply what I found and continue on with my app, should be on the App Store by mid July.
I am looking for an android way to flush the characteristics the app receives from a Ble device, or at least know from the data that the connection has been lost as soon as it actually is except around 15 seconds after it disconnected. If there is a way to change the gatt connection timeout, that would be significantly better.
To repeat in a different form, I would like a solution (or a link that can explain) to detect a disconnect of the BLE device faster than whatever the timeout value currently is, by a means of seeing if the value I am getting is fresh by flushing the characteristic, or changing the disconnect timeout on the gatt side, so I can see within a second of it disconnecting to trigger other code.
Other answers in here may be better than this one, but this was my solution to the problem. Be sure to attempt Emil's answer before using this.
What I did since the time was too slow to wait for it was to check the rssi since it always is changing. If there is a period of time, lets say 3 seconds, where the value stays the same, it disconnects from the device. This goes around the 15 second timeout and adds our own timeout.
This would be what would be needed to check signal strength. This was written a couple of years ago, so some things may need to be changed.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status){
//check for signal strength changes. It will stay the same if we
//are getting no updates
if(mLastRssi == rssi){
disconnectCounter++;
if(disconnectCounter> 140) {
//disconnect logic as if we are done with connection
//maybe start listening for device again to reconnect
disconnectCounter = 0;
}
}
else{
//we are connected. reset counter
disconnectCounter = 0;
}
//store last value as global for comparison
mLastRssi= rssi;
}
}
Somewhere in a loop, call
mBluetoothGatt.readRemoteRssi()
Don't know if this would be of help, but you can take advantage (if you have it) of a periodic data that is transmitted in the gatt. So if for example you have a measurement of 1 second of periodicity you can do something like:
// runnable to detect the lack of activity:
private final Runnable watchDog = new Runnable() {
#Override
public void run() {
measurement_timeout--;
if(measurement_timeout==0) {
Log.d("BLE_CONTROLLER", "PROBE WITH NO ACTIVITY");
}
}
};
// this should be in the reception of the periodic data:
measurement_timeout++;
mHandler.postDelayed(watchDog, 3000);
So the "measurement_timeout" will work as an actual timeout that when it reaches the 0 means that you don't have data received in the period of 3000 ms.
Notice that you must have a watch time > 2*data period.
The only way I have managed to achieve a fast gatt disconnect has been to ensure that the peripheral device sends a BLE disconnect instruction before it powers down or severs the connection.
Once android receives the disconnect instruction, the gatt tidies up immediately instead of taking 15 seconds to realise the peripheral is missing.
It would seem that most peripherals do not bother and just disappear.
Clearly this approach is only possible if you are able to modify the peripheral.
The proper way is to use the Connection Parameter Update Request from the peripheral side to change the timeout to a lower value.
There is a callback in Android :
BluetoothGattCallback btleGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange( BluetoothGatt gatt,int status,int newState){
if(newState == BluetoothProfile.STATE_DISCONNECTED){
//your code here
}
}
}
Couple of days back, I made my first app on Android. The basic concept is to monitor the proximity sensor, if there is an obstacle at the sensor I will increment a counter. If the counter crosses the threshold I will trigger an action.
I have implemented the sensor monitoring SW in a service, this service is called from an Activity in every 10 Min so as awake the cpu and start the service if it is stopped.
Everything was perfect, got few thousands of downloads in market with good ratings. This was fine until Android 2.3.3. Recently my mobile got upgraded to Android 2.3.6 and unfortunately the app is not working as expected.
Sensor listener does not trigger when the screen is OFF. Some times it works fine, most of the times it is not working. After giving several inputs at the sensor, after a while if I switch ON the screen, automatically all the triggers at the sensor are called at once and the counter increments and triggers the action.
To summarize, sensor listener does not work when screen goes OFF (in Android 2.3.6), this was working fine until Android 2.3.3. If I connect the debugger, phone does not go to sleep and everything works fine so I am not able to find the problem. Please help me .
Here is my code .
Calling the service at every 10 min ..
Thread trd = new Thread(){
public void run(){
int sec = 1000;
int min = 60 * sec;
Calendar cal = Calendar.getInstance();
alarmMngr.setRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
10 * min,
PendInt);
}
};
trd.start();
In the service ..
// On sensor change
public void onSensorChanged(SensorEvent event){
if(event.sensor == SnsrProx){
if(event.values[0] <= 5){
IncProxCntr(1);
}else{
IncProxCntr(0);
}
}
}
private void IncProxCntr(int x){
if( x == 1){
FakeCall_SnsrCnt++;
vibrate(VIBRATE_SHORT);
}
if(FakeCall_SnsrCnt >= Settings.getMaxSnsrCnts(this)){
Trig_IncominCall();
}
}
Acquire wakelock in the service also