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.
Related
My app using firebase realtime database and I setPersistenceEnabled(true) to make it still work when device goes offline. Everything is ok when device offline, every operation like add, change, and remove data can work fine.
Problem come when device come back online after do too many operation for example delete much data when offline. After I see many data in my realtime database was delete simultaneously, I cannot do operation like add and change data for several times (5-10 minute) and it depend on how much data I was delete when offline. I can only see my add and change operation after that time.
My question is how many operation firebase can handle when offline and make it still smooth when it come back online, so my app not like freeze for several time when user add and change another data?, or
is there any trick to make it smooth when transition from offline to online when I have many operation to do in offline mode?
below is my code to update my data before I delete it, and when offline my app can run this block of code until 100 times for example in 1 hour:
public void ritase(String number){
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("/vehicles/").child(number);
HashMap<String, Object> childUpdates = new HashMap<String, Object>();
childUpdates.put("ritase/from", from);
childUpdates.put("ritase/to", to);
childUpdates.put("ritase/accept", accept);
childUpdates.put("ritase/userid", userid);
childUpdates.put("ritase/passenger", passenger);
childUpdates.put("ritase/stat", 1);
childUpdates.put("ritase/time_out", time);
childUpdates.put("trips/content/time_out", time);
childUpdates.put("trips/content/stat", 1);
ref.updateChildren(childUpdates);
ref.removeValue();
}
and after my app back to online again, below block of code operation was stuck for several minutes. Stuck here means I cannot see the change immediately in my app:
Public void updateStatus(String number){
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("/vehicles/").child(number);
HashMap<String, Object> childUpdates = new HashMap<String, Object>();
childUpdates.put("driver/name", name);
childUpdates.put("driver/nip", nip);
if (PrefHelper.getPref(context,VarConstant.ISBARCODE) == "true") {
childUpdates.put("is_barcode", 1);
} else {
childUpdates.put("is_barcode", 0);
}
childUpdates.put("position/content/location", location);
childUpdates.put("position/content/time_in", time);
childUpdates.put("position/content/time_out", 0);
childUpdates.put("position/content/stat", 0);
childUpdates.put("position/content/username", username);
int status;
if (PrefHelper.getPref(context, VarConstant.TYPE).contains(VarConstant.PERIMETER)) {
status = 0;
childUpdates.put("trips/content/status", status);
childUpdates.put("trips/content/time_start", 0);
childUpdates.put("trips/content/time_stop", 0);
} else {
status = 2;
childUpdates.put("trips/content/status", status);
childUpdates.put("trips/content/time_start", time);
childUpdates.put("trips/content/time_stop", time);
}
ref.updateChildren(childUpdates);
}
I also try to use completion listener for removeValue(), but it fire very late even in firebase realtime database the data was delete.
When you use disk persistence, Firebase stores two types of data on disk:
A cache of recently read data.
A queue of pending writes.
It also keeps an in-memory copy of all active data, which means: any data that you're currently listening for. In this in-memory copy, the pending writes are applied to the data.
When you restart your app and attach a listener, Firebase loads the cached data and applies any pending writes it has. This process has linear performance, and can be quite slow due to the hashing algorithm used.
This means that restarting an app that has a lot of cached data with many pending writes can indeed take some time. This is expected behavior.
To reduce the startup time, limit the amount of data you keep offline, and limit the number of pending writes.
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!
I have a Mongoose schema with the timestamp option set as true.
schema = new mongoose.Schema({
...
},
{ timestamps: true });
Now I have an Android application that gets the timestamp using System.currentTimeMillis() which works all well and good and gives me number of milliseconds since UNIX epoch time.
I send this data across to my Node.js / Express server which takes the time and returns only documents created after that particular date.
// get all docs
router.get('/api/seekers', function(req, res) {
Seeker.find({createdAt:{ $gt: new Date(req.query.timestamp) }}, function(err, seekers) {
if(err)
res.send(err);
else
res.json(seekers);
});
});
So I send https://api_url.com/api/seekers?timestamp=1479431351762 as a request to the server.
Now a couple of things happen:
I send the value in milliseconds and get this error
{"message":"Cast to date failed for value \"Invalid Date\" at path \"updatedAt\"","name":"CastError","kind":"date","value":null,"path":"updatedAt"}
After a little bit of investigation, it turns out you need to pass seconds to Date(). So,
I divide the value by 1000 to get seconds (req.query.timestamp/1000). Now I wasn't getting an error, but the query constraint was not working. I'm getting all values since the beginning of time.
I moved over to the Mongo shell to check whether the issue persists, to which it turns out it doesn't since I can pass the millisecond value to Mongo's Date:
> new Date(1479431351762)
ISODate("2016-11-18T01:09:11.762Z")
But if I tried passing the second value to Date(), it turns out it actually was sending me to the beginning of time:
> new Date(1479431351)
ISODate("1970-01-18T02:57:11.351Z")
I'm unable to figure this out, what can I do so server request and mongoose correctly processes the timestamp and queries my db?
Any wanderers with the same issue, who might have missed chridam's comment, you just need to cast the passed timestamp to int before parsing. This works:
new Date(parseInt(req.query.timestamp))
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'm making a back-end function for another area of a program that will add events to the user's calendar. Basically someone will pick an event out from options in a GUI and I want to set an event on the calendar that matches the choice.
The code to make it more clear what I'm working with:
java.sql.Timestamp tsStart = java.sql.Timestamp.valueOf(year + "-" + month + "-" + day + " " + startHour + ":" + startMinute + ":00");
java.sql.Timestamp tsEnd = java.sql.Timestamp.valueOf(year + "-" + month + "-" + day + " " + endHour + ":" + endMinute + ":00");
long startTime = tsStart.getTime();
long endTime = tsEnd.getTime();
Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setType("vnd.android.cursor.item/event");
intent.putExtra("beginTime", startTime);
intent.putExtra("allDay", false);
intent.putExtra("rrule", "FREQ=WEEKLY;COUNT="+numWeeks);
intent.putExtra("endTime", endTime);
intent.putExtra("title", title);
intent.putExtra("description", description);
intent.putExtra("eventLocation", location);
startActivity(intent);
I've been using intent to go about doing this, but there are a few extras that I'd rather not have:
1. When the intent launches, it starts in the text entry for the What field. I've automatically filled all of these fields, so the user shouldn't need to do anything, and when it launches like this, the keyboard takes up a lot of space and looks messy. Is there any way I can either set the focus not to be in the textbox or to fake a back button press?
2. Is it possible to make some of the sections of the intent not show? I don't think it's necessary to ask the time zone, don't need the all day check (because I tell it the start and end time), don't need Guests, would rather hide the repetition because it's customized and might confuse the end user to see, and I DO NOT want reminders, which it automatically makes one for 10 minutes.
-> Is it possible to hide any/all of those items?
3. Is it possible to even make this never display to the user? I like the fact that it allows the user to pick which calendar to use, but I'm fine with it using their default since most people link their phone with their other accounts, and the phone calendar is my main focus. If I can make the 10 minute reminder go away, I would to just make it never display to the user and have it just populate their calendar as I tell it to.
Thanks to anyone who can give any help. I've been reading over intents, calendars, and anything I could think of over at Android Developers, and I've hit a wall that I can't find these answers. Which reminds me, is there a listing anywhere of all of the valid putExtra's? The Android Developers page was good for listing all of the methods, etc, but aside from finding some examples, I don't know what all I can put as valid arguments inside the putExtra.
When you send an intent to add an event to the Calendar, you're launching the Calendar activity. Intents are simply a message out to the system; any activity that can handle the intent is free to "speak up". If more than one activity's intent filter matches the intent, the user sees a "disambiguation" screen, which allows him or her to choose the app to use. In the case of most Intents, it's the MIME type that determines which app(s) are displayed. You could write your own activity for handling events, if you wanted. The activity's intent filter would have to match the Calendar's, and I wouldn't recommend doing this since you're signing yourself up for handling every intent that tries to add something to the calendar!
You have the choice of sending an intent to the Calendar Provider (actually the Calendar app, which accesses the provider) or inserting the data yourself using the ContentResolver API with the Calendar Provider.
You might consider the latter course of action, and provide your own UI instead of using the Calendar activity, but I advise you to use caution in adding recurring events, because getting them right is tricky. In general, developers should use the Calendar activity to allow users to add events.
If you use the Intent to start the Calendar "insert event" activity, you have no control over its UI. As a convenience, the Calendar activity will populate the UI with the Extras you send. If you don't send an Extra, the activity will either populate the field with the default or leave it blank. I'm not certain that it does, but this is standard practice.
Developers often overlook the Developer guides when they develop apps. Take a look at
http://developer.android.com/guide/topics/providers/calendar-provider.html#intents, which describes the Calendar Provider in detail. This page lists all the available Extras, tells you how to use the ContentResolver() process for inserting events, and elaborates on using Intents.
At the moment, I don't think there's a standard way for an application to expose the structure of the Intents it handles, but for the built-in or bundled apps that appear in on a device, you can always just ask here for more information. Remember that some apps are bundled with the platform, but others (such as Google Maps) are separate. They may have public intents/APIs, but you need to be aware that they may not be available for a particular user's device.