fiddler fiddler - 4 months ago 56
Android Question

Cannot delete Android calendar

I've been playing around with the Android Calendar Provider to create local (non-synced) calendars but I finally ended up with calendars with null

ACCOUNT_TYPE
and
ACCOUNT_NAME
. I can see them in:

getContentResolver().query(CalendarContract.Calendars.CONTENT_URI, null, CalendarContract.Calendars.ACCOUNT_TYPE + " IS NULL", null, null);


And now my Google Calendar app crashes at startup :(

I've tried to delete these dummy calendars with this piece of code (after succesfully requesting the
WRITE_CALENDAR
permission):

getContentResolver().delete(CalendarContract.Calendars.CONTENT_URI, CalendarContract.Calendars.ACCOUNT_TYPE + " IS NULL", null);


but it raises the following error


java.lang.IllegalArgumentException: the name must not be empty: null
at
android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:165)
at
android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at
android.content.ContentProviderProxy.delete(ContentProviderNative.java:544)
at android.content.ContentResolver.delete(ContentResolver.java:1327)


which, I assume, is caused by their account type/name being null.

Do you have any idea of how I could get rid of them?

NB: Device's Android version is 6.0.1

Answer

Here is what happens (note all links point to the 5.1.1 CalendarProvider, but it's probably safe to assume that it works the same in Android 6):

  1. Deleting a Calendar will always pass this line: CalendarProvider2.java, line 3206
  2. Now in this line the method modifyCalendarSubscription is called for every calendar to remove (no matter how you selected them).
  3. In modifyCalendarSubscription the provider reads the ACCOUNT_NAME and ACCOUNT_TYPE column for each of these calendars and tries to create an Account instance
  4. Since the account name and type in the database are null, it crashes in the Account constructor when it checks for null values. That's where the eException you see is actually thrown.

So, not matter how you delete the calendar, it will always fail at the Account constructor because the account name in the database is empty.

I didn't check it yet, but you might be able to override account name and type with an update operation. So try to set it to something that's not null.

If that doesn't work you either need root access to remove the calendar manually or you go to Settings -> Apps -> All apps -> Calendar storage and clear the entire calendar database (clear data).

Update

Overriding the ACCOUNT_NAME and ACCOUNT_TYPE columns will only work if you manage to match the conditions to pass this line: CalendarProvider2.java, line 3989 given that line and the conditions to get there still exists in Android 6. It think it should work if you don't append the calendar id to the Uri and you don't select the calendar by their id. So making your delete an update and resetting ACCOUNT_NAME and ACCOUNT_TYPE to something that's not null should do the trick.

Comments