I am working on a project that requires the actions of a user to be time logged and represented as for example : 1 min ago, ...3hrs ago...5 days ago. I am new to this and don't know how to proceed. Keep in mind the project is NOT REST based. How do I implement this?
Get time in milliseconds for user action, save that time somewhere and then every time take difference of that time with current time to find out how long this action happens
you can get time in millisecond using
Calendar calendar = Calendar.getInstance();
calendar.getTimeInMillis();
You can get the actual timestamp with:
long timestamp = System.currentTimeMillis();
Regarding your question you can do something like:
long eventTimestamp = System.currentTimeMillis();
..
// some other stuff happens
..
//get the passed time
long actualTimestamp = System.currentTimeMillis();
long timestampDifference = actualTimestamp - eventTimestamp;
int passedSeconds = timestampDifference / 1000; //get the passed time in seconds
int passedMinutes= passedSeconds / 60; //get the passed time in minutes
Since you are on Android you could try the helper class DateUtils built into Android platform. Something similar to this untested code:
String relativeTime =
DateUtils.getRelativeTimeSpanString(
jud.getTime(),
System.currentTimeMillis(),
DateUtils.MINUTE_IN_MILLIS,
DateUtils.FORMAT_ABBREV_RELATIVE);
If you don't like the API-style or don't find enough features or see other problems like missing timezone awareness then you can also download and try one of two external libraries:
PrettyTime (slim classic library for relative times)
// your possible input
Date jud = new Date(System.currentTimeMillis() - 3600000);
org.ocpsoft.prettytime.PrettyTime pt =
new org.ocpsoft.prettytime.PrettyTime(Locale.ENGLISH);
String relativeTime = pt.format(jud);
System.out.println(relativeTime); // output: 1 hour ago
or my library Time4A (bigger but also more features and languages):
// your possible input
Date jud = new Date(System.currentTimeMillis() - 3600000);
Moment moment = TemporalType.JAVA_UTIL_DATE.translate(jud);
String relativeTime =
net.time4j.PrettyTime.of(Locale.US)
.withShortStyle()
.printRelativeInStdTimezone(moment);
System.out.println(relativeTime); // output: 1 hr. ago
Other libraries don't support printing of relative times well, if at all.
Related
everyone. I'm a newbie to android, so please forgive me for asking questions that may be a bit elementary.
I need to calculate the running time (in nanoseconds) of a code segment, and I just started using System.nanoTime(), something like this:
long startTime = System.nanoTime();
// some code seqment
long endTime = System.nanoTime();
long elapsedTime = startTime - endTime;
But I've observed online that sometimes elapsedTime is a negative number! After checking, it seems that the problem is due to the size of the cores in android, the frequency of the two cores is different and if my starttime and endTime run on different cores, the calculation is not credible.
I found elapsedRealTime,elpseRealTimeNanos, in the android documentation and they seem to meet my needs, but I don't know if they have the same problem as System.nanoTime, and I didn't find them on google, so I would like to ask if these two functions can meet my needs
It must be endTime - startTime to get positive number.
long elapsedTime = endTime - startTime;
OR you can try to use elapsedRealtime. (Not that it changed if device is reboot).
val startTime = SystemClock.elapsedRealtime()
// your code segment
val elapsedTime = SystemClock.elapsedRealtime() - startTime
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.
Background
Google has deprecated the function "getRecentTasks" of "ActivityManager" class. Now all it does is to get the list of apps that the current app has opened.
I've even written a post about it here on StackOverflow, but I noticed it's impossible.
The problem
I've made a post about it (here, and another, similar one created by someone else, here) and requested to re-consider it, and Google decided to make a new class, that seem to provide a similar functionality (more like statistics, but might also be useful), but I can't find out how to use it.
The class is called "UsageStatsManager", and my guess is that the function "queryUsageStats" does the job.
Also, it seems it has a new permission ("android.permission.PACKAGE_USAGE_STATS"), which is a system permission, but it's written that:
declaring the permission implies intention to use the API and the user
of the device can grant permission through the Settings application.
Here's another link about this new functionality.
What I've found
I've looked at the code of Android, and noticed that "Context" has USAGE_STATS_SERVICE , which in the JavaDocs say the next thing:
/**
* Use with {#link #getSystemService} to retrieve a {#link
* android.app.UsageStatsManager} for interacting with the status bar.
*
* #see #getSystemService
* #see android.app.UsageStatsManager
* #hide
*/
public static final String USAGE_STATS_SERVICE = "usagestats";
The weird thing is that not only it says "status bar", but also the packageName doesn't match (should be "android.app.usage.UsageStatsManager" instead) .
I've also added the correct permission:
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
and here's the code I use:
final UsageStatsManager usageStatsManager=(UsageStatsManager)context.getSystemService("usagestats");// Context.USAGE_STATS_SERVICE);
final int currentYear=Calendar.getInstance().get(Calendar.YEAR);
final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,currentYear-2,currentYear);
In the emulator itself, I went to "Settings"->"security"->"apps with usage access" , and enabled my app.
However, when running the code, all I get is an empty list...
The question
How do you use UsageStatsManager ?
Also, how do you let the user to grant the permission in the easiest way possible? Or is it automatically done, as soon as the app tries to get the needed information?
What happens when trying to use this class yet the user hasn't confirmed it yet?
How can I make the code return me a real list of apps?
I think the documentation was just short hand for the Calendar stuff. I don't think it actually works with just 2014; however I can be wrong.
In order to access the actually list of UsageStats, you would need to create a Calendar object with the correct month,day, and year. Exactly how MRK said in the other answer. I copied and corrected the errors in MRK's code so anyone who sees it in the future can see it.
Calendar beginCal = Calendar.getInstance();
beginCal.set(Calendar.DATE, 1);
beginCal.set(Calendar.MONTH, 0);
beginCal.set(Calendar.YEAR, 2012);
Calendar endCal = Calendar.getInstance();
endCal.set(Calendar.DATE, 1);
endCal.set(Calendar.MONTH, 0);
endCal.set(Calendar.YEAR, 2014);
final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, beginCal.getTimeInMillis(), endCal.getTimeInMillis());
-Credit MRK; corrected by me (he accidentally just put cal instead of beginCal and endCal)
The code for the usage access settings is below. :)
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
I've created a sample of how to use UsageStats on my Github.
Hopefully it can be of help to someone
https://github.com/ColeMurray/UsageStatsSample
Answering your last question "How can I make the code return me a real list of apps?".
queryUsageStats takes begin time and end time in milliseconds, not the value of the year in int.
Calendar beginCal = Calendar.getInstance();
beginCal.set(Calendar.DATE, 1);
beginCal.set(Calendar.MONTH, 0);
beginCal.set(Calendar.YEAR, 2012);
Calendar endCal = Calendar.getInstance();
endCal.set(Calendar.DATE, 1);
endCal.set(Calendar.MONTH, 0);
endCal.set(Calendar.YEAR, 2014);
final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, beginCal.getTimeInMillis(), endCal.getTimeInMillis());
This should return a list of UsageStats for the years 2012 and 2013 (keep in mind the end time is exclusive of the end result time range).
There is actually an example app included in AOSP sample code: developers/samples/android/system/AppUsageStatistics/
It includes all the bits necessary to use UsageStats in an app:
Declaring the permission in AndroidManifest.xml
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
Show settings to grant permission to access UsageStatsManager
startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
Query UsageStatsManager for statistics.
Calendar cal = Calendar.getInstance();
cal.add(Calendar.YEAR, -1);
List<UsageStats> queryUsageStats = mUsageStatsManager
.queryUsageStats(intervalType, cal.getTimeInMillis(),
System.currentTimeMillis());
Creating a list of apps based on UsageStats
To summarize and apply to your example:
You seem to correctly ask for and grant permissions to access usage stats.
You correctly get the UsageStats system service.
However, the time period you query for is way too short: Arguments beginTime and endTime are measured in milliseconds since the epoch. Calendar instances can give you this value with getTimeinMillis(). What you erroneously do is to only give the year numbers (2015 and2017 if you would run the program today). These values are interpreted as milliseconds since the epoch and thus the interval is only 2 milliseconds long and is some time in 1970.
Instead of the following code snippet that you posted, you should copy the example I posted below:
Wrong:
final int currentYear=Calendar.getInstance().get(Calendar.YEAR);
final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,currentYear-2,currentYear);
Correct:
final long currentTime = System.currentTimeMillis(); // Get current time in milliseconds
final Calendar cal = Calendar.getInstance();
cal.add(Calendar.YEAR, -2); // Set year to beginning of desired period.
final long beginTime = cal.getTimeInMillis(); // Get begin time in milliseconds
final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, beginTime, currentTime);
Use UsageStats will get the wrong information when user opens the notification drawer or on a locked screen. You have to use UsageStatsManager.queryEvents() and look for the latest event with MOVE_TO_FOREGROUND event type.
If you want to see usage statistics of a specific time period, you have to first calculate the length of time in milliseconds of the start and end of your time period since the epoch. (epoch is the number of seconds that have elapsed since 00:00:00 UTC, Thursday 1, 1970.) Or, as I will show in the following sample code, an easy way is to calculate backwards from the current time in milliseconds.
For example, if you want a usage statistic of the past 4 days, you can use the following code:
UsageStatsManager mUsageStatsManager = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE);
List<UsageStats> queryUsageStats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
(System.currentTimeMillis() - 345600000), System.currentTimeMillis());
The number 345600000 is the number of milliseconds in 4 days.
And for the INTERVAL_TYPE this article explains it well.
The system collects and aggregates the data over 4 different intervals
and they are: INTERVAL_DAILY, INTERVAL_WEEKLY, INTERVAL_MONTHLY and
INTERVAL_YEARLY. The system records are limited in time, so you’ll be
able to retrieve app usage data for up to 7 days for interval daily,
up to 4 weeks for interval weekly, up to 6 months for monthly and
finally up to 2 years for yearly.
There’s a fifth option to mention:
INTERVAL_BEST will choose the best fitting interval between the four
above based on the timespan you’ve chosen.
you can do like this
//noinspection ResourceType
final UsageStatsManager usageStatsManager=(UsageStatsManager)context.getSystemService("usagestats");// Context.USAGE_STATS_SERVICE);
final int currentYear=Calendar.getInstance().get(Calendar.YEAR);
final List<UsageStats> queryUsageStats=usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,currentYear-2,currentYear);
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.
I would like in my application to find a way to synch the date and time with something given by an external source.
I don't want to use the phone time because I might get a difference of maybe 5 minutes around real time. and 5 minutes extra or less = 10 minutes!
I have heard about time information in the GPS satellites or in Network antennas.
I have tried with System.getCurrentTime but i get the current the of the device, so, if my device is set up 5 minutes earlier, it display the wrong time.
EDIT
To make a short question: how can I get this time?
I didn't know, but found the question interesting. So I dug in the android code... Thanks open-source :)
The screen you show is DateTimeSettings. The checkbox "Use network-provided values" is associated to the shared preference String KEY_AUTO_TIME = "auto_time"; and also to Settings.System.AUTO_TIME
This settings is observed by an observed called mAutoTimeObserver in the 2 network ServiceStateTrackers:
GsmServiceStateTracker and CdmaServiceStateTracker.
Both implementations call a method called revertToNitz() when the settings becomes true.
Apparently NITZ is the equivalent of NTP in the carrier world.
Bottom line: You can set the time to the value provided by the carrier thanks to revertToNitz().
Unfortunately, I haven't found a mechanism to get the network time.
If you really need to do this, I'm afraid, you'll have to copy these ServiceStateTrackers implementations, catch the intent raised by the framework (I suppose), and add a getter to mSavedTime.
Get the library from http://commons.apache.org/net/download_net.cgi
//NTP server list: http://tf.nist.gov/tf-cgi/servers.cgi
public static final String TIME_SERVER = "time-a.nist.gov";
public static long getCurrentNetworkTime() {
NTPUDPClient timeClient = new NTPUDPClient();
InetAddress inetAddress = InetAddress.getByName(TIME_SERVER);
TimeInfo timeInfo = timeClient.getTime(inetAddress);
//long returnTime = timeInfo.getReturnTime(); //local device time
long returnTime = timeInfo.getMessage().getTransmitTimeStamp().getTime(); //server time
Date time = new Date(returnTime);
Log.d(TAG, "Time from " + TIME_SERVER + ": " + time);
return returnTime;
}
getReturnTime() is same as System.currentTimeMillis().
getReceiveTimeStamp() or getTransmitTimeStamp() method should be used.
You can see the difference after setting system time to 1 hour ago.
local time :
System.currentTimeMillis()
timeInfo.getReturnTime()
timeInfo.getMessage().getOriginateTimeStamp().getTime()
NTP server time :
timeInfo.getMessage().getReceiveTimeStamp().getTime()
timeInfo.getMessage().getTransmitTimeStamp().getTime()
Try this snippet of code:
String timeSettings = android.provider.Settings.System.getString(
this.getContentResolver(),
android.provider.Settings.System.AUTO_TIME);
if (timeSettings.contentEquals("0")) {
android.provider.Settings.System.putString(
this.getContentResolver(),
android.provider.Settings.System.AUTO_TIME, "1");
}
Date now = new Date(System.currentTimeMillis());
Log.d("Date", now.toString());
Make sure to add permission in Manifest
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
NITZ is a form of NTP and is sent to the mobile device over Layer 3 or NAS layers.
Commonly this message is seen as GMM Info and contains the following informaiton:
Certain carriers dont support this and some support it and have it setup incorrectly.
LAYER 3 SIGNALING MESSAGE
Time: 9:38:49.800
GMM INFORMATION 3GPP TS 24.008 ver 12.12.0 Rel 12 (9.4.19)
M Protocol Discriminator (hex data: 8)
(0x8) Mobility Management message for GPRS services
M Skip Indicator (hex data: 0)
Value: 0
M Message Type (hex data: 21)
Message number: 33
O Network time zone (hex data: 4680)
Time Zone value: GMT+2:00
O Universal time and time zone (hex data: 47716070 70831580)
Year: 17
Month: 06
Day: 07
Hour: 07
Minute :38
Second: 51
Time zone value: GMT+2:00
O Network Daylight Saving Time (hex data: 490100)
Daylight Saving Time value: No adjustment
Layer 3 data:
08 21 46 80 47 71 60 70 70 83
15 80 49 01 00
This seemed to work for me:
LocationManager locMan = (LocationManager) activity.getSystemService(activity.LOCATION_SERVICE);
long networkTS = locMan.getLastKnownLocation(LocationManager.NETWORK_PROVIDER).getTime();
Working on Android 2.2 API (Level 8)
Now you can get time for the current location but for this you have to set the system's persistent default time zone.setTimeZone(String timeZone) which can be get from
Calendar calendar = Calendar.getInstance();
long now = calendar.getTimeInMillis();
TimeZone current = calendar.getTimeZone();
setAutoTimeEnabled(boolean enabled)
Sets whether or not wall clock time should sync with automatic time updates from NTP.
TimeManager timeManager = TimeManager.getInstance();
// Use 24-hour time
timeManager.setTimeFormat(TimeManager.FORMAT_24);
// Set clock time to noon
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MILLISECOND, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.HOUR_OF_DAY, 12);
long timeStamp = calendar.getTimeInMillis();
timeManager.setTime(timeStamp);
I was looking for that type of answer I read your answer but didn't satisfied and it was bit old. I found the new solution and share it. :)
For more information visit: https://developer.android.com/things/reference/com/google/android/things/device/TimeManager.html
I read that this
LocationManager locMan = (LocationManager) activity.getSystemService(activity.LOCATION_SERVICE);
long time = locMan.getLastKnownLocation(LocationManager.NETWORK_PROVIDER).getTime();
provides correct time, without internet at the cost of some blocking processing.
the time signal is not built into network antennas: you have to use the NTP protocol in order to retrieve the time on a ntp server. there are plenty of ntp clients, available as standalone executables or libraries.
the gps signal does indeed include a precise time signal, which is available with any "fix".
however, if nor the network, nor the gps are available, your only choice is to resort on the time of the phone... your best solution would be to use a system wide setting to synchronize automatically the phone time to the gps or ntp time, then always use the time of the phone.
note that the phone time, if synchronized regularly, should not differ much from the gps or ntp time. also note that forcing a user to synchronize its time may be intrusive, you 'd better ask your user if he accepts synchronizing. at last, are you sure you absolutely need a time that precise ?