Android Calendar timezone not changing with CalendarContract - android

I am using the following code to add an event to the calender
Intent intent = new Intent(Intent.ACTION_INSERT);
intent.setType("vnd.android.cursor.item/event");
intent.putExtra(Events.TITLE, "my event title");
intent.putExtra(Events.EVENT_LOCATION, "my city");
intent.putExtra(Events.DESCRIPTION, "description of this event");
intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, dep.getTimeInMillis());
intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, arr.getTimeInMillis());
intent.putExtra(CalendarContract.Events.EVENT_TIMEZONE, departureTimeZone);
intent.putExtra(CalendarContract.Events.EVENT_END_TIMEZONE, arrivalTimeZone);
// Making it private and shown as busy
intent.putExtra(Events.ACCESS_LEVEL, Events.ACCESS_PRIVATE);
intent.putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
CoreApplication.getContext().startActivity(intent);
The problem is that the time it picks up is
One Hour SHORTER than the original time i send and
timezone is always set to device's timezone like "Central European Summer Time GMT +2"
HELP PLEASE!!!!!!!!!!!!!!!

Had the same trouble but found a way out.
TimeZone sets to the device's timeZone by default. To change this and to set it to a specific timeZone use the getRawOffset() property.
This method calculates the milliseconds from the current time. So you can add the milliseconds for your specified timeZone and subtract those for the default timeZone.
When I tried to change it to timeZone 'GMT_ID'
values.put(CalendarContract.Events.DTSTART, startDate.getTime() +TimeZone.getTimeZone(GMT_ID).getRawOffset() -TimeZone.getDefault().getRawOffset());
Hope this helps.

You should check this link Calendar Provider intents, it says that we can't put timezone as intent extras, so send the beginTime and endTime of the event in UTC.
Mentioned in the example of event insert intent, "It uses the CalendarContract.EXTRA_EVENT_BEGIN_TIME and CalendarContract.EXTRA_EVENT_END_TIME extra fields to pre-populate the form with the time of the event. The values for these times must be in UTC milliseconds from the epoch."

Related

Is it possible to set a specific date with the Alarm Clock?

this is how I set my alarm clock:
//all this inside a onClickListener
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_MONTH, 30);
cal.set(Calendar.MONTH, 8);
cal.set(Calendar.YEAR, 2020);
Intent intent = new Intent(AlarmClock.ACTION_SET_ALARM);
intent.putExtra(AlarmClock.EXTRA_HOUR, Integer.parseInt(str1));
intent.putExtra(AlarmClock.EXTRA_MINUTES, Integer.parseInt(str2));
intent.putExtra(AlarmClock.EXTRA_MESSAGE, title.getText().toString());
intent.putExtra(AlarmClock.EXTRA_DAYS, cal.get(Calendar.DAY_OF_MONTH));
intent.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
startActivity(intent);
All this set very well the app alarm clock on my device regarding the time, but not for the date.
Example:
Current time: 12:00 Monday
Time from my code: 13:00 Saturday
The alarm clock sets to play (the ringtone) in 1 hour
Current time: 12:00 Monday
Time from my code: 11:00 Tuesday
The alarm clock sets to play (the ringtone) in 25 hours
I dont know how to use in particular this line of code:
intent.putExtra(AlarmClock.EXTRA_DAYS, cal.get(Calendar.DAY_OF_MONTH));
Thanks in advance
You cannot set the an alarm for a specific date with an AlarmClock provider.
AlarmClock.EXTRA_DAYS is for repeating alarms. You could use something like Calendar.SUNDAY and it would ring every Sunday.
If you want more control over an alarm, you have to program it yourself. Look into the AlarmManager class. It allows you to schedule your application to be run at some point in the future.

Setting Notification using AlarmManager by passing calendar.getTimeInMillis(),triggers notification instantly not at the time intended

I have followed the following link https://developer.android.com/training/scheduling/alarms.html.
RTC examples first one, to set an alarm for a specific time on all days. Even after following the same code, the alarm is not triggered at the time it is suppose to get triggered. Instead the notification gets triggered immediately after setting the time which is done with the help of a time picker. Following is my code snippet,
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, NotificationReceiver.class);
PendingIntent intentalarm = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY,4);
calendar.set(Calendar.MINUTE, 30);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, intentalarm);
Instead of setRepeating I also tried setInexactRepeating but there was no luck.I would also like to add that when I changed the
calendar.getTimeInMillis() and used SystemClock.elapsedRealtime() + 120 * 1000 the alarm triggered exactly after 2 minutes from the time it was set.
But when calendar.getTimeInMillis() is being used the intended working does not happen instead immediate triggering occurs.
Would be indeed very helpful if anyone can help me out find a solution.Only for a note, I could learn if alarm is set before current device time the alarm would be triggered immediately but that is not the case here.
NotificationReceiver.class is working fine as it is generated and appears on the title. But the time it appears is the cause of concern.
You are using both setTimeInMillis and hourofday and minute.
If you want your alarm to be triggered at 4:30 just add hourofday and minute.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY,4);
calendar.set(Calendar.MINUTE, 30);`
I could Identify the issue I was facing. I was using a TimePicker with 24 hour format. But I used SimpleDateFormat "hh:mm". What 'h' stands for is as follows "h->Hour in am/pm (1-12) ". So any alarm that I set at AM triggers correctly. When I set a time at PM since I had used 1-12 'h' format, alarm gets set for a AM time and since that time is already passed when compared to the device time the alarm/notification got triggered immediately.The right format to use was "HH:MM" where 'H' stands for "H->Hour in day (0-23)". This resolved my issue.
Checking the TimeinMillis on online epoch time converter helped me identify this issue.Once again thanks for helping me.

Android AllDay events start or finish on the wrong day

I am working on an android app whose goal is to synchronize events between a PHP application and the smartphone. Everything work fine for “regular” events, but I have an issue with “all day” events. I followed the official Android documentation, setting the EVENT_TIMEZONE to UTC and setting timestamps for dtstart and dtend that corresponds to midnight UTC.
However, depending on the phone timezone at event creation time, when I open Google Calendar, events are:
Showing correctly when phone timezone is GMT+2
Starting one day before when phone timezone is GMT-11 -> GMT+1
Finishing one day after when phone timezone is GMT+3 -> GMT+13
You should know that my tests are made in France and we currently are at GMT+2. Google Calendar is configured to use the phone timezone.
Here is a dump of event’s information before insertion :
06-22 17:41:02.339: V/EventEntity - addToCalendar(6535):
Event to be inserted :
calendar_id=8
dtstart=1466719200000 ( = 24/6/2016 0:00:00 )
eventLocation=
title=Server AllDay Event
dtend=1466805600000 ( = 25/6/2016 0:00:00 )
allDay=true
description=
hasAlarm=1
eventStatus=1
eventTimezone=UTC
and here is the code of the method that does the event's insertion, where the previous log comes from :
Context context = AppContext.getAppContext();
ContentValues eventValues = this.getValuesForCalendar();
Log.v("EventEntity - addToCalendar", "Event to be inserted : " + eventValues);
Uri eventUri = context.getContentResolver().insert(Uri.parse("content://com.android.calendar/events"), eventValues);
this.setSystem_id(Long.parseLong(eventUri.getLastPathSegment()));
// === RAPPEL DE RDV ===
String reminderUriString = "content://com.android.calendar/reminders";
ContentValues reminderValues = new ContentValues();
reminderValues.put("event_id", this.getSystem_id());
reminderValues.put("minutes", 5);
// Default(0), Alert(1), Email(2), SMS(3)
reminderValues.put("method", 0);
context.getContentResolver().insert(Uri.parse(reminderUriString), reminderValues);
// =====================
And still, when events are showing correctly, if phone timezone is changed, events span on previous or next day. The behavior in not the same with “all day” events created with Google Calendar :
Events with phone at GMT+2 :
Events with phone's timezone changed to GMT-1 :
So I dumped the calendar with those all day events in it, one created with my app and another created with Google Calendar :
As you can see, the event created through Google Calendar is set to start at 2AM and not at midnight! So I tried setting the dstart and dtend timestamps to midnight at phone timezone (ie at 2AM if phone’s timezone is GMT+2, or 23PM the day before if GMT-1) but events are still spanning to previous or next day.
In a nutshell: I’m lost and I don’t get how to have correct all day events that start and end at the right day and won’t move around the calendar when phone’s timezone changes !

How to use UsageStatsManager?

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);

Android Dev: Current Time range check

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.

Categories

Resources