diff --git a/api/current.xml b/api/current.xml index 58c0bf84356c4..8fab6621bb06b 100644 --- a/api/current.xml +++ b/api/current.xml @@ -27032,6 +27032,21 @@ + + + + + + + + + + + + + + 0 if it is syncable, 0 if not, and <0 if the state isn't known yet. + */ + public int getIsSyncable(Account account, String authority) { + try { + return getContentService().getIsSyncable(account, authority); + } catch (RemoteException e) { + throw new RuntimeException("the ContentService should always be reachable", e); + } + } + + /** + * Set whether this account/provider is syncable. + * @param syncable, >0 denotes syncable, 0 means not syncable, <0 means unknown + */ + public void setIsSyncable(Account account, String authority, int syncable) { + try { + getContentService().setIsSyncable(account, authority, syncable); + } catch (RemoteException e) { + // exception ignored; if this is thrown then it means the runtime is in the midst of + // being restarted + } + } + /** * Gets the master auto-sync setting that applies to all the providers and accounts. * If this is false then the per-provider auto-sync setting is ignored. diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java index 7a1ad2b9e6dfa..c4d8aafd41780 100644 --- a/core/java/android/content/ContentService.java +++ b/core/java/android/content/ContentService.java @@ -272,6 +272,37 @@ public final class ContentService extends IContentService.Stub { } } + public int getIsSyncable(Account account, String providerName) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, + "no permission to read the sync settings"); + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + return syncManager.getSyncStorageEngine().getIsSyncable( + account, providerName); + } + } finally { + restoreCallingIdentity(identityToken); + } + return -1; + } + + public void setIsSyncable(Account account, String providerName, int syncable) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, + "no permission to write the sync settings"); + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + syncManager.getSyncStorageEngine().setIsSyncable( + account, providerName, syncable); + } + } finally { + restoreCallingIdentity(identityToken); + } + } + public boolean getMasterSyncAutomatically() { mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, "no permission to read the sync settings"); diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl index 658a5bcd2d82c..b0f14c15cbb49 100644 --- a/core/java/android/content/IContentService.aidl +++ b/core/java/android/content/IContentService.aidl @@ -54,6 +54,18 @@ interface IContentService { */ void setSyncAutomatically(in Account account, String providerName, boolean sync); + /** + * Check if this account/provider is syncable. + * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet. + */ + int getIsSyncable(in Account account, String providerName); + + /** + * Set whether this account/provider is syncable. + * @param syncable, >0 denotes syncable, 0 means not syncable, <0 means unknown + */ + void setIsSyncable(in Account account, String providerName, int syncable); + void setMasterSyncAutomatically(boolean flag); boolean getMasterSyncAutomatically(); diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index f25639496186f..f50fd74662aeb 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -589,22 +589,21 @@ class SyncManager implements OnAccountsUpdatedListener { // if the url was specified then replace the list of authorities with just this authority // or clear it if this authority isn't syncable if (requestedAuthority != null) { - final boolean isSyncable = syncableAuthorities.contains(requestedAuthority); + final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority); syncableAuthorities.clear(); - if (isSyncable) syncableAuthorities.add(requestedAuthority); + if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority); } for (String authority : syncableAuthorities) { for (Account account : accounts) { + boolean isSyncable = mSyncStorageEngine.getIsSyncable(account, authority) > 0; + if (!isSyncable) { + continue; + } if (mSyncAdapters.getServiceInfo(new SyncAdapterType(authority, account.type)) != null) { scheduleSyncOperation( new SyncOperation(account, source, authority, extras, delay)); - // TODO: remove this when Calendar supports multiple accounts. Until then - // pretend that only the first account exists when syncing calendar. - if ("calendar".equals(authority)) { - break; - } } } } @@ -1589,9 +1588,11 @@ class SyncManager implements OnAccountsUpdatedListener { final boolean syncAutomatically = mSyncStorageEngine.getSyncAutomatically(op.account, op.authority) && mSyncStorageEngine.getMasterSyncAutomatically(); + boolean isSyncable = + mSyncStorageEngine.getIsSyncable(op.account, op.authority) > 0; boolean syncAllowed = manualSync || (backgroundDataUsageAllowed && syncAutomatically); - if (!syncAllowed) { + if (!syncAllowed || !isSyncable) { if (isLoggable) { Log.v(TAG, "runStateIdle: sync off, dropping " + op); } diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index b3f9bbbb520f9..264796281283f 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -155,12 +155,15 @@ public class SyncStorageEngine extends Handler { final String authority; final int ident; boolean enabled; + int syncable; AuthorityInfo(Account account, String authority, int ident) { this.account = account; this.authority = authority; this.ident = ident; enabled = SYNC_ENABLED_DEFAULT; + // TODO: change the default to -1 when the syncadapters are changed to set this + syncable = 1; } } @@ -392,6 +395,44 @@ public class SyncStorageEngine extends Handler { reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); } + public int getIsSyncable(Account account, String providerName) { + synchronized (mAuthorities) { + if (account != null) { + AuthorityInfo authority = getAuthorityLocked(account, providerName, + "getIsSyncable"); + if (authority == null) { + return -1; + } + return authority.syncable; + } + + int i = mAuthorities.size(); + while (i > 0) { + i--; + AuthorityInfo authority = mAuthorities.get(i); + if (authority.authority.equals(providerName)) { + return authority.syncable; + } + } + return -1; + } + } + + public void setIsSyncable(Account account, String providerName, int syncable) { + int oldState; + synchronized (mAuthorities) { + AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false); + oldState = authority.syncable; + authority.syncable = syncable; + writeAccountInfoLocked(); + } + + if (oldState <= 0 && syncable > 0) { + mContext.getContentResolver().requestSync(account, providerName, new Bundle()); + } + reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); + } + public void setMasterSyncAutomatically(boolean flag) { boolean old; synchronized (mAuthorities) { @@ -1064,10 +1105,12 @@ public class SyncStorageEngine extends Handler { null, "authority"); String enabled = parser.getAttributeValue( null, "enabled"); - AuthorityInfo authority = mAuthorities.get(id); + String syncable = parser.getAttributeValue(null, "syncable"); + AuthorityInfo authority = mAuthorities.get(id); if (DEBUG_FILE) Log.v(TAG, "Adding authority: account=" + accountName + " auth=" + authorityName - + " enabled=" + enabled); + + " enabled=" + enabled + + " syncable=" + syncable); if (authority == null) { if (DEBUG_FILE) Log.v(TAG, "Creating entry"); authority = getOrCreateAuthorityLocked( @@ -1077,10 +1120,19 @@ public class SyncStorageEngine extends Handler { if (authority != null) { authority.enabled = enabled == null || Boolean.parseBoolean(enabled); + if ("unknown".equals(syncable)) { + authority.syncable = -1; + } else { + authority.syncable = + (syncable == null || Boolean.parseBoolean(enabled)) + ? 1 + : 0; + } } else { Log.w(TAG, "Failure adding authority: account=" + accountName + " auth=" + authorityName - + " enabled=" + enabled); + + " enabled=" + enabled + + " syncable=" + syncable); } } } @@ -1133,6 +1185,11 @@ public class SyncStorageEngine extends Handler { if (!authority.enabled) { out.attribute(null, "enabled", "false"); } + if (authority.syncable < 0) { + out.attribute(null, "syncable", "unknown"); + } else if (authority.syncable == 0) { + out.attribute(null, "syncable", "false"); + } out.endTag(null, "authority"); } @@ -1268,6 +1325,7 @@ public class SyncStorageEngine extends Handler { AuthorityInfo authority = mAuthorities.get(i); if (authority.authority.equals(provider)) { authority.enabled = value == null || Boolean.parseBoolean(value); + authority.syncable = 1; } } }