- add a "isSyncable" flag to a given account/authority pair that
indicates whether or not syncs should be attempted for it.
- add public methods to get and set this parameter
diff --git a/api/current.xml b/api/current.xml
index 58c0bf8..8fab662 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -27032,6 +27032,21 @@
<parameter name="selectionArgs" type="java.lang.String[]">
</parameter>
</method>
+<method name="getIsSyncable"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+</method>
<method name="getMasterSyncAutomatically"
return="boolean"
abstract="false"
@@ -27329,6 +27344,23 @@
<parameter name="extras" type="android.os.Bundle">
</parameter>
</method>
+<method name="setIsSyncable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="syncable" type="int">
+</parameter>
+</method>
<method name="setMasterSyncAutomatically"
return="void"
abstract="false"
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 98ed098..16460db 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1012,6 +1012,31 @@
}
/**
+ * 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.
+ */
+ 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 7a1ad2b..c4d8aaf 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -272,6 +272,37 @@
}
}
+ 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 658a5bc..b0f14c1 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -54,6 +54,18 @@
*/
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 f256394..f50fd74 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -589,22 +589,21 @@
// 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 @@
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 b3f9bbb..2647962 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -155,12 +155,15 @@
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 @@
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 @@
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 @@
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 @@
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 @@
AuthorityInfo authority = mAuthorities.get(i);
if (authority.authority.equals(provider)) {
authority.enabled = value == null || Boolean.parseBoolean(value);
+ authority.syncable = 1;
}
}
}