Obtain current heart rate Samsung health - android

I am trying to get the current heart beat rate using Samsung health. I am using Samsung's SDK for Android basing my code on the example provided to count the steps. Here is how I adapted the code for some tests I did at 6pm:
HealthDataResolver resolver = new HealthDataResolver(mStore, null);
// Set time range from start time of today to the current time
long startTime = 16 * 60 * 60 * 1000;
long endTime = startTime + 2 * 60 * 60 * 1000;
HealthDataResolver.Filter filter = HealthDataResolver.Filter.and(
HealthDataResolver.Filter.greaterThanEquals(HealthConstants.HeartRate.START_TIME, startTime),
HealthDataResolver.Filter.lessThanEquals(HealthConstants.HeartRate.END_TIME, endTime));
HealthDataResolver.ReadRequest request = new ReadRequest.Builder()
.setDataType(HealthConstants.HeartRate.HEALTH_DATA_TYPE)//.setDataType(HealthConstants.StepCount.HEALTH_DATA_TYPE)
.setProperties(new String[] {HealthConstants.HeartRate.HEART_RATE})
.setLocalTimeRange(
HealthConstants.StepCount.START_TIME,
HealthConstants.StepCount.TIME_OFFSET,
startTime, endTime)
.setFilter(filter)
.build();
try {
resolver.read(request).setResultListener(mListener);
} catch (Exception e) {
Log.e(MainActivity.APP_TAG, "Getting step count fails.", e);
}
So basically, the problem is that originally, the steps code meassured the interval of the whole day (endTime = startTime + ONE_DAY_IN_MILISECONDS). I tried to adapt this code to obtain the heart beat average of the last 20 seconds, but when I shrink the margin between the startTime and the endTime to an interval lower than one hour, the average I retrieve is zero. Therefore, my question is: is this the right way to obtain the current heart beat? If so, what I am doing wrong or how can this be achieved?

I finally found the answer. Samsung Health updates it's data with a very low frequency. That cannot be changed and therefore, when trying to access to small time intervals, it does not find any register and retrieves a zero value. The correct way to do this is to directly connect to the wristband via BLE using the Samsung SDK for Devices. There are a bunch of guidelines in order to obtain the different meassurements. For this case, it should be used the Heart Rate Monitor Guide.

Related

ISipRegistrationListener.OnRegistrationDone( ) giving too high values for expiration time

I'm successfully registering a SipProfile with 1 hour expiration. I see the REGISTER message in Wireshark on the SIP server machine, re-sent with authorization.
Brekeke replies immediately with a STATUS: 200 OK, passing back 'Expires:3600'.
Both Xamarin and Android docs tell me that lExpire should be duration in seconds before the registration expires, so it represents an interval. I want to expose received values, so multiply by TimeSpan.TicksPerSecond (to convert to TimeSpan), 3600 would result in 0.01:00:00:
void ISipRegistrationListener.OnRegistrationDone( string lclPrfUri, long lExpire )
{
long l= DateTime.Now.Ticks;
double d= (double)l / lExpire;
string s= string.Format( "RegSucced( '{0}', {1} ), {2}, {3}", lclPrfUri, lExpire,
new TimeSpan( lExpire * TimeSpan.TicksPerSecond )
.ToString( "d\\.hh\\:mm\\:ss" ), d );
..
}
But i'm getting lExpire values in the range of 1.5 trillions (1'541'195'345'242)!
As i saw it constantly growing with time, i thought it might be related to Ticks, so i exposed both and gathered the following statistics (H == T + 1 hour -- expected expiration):
# DT.Now.Ticks (T) lExpire (E) T/E ratio T+36000000000 (H) H/E ratio
1 636767624266839520 1541183611836 413167.918 636767660266839520 413167.941
2 636767669188704010 1541188122398 413166.738 636767705188704010 413166.761
3 636767670260843180 1541188229643 413166.710 636767706260843180 413166.733
4 636767670974718350 1541188301027 413166.691 636767706974718350 413166.715
5 636767693193745790 1541190522922 413166.110 636767729193745790 413166.133
And the ratios look surprisingly consistent, though the magic of 413166 escapes me.. And from that lExpire looks more like a reference to a point in time, than an interval, no?
But according to docs i should get 3600 without any scaling factors, right? What is going on??!
UPDATE (2019-Jan-25)
Finally got closer to an answer. Digging through Android source files (e.g. https://android.googlesource.com/platform/frameworks/base/+/431bb2269532f2514861b908d5fafda8fa64da79/voip/java/com/android/server/sip/SipService.java) i found the following fragment:
#Override
public void onRegistrationDone(ISipSession session, int duration) {
if (DEBUG) Log.d(TAG, "onRegistrationDone(): " + session);
synchronized (SipService.this) {
if (notCurrentSession(session)) return;
mProxy.onRegistrationDone(session, duration);
if (duration > 0) {
mSession.clearReRegisterRequired();
mExpiryTime = SystemClock.elapsedRealtime() + (duration * 1000);
..
SystemClock.elapsedRealtime() returns milliseconds since boot, including time spent in sleep.
Time in UNIX/Linux/Java is kept as number of seconds since epoch (1970-01-01T00:00:00Z).
Wikipedia's page shows Current Unix time as 1548450313 (2019-01-25T21:05:13+00:00), which is only a 1000 times (s-to-ms multiplier!) different in range from lExpire values i observe. The formula for mExpiryTime in the last line kinda gives hope.. "Eureka!"?
Let's check if they conform to "# of ms since epoch" theory:
DateTime dtEpoch = new DateTime( 1970, 1, 1, 0, 0, 0, DateTimeKind.Utc );
void ISipRegistrationListener.OnRegistrationDone( string lclPrfUri, long lExpire )
{
DateTime dt = dtEpoch.AddMilliseconds( lExpire ).ToLocalTime( );
string s= string.Format( "RegSucced( '{0}', {1}, {2} )", lclPrfUri, lExpire,
dt.ToString( "yyyy-MM-dd HH:mm:ss.fff" ) );
..
}
Yesterday's screenshots - with that addition (magenta arrows mark exposed values):
As you can see, the difference between lExpire converted into time and DateTime.Now (captured in the log) is negligible - in ms range!
I actually like the idea of being given an expiration moment instead of duration (which need to be added to an undefined starting point). Was about to answer my question..
But still, there are follow-up unresolved mysteries:
Why documentation says the argument is duration in seconds?
Xamarin may be just copying Android docs, but the source is way wrong!
Is this really how lame Android devs are? Reckon that should be rethorical ((..
Does anybody care that requested expiration period may be trumped [down] by PBX /SIP server, and thus they have to re-register more often?
All calls to .onRegistrationDone(session, duration) in the source files specify duration, not mExpiryTime.
There are constant definitions (EXPIRY_TIME = 3600, SHORT_EXPIRY_TIME = 10, MIN_EXPIRY_TIME = 60) and comparisons of duration to these..
Range of values is drastically different between the two (3600 vs 15 trillion).
How/where does mExpiryTime (expiration moment) make it into the argument of my method?
ms since boot and s (or ms) since epoch are still very different, what makes that adjustment?
and finally, asking a 1 hr expiration and receiving it in the OK reply from SIP server, i expect that to be reflected here too, so lExpire should be 1 hr in the future, not now!!
Any ideas?

Mana recovery issue

We're making a game in Android Studio and we got stuck. The resource (mana) used for specific spells should recover on time, e.g. 1 mana point per 5 minutes. We don't really get how to make it recover while the game is off. Is there a method to check current date/time and count the amount of mana replenished? Converting date and time to String and comparing it with the new date/time seems to be an "exciting" work to do, but we would bypass these mechanics if there is a way.
Thank you in advance.
The best way to do this in the background is to register a receiver in your manifest. This means the receiver will keep listening for broadcasts even if the app is off.
What you need is this particular action when registering your receiver Intent.ACTION_TIME_TICK
There is a more detailed answer about this matter here Time change listener
Another solution is to use the Calendar class in java. With it you can get the exact minutes passed from a point in the past to this moment. This way you don't have to worry about parsing dates and similar. I can't provide you specific examples because me myself have not used the Calendar class very much, but I'm sure you can find lots of stuff in the official documentation and on stackoverflow about it.
No need to work with Date objects, the simple usage of System.currentTimeMillis() should work. Here's a basic outline:
long mLastManaRefreshTime = System.currentTimeMillis();
void refreshMana()
{
long timeDelta = System.currentTimeMillis() - mLastManaRefreshTime;
mLastManaRefreshTime = System.currentTimeMillis();
float totalManaToRefresh = (float)AMOUNT_TO_REFRESH_IN_ONE_MINUTE * ((float)timeDelta / 60000f);
mMana += totalManaToRefresh;
if (mMana > MAX_MANA)
mMana = MAX_MANA;
}
This method is of course just an outline. You will need to call this once every update cycle. It will calculate how much time passed since the last time refreshMana was called, and replenish the required amount.
If you need this to work while the game is off, you can save the mLastManaRefreshTime to a SharedPreferences object and reload it when the game loads up again.
With System.currentTimeMillis() you can a current time-stamp in milliseconds.
You could save the latest time-stamp in your Preferences with every 5 min tick of the running game. For the other case, when your App comes back from a state where it does not do this (i.e. called the first time, woken up etc.).
Something like this:
int manacycles = ((int) (((System.currentTimeMillis() - oldtimestamp) / 1000) / 60) ) % 5;
would give you the number of Mana points you would have to add.
Alternately you could do the same thing with the Calendar class.
Also keep in mind players could cheat this way by simply changing their time. If your game is online you could get the time from the internet, with something like this:
try {
TimeTCPClient client = new TimeTCPClient();
try {
// Set timeout of 60 seconds
client.setDefaultTimeout(60000);
// Connecting to time server
// Other time servers can be found at : http://tf.nist.gov/tf-cgi/servers.cgi#
// Make sure that your program NEVER queries a server more frequently than once every 4 seconds
client.connect("nist.time.nosc.us");
System.out.println(client.getDate());
} finally {
client.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}

SensorEvent.timestamp inconsistency

my application performs in background step counting using the step detector sensor API's introduced in android 4.4.X.
It's essential to my app to know the exact time (at least accuracy of a second) each step event has accrued.
because I perform sensor batching , the time onSensorChanged(SensorEvent event) been called is not the same time when the step event took place - I must use the event.timestampfield to get the event time.
the documentation about this field is:
The time in nanosecond at which the event happened
The problem:
In some devices (such Moto X 2013) seems like this timestamp is time in nano seconds since boot, while in some devices (such Nexus 5) it's actually returns universal system time in nano seconds same as System.currentTimeMills() / 1000.
I understand, there's already an old open issue about that, but since sensor batching is introduced - it becomes important to use this field to know the event time, and it's not possible to rely anymore on the System.currentTimeMills()
My question:
What should I do to get always the event time in system milliseconds across all devices?
Instead of your "2-day" comparison, you could just check if event.timestamp is less than e.g. 1262304000000000000 - that way you'd only have a problem if the user's clock is set in the past, or their phone has been running for 40 years...
Except that a comment on this issue indicates that sometimes it's even milliseconds instead of nanoseconds. And other comments indicate that there's an offset applied, in which case it won't be either system time or uptime-based.
If you really have to be accurate, the only way I can see is to initially capture an event (or two, for comparison) with max_report_latency_ns set to 0 (i.e. non-batched) and compare the timestamp to the system time and/or elapsedRealtime. Then use that comparison to calculate an offset (and potentially decide whether you need to compensate for milliseconds vs nanoseconds) and use that offset for your batched events.
E.g. grab a couple of events, preferably a couple of seconds apart, recording the System.currentTimeMillis() each time and then do something like this:
long timestampDelta = event2.timestamp - event1.timestamp;
long sysTimeDelta = sysTimeMillis2 - sysTimeMillis1;
long divisor; // to get from timestamp to milliseconds
long offset; // to get from event milliseconds to system milliseconds
if (timestampDelta/sysTimeDelta > 1000) { // in reality ~1 vs ~1,000,000
// timestamps are in nanoseconds
divisor = 1000000;
} else {
// timestamps are in milliseconds
divisor = 1;
}
offset = sysTimeMillis1 - (event1.timestamp / divisor);
And then for your batched events
long eventTimeMillis = (event.timestamp / divisor) + offset;
One final caveat - even if you do all that, if the system time changes during your capture, it may affect your timestamps. Good luck!
I found a work-around solution that solving the problem. the solution assumes that the timestamp can be only one of the two: system timestamp, or boot time:
protected long getEventTimestampInMills(SensorEvent event) {
long timestamp = event.timestamp / 1000 / 1000;
/**
* work around the problem that in some devices event.timestamp is
* actually returns nano seconds since last boot.
*/
if (System.currentTimeMillis() - timestamp > Consts.ONE_DAY * 2) {
/**
* if we getting from the original event timestamp a value that does
* not make sense(it is very very not unlikely that will be batched
* events of two days..) then assume that the event time is actually
* nano seconds since boot
*/
timestamp = System.currentTimeMillis()
+ (event.timestamp - System.nanoTime()) / 1000000L;
}
return timestamp;
}
According to the link in your question:
This is, in fact, "working as intended". The timestamps are not
defined as being the Unix time; they're just "a time" that's only
valid for a given sensor. This means that timestamps can only be
compared if they come from the same sensor.
So, the timestamp-field could be completely unrelated to the current system time.
However; if at startup you were to take two sensor samples, without batching, you could calculate the difference between the System.currentTimeMillis() and the timestamp, as well as the quotient to the differences between the different times you should be able to convert between the different times:
//receive event1:
long t1Sys = System.currentTimeMillis();
long t1Evt = event.timestamp;
//receive event2:
long t2Sys = System.currentTimeMillis();
long t2Evt = event.timestamp;
//Unregister sensor
long startoffset = t1Sys - t1Evt; //not exact, but should definitely be less than a second, possibly use an averaged value.
long rateoffset = (t2Sys - t1Sys) / (t2Evt - t1Evt);
Now any timestamp from that sensor can be converted
long sensorTimeMillis = event.timestamp * rateoffset + startoffset;

opengl android time too fast

I'm trying to get the time using android and open gl for my racing game.
My code now is:
deltaTime = (System.currentTimeMillis() + startTime) / 1000000000000.0f;
startTime = System.currentTimeMillis();
tickTime += deltaTime;
DecimalFormat dec = new DecimalFormat("#.##");
Log.d("time", dec.format(tickTime/100));
but it's a bit too fast.
You may want to look at a bit of Android Breakout:
http://code.google.com/p/android-breakout/source/browse/src/com/faddensoft/breakout/GameState.java#1001
The computation is similar, but note it uses System.nanoTime(), which uses the monotonic clock. You don't want to use System.currentTimeMillis(), which uses the wall clock. If the device is connected to a network, the wall clock can be updated, which can cause big jumps forward or backward.
The code also includes a (disabled) frame-rate-smoothing experiment that didn't seem to matter much.
As I think you discovered, the key to this approach is to recognize that the time interval between frames is not constant, and you need to update the game state based on how much time has actually elapsed, not a fixed notion of display update frequency.
Since you're working in milliseconds, shouldn't you be dividing by 1000f instead of 1000000000000.0f?

Android Sensor Timestamp reference time

I'm reading timestamp values from SensorEvent data but I can't work out the reference time for these values. Android documentation just says "The time in nanosecond at which the event happened" As an example:
My current Android device date, October 14th 2011 23:29:56.421 (GMT+2)
System.currentTimeMillis * 1000000 (nanosec) = 1318627796431000000 (that's ok)
sensorevent.timestamp (nanosec) = 67578436328000 = 19 hours 46 min ????
May you help me?
thanks
It appears that what you are dealing with is the number of nanoseconds since the operating system started, also known as "uptime".
Further info on the issue: http://code.google.com/p/android/issues/detail?id=7981
I should add that the linked question SensorEvent.timestamp to absolute (utc) timestamp? deals with the same issue and is where I found the answer.
I know that it's a very old question, but, I'm also struggling for converting SensorEvent.timestamp to a human readable time. So I'm writing here what I've understood so far and how I'm converting it in order to get better solutions from you guys. Any comments will be welcomed.
As I understood, SensorEvent.timestamp is an elapsed time since the device's boot-up. So I have to know the uptime of the device. So if there is an API returning device's boot-up, it will be very easy, but, I haven't found it.
So I'm using SystemClock.elapsedRealtime() and System.currentTimeMillis() to 'estimate' a device's uptime. This is my code.
private long mUptimeMillis; // member variable of the activity or service
...
atComponentsStartUp...() {
...
/* Call elapsedRealtime() and currentTimeMillis() in a row
in order to minimize the time gap */
long elapsedRealtime = SystemClock.elapsedRealtime();
long currentTimeMillis = System.currentTimeMillis();
/* Get an uptime. It assume that elapsedRealtime() and
currentTimeMillis() are called at the exact same time.
Actually they don't, but, ignore the gap
because it is not a significant value.
(On my device, it's less than 1 ms) */
mUptimeMillis = (currentTimeMillis - elapsedRealtime);
....
}
...
public void onSensorChanged(SensorEvent event) {
...
eventTimeMillis = ((event.timestamp / 1000000) + mUptimeMillis);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(eventTimeMillis);
...
}
I think this works for Apps that a millisecond time error is okey. Please, leave your ideas.

Categories

Resources