I have a program where it relies heavily on identifying the week number for the year. I have done the leg work and figured out all the problems that will cause and settle with this method. I works perfect for years that have 53 weeks and such. My only issue is that when I run it on my emulator for 2.2 it works perfect, like this is week 19 and its correct. when I run it on my phone a G1, the week shows 20. How do I fix this?
Here is my week code:
/**
* Format the date into a number that is the year*100 plus the week i.e. 2008 and its week 11
* would show as 811
* #param - String of a date to create a week id, must be in format of 2011-01-31 (YYYY-MM-DD)
* #return returns next weeks id
*/
public static int getWeekId(String date){
// Set the first day of week to Monday and set the starting new year weeks
// as a full first week in the new year.
Calendar c = Calendar.getInstance();
c.setFirstDayOfWeek(Calendar.MONDAY);
c.setMinimalDaysInFirstWeek(7);
if (!date.equalsIgnoreCase("")) {
String[] token = date.split("-", 3);
int year = Integer.parseInt(token[0]);
int month = Integer.parseInt(token[1])-1; // months are 0-11 stupid..
int day = Integer.parseInt(token[2]);
c.set(year, month, day);
}
int yearWeek = ( (c.get(Calendar.YEAR) - 2000)*100 + (c.get(Calendar.WEEK_OF_YEAR)));
Log.d("getWeekId()"," WEEK_OF_YEAR: " + c.get(Calendar.WEEK_OF_YEAR));
return yearWeek;
}
(I'd leave this in a comment, but my account does not yet have commenting permissions.)
When called with 2011-01-01, the code currently returns 1152. Is this as intended?
For what it's worth, there is likely more intricacy to it than you've written. I don't say this to be mean, it's just that there are probably lots of interesting weird cases that you haven't considered. There is a good Java library that knows a ton of stuff about times, and may have this code written already, Check it out: http://joda-time.sourceforge.net/
Apparently its a bug in the android phone...so watch out for this when using android 1.6.
Related
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.
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 have two devices HTC with android 2.3.5 and Samsung with 2.3.6
now the problem i am facing is
i need the date's week of month.
So i've written this code and installed on both the phones. and set the system date as
27th Jan 2013
Calendar calendar = Calendar.getInstance();
int weekOfMonth = calendar.get(Calendar.WEEK_OF_MONTH);
Log.i(TAG,"weekOfMonth = "+weekOfMonth);
now on HTC the output is
weekOfMonth = 5
while on samsung running the same code produces
weekOfMonth = 4
this really is screwing my logic n calculations ahead.
am i doing something wrong ?
It is probably due to Locales. In Java
Calendar calFr = Calendar.getInstance(TimeZone.getTimeZone("Europe/Paris"), Locale.FRANCE);
Calendar calUs = Calendar.getInstance(TimeZone.getTimeZone("US/Eastern"), Locale.US);
Calendar calUk = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.UK);
calFr.set(2013, Calendar.JANUARY, 27);
calUs.set(2013, Calendar.JANUARY, 27);
calUk.set(2013, Calendar.JANUARY, 27);
int weekOfMonthFr = calFr.get(Calendar.WEEK_OF_MONTH);
int weekOfMonthUs = calUs.get(Calendar.WEEK_OF_MONTH);
int weekOfMonthUk = calUk.get(Calendar.WEEK_OF_MONTH);
System.out.println("France week of month is " + weekOfMonthFr);
System.out.println("USA week of month is " + weekOfMonthUs);
System.out.println("UK week of month is " + weekOfMonthUk);
will give you
France week of month is 4
USA week of month is 5
UK week of month is 4
Double check the year that it is set to, if one is set to 2012 and the other 2013, that would explain the difference.
Can you get the applications to log the date held in the calendar object and post it here as well just to make sure they have correct information.
I'm working on an android application, as part of me trying to learn android programming, that will switch audio profiles based on day and time (provided by the user)... So far I have got most of the layout done, I have also created a service that will run in the background to perform few checks...
Right now I'm having a hard time trying to find an elegant way to handle checking if current time falls in time range saved by the user... I'm saving the user's preference for time range in a string format from androids TimerPicker control, I need to check if the current time falls in the user saved times...
Right now I have the following code:
the 'from time' is coming in with the following: hour:minute:AM/PM -- 8:59:AM in string format
the 'to time' is coming in with the following: hour:minute:AM/PM -- 4:59:PM in string format
if(fromAMPM.equals("AM")){
from.set(from.AM_PM, from.AM);
} else {
from.set(from.AM_PM, from.PM);
}
//dont care about the YEAR and MONTH, so set it to current MONTH and YEAR
from.set(rightNow.get(rightNow.YEAR), rightNow.get(rightNow.MONTH), dayOfWeek, fromHour, fromMinute);
if(toAMPM.equals("AM")){
to.set(to.AM_PM, to.AM);
}else{
to.set(to.AM_PM, to.PM);
}
//dont care about the YEAR and MONTH, so set it to current MONTH and YEAR
to.set(rightNow.get(rightNow.YEAR), rightNow.get(rightNow.MONTH), dayOfWeek, toHour, toMinute);
//this is just for me to see what got set:
SimpleDateFormat df3 = new SimpleDateFormat("HH:mm aaa");
String formattedDate1 = df3.format(from.getTime());
String formattedDate2 = df3.format(to.getTime());
After all this processing:
formattedDate1 is returning: 08:59 AM
formattedDate2 is returning: 04:59 AM
Any suggestions?
Thanks
Take a look at the Calendar documentation, under the section "Inconsistent Information"
http://developer.android.com/reference/java/util/Calendar.html
You call:
to.set(rightNow.get(rightNow.YEAR), rightNow.get(rightNow.MONTH), dayOfWeek, toHour, toMinute);
Which sends toHour as HOUR_OF_DAY (24h), not HOUR (12h).
It says that when you supply it with inconsistent information, it just uses the latest information. You're telling it that toHour is 4 on a 24hour scale, which is inconsistent with your PM setting, so it throws the PM setting away.
The easiest change would probably be just to add 12 to toHour instead of setting the AM_PM. Or, don't use the set(year, month, day, hourofday, minute) command and just set hour and am_pm separately.
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.