I inserted a calender contract entry like this:
ContentValues values = new ContentValues();
values.put(CalendarContract.Calendars.ACCOUNT_NAME, account.name);
values.put(CalendarContract.Calendars.ACCOUNT_TYPE, account.type);
values.put(CalendarContract.Calendars.NAME, name);
values.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, getDisplayName(account));
values.put(CalendarContract.Calendars.CALENDAR_COLOR, 0xffff0000);
values.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_READ);
values.put(CalendarContract.Calendars.OWNER_ACCOUNT, getMailAddressOf(account));
values.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, TimeZone.getTimeZone("GMT").getDisplayName());
values.put(CalendarContract.Calendars.SYNC_EVENTS, 1);
Uri.Builder builder = CalendarContract.Calendars.CONTENT_URI.buildUpon();
builder.appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, account.name);
builder.appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, account.type);
builder.appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true");
Uri result = getContext().getContentResolver().insert(builder.build(), values);
This works great, I can enter calender entries etc. But I need to make it now read only so that the user cannot edit the calendar entry.
I thought that when I set CALENDAR_ACCESS_LEVEL to CAL_ACCESS_READ it should be enough to make the calendar read only.
Any idea how to achieve that? By the way I'm testing on a Pixel with Android O.
Don't make the user to be the organizer. When adding the event, the default organizer will be the user. To change it, add this line to the ContentValues when adding the event, assign an organizer email address like this
values.put(CalendarContract.Events.ORGANIZER,"an_organizer_name#gmail.com";
Since the user is not the organizer, the user can still delete the event but not able to edit the event content such as time, title, description, etc.
Well that took some time. In the end I found out that I have to change the mail address of the CalendarContract.Events.ORGANIZER value to prevent that I can edit the calender entry. Just as a hint for others how I sloved the problem I tried a lot of stupid things but then I had the idea to check how it is done in AOSP. So I just searched for "calendar aosp code" and found the code mirrowed on GitHub. After using the code search within the repo I found the method canModifyEvent(...). Now it became oblivious:
public static boolean canModifyEvent(CalendarEventModel model) {
return canModifyCalendar(model)
&& (model.mIsOrganizer || model.mGuestsCanModify);
}
Make sure that the event cannot been edited by guests and by don't be the organizer.
Happy Coding!
Related
I have a very weired problem with my app while I try to add a birthday event on a picked contact.
My code for this is:
int mret = np2.getValue()+1;
ContentResolver cr = v.getContext().getContentResolver();
ContentValues values = new ContentValues();
values.put(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
values.put(ContactsContract.RawContacts.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.CommonDataKinds.Event.TYPE, ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY);
if (boolyear == true) {
values.put(ContactsContract.CommonDataKinds.Event.START_DATE, np3.getValue() + "-" + mret + "-" + np1.getValue());
} else {
values.put(ContactsContract.CommonDataKinds.Event.START_DATE, "0000-" + mret + "-" + np1.getValue());
}
Uri bduri= null;
try {
bduri= cr.insert(ContactsContract.Data.CONTENT_URI,values);
} catch (Exception e) {}
The above code works fine as it creates the birthday event but a few seconds later appears a second birthday entry which possibly is a result of sync as it happens only if there is an Internet connection.
This is not a problem of the device because other apps downloaded from Play Store work as expected. It's only my app that creates double birthday entries.
Why is this happening and how to fix that?
Thank you in advance.
UPDATE: I managed to fix it. The problem was the date format. All values (day and month) must be in a two-digit format. E.g. "1980-07-01", not "1980-7-1".
I managed to fix it. The problem was the date format. All values (day and month) must be in a two-digit format. E.g. "1980-07-01", not "1980-7-1".
I am assuming that you are using a Sync Adapter to interface with the Calendar.
The Sync Adapter has two important methods:
onPerformSync(...), and onSyncCanceled(...)
onPerformSync is called whenever you make a ContentResolver.requestSync call or if automatic sync is set to true.
While executing, onPerformSync can be interrupted by Android. This can happen if the device is running low on resources of if your app is not in the foreground anymore.
When interupted, the Sync Adapter will stop execution where it's at and will call onSyncCanceled. The default behavior of the Sync Adapter is to retry the failed sync messages the first chance it gets. So if your app manages to grab onto OS resources again, it will replay the interrupted sync message.
It is possible that some of your messages are being fully processed and, just before onPerformSync is about to complete, the Sync Adapter is interrupted. At this point you managed to save the event, however, the Sync Adapter believes that the sync failed, and therefore will replay the same message again the next time it tries to sync.
I am not sure if you are syncing one event at a time so I can't offer a definitive solution. However, what you can do is change the default behaviour of the Sync Adapter to stop it from replaying "failed" messages.
Bundle extras = new Bundle();
...
extras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true);
CalendarConstants.AUTHORITY, true);
ContentResolver.requestSync(mAccount, CalendarConstants.AUTHORITY, extras);
In OnSyncCanceled, you can do some light checks to make sure the message succeeded, i.e. is present in the calendar's events table. If not, then manually replay it. If it is present, the SyncAdapter will simply move on to the next message, and you won't get any duplicates.
Alternatively, you could make sure all operations within onPerformSync are atomic.
Background
I'm trying to update contacts data and put there the birthdate of each.
The problem
It seems that for each device I try (and I didn't even try that many devices), the insertion has one or more of those issues:
when viewing/editing the contact, the brithdate can't be clicked and edited.
when viewing/editing the contact, the format that's shown isn't the same as the one that's shown when the user puts the birthdate
Missing year, or totally wrong year.
when viewing the contact, the birthdate isn't shown, yet when editing it, it is shown. Also, the opposite.
What I've tried
I've tried using a timestamp and a full ISO8601 format (because of this link, meaning it's "yyyy-MM-dd HH:mm:ss"). I've also tried "yyyy-MM-dd" and I tried using the default format of the date of the device.
All had the mentioned issues (at least one for each).
Here's a piece of the code:
final Date birthdate = ...
// String birthdateStr = new SimpleDateFormat("yyyy-MM-dd").format(birthdate);
// String birthdateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(birthdate);
// String birthdateStr = new SimpleDateFormat(((SimpleDateFormat) java.text.DateFormat.getDateInstance(java.text.DateFormat.DEFAULT, Locale.getDefault())).toLocalizedPattern(),Locale.getDefault()).format(birthdate);
String birthdateStr = Long.toString(birthdate.getTime()/1000);
final Builder builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValue(Data.RAW_CONTACT_ID, ...)
.withValue(ContactsContract.Data.MIMETYPE, Event.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Event.START_DATE, birthdateStr)
.withValue(ContactsContract.CommonDataKinds.Event.TYPE,
ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY);
Of course, I've also looked on this issue here, and found similar issues, but none of the proposed solutions seem to work well.
The question
How should I really insert a birthdate into the contacts? How come each device has its own way to interpret the dates? What's the correct standard to put the birthdate ?
Based on this answer, I would say that you should use the format YYYY-MM-DD, but you need to define a account type and account name. So add those lines:
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
Let me know if this helps.
I know, I am not the first one who ask this. I found many questions in stack itself, like
Delete only one instance of a recurring event from my Android calendar
Android Calendar Provider exception on recurring events
Android Calendar Specific Event Deletion
but none of above solved the issue. Now to my code.
I am using calendar contract provider api for all operations (dont need support for older android versions). and its NOT A SYNC ADAPTER. We are successful in deleting all events (By deleting the events from event table itself).But when I try to delete an occurrence of event using the Events.CONTENT_EXCEPTION_URI (by inserting) All events are getting disappeared. Following is my code
ContentValues args = new ContentValues();
args.put(Events.TITLE, eNote.getEventTitle());
args.put(Events.DTSTART, eNote.getStartTimeMill());
args.put(CalendarContract.Events.ORIGINAL_INSTANCE_TIME, eNote.getStartTimeMill());
args.put(Events.ORIGINAL_SYNC_ID, 1);
args.put(Events.HAS_ALARM, "0");
args.put(Events.HAS_ATTENDEE_DATA,"0");
args.put(CalendarContract.Events.EVENT_TIMEZONE, eNote.getTimeZone());
args.put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_CANCELED);
Uri.Builder eventUriBuilder = CalendarContract.Events.CONTENT_EXCEPTION_URI.buildUpon();
ContentUris.appendId(eventUriBuilder, eventID);
try {
final Uri resultUri = activity.getContentResolver().insert(eventUriBuilder.build(), args);
int eventIDNew = Integer.parseInt(resultUri.getLastPathSegment());
Log.i(Global.DEBUG_TAG,"eventIDNew : " +eventIDNew);
} catch (Exception e) {
e.printStackTrace();
Log.i(Global.DEBUG_TAG,
"Eroor : " +e.getMessage() );
}
eNote is an object stores the details of an event from the instance table,
given the value args.put(Events.ORIGINAL_SYNC_ID, 1); directly, As I am not setting the sync id while creating the event and we don't need any sync operations
Insertion to the exception uri returns a new ID but this makes all events get disappeared.
what is wrong with the code..
please helps us, we welcomes all suggestions and advance thanks to all...
Here are the basics (as I've answered here)
Find the instance you want to delete. (using Instances.query())
Create the exception URI with the event ID appended.
Create ContentValues. Put your instance's BEGIN value as ...Events.ORIGINAL_INSTANCE_TIME. Put STATUS_CANCELED as ...Events.STATUS
Now only insert(yourURI, yourValues) and that's it!
I want to show calendar events (daily agenda) from specific calendars on an Android Wear watchface.
Is the Calendar Provider available for query in an Android Wear Watchface?
How do I make sure it stays in sync throughout the day?
Depends on what info you need to look up. See WearableCalendarContract (though I don't think they've posted the JavaDocs yet, so I've only found a little info here). I'm able to, for example, get a range of event instances with this:
long begin = _time.toMillis(false);
Uri.Builder builder = WearableCalendarContract.Instances.CONTENT_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, begin + DateUtils.DAY_IN_MILLIS);
Uri instURI = builder.build();
Cursor cursor = getContentResolver().query(instURI, INSTANCE_PROJECTION, null, null, null);
But my attempts at reading the event table to find out more about the instances haven't worked (note that the WearableCalendarContract doesn't include an Events URI). I've tried both authorities to no avail.
AFAIK, the content provider is not available. Take a look into how to sync data in here: http://developer.android.com/training/wearables/data-layer/index.html
I tried deleting a reminder for an event by using this code:
int result = getContentResolver().delete(
Reminders.CONTENT_URI,
Reminders.EVENT_ID + " = ?",
new String[] { "44" }
);
This shows it deleted 1 row. However, when I view the event in the calendar app, the reminder is still there. Even if I updated the "hasAlarm" field, I don't think it will update the event in Exchange. How do I properly (using Ice Cream Sandwich - API 14 - or later) remove a reminder from a calendar event?
Instead of deleting , try with update query , it works . IF it doesn't work lemme know i'll try to help with code snippet.