I need to get the current value of the proximity sensor (rather than implementing a continuous listener). On some devices, the first reported value will be a default value (e.g. "FAR") that isn't necessarily accurate, and actual values will only start appearing after the second or third reading. At the moment, I've implemented a 1-second Handler and use the last reported value (after the second has elapsed) as the "true" value, but this solution seems crude (and slow). Is there a better approach that works on all 4.0+ devices? I could simply count up until I've received 3 readings, but on some devices (e.g. GNex), the first value will be correct, and the value will only change after that if there is actually a change in the sensor.
You can do what I did:
You probably have an if statement on the listener - one logic flow for near and one for far.
Instead of waiting on the handler - do this:
if(near) {
myHandler.removeCallbacks(yourRunnableForFar);
myHandler.postDelayed(yourRunnableForNear,100);
else {
myHandler.removeCallbacks(yourRunnableForNear);
myHandler.postDelayed(yourRunnableForFar,100);
}
Notice that the inaccurate first reading(s) will immediately be followed by an accurate one, so the last one "wins".
This code works well if you didn't register sensors other than proximity. If you have a flow of readings from other sensors, than use a static flag (such as the boolean near) to trigger the handler calls only on state change.
Elaboration:
yourRunnableForFar and yourRunnableForNear - are placeholders that implement Runnable to hold your app logic on what to do when the proximity sensor returns "near" (event.values[0] == 0) or "far" (not 0).
myHandler is just any Handler you might created, or declare one just for this with Handler myHandler = new Handler(Looper.getMainLooper());
You might want to acquire a proximity lock on near, and release it and clear the listener on far. But this is app logic that might be completely different from app to app.
Related
I am developing a Pedometer Android application to count number of steps taken and using the steps calculate the distance covered and calories burned. I have followed the tutorial
Create a Simple Pedometer and Step Counter in Android and done exactly like it. It detects number of steps when the sensor detects motion.
But there are some problems with it:
When I stand at the same place with my device in my hand and just move my hand or give a jerk to device, it detects the change and adds to step count.
If I move very slowly with device in my hand it does not detect the change.
If i jump, then it adds several steps in the counter.
I have checked some other applications from Play Store they do not do this kind of stuff.
I have searched but cannot find an appropriate solution or tutorial for it. Any help or suggestions. Thanks
The problem here is that your implementation is not sophisticated enough: it only checks if there is a spike in the accelerometer data and assumes that the spike is coming from a step. It has no idea where the spike in acceleration is really coming from: it might as well come from you jumping or shaking the device in your hand.
How to make it more accurate then? Well, that is a really difficult question which has been topic for scientific papers for a really long time. Even the most sophisticated fitness trackers (which use machine learning, signal processing and other statistical methods) have difficulties to determine when the step is real and when it is just noice or user playing with the device.
Luckily Android does have it's own builtin step counter and step detector, which are more sophisticated than the class in yor example.
So unless you really want to learn signal processing and AI (which I highly recommended, although I don't know much about the data science of step detection), I would suggest to use builtin detector and counter.
By implementing SensorEventListener listener within a class and overriding the two methods onSensorChanged and onAccuracyChanged you can start tracking steps.
public class StepActivity extends Activity implements SensorEventListener{
SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Sensor sSensor= sensorManager .getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);
...
}
Now we have initialised the SensorManager and Sensor and have the Sensor registered as a listener within the activity, we now need to implement the onSensorChanged function that will be triggered by a SensorEvent whenever there is a change to the Sensor we registered, in our case the TYPE_STEP_DETECTOR.
private long steps = 0;
#Override
public void onSensorChanged(SensorEvent event) {
Sensor sensor = event.sensor;
float[] values = event.values;
int value = -1;
if (values.length > 0) {
value = (int) values[0];
}
if (sensor.getType() == Sensor.TYPE_STEP_DETECTOR) {
steps++;
}
}
That's a very naive method to achieve step count. You should use Android's built-in step counter because it also uses other sensors if available such as gyroscope which can improve the step detection. You should especially use this built-in version if you are going to built things on top it. You need a reliable underlying layer. You can also try using linear acceleration sensor which is calculated by removing gravity component from the accelerometer. The gravity makes accelerometer very sensitive, that's why you see step counter increasing when you are just standing.
The details can be found here:
https://source.android.com/devices/sensors/sensor-types#step_detector
If you still want to develop your own from scratch, then look at this code:
https://github.com/bagilevi/android-pedometer
You can also try Google scholar for the latest papers on step counting algorithms. Especially try to read the latest survey on the topic.
I have to get the accelerometer values in time.
I saw the Sensor class and the SensorEventListener but this listener notify only when the value changes and I need a periodic notification (also if the value do not change).
Otherwise I would like to continuously read the accelerometer value but it is not possible according to this thread: Get current SensorEvent value
What can I do?
Why do you need to continuously "read" the sensor values even when they are the same as before? If you need to calculate some output on a regular basis, then a better solution might be to set up a timer that triggers on the required intervals at which time you use the values from a set of variables that are updated whenever the sensor values change. That way even if they don't change, the timer will initiate the calculations.
Kaamel
I have a test case for my app which fills in the TextViews in an Activity and then simulates clicking the Save button which commits the data to a database. I repeat this several times with different data, call Instrumentation.waitForIdleSync(), and then check that the data inserted is in fact in the database. I recently ran this test three times in a row without changing or recompiling my code. The result each time was different: one test run passed and the other two test runs reported different data items missing from the database. What could cause this kind of behavior? Is it possibly due to some race condition between competing threads? How do I debug this when the outcome differs each time I run it?
Looks like a race condition.
remember in the world of threading there is no way to ensure runtime order.
I'm not an android dev so I'm only speculating but UI is only on one event thread generally so when you call the method from another thread (your test) you're probably breaking that as you're outside of the event thread.
You could try using a semaphore or more likely a lock on the resource.
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.html
I (finally!) found a solution to this problem. I now call finish() on the tested Activity to make sure that all of its connections to the database are closed. This seems to ensure consistency in the data when I run the assertions.
I would suggest making a probe for the database data rather than a straight assert on it. By this I mean make a piece of code that will keep checking the database for up to a certain amount of time for a condition rather than waiting for x seconds (or idle time) then check, I am not on a proper computer so the following is only pseudo code
public static void assertDatabaseHasData(String message, String dataExpected, long maxTimeToWaitFor){
long timeToWaitUntil = System.getCurrentTimeMillis() + maxTimeToWaitFor;
boolean expectationMatched = false;
do {
if(databaseCheck() == dataExpected){
expecttionMatched == true;
}
}while(!expectationMatched && System.getCurrentTimeMillis() < timeToWaituntil);
assertTrue(message, expectationMatched);
}
When i get to a computer i will try to relook into the above and make it better (I would actually of used hamcrest rather than asserts but that is personal preference)
I need to limit number of key events handled per second.
The idea is, because in my app users can use keyboard.
When user hold down on right navigation button, for example.
I don't want to handle every event, because my app can get stucked in calculation loop.
And then force close, wait dialog appears.
I want to handle 2,3 events per second and other just to ignore.
So I can add little cool down time for the app and calculation thread.
Is is possible?
I think I must use some timers or simple sleep function in my key listener, but I can't figure out right way to do this.
Any idea?
A simple solution would be doing some time comparison when you receive a key event:
// a variable in your class:
private long mPreviousKeyEventTime = 0;
// in the key event handling function:
if(System.currentTimeMillis() - mPreviousKeyEventTime < 300) return;
mPreviousKeyEventTime = System.currentTimeMillis();
300 is the time in milliseconds - change it to suite your needs.
Edit: if the keyboard is also used for typing, then make these restrictions only when navigating.
I need some help getting info from the orientation sensor. As I have seen in just about every tutorial/guide out there, the values are passed to an event (onSensorChanged(SensorEvent event) in which they can be manipulated.
My problem is that I don't want to keep the electro-magnetic/orientation sensor running constantly (for the sake of battery life). I want to be able to turn it on, grab the current value and switch it off. Is there any way to do this?
I have done some searching and found that I can try multi-threading, but I'm not fully comfortable with that.
What I'm looking for is something like (Sorry for lack of formatting I can't seem to figure it out):
private void getOrientationNOW() {
m_SensorManager.registerListener(mySensorEventListener, m_MagneticSensor, SensorManager.SENSOR_DELAY_FASTEST);
//---->Something here to get the current value from the sensor
m_SensorManager.unregisterListener(mySensorEventListener);
}
If this is possible, please help me!
Thank you all in advance!
When you register a listener for a sensor the activity will be called every time the sensor values changes according to the parameters. So if you want to get the values only one once what you could do is unregister the listener for that sensor after getting the value once.