"Too many Calendar deletes" error by Android calendar provider - android

I am using calendar provider to create and delete events.
The problem occurs in some devices when I try to remove events. Android OS shows a notification saying:
"Too many Calendar deletes"
with options to proceed.
I couldn't find an answer to fix it in Android, only read about calendar API limitation. But it's unacceptable to offer a feature to clientes with this notification.
I am running the following line to remove an event:
context.getContentResolver().delete(eventUri, null, null);
Thanks!

I'm afraid, there is no "correct" way to bypass this message and you also shouldn't even try. This is shown because the sync adapter has set the tooManyDeletions flag in the SyncResult object to true after trying to sync.
The sync manager will always show this message if the flag is set to true.
The number of allowed deletions is defined by the respective sync adapter or by the API it's syncing to. So if you see the message depends on the account type and maybe even on the version of the sync adapter.
This is a mechanism to protect the user's data from being deleted due to a mistake (either by himself or by broken software).
You could try to trick the SyncManager and the sync adapter by triggering a sync on the respective account with the SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS flag being set by your code, but you really shouldn't do that. Actually I would consider this a bug in Android if it works.
You should communicate this to the user and sell it as a feature.
Update:
To trigger a sync with SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS call this:
Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
extras.putBoolean(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS, true);
ContentResolver.requestSync(accountOfCalendar, CalendarContract.Authority, extras);
accountOfCalendar is the account of the calendar that you deleted the events from.
Use it with care.

Related

How do I use the android intents with Chrome to open a recurring event in Google Calendar?

I'm trying to use an Android Intent in Chrome to open calendar events in Google Calendar. For most events, the following intent works:
intent://com.android.calendar/events/{event_id}#Intent;scheme=content;component=com.google.android.calendar.event.LaunchInfoActivity;end
But this format does not work for recurring events, which share an event id. According to Google's documentation, I need to include extra information: the event start time and end time. So I tried adding that information by following this guide to pass the additional parameters:
intent://com.android.calendar/events/{event_id}#Intent;scheme=content;component=com.google.android.calendar.event.LaunchInfoActivity;S.CalendarContract.EXTRA_EVENT_BEGIN_TIME={start_time_ms_since_epoch};S.CalendarContract.EXTRA_EVENT_END_TIME={end_time_ms_since_epoch};end
For example,
intent://com.android.calendar/events/1284#Intent;scheme=content;component=com.google.android.calendar.event.LaunchInfoActivity;S.CalendarContract.EXTRA_EVENT_BEGIN_TIME=1661904000000;S.CalendarContract.EXTRA_EVENT_END_TIME=1661911200000;end
But unfortunately that didn't work--It just opens and immediately closes the Google Calendar app and then flashes "Event not found." I am 100% sure the parameters I am entering are correct (unless I'm formatting them incorrectly); they are coming directly from my phone's event database. And I have tried different variations, like leaving out the "CalendarContract" class, but nothing that I try works.
I would appreciate any help, thank you!

Detect application is being uninstalled in lollipop devices

I would like to know which users have uninstalled my application so that I can ask them for a feedback to improve the app. Hence, I would like to detect when the user has initiated the uninstallation process on my app.
One of the older solutions on StackOverflow had the following steps:
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(MAX_PRIORITY);
String activityName = taskInfo.get(0).topActivity.getClassName();
if (activityName.equals("com.android.packageinstaller.UninstallerActivity")) {
// do whatever is needed
Since Lollipop, getRunningTasks has been deprecated. So how can com.android.packageinstaller.UninstallerActivity activity be detected without getRunningTask?
Alternatively is there any other method to detect uninstallation process has been started on my app? Using getAppTask probably?
Apparently you wont be able to do this, you will have to rely on something called silent notification.
What we did was we sent notification every 3 days or whatever frequency you want.
On the client side as soon as a notification is received we hit a network call which mark NotificationReceived for the client. Now since notification are not full proof we assumed a threshold of 2/3 missed notification as uninstall event. And for the client we have this counter above decided threshold we contacted them for feedback.
Also no one will be willing to fill your form at the time of uninstallation as user has already decided to uninstall your application.
Read these 2 questions and answers:
native solution
GCM solution
As I know you have to mix the two. Read the limitations of first solution. You have to confirm uninstallation event of the first solution with the second solution for a complete implementation.
Hopefully, this solution will work for you. It helps you understand the reasons for your app uninstalls, reduce the uninstall rate using a powerful predictive engine and also get app Re-installs through a unique actionable channel (Android version 4.0 and above).
Just set a variable named appLastPresent for every user in the server-side and update that variable every day by calling an API using WorkManager's PeriodicWorkRequest. Also set installedDate variable when the user installs the app.
Now set up a chron job on the server side to check if the difference between installedDate and appLastPresent is greater than 7 days. Then send the user an email or message enquiring for issues or feedback, if it is greater.
NB: User can be offline for 7 days. Therefore only send email enquiring like why you are not using the app, if uninstalled please let us know why

Android SyncAdapter not firing automatically

I'm following the SyncAdapter tutorial at https://developer.android.com/training/sync-adapters/index.html. So I've got all of the Stub classes in place, and it's all wired up. The SyncAdapter itself is the one from the tutorial, so does nothing but log a message. The following all work:-
The account is visible in settings/accounts
Disabling/enabling sync in settings causes a sync
Choosing "sync now" causes a sync
Calling mResolver.requestSync(mAccount, AUTHORITY, settingsBundle); causes a sync
However, that's as far as it goes. I'm expecting network events, (eg WiFi becoming available) to trigger a sync, but it isn't.
Have I misunderstood what mResolver.setSyncAutomatically(mAccount,AUTHORITY,true); does, or is there something else preventing automatic syncing?

How do I implement an Account on Android without a SyncAdapter

I am implementing a login system for an Android application utilizing the built-in accounts system (with the AccountManager APIs).
All is well and good on Android 2.2+, but on Android 2.1 not including a SyncAdapter causes reboots in the account settings screen (see http://code.google.com/p/android/issues/detail?id=5009 and AccountManager without a SyncAdapter?)
To get around this I implemented a stub SyncAdapter, which just returns null from IBinder onBind(Intent intent), and added the relevant stuff to the manifest. This resolves the reboot issue on Android 2.1.
However it introduces a further problem: after an account is added the Android system will, sometime later, initiate an account sync. Although no errors occur (indeed my SyncAdapter does nothing, it has no way to cause errors unless by returning null), the sync icon stays stuck in the notification bar at the top. This results in the Android sync system maintaining a permanent wake-lock, preventing the device from sleeping.
The account does not list any syncable components in the account settings screen (under the 'Data and synchronization' header), and always displays 'Sync is off' for the sync status in the list of accounts (even while the sync icon is visible in the notifications bar). Disabling account syncing does not remove the problem. Removing the account stops the problem.
My guess is I should not be returning null. Should I be returning a basic implementation of ThreadedSyncAdapter? Any help getting an account system without an associated sync working properly on 2.1 and 2.2+ is much appreciated.
Since this is the only question I've seen related to this problem, here's a >year late answer. I also came across the permanent wake-lock problem due to the android system syncing my custom account automatically.
The best way to handle this, which requires minimum code and actually makes it so the account never syncs unless specifically called to sync in code:
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
Now this requires that the moment you create your account you call this static method. Whereas the first parameter being the account to set this setting for, the second parameter being the used contentprovider's authority, and the third being the integer that when set to a positive number enables syncing, when set to 0 disables syncing and when set to anything else makes it unknown. The authority to use can be found inside your "sync_something.xml" under the contentAuthority attribute, which is used by your SyncAdapter :
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts"
android:accountType="com.myapp.account"/> <!-- This being your own account type-->
The above xml file is specified inside the service part of your AndroidManifest.xml:
<service android:name=".DummySyncAdapterService"
exported="true"
android:process=":contacts">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="#xml/sync_something" /> <!--This points to your SyncAdapter XML-->
</service>
This is the code snippet I use to create my custom account inside my LoginActivity:
Account account = new Account("John Doe", "com.myapp.account");
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
AccountManager am = AccountManager.get(LoginActivity.this);
boolean accountCreated = am.addAccountExplicitly(account, "Password", null);
Bundle extras = LoginActivity.this.getIntent().getExtras();
if(extras != null){
if (accountCreated) {
AccountAuthenticatorResponse response = extras.getParcelable(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, "John Doe");
result.putString(AccountManager.KEY_ACCOUNT_TYPE, "com.myapp.account");
response.onResult(result);
}
}
The great part of this is that when the system tries to sync the service, it checks if the service is syncable first, if it is set to false it cancels the syncing. Now you don't have to create your own ContentProvider nor does your ContentProvider get shown under Data and Synchronization. However you do need to have a stub implementation of AbstractThreadedSyncAdapter which returns an IBinder inside it's onBind method. And last but not least it makes it so that an user can't enable syncing or use the "Sync Now" button for this account unless you've added the functionality inside your app.
I sort of solved my own problem: you cannot return null from the onBind method of your service - you must return the IBinder of an AbstractThreadedSyncAdapter.
This has the undesired effect of adding an entry into the Data and Synchronization section of the account settings page, even though my implementation of AbstractThreadedSyncAdapter does nothing; I was hoping to avoid this.
To summarize, in order to make use of the accounts system in Android you must:
Implement a service that has an IntentFilter for android.content.SyncAdapter.
This service must return the IBinder of an AbstractThreadedSyncAdapter implementation from it's onBind method.
This then necessitates that you have a ContentProvider (can just be a stub implementation) that is referred to as the contentAuthority in your SyncAdapter XML file.
This has the down-side that your ContentProvider is listed under the Data and Synchronization header on your account settings page.

Android: Enable/Disable Auto Sync and Background Data

I want to develop an application that disables the Background Data (new feature in Android 1.5) and Auto Sync and then enables GPRS/EDGE connection and vice versa.
I figured out how to enable/disable GPRS/EDGE by changing the APN settings. (weird solution. However; Android developers couldn't think a user may want to disable GPRS/EDGE) But, I couldn't find a way to enable/disable Auto Sync and Background data.
I investigated the Android code and as I understood, the Sync operation is an intent. So, I wanted to reach with putExtra to the intent and trigger the enabling/disabling. But; I couldn't find the correct keyword. Or maybe I was totally wrong.
What is the right way to solve this?
In my HTC dreams, there is a checkbox to disable the auto sync. I can look for the menu arborescence if you wish so you can find what the callback function is in the Android source code. But I am pretty sure auto sync cannot be completely disabled. Unchecking auto sync will prevent sync from being performed on a timed basis, but it will occur everytime you run an app with sync capabilities if any network data connection is available.
Good luck anyway.
EDIT :
There are two ways to get the info you desire.
First, I think you can use the code in android-sources/packages/apps/Settings/src/com/android/settings/Utils.java to create an activity that will enlist all the keys of the intent then find the one you want.
The other way is to write a nice mail to the guy who made the Toggle Setting app (http://smartphoneandroid.com/2008/12/28/toggle-setting-perfect-app-for-android-phone.html) since he obviously found a solution to your problem. His email address is written in the app sheet on the android market. I won't write it here, but if you do not have access to real android phone, I can mail it to you on your mail address.
Background data is a secure setting, so cannot be changed by user applications. But bear in mind, it's just a setting - it's not enforced. Apps are meant to read it and respect it but I bet some don't.
To Disable the AutoSynch
ContentResolver.setMasterSyncAutomatically(false);
To Enable the AutoSynch
ContentResolver.setMasterSyncAutomatically(true);
Permission you require is
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
setMasterSyncAutomatically() on ContentResolver should do it. Check: general-sync-settings-auto-sync-checkbox-programtically

Categories

Resources