diff options
| -rw-r--r-- | api/current.xml | 245 | ||||
| -rw-r--r-- | core/java/android/content/AbstractSyncableContentProvider.java | 3 | ||||
| -rw-r--r-- | core/java/android/content/ContentResolver.java | 249 | ||||
| -rw-r--r-- | core/java/android/content/ContentService.java | 71 | ||||
| -rw-r--r-- | core/java/android/content/IContentService.aidl | 23 | ||||
| -rw-r--r-- | core/java/android/content/SyncAdapterType.aidl | 20 | ||||
| -rw-r--r-- | core/java/android/content/SyncAdapterType.java | 27 | ||||
| -rw-r--r-- | core/java/android/content/SyncManager.java | 179 | ||||
| -rw-r--r-- | core/java/android/content/SyncStatusObserver.java | 21 | ||||
| -rw-r--r-- | core/java/android/content/SyncStorageEngine.java | 103 | ||||
| -rw-r--r-- | core/java/android/content/TempProviderSyncAdapter.java | 10 | ||||
| -rw-r--r-- | core/java/android/provider/Sync.java | 649 | ||||
| -rw-r--r-- | packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java | 21 | ||||
| -rw-r--r-- | test-runner/android/test/SyncBaseInstrumentation.java | 33 |
14 files changed, 763 insertions, 891 deletions
diff --git a/api/current.xml b/api/current.xml index 72c85be..a3a8c61 100644 --- a/api/current.xml +++ b/api/current.xml @@ -29249,6 +29249,21 @@ <parameter name="name" type="java.lang.String"> </parameter> </method> +<method name="addStatusChangeListener" + return="java.lang.Object" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="mask" type="int"> +</parameter> +<parameter name="callback" type="android.content.SyncStatusObserver"> +</parameter> +</method> <method name="applyBatch" return="android.content.ContentProviderResult[]" abstract="false" @@ -29290,12 +29305,27 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="uri" type="android.net.Uri"> </parameter> </method> +<method name="cancelSync" + return="void" + abstract="false" + native="false" + synchronized="false" + static="true" + 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="delete" return="int" abstract="false" @@ -29313,6 +29343,43 @@ <parameter name="selectionArgs" type="java.lang.String[]"> </parameter> </method> +<method name="getMasterSyncAutomatically" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getSyncAdapterTypes" + return="android.content.SyncAdapterType[]" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getSyncAutomatically" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="true" + 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="getType" return="java.lang.String" abstract="false" @@ -29341,6 +29408,36 @@ <parameter name="values" type="android.content.ContentValues"> </parameter> </method> +<method name="isSyncActive" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="true" + 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="isSyncPending" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="true" + 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="notifyChange" return="void" abstract="false" @@ -29513,6 +29610,66 @@ <parameter name="observer" type="android.database.ContentObserver"> </parameter> </method> +<method name="removeStatusChangeListener" + return="void" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="handle" type="java.lang.Object"> +</parameter> +</method> +<method name="requestSync" + return="void" + abstract="false" + native="false" + synchronized="false" + static="true" + 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="extras" type="android.os.Bundle"> +</parameter> +</method> +<method name="setMasterSyncAutomatically" + return="void" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="sync" type="boolean"> +</parameter> +</method> +<method name="setSyncAutomatically" + return="void" + abstract="false" + native="false" + synchronized="false" + static="true" + 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="sync" type="boolean"> +</parameter> +</method> <method name="startSync" return="void" abstract="false" @@ -29520,7 +29677,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="uri" type="android.net.Uri"> @@ -29635,7 +29792,7 @@ value=""account"" static="true" final="true" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </field> @@ -29668,6 +29825,17 @@ value=""force"" static="true" final="true" + deprecated="deprecated" + visibility="public" +> +</field> +<field name="SYNC_EXTRAS_MANUAL" + type="java.lang.String" + transient="false" + volatile="false" + value=""force"" + static="true" + final="true" deprecated="not deprecated" visibility="public" > @@ -37903,6 +38071,8 @@ deprecated="not deprecated" visibility="public" > +<implements name="android.os.Parcelable"> +</implements> <constructor name="SyncAdapterType" type="android.content.SyncAdapterType" static="false" @@ -37915,6 +38085,52 @@ <parameter name="accountType" type="java.lang.String"> </parameter> </constructor> +<constructor name="SyncAdapterType" + type="android.content.SyncAdapterType" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="source" type="android.os.Parcel"> +</parameter> +</constructor> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="dest" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="accountType" type="java.lang.String" transient="false" @@ -37936,6 +38152,27 @@ > </field> </class> +<interface name="SyncStatusObserver" + abstract="true" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="onStatusChanged" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="which" type="int"> +</parameter> +</method> +</interface> <class name="UriMatcher" extends="java.lang.Object" abstract="false" @@ -117418,7 +117655,7 @@ > <parameter name="uri" type="android.net.Uri"> </parameter> -<parameter name="account" type="java.lang.String"> +<parameter name="accountName" type="java.lang.String"> </parameter> <parameter name="authority" type="java.lang.String"> </parameter> diff --git a/core/java/android/content/AbstractSyncableContentProvider.java b/core/java/android/content/AbstractSyncableContentProvider.java index e628dcd..db73dd5 100644 --- a/core/java/android/content/AbstractSyncableContentProvider.java +++ b/core/java/android/content/AbstractSyncableContentProvider.java @@ -141,7 +141,8 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (!upgradeDatabase(db, oldVersion, newVersion)) { mSyncState.discardSyncData(db, null /* all accounts */); - getContext().getContentResolver().startSync(mContentUri, new Bundle()); + ContentResolver.requestSync(null /* all accounts */, + mContentUri.getAuthority(), new Bundle()); } } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index a01c5d1..98ed098 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -48,9 +48,18 @@ import java.util.ArrayList; * This class provides applications access to the content model. */ public abstract class ContentResolver { - public final static String SYNC_EXTRAS_ACCOUNT = "account"; + /** + * @deprecated instead use + * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} + */ + public static final String SYNC_EXTRAS_ACCOUNT = "account"; public static final String SYNC_EXTRAS_EXPEDITED = "expedited"; + /** + * @deprecated instead use + * {@link #SYNC_EXTRAS_MANUAL} + */ public static final String SYNC_EXTRAS_FORCE = "force"; + public static final String SYNC_EXTRAS_MANUAL = "force"; public static final String SYNC_EXTRAS_UPLOAD = "upload"; public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override"; public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions"; @@ -90,7 +99,35 @@ public abstract class ContentResolver { * in the cursor is the same. */ public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir"; - + + /** @hide */ + public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1; + /** @hide */ + public static final int SYNC_ERROR_AUTHENTICATION = 2; + /** @hide */ + public static final int SYNC_ERROR_IO = 3; + /** @hide */ + public static final int SYNC_ERROR_PARSE = 4; + /** @hide */ + public static final int SYNC_ERROR_CONFLICT = 5; + /** @hide */ + public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6; + /** @hide */ + public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7; + /** @hide */ + public static final int SYNC_ERROR_INTERNAL = 8; + + /** @hide */ + public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0; + /** @hide */ + public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1; + /** @hide */ + public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2; + /** @hide */ + public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3; + /** @hide */ + public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff; + public ContentResolver(Context context) { mContext = context; } @@ -829,11 +866,42 @@ public abstract class ContentResolver { * * @param uri the uri of the provider to sync or null to sync all providers. * @param extras any extras to pass to the SyncAdapter. + * @deprecated instead use + * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} */ public void startSync(Uri uri, Bundle extras) { + Account account = null; + if (extras != null) { + String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT); + if (!TextUtils.isEmpty(accountName)) { + account = new Account(accountName, "com.google.GAIA"); + } + extras.remove(SYNC_EXTRAS_ACCOUNT); + } + requestSync(account, uri != null ? uri.getAuthority() : null, extras); + } + + /** + * Start an asynchronous sync operation. If you want to monitor the progress + * of the sync you may register a SyncObserver. Only values of the following + * types may be used in the extras bundle: + * <ul> + * <li>Integer</li> + * <li>Long</li> + * <li>Boolean</li> + * <li>Float</li> + * <li>Double</li> + * <li>String</li> + * </ul> + * + * @param account which account should be synced + * @param authority which authority should be synced + * @param extras any extras to pass to the SyncAdapter. + */ + public static void requestSync(Account account, String authority, Bundle extras) { validateSyncExtrasBundle(extras); try { - getContentService().startSync(uri, extras); + getContentService().requestSync(account, authority, extras); } catch (RemoteException e) { } } @@ -874,13 +942,186 @@ public abstract class ContentResolver { } } + /** + * Cancel any active or pending syncs that match the Uri. If the uri is null then + * all syncs will be canceled. + * + * @param uri the uri of the provider to sync or null to sync all providers. + * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)} + */ public void cancelSync(Uri uri) { + cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null); + } + + /** + * Cancel any active or pending syncs that match account and authority. The account and + * authority can each independently be set to null, which means that syncs with any account + * or authority, respectively, will match. + * + * @param account filters the syncs that match by this account + * @param authority filters the syncs that match by this authority + */ + public static void cancelSync(Account account, String authority) { + try { + getContentService().cancelSync(account, authority); + } catch (RemoteException e) { + } + } + + /** + * Get information about the SyncAdapters that are known to the system. + * @return an array of SyncAdapters that have registered with the system + */ + public static SyncAdapterType[] getSyncAdapterTypes() { + try { + return getContentService().getSyncAdapterTypes(); + } catch (RemoteException e) { + throw new RuntimeException("the ContentService should always be reachable", e); + } + } + + /** + * Check if the provider should be synced when a network tickle is received + * + * @param account the account whose setting we are querying + * @param authority the provider whose setting we are querying + * @return true if the provider should be synced when a network tickle is received + */ + public static boolean getSyncAutomatically(Account account, String authority) { + try { + return getContentService().getSyncAutomatically(account, authority); + } catch (RemoteException e) { + throw new RuntimeException("the ContentService should always be reachable", e); + } + } + + /** + * Set whether or not the provider is synced when it receives a network tickle. + * + * @param account the account whose setting we are querying + * @param authority the provider whose behavior is being controlled + * @param sync true if the provider should be synced when tickles are received for it + */ + public static void setSyncAutomatically(Account account, String authority, boolean sync) { try { - getContentService().cancelSync(uri); + getContentService().setSyncAutomatically(account, authority, sync); } 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. + * + * @return the master auto-sync setting that applies to all the providers and accounts + */ + public static boolean getMasterSyncAutomatically() { + try { + return getContentService().getMasterSyncAutomatically(); + } catch (RemoteException e) { + throw new RuntimeException("the ContentService should always be reachable", e); + } + } + + /** + * Sets 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. + * + * @param sync the master auto-sync setting that applies to all the providers and accounts + */ + public static void setMasterSyncAutomatically(boolean sync) { + try { + getContentService().setMasterSyncAutomatically(sync); + } catch (RemoteException e) { + // exception ignored; if this is thrown then it means the runtime is in the midst of + // being restarted + } + } + + /** + * Returns true if there is currently a sync operation for the given + * account or authority in the pending list, or actively being processed. + * @param account the account whose setting we are querying + * @param authority the provider whose behavior is being queried + * @return true if a sync is active for the given account or authority. + */ + public static boolean isSyncActive(Account account, String authority) { + try { + return getContentService().isSyncActive(account, authority); + } catch (RemoteException e) { + throw new RuntimeException("the ContentService should always be reachable", e); + } + } + + /** + * If a sync is active returns the information about it, otherwise returns false. + * @return the ActiveSyncInfo for the currently active sync or null if one is not active. + * @hide + */ + public static ActiveSyncInfo getActiveSync() { + try { + return getContentService().getActiveSync(); + } catch (RemoteException e) { + throw new RuntimeException("the ContentService should always be reachable", e); + } + } + + /** + * Returns the status that matches the authority. If there are multiples accounts for + * the authority, the one with the latest "lastSuccessTime" status is returned. + * @param account the account whose setting we are querying + * @param authority the provider whose behavior is being queried + * @return the SyncStatusInfo for the authority, or null if none exists + * @hide + */ + public static SyncStatusInfo getSyncStatus(Account account, String authority) { + try { + return getContentService().getSyncStatus(account, authority); + } catch (RemoteException e) { + throw new RuntimeException("the ContentService should always be reachable", e); + } + } + + /** + * Return true if the pending status is true of any matching authorities. + * @param account the account whose setting we are querying + * @param authority the provider whose behavior is being queried + * @return true if there is a pending sync with the matching account and authority + */ + public static boolean isSyncPending(Account account, String authority) { + try { + return getContentService().isSyncPending(account, authority); + } catch (RemoteException e) { + throw new RuntimeException("the ContentService should always be reachable", e); + } + } + + public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) { + try { + ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() { + public void onStatusChanged(int which) throws RemoteException { + callback.onStatusChanged(which); + } + }; + getContentService().addStatusChangeListener(mask, observer); + return observer; + } catch (RemoteException e) { + throw new RuntimeException("the ContentService should always be reachable", e); + } + } + + public static void removeStatusChangeListener(Object handle) { + try { + getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle); + } catch (RemoteException e) { + // exception ignored; if this is thrown then it means the runtime is in the midst of + // being restarted + } + } + + private final class CursorWrapperInner extends CursorWrapper { private IContentProvider mContentProvider; public static final String TAG="CursorWrapperInner"; diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java index c768ffa..7a1ad2b 100644 --- a/core/java/android/content/ContentService.java +++ b/core/java/android/content/ContentService.java @@ -161,7 +161,9 @@ public final class ContentService extends IContentService.Stub { } if (syncToNetwork) { SyncManager syncManager = getSyncManager(); - if (syncManager != null) syncManager.scheduleLocalSync(uri); + if (syncManager != null) { + syncManager.scheduleLocalSync(null /* all accounts */, uri.getAuthority()); + } } } finally { restoreCallingIdentity(identityToken); @@ -187,14 +189,16 @@ public final class ContentService extends IContentService.Stub { } } - public void startSync(Uri url, Bundle extras) { + public void requestSync(Account account, String authority, Bundle extras) { ContentResolver.validateSyncExtrasBundle(extras); // This makes it so that future permission checks will be in the context of this // process rather than the caller's process. We will restore this before returning. long identityToken = clearCallingIdentity(); try { SyncManager syncManager = getSyncManager(); - if (syncManager != null) syncManager.startSync(url, extras); + if (syncManager != null) { + syncManager.scheduleSync(account, authority, extras, 0 /* no delay */); + } } finally { restoreCallingIdentity(identityToken); } @@ -202,34 +206,50 @@ public final class ContentService extends IContentService.Stub { /** * Clear all scheduled sync operations that match the uri and cancel the active sync - * if it matches the uri. If the uri is null, clear all scheduled syncs and cancel - * the active one, if there is one. - * @param uri Filter on the sync operations to cancel, or all if null. + * if they match the authority and account, if they are present. + * @param account filter the pending and active syncs to cancel using this account + * @param authority filter the pending and active syncs to cancel using this authority */ - public void cancelSync(Uri uri) { + public void cancelSync(Account account, String authority) { // This makes it so that future permission checks will be in the context of this // process rather than the caller's process. We will restore this before returning. long identityToken = clearCallingIdentity(); try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { - syncManager.clearScheduledSyncOperations(uri); - syncManager.cancelActiveSync(uri); + syncManager.clearScheduledSyncOperations(account, authority); + syncManager.cancelActiveSync(account, authority); } } finally { restoreCallingIdentity(identityToken); } } - public boolean getSyncProviderAutomatically(String providerName) { + /** + * Get information about the SyncAdapters that are known to the system. + * @return an array of SyncAdapters that have registered with the system + */ + public SyncAdapterType[] getSyncAdapterTypes() { + // This makes it so that future permission checks will be in the context of this + // process rather than the caller's process. We will restore this before returning. + long identityToken = clearCallingIdentity(); + try { + SyncManager syncManager = getSyncManager(); + return syncManager.getSyncAdapterTypes(); + } finally { + restoreCallingIdentity(identityToken); + } + } + + public boolean getSyncAutomatically(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().getSyncProviderAutomatically( - null, providerName); + return syncManager.getSyncStorageEngine().getSyncAutomatically( + account, providerName); } } finally { restoreCallingIdentity(identityToken); @@ -237,29 +257,29 @@ public final class ContentService extends IContentService.Stub { return false; } - public void setSyncProviderAutomatically(String providerName, boolean sync) { + public void setSyncAutomatically(Account account, String providerName, boolean sync) { 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().setSyncProviderAutomatically( - null, providerName, sync); + syncManager.getSyncStorageEngine().setSyncAutomatically( + account, providerName, sync); } } finally { restoreCallingIdentity(identityToken); } } - public boolean getListenForNetworkTickles() { + public boolean getMasterSyncAutomatically() { 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().getListenForNetworkTickles(); + return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(); } } finally { restoreCallingIdentity(identityToken); @@ -267,14 +287,14 @@ public final class ContentService extends IContentService.Stub { return false; } - public void setListenForNetworkTickles(boolean flag) { + public void setMasterSyncAutomatically(boolean flag) { 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().setListenForNetworkTickles(flag); + syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag); } } finally { restoreCallingIdentity(identityToken); @@ -312,7 +332,7 @@ public final class ContentService extends IContentService.Stub { return null; } - public SyncStatusInfo getStatusByAuthority(String authority) { + public SyncStatusInfo getSyncStatus(Account account, String authority) { mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, "no permission to read the sync stats"); long identityToken = clearCallingIdentity(); @@ -328,15 +348,14 @@ public final class ContentService extends IContentService.Stub { return null; } - public boolean isAuthorityPending(Account account, String authority) { + public boolean isSyncPending(Account account, String authority) { mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, "no permission to read the sync stats"); long identityToken = clearCallingIdentity(); try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { - return syncManager.getSyncStorageEngine().isAuthorityPending( - account, authority); + return syncManager.getSyncStorageEngine().isSyncPending(account, authority); } } finally { restoreCallingIdentity(identityToken); @@ -349,8 +368,7 @@ public final class ContentService extends IContentService.Stub { try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { - syncManager.getSyncStorageEngine().addStatusChangeListener( - mask, callback); + syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback); } } finally { restoreCallingIdentity(identityToken); @@ -362,8 +380,7 @@ public final class ContentService extends IContentService.Stub { try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { - syncManager.getSyncStorageEngine().removeStatusChangeListener( - callback); + syncManager.getSyncStorageEngine().removeStatusChangeListener(callback); } } finally { restoreCallingIdentity(identityToken); diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl index 4352227..658a5bc 100644 --- a/core/java/android/content/IContentService.aidl +++ b/core/java/android/content/IContentService.aidl @@ -19,6 +19,7 @@ package android.content; import android.accounts.Account; import android.content.ActiveSyncInfo; import android.content.ISyncStatusObserver; +import android.content.SyncAdapterType; import android.content.SyncStatusInfo; import android.net.Uri; import android.os.Bundle; @@ -35,15 +36,15 @@ interface IContentService { void notifyChange(in Uri uri, IContentObserver observer, boolean observerWantsSelfNotifications, boolean syncToNetwork); - void startSync(in Uri url, in Bundle extras); - void cancelSync(in Uri uri); + void requestSync(in Account account, String authority, in Bundle extras); + void cancelSync(in Account account, String authority); /** * Check if the provider should be synced when a network tickle is received * @param providerName the provider whose setting we are querying * @return true of the provider should be synced when a network tickle is received */ - boolean getSyncProviderAutomatically(String providerName); + boolean getSyncAutomatically(in Account account, String providerName); /** * Set whether or not the provider is synced when it receives a network tickle. @@ -51,11 +52,11 @@ interface IContentService { * @param providerName the provider whose behavior is being controlled * @param sync true if the provider should be synced when tickles are received for it */ - void setSyncProviderAutomatically(String providerName, boolean sync); + void setSyncAutomatically(in Account account, String providerName, boolean sync); - void setListenForNetworkTickles(boolean flag); + void setMasterSyncAutomatically(boolean flag); - boolean getListenForNetworkTickles(); + boolean getMasterSyncAutomatically(); /** * Returns true if there is currently a sync operation for the given @@ -66,17 +67,23 @@ interface IContentService { ActiveSyncInfo getActiveSync(); /** + * Returns the types of the SyncAdapters that are registered with the system. + * @return Returns the types of the SyncAdapters that are registered with the system. + */ + SyncAdapterType[] getSyncAdapterTypes(); + + /** * Returns the status that matches the authority. If there are multiples accounts for * the authority, the one with the latest "lastSuccessTime" status is returned. * @param authority the authority whose row should be selected * @return the SyncStatusInfo for the authority, or null if none exists */ - SyncStatusInfo getStatusByAuthority(String authority); + SyncStatusInfo getSyncStatus(in Account account, String authority); /** * Return true if the pending status is true of any matching authorities. */ - boolean isAuthorityPending(in Account account, String authority); + boolean isSyncPending(in Account account, String authority); void addStatusChangeListener(int mask, ISyncStatusObserver callback); diff --git a/core/java/android/content/SyncAdapterType.aidl b/core/java/android/content/SyncAdapterType.aidl new file mode 100644 index 0000000..e67841f --- /dev/null +++ b/core/java/android/content/SyncAdapterType.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +parcelable SyncAdapterType; + diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java index 368a879..5a96003 100644 --- a/core/java/android/content/SyncAdapterType.java +++ b/core/java/android/content/SyncAdapterType.java @@ -17,12 +17,14 @@ package android.content; import android.text.TextUtils; +import android.os.Parcelable; +import android.os.Parcel; /** * Value type that represents a SyncAdapterType. This object overrides {@link #equals} and * {@link #hashCode}, making it suitable for use as the key of a {@link java.util.Map} */ -public class SyncAdapterType { +public class SyncAdapterType implements Parcelable { public final String authority; public final String accountType; @@ -54,4 +56,27 @@ public class SyncAdapterType { public String toString() { return "SyncAdapterType {name=" + authority + ", type=" + accountType + "}"; } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(authority); + dest.writeString(accountType); + } + + public SyncAdapterType(Parcel source) { + this(source.readString(), source.readString()); + } + + public static final Creator<SyncAdapterType> CREATOR = new Creator<SyncAdapterType>() { + public SyncAdapterType createFromParcel(Parcel source) { + return new SyncAdapterType(source); + } + + public SyncAdapterType[] newArray(int size) { + return new SyncAdapterType[size]; + } + }; }
\ No newline at end of file diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index c7954a5..f73b394 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -35,7 +35,6 @@ import android.content.pm.ResolveInfo; import android.content.pm.RegisteredServicesCache; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; @@ -72,7 +71,7 @@ import java.util.List; import java.util.Map; import java.util.PriorityQueue; import java.util.Random; -import java.util.Set; +import java.util.Collection; /** * @hide @@ -160,7 +159,7 @@ class SyncManager implements OnAccountsUpdatedListener { Log.v(TAG, "Internal storage is low."); } mStorageIsLow = true; - cancelActiveSync(null /* no url */); + cancelActiveSync(null /* any account */, null /* any authority */); } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Internal storage is ok."); @@ -204,7 +203,7 @@ class SyncManager implements OnAccountsUpdatedListener { if (hadAccountsAlready && accounts.length > 0) { // request a sync so that if the password was changed we will // retry any sync that failed when it was wrong - startSync(null /* all providers */, null /* no extras */); + scheduleSync(null, null, null, 0 /* no delay */); } } @@ -327,7 +326,7 @@ class SyncManager implements OnAccountsUpdatedListener { mHandleAlarmWakeLock.setReferenceCounted(false); mSyncStorageEngine.addStatusChangeListener( - SyncStorageEngine.CHANGE_SETTINGS, new ISyncStatusObserver.Stub() { + ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, new ISyncStatusObserver.Stub() { public void onStatusChanged(int which) { // force the sync loop to run if the settings change sendCheckAlarmsMessage(); @@ -406,7 +405,8 @@ class SyncManager implements OnAccountsUpdatedListener { scheduleSyncPollAlarm(nextRelativePollTimeMs); // perform a poll - scheduleSync(null /* sync all syncable providers */, new Bundle(), 0 /* no delay */); + scheduleSync(null /* sync all syncable accounts */, null /* sync all syncable providers */, + new Bundle(), 0 /* no delay */); } private void writeSyncPollTime(long when) { @@ -502,20 +502,21 @@ class SyncManager implements OnAccountsUpdatedListener { * * <p>You'll start getting callbacks after this. * - * @param url The Uri of a specific provider to be synced, or - * null to sync all providers. + * @param requestedAccount the account to sync, may be null to signify all accounts + * @param requestedAuthority the authority to sync, may be null to indicate all authorities * @param extras a Map of SyncAdapter-specific information to control * syncs of a specific provider. Can be null. Is ignored * if the url is null. * @param delay how many milliseconds in the future to wait before performing this - * sync. -1 means to make this the next sync to perform. */ - public void scheduleSync(Uri url, Bundle extras, long delay) { + public void scheduleSync(Account requestedAccount, String requestedAuthority, + Bundle extras, long delay) { boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); if (isLoggable) { Log.v(TAG, "scheduleSync:" + " delay " + delay - + ", url " + ((url == null) ? "(null)" : url) + + ", account " + requestedAccount + + ", authority " + requestedAuthority + ", extras " + ((extras == null) ? "(null)" : extras)); } @@ -539,9 +540,8 @@ class SyncManager implements OnAccountsUpdatedListener { } Account[] accounts; - Account accountFromExtras = extras.getParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT); - if (accountFromExtras != null) { - accounts = new Account[]{accountFromExtras}; + if (requestedAccount != null) { + accounts = new Account[]{requestedAccount}; } else { // if the accounts aren't configured yet then we can't support an account-less // sync request @@ -563,14 +563,14 @@ class SyncManager implements OnAccountsUpdatedListener { } final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false); - final boolean force = extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false); + final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false); int source; if (uploadOnly) { source = SyncStorageEngine.SOURCE_LOCAL; - } else if (force) { + } else if (manualSync) { source = SyncStorageEngine.SOURCE_USER; - } else if (url == null) { + } else if (requestedAuthority == null) { source = SyncStorageEngine.SOURCE_POLL; } else { // this isn't strictly server, since arbitrary callers can (and do) request @@ -578,9 +578,9 @@ class SyncManager implements OnAccountsUpdatedListener { source = SyncStorageEngine.SOURCE_SERVER; } - // compile a list of authorities that have sync adapters - // for each authority sync each account that matches a sync adapter - Set<String> syncableAuthorities = new HashSet<String>(); + // Compile a list of authorities that have sync adapters. + // For each authority sync each account that matches a sync adapter. + final HashSet<String> syncableAuthorities = new HashSet<String>(); for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter : mSyncAdapters.getAllServices()) { syncableAuthorities.add(syncAdapter.type.authority); @@ -588,10 +588,10 @@ 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 (url != null) { - boolean isSyncable = syncableAuthorities.contains(url.getAuthority()); + if (requestedAuthority != null) { + final boolean isSyncable = syncableAuthorities.contains(requestedAuthority); syncableAuthorities.clear(); - if (isSyncable) syncableAuthorities.add(url.getAuthority()); + if (isSyncable) syncableAuthorities.add(requestedAuthority); } for (String authority : syncableAuthorities) { @@ -614,10 +614,10 @@ class SyncManager implements OnAccountsUpdatedListener { mStatusText = message; } - public void scheduleLocalSync(Uri url) { + public void scheduleLocalSync(Account account, String authority) { final Bundle extras = new Bundle(); extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true); - scheduleSync(url, extras, LOCAL_SYNC_DELAY); + scheduleSync(account, authority, extras, LOCAL_SYNC_DELAY); } private IPackageManager getPackageManager() { @@ -631,18 +631,16 @@ class SyncManager implements OnAccountsUpdatedListener { return mPackageManager; } - /** - * Initiate a sync for this given URL, or pass null for a full sync. - * - * <p>You'll start getting callbacks after this. - * - * @param url The Uri of a specific provider to be synced, or - * null to sync all providers. - * @param extras a Map of SyncAdapter specific information to control - * syncs of a specific provider. Can be null. Is ignored - */ - public void startSync(Uri url, Bundle extras) { - scheduleSync(url, extras, 0 /* no delay */); + public SyncAdapterType[] getSyncAdapterTypes() { + final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos = + mSyncAdapters.getAllServices(); + SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()]; + int i = 0; + for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) { + types[i] = serviceInfo.type; + ++i; + } + return types; } public void updateHeartbeatTime() { @@ -725,17 +723,22 @@ class SyncManager implements OnAccountsUpdatedListener { } /** - * Cancel the active sync if it matches the uri. The uri corresponds to the one passed - * in to startSync(). - * @param uri If non-null, the active sync is only canceled if it matches the uri. - * If null, any active sync is canceled. + * Cancel the active sync if it matches the authority and account. + * @param account limit the cancelations to syncs with this account, if non-null + * @param authority limit the cancelations to syncs with this authority, if non-null */ - public void cancelActiveSync(Uri uri) { + public void cancelActiveSync(Account account, String authority) { ActiveSyncContext activeSyncContext = mActiveSyncContext; if (activeSyncContext != null) { - // if a Uri was specified then only cancel the sync if it matches the the uri - if (uri != null) { - if (!uri.getAuthority().equals(activeSyncContext.mSyncOperation.authority)) { + // if an authority was specified then only cancel the sync if it matches + if (account != null) { + if (!account.equals(activeSyncContext.mSyncOperation.account)) { + return; + } + } + // if an account was specified then only cancel the sync if it matches + if (authority != null) { + if (!authority.equals(activeSyncContext.mSyncOperation.authority)) { return; } } @@ -787,14 +790,13 @@ class SyncManager implements OnAccountsUpdatedListener { } /** - * Remove any scheduled sync operations that match uri. The uri corresponds to the one passed - * in to startSync(). - * @param uri If non-null, only operations that match the uri are cleared. - * If null, all operations are cleared. + * Remove scheduled sync operations. + * @param account limit the removals to operations with this account, if non-null + * @param authority limit the removals to operations with this authority, if non-null */ - public void clearScheduledSyncOperations(Uri uri) { + public void clearScheduledSyncOperations(Account account, String authority) { synchronized (mSyncQueue) { - mSyncQueue.clear(null, uri != null ? uri.getAuthority() : null); + mSyncQueue.clear(account, authority); } } @@ -1558,14 +1560,14 @@ class SyncManager implements OnAccountsUpdatedListener { // Otherwise consume SyncOperations from the head of the SyncQueue until one is // found that is runnable (not disabled, etc). If that one is ready to run then // start it, otherwise just get out. - SyncOperation syncOperation; + SyncOperation op; final ConnectivityManager connManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - final boolean backgroundDataSetting = connManager.getBackgroundDataSetting(); + final boolean backgroundDataUsageAllowed = connManager.getBackgroundDataSetting(); synchronized (mSyncQueue) { while (true) { - syncOperation = mSyncQueue.head(); - if (syncOperation == null) { + op = mSyncQueue.head(); + if (op == null) { if (isLoggable) { Log.v(TAG, "runStateIdle: no more sync operations, returning"); } @@ -1575,39 +1577,40 @@ class SyncManager implements OnAccountsUpdatedListener { // Sync is disabled, drop this operation. if (!isSyncEnabled()) { if (isLoggable) { - Log.v(TAG, "runStateIdle: sync disabled, dropping " + syncOperation); + Log.v(TAG, "runStateIdle: sync disabled, dropping " + op); } mSyncQueue.popHead(); continue; } - // skip the sync if it isn't a force and the settings are off for this provider - final boolean force = syncOperation.extras.getBoolean( - ContentResolver.SYNC_EXTRAS_FORCE, false); - if (!force && (!backgroundDataSetting - || !mSyncStorageEngine.getListenForNetworkTickles() - || !mSyncStorageEngine.getSyncProviderAutomatically( - null, syncOperation.authority))) { + // skip the sync if it isn't manual and auto sync is disabled + final boolean manualSync = op.extras.getBoolean( + ContentResolver.SYNC_EXTRAS_MANUAL, false); + final boolean syncAutomatically = + mSyncStorageEngine.getSyncAutomatically(op.account, op.authority) + || mSyncStorageEngine.getMasterSyncAutomatically(); + boolean syncAllowed = + manualSync || (backgroundDataUsageAllowed && syncAutomatically); + if (!syncAllowed) { if (isLoggable) { - Log.v(TAG, "runStateIdle: sync off, dropping " + syncOperation); + Log.v(TAG, "runStateIdle: sync off, dropping " + op); } mSyncQueue.popHead(); continue; } // skip the sync if the account of this operation no longer exists - if (!ArrayUtils.contains(accounts, syncOperation.account)) { + if (!ArrayUtils.contains(accounts, op.account)) { mSyncQueue.popHead(); if (isLoggable) { - Log.v(TAG, "runStateIdle: account not present, dropping " - + syncOperation); + Log.v(TAG, "runStateIdle: account not present, dropping " + op); } continue; } // go ahead and try to sync this syncOperation if (isLoggable) { - Log.v(TAG, "runStateIdle: found sync candidate: " + syncOperation); + Log.v(TAG, "runStateIdle: found sync candidate: " + op); } break; } @@ -1615,11 +1618,10 @@ class SyncManager implements OnAccountsUpdatedListener { // If the first SyncOperation isn't ready to run schedule a wakeup and // get out. final long now = SystemClock.elapsedRealtime(); - if (syncOperation.earliestRunTime > now) { + if (op.earliestRunTime > now) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "runStateIdle: the time is " + now + " yet the next " - + "sync operation is for " + syncOperation.earliestRunTime - + ": " + syncOperation); + + "sync operation is for " + op.earliestRunTime + ": " + op); } return; } @@ -1627,14 +1629,14 @@ class SyncManager implements OnAccountsUpdatedListener { // We will do this sync. Remove it from the queue and run it outside of the // synchronized block. if (isLoggable) { - Log.v(TAG, "runStateIdle: we are going to sync " + syncOperation); + Log.v(TAG, "runStateIdle: we are going to sync " + op); } mSyncQueue.popHead(); } // connect to the sync adapter - SyncAdapterType syncAdapterType = new SyncAdapterType(syncOperation.authority, - syncOperation.account.mType); + SyncAdapterType syncAdapterType = new SyncAdapterType(op.authority, + op.account.mType); RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType); if (syncAdapterInfo == null) { @@ -1646,7 +1648,7 @@ class SyncManager implements OnAccountsUpdatedListener { } ActiveSyncContext activeSyncContext = - new ActiveSyncContext(syncOperation, insertStartSyncEvent(syncOperation)); + new ActiveSyncContext(op, insertStartSyncEvent(op)); mActiveSyncContext = activeSyncContext; if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "runStateIdle: setting mActiveSyncContext to " + mActiveSyncContext); @@ -1776,21 +1778,21 @@ class SyncManager implements OnAccountsUpdatedListener { */ private int syncResultToErrorNumber(SyncResult syncResult) { if (syncResult.syncAlreadyInProgress) - return SyncStorageEngine.ERROR_SYNC_ALREADY_IN_PROGRESS; + return ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS; if (syncResult.stats.numAuthExceptions > 0) - return SyncStorageEngine.ERROR_AUTHENTICATION; + return ContentResolver.SYNC_ERROR_AUTHENTICATION; if (syncResult.stats.numIoExceptions > 0) - return SyncStorageEngine.ERROR_IO; + return ContentResolver.SYNC_ERROR_IO; if (syncResult.stats.numParseExceptions > 0) - return SyncStorageEngine.ERROR_PARSE; + return ContentResolver.SYNC_ERROR_PARSE; if (syncResult.stats.numConflictDetectedExceptions > 0) - return SyncStorageEngine.ERROR_CONFLICT; + return ContentResolver.SYNC_ERROR_CONFLICT; if (syncResult.tooManyDeletions) - return SyncStorageEngine.ERROR_TOO_MANY_DELETIONS; + return ContentResolver.SYNC_ERROR_TOO_MANY_DELETIONS; if (syncResult.tooManyRetries) - return SyncStorageEngine.ERROR_TOO_MANY_RETRIES; + return ContentResolver.SYNC_ERROR_TOO_MANY_RETRIES; if (syncResult.databaseError) - return SyncStorageEngine.ERROR_INTERNAL; + return ContentResolver.SYNC_ERROR_INTERNAL; throw new IllegalStateException("we are not in an error state, " + syncResult); } @@ -1831,9 +1833,10 @@ class SyncManager implements OnAccountsUpdatedListener { } else { final boolean timeToShowNotification = now > mSyncNotificationInfo.startTime + SYNC_NOTIFICATION_DELAY; - final boolean syncIsForced = syncOperation.extras - .getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false); - shouldInstall = timeToShowNotification || syncIsForced; + // show the notification immediately if this is a manual sync + final boolean manualSync = syncOperation.extras + .getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false); + shouldInstall = timeToShowNotification || manualSync; } } @@ -2088,9 +2091,9 @@ class SyncManager implements OnAccountsUpdatedListener { SyncOperation existingOperation = mOpsByKey.get(operationKey); // if this operation matches an existing operation that is being retried (delay > 0) - // and this operation isn't forced, ignore this operation + // and this isn't a manual sync operation, ignore this operation if (existingOperation != null && existingOperation.delay > 0) { - if (!operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)) { + if (!operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) { return false; } } diff --git a/core/java/android/content/SyncStatusObserver.java b/core/java/android/content/SyncStatusObserver.java new file mode 100644 index 0000000..663378a --- /dev/null +++ b/core/java/android/content/SyncStatusObserver.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +public interface SyncStatusObserver { + void onStatusChanged(int which); +} diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index aaa763d..aaba7c7 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -49,8 +49,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.TimeZone; -import com.google.android.collect.Sets; - /** * Singleton that tracks the sync data and overall sync * history on the device. @@ -89,6 +87,9 @@ public class SyncStorageEngine extends Handler { /** Enum value for a user-initiated sync. */ public static final int SOURCE_USER = 3; + private static final Intent SYNC_CONNECTION_SETTING_CHANGED_INTENT = + new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED"); + // TODO: i18n -- grab these out of resources. /** String names for the sync source types. */ public static final String[] SOURCES = { "SERVER", @@ -96,26 +97,10 @@ public class SyncStorageEngine extends Handler { "POLL", "USER" }; - // Error types - public static final int ERROR_SYNC_ALREADY_IN_PROGRESS = 1; - public static final int ERROR_AUTHENTICATION = 2; - public static final int ERROR_IO = 3; - public static final int ERROR_PARSE = 4; - public static final int ERROR_CONFLICT = 5; - public static final int ERROR_TOO_MANY_DELETIONS = 6; - public static final int ERROR_TOO_MANY_RETRIES = 7; - public static final int ERROR_INTERNAL = 8; - // The MESG column will contain one of these or one of the Error types. public static final String MESG_SUCCESS = "success"; public static final String MESG_CANCELED = "canceled"; - public static final int CHANGE_SETTINGS = 1<<0; - public static final int CHANGE_PENDING = 1<<1; - public static final int CHANGE_ACTIVE = 1<<2; - public static final int CHANGE_STATUS = 1<<3; - public static final int CHANGE_ALL = 0x7fffffff; - public static final int MAX_HISTORY = 15; private static final int MSG_WRITE_STATUS = 1; @@ -166,7 +151,7 @@ public class SyncStorageEngine extends Handler { final String authority; final int ident; boolean enabled; - + AuthorityInfo(Account account, String authority, int ident) { this.account = account; this.authority = authority; @@ -259,7 +244,7 @@ public class SyncStorageEngine extends Handler { private int mNumPendingFinished = 0; private int mNextHistoryId = 0; - private boolean mListenForTickles = true; + private boolean mMasterSyncAutomatically = true; private SyncStorageEngine(Context context) { mContext = context; @@ -356,14 +341,14 @@ public class SyncStorageEngine extends Handler { } } - public boolean getSyncProviderAutomatically(Account account, String providerName) { + public boolean getSyncAutomatically(Account account, String providerName) { synchronized (mAuthorities) { if (account != null) { AuthorityInfo authority = getAuthorityLocked(account, providerName, - "getSyncProviderAutomatically"); - return authority != null ? authority.enabled : false; + "getSyncAutomatically"); + return authority != null && authority.enabled; } - + int i = mAuthorities.size(); while (i > 0) { i--; @@ -377,42 +362,31 @@ public class SyncStorageEngine extends Handler { } } - public void setSyncProviderAutomatically(Account account, String providerName, - boolean sync) { + public void setSyncAutomatically(Account account, String providerName, boolean sync) { synchronized (mAuthorities) { - if (account != null) { - AuthorityInfo authority = getAuthorityLocked(account, providerName, - "setSyncProviderAutomatically"); - if (authority != null) { - authority.enabled = sync; - } - } else { - int i = mAuthorities.size(); - while (i > 0) { - i--; - AuthorityInfo authority = mAuthorities.get(i); - if (authority.authority.equals(providerName)) { - authority.enabled = sync; - } - } + AuthorityInfo authority = getAuthorityLocked(account, providerName, + "setSyncAutomatically"); + if (authority != null) { + authority.enabled = sync; } writeAccountInfoLocked(); } - reportChange(CHANGE_SETTINGS); + reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); } - public void setListenForNetworkTickles(boolean flag) { + public void setMasterSyncAutomatically(boolean flag) { synchronized (mAuthorities) { - mListenForTickles = flag; + mMasterSyncAutomatically = flag; writeAccountInfoLocked(); } - reportChange(CHANGE_SETTINGS); + reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); + mContext.sendBroadcast(SYNC_CONNECTION_SETTING_CHANGED_INTENT); } - public boolean getListenForNetworkTickles() { + public boolean getMasterSyncAutomatically() { synchronized (mAuthorities) { - return mListenForTickles; + return mMasterSyncAutomatically; } } @@ -481,7 +455,7 @@ public class SyncStorageEngine extends Handler { status.pending = true; } - reportChange(CHANGE_PENDING); + reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING); return op; } @@ -527,7 +501,7 @@ public class SyncStorageEngine extends Handler { } } - reportChange(CHANGE_PENDING); + reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING); return res; } @@ -543,7 +517,7 @@ public class SyncStorageEngine extends Handler { } writePendingOperationsLocked(); } - reportChange(CHANGE_PENDING); + reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING); return num; } @@ -650,14 +624,14 @@ public class SyncStorageEngine extends Handler { } } - reportChange(CHANGE_ACTIVE); + reportChange(ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE); } /** * To allow others to send active change reports, to poke clients. */ public void reportActiveChange() { - reportChange(CHANGE_ACTIVE); + reportChange(ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE); } /** @@ -689,7 +663,7 @@ public class SyncStorageEngine extends Handler { if (DEBUG) Log.v(TAG, "returning historyId " + id); } - reportChange(CHANGE_STATUS); + reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS); return id; } @@ -793,7 +767,7 @@ public class SyncStorageEngine extends Handler { } } - reportChange(CHANGE_STATUS); + reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS); } /** @@ -851,7 +825,7 @@ public class SyncStorageEngine extends Handler { /** * Return true if the pending status is true of any matching authorities. */ - public boolean isAuthorityPending(Account account, String authority) { + public boolean isSyncPending(Account account, String authority) { synchronized (mAuthorities) { final int N = mSyncStatus.size(); for (int i=0; i<N; i++) { @@ -907,7 +881,7 @@ public class SyncStorageEngine extends Handler { */ public long getInitialSyncFailureTime() { synchronized (mAuthorities) { - if (!mListenForTickles) { + if (!mMasterSyncAutomatically) { return 0; } @@ -1041,7 +1015,7 @@ public class SyncStorageEngine extends Handler { if ("accounts".equals(tagName)) { String listen = parser.getAttributeValue( null, "listen-for-tickles"); - mListenForTickles = listen == null + mMasterSyncAutomatically = listen == null || Boolean.parseBoolean(listen); eventType = parser.next(); do { @@ -1122,7 +1096,7 @@ public class SyncStorageEngine extends Handler { out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); out.startTag(null, "accounts"); - if (!mListenForTickles) { + if (!mMasterSyncAutomatically) { out.attribute(null, "listen-for-tickles", "false"); } @@ -1262,13 +1236,18 @@ public class SyncStorageEngine extends Handler { String value = c.getString(c.getColumnIndex("value")); if (name == null) continue; if (name.equals("listen_for_tickles")) { - setListenForNetworkTickles(value == null - || Boolean.parseBoolean(value)); + setMasterSyncAutomatically(value == null || Boolean.parseBoolean(value)); } else if (name.startsWith("sync_provider_")) { String provider = name.substring("sync_provider_".length(), name.length()); - setSyncProviderAutomatically(null, provider, - value == null || Boolean.parseBoolean(value)); + int i = mAuthorities.size(); + while (i > 0) { + i--; + AuthorityInfo authority = mAuthorities.get(i); + if (authority.authority.equals(provider)) { + authority.enabled = value == null || Boolean.parseBoolean(value); + } + } } } diff --git a/core/java/android/content/TempProviderSyncAdapter.java b/core/java/android/content/TempProviderSyncAdapter.java index 0cbe01e..fb05fe7 100644 --- a/core/java/android/content/TempProviderSyncAdapter.java +++ b/core/java/android/content/TempProviderSyncAdapter.java @@ -63,12 +63,10 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { * * @param context allows you to publish status and interact with the * @param account the account to sync - * @param forced if true then the sync was forced + * @param manualSync true if this sync was requested manually by the user * @param result information to track what happened during this sync attempt - * @return true, if the sync was successfully started. One reason it can - * fail to start is if there is no user configured on the device. */ - public abstract void onSyncStarting(SyncContext context, Account account, boolean forced, + public abstract void onSyncStarting(SyncContext context, Account account, boolean manualSync, SyncResult result); /** @@ -229,12 +227,12 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { mAdapterSyncStarted = false; String message = null; - boolean syncForced = extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false); + boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false); try { mProvider.onSyncStart(syncContext, account); mProviderSyncStarted = true; - onSyncStarting(syncContext, account, syncForced, mResult); + onSyncStarting(syncContext, account, manualSync, mResult); if (mResult.hasError()) { message = "SyncAdapter failed while trying to start sync"; return; diff --git a/core/java/android/provider/Sync.java b/core/java/android/provider/Sync.java deleted file mode 100644 index c9bde0e..0000000 --- a/core/java/android/provider/Sync.java +++ /dev/null @@ -1,649 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.provider; - -import android.content.ContentQueryMap; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; -import android.os.Handler; -import android.accounts.Account; -import android.text.TextUtils; - -import java.util.Map; - -/** - * The Sync provider stores information used in managing the syncing of the device, - * including the history and pending syncs. - * - * @hide - */ -public final class Sync { - // utility class - private Sync() {} - - /** - * The content url for this provider. - */ - public static final Uri CONTENT_URI = Uri.parse("content://sync"); - - /** - * Columns from the stats table. - */ - public interface StatsColumns { - /** - * The sync account. - * <P>Type: TEXT</P> - */ - public static final String ACCOUNT = "account"; - - /** - * The sync account type. - * <P>Type: TEXT</P> - */ - public static final String ACCOUNT_TYPE = "account_type"; - - /** - * The content authority (contacts, calendar, etc.). - * <P>Type: TEXT</P> - */ - public static final String AUTHORITY = "authority"; - } - - /** - * Provides constants and utility methods to access and use the stats table. - */ - public static final class Stats implements BaseColumns, StatsColumns { - - // utility class - private Stats() {} - - /** - * The content url for this table. - */ - public static final Uri CONTENT_URI = - Uri.parse("content://sync/stats"); - - /** Projection for the _id column in the stats table. */ - public static final String[] SYNC_STATS_PROJECTION = {_ID}; - } - - /** - * Columns from the history table. - */ - public interface HistoryColumns { - /** - * The ID of the stats row corresponding to this event. - * <P>Type: INTEGER</P> - */ - public static final String STATS_ID = "stats_id"; - - /** - * The source of the sync event (LOCAL, POLL, USER, SERVER). - * <P>Type: INTEGER</P> - */ - public static final String SOURCE = "source"; - - /** - * The type of sync event (START, STOP). - * <P>Type: INTEGER</P> - */ - public static final String EVENT = "event"; - - /** - * The time of the event. - * <P>Type: INTEGER</P> - */ - public static final String EVENT_TIME = "eventTime"; - - /** - * How long this event took. This is only valid if the EVENT is EVENT_STOP. - * <P>Type: INTEGER</P> - */ - public static final String ELAPSED_TIME = "elapsedTime"; - - /** - * Any additional message associated with this event. - * <P>Type: TEXT</P> - */ - public static final String MESG = "mesg"; - - /** - * How much activity was performed sending data to the server. This is sync adapter - * specific, but usually is something like how many record update/insert/delete attempts - * were carried out. This is only valid if the EVENT is EVENT_STOP. - * <P>Type: INTEGER</P> - */ - public static final String UPSTREAM_ACTIVITY = "upstreamActivity"; - - /** - * How much activity was performed while receiving data from the server. - * This is sync adapter specific, but usually is something like how many - * records were received from the server. This is only valid if the - * EVENT is EVENT_STOP. - * <P>Type: INTEGER</P> - */ - public static final String DOWNSTREAM_ACTIVITY = "downstreamActivity"; - } - - /** - * Columns from the history table. - */ - public interface StatusColumns { - /** - * How many syncs were completed for this account and authority. - * <P>Type: INTEGER</P> - */ - public static final String NUM_SYNCS = "numSyncs"; - - /** - * How long all the events for this account and authority took. - * <P>Type: INTEGER</P> - */ - public static final String TOTAL_ELAPSED_TIME = "totalElapsedTime"; - - /** - * The number of syncs with SOURCE_POLL. - * <P>Type: INTEGER</P> - */ - public static final String NUM_SOURCE_POLL = "numSourcePoll"; - - /** - * The number of syncs with SOURCE_SERVER. - * <P>Type: INTEGER</P> - */ - public static final String NUM_SOURCE_SERVER = "numSourceServer"; - - /** - * The number of syncs with SOURCE_LOCAL. - * <P>Type: INTEGER</P> - */ - public static final String NUM_SOURCE_LOCAL = "numSourceLocal"; - - /** - * The number of syncs with SOURCE_USER. - * <P>Type: INTEGER</P> - */ - public static final String NUM_SOURCE_USER = "numSourceUser"; - - /** - * The time in ms that the last successful sync ended. Will be null if - * there are no successful syncs. A successful sync is defined as one having - * MESG=MESG_SUCCESS. - * <P>Type: INTEGER</P> - */ - public static final String LAST_SUCCESS_TIME = "lastSuccessTime"; - - /** - * The SOURCE of the last successful sync. Will be null if - * there are no successful syncs. A successful sync is defined - * as one having MESG=MESG_SUCCESS. - * <P>Type: INTEGER</P> - */ - public static final String LAST_SUCCESS_SOURCE = "lastSuccessSource"; - - /** - * The end time in ms of the last sync that failed since the last successful sync. - * Will be null if there are no syncs or if the last one succeeded. A failed - * sync is defined as one where MESG isn't MESG_SUCCESS or MESG_CANCELED. - * <P>Type: INTEGER</P> - */ - public static final String LAST_FAILURE_TIME = "lastFailureTime"; - - /** - * The SOURCE of the last sync that failed since the last successful sync. - * Will be null if there are no syncs or if the last one succeeded. A failed - * sync is defined as one where MESG isn't MESG_SUCCESS or MESG_CANCELED. - * <P>Type: INTEGER</P> - */ - public static final String LAST_FAILURE_SOURCE = "lastFailureSource"; - - /** - * The MESG of the last sync that failed since the last successful sync. - * Will be null if there are no syncs or if the last one succeeded. A failed - * sync is defined as one where MESG isn't MESG_SUCCESS or MESG_CANCELED. - * <P>Type: STRING</P> - */ - public static final String LAST_FAILURE_MESG = "lastFailureMesg"; - - /** - * Is set to 1 if a sync is pending, 0 if not. - * <P>Type: INTEGER</P> - */ - public static final String PENDING = "pending"; - } - - /** - * Provides constants and utility methods to access and use the history - * table. - */ - public static class History implements BaseColumns, - StatsColumns, - HistoryColumns { - - /** - * The content url for this table. - */ - public static final Uri CONTENT_URI = - Uri.parse("content://sync/history"); - - /** Enum value for a sync start event. */ - public static final int EVENT_START = 0; - - /** Enum value for a sync stop event. */ - public static final int EVENT_STOP = 1; - - // TODO: i18n -- grab these out of resources. - /** String names for the sync event types. */ - public static final String[] EVENTS = { "START", "STOP" }; - - /** Enum value for a server-initiated sync. */ - public static final int SOURCE_SERVER = 0; - - /** Enum value for a local-initiated sync. */ - public static final int SOURCE_LOCAL = 1; - /** - * Enum value for a poll-based sync (e.g., upon connection to - * network) - */ - public static final int SOURCE_POLL = 2; - - /** Enum value for a user-initiated sync. */ - public static final int SOURCE_USER = 3; - - // TODO: i18n -- grab these out of resources. - /** String names for the sync source types. */ - public static final String[] SOURCES = { "SERVER", - "LOCAL", - "POLL", - "USER" }; - - // Error types - public static final int ERROR_SYNC_ALREADY_IN_PROGRESS = 1; - public static final int ERROR_AUTHENTICATION = 2; - public static final int ERROR_IO = 3; - public static final int ERROR_PARSE = 4; - public static final int ERROR_CONFLICT = 5; - public static final int ERROR_TOO_MANY_DELETIONS = 6; - public static final int ERROR_TOO_MANY_RETRIES = 7; - public static final int ERROR_INTERNAL = 8; - - // The MESG column will contain one of these or one of the Error types. - public static final String MESG_SUCCESS = "success"; - public static final String MESG_CANCELED = "canceled"; - - private static final String FINISHED_SINCE_WHERE_CLAUSE = EVENT + "=" + EVENT_STOP - + " AND " + EVENT_TIME + ">? AND " + ACCOUNT + "=? AND " + ACCOUNT_TYPE + "=?" - + " AND " + AUTHORITY + "=?"; - - public static String mesgToString(String mesg) { - if (MESG_SUCCESS.equals(mesg)) return mesg; - if (MESG_CANCELED.equals(mesg)) return mesg; - switch (Integer.parseInt(mesg)) { - case ERROR_SYNC_ALREADY_IN_PROGRESS: return "already in progress"; - case ERROR_AUTHENTICATION: return "bad authentication"; - case ERROR_IO: return "network error"; - case ERROR_PARSE: return "parse error"; - case ERROR_CONFLICT: return "conflict detected"; - case ERROR_TOO_MANY_DELETIONS: return "too many deletions"; - case ERROR_TOO_MANY_RETRIES: return "too many retries"; - case ERROR_INTERNAL: return "internal error"; - default: return "unknown error"; - } - } - - // utility class - private History() {} - - /** - * returns a cursor that queries the sync history in descending event time order - * @param contentResolver the ContentResolver to use for the query - * @return the cursor on the History table - */ - public static Cursor query(ContentResolver contentResolver) { - return contentResolver.query(CONTENT_URI, null, null, null, EVENT_TIME + " desc"); - } - - public static boolean hasNewerSyncFinished(ContentResolver contentResolver, - Account account, String authority, long when) { - Cursor c = contentResolver.query(CONTENT_URI, new String[]{_ID}, - FINISHED_SINCE_WHERE_CLAUSE, - new String[]{Long.toString(when), account.mName, account.mType, authority}, - null); - try { - return c.getCount() > 0; - } finally { - c.close(); - } - } - } - - /** - * Provides constants and utility methods to access and use the authority history - * table, which contains information about syncs aggregated by account and authority. - * All the HistoryColumns except for EVENT are present, plus the AuthorityHistoryColumns. - */ - public static class Status extends History implements StatusColumns { - - /** - * The content url for this table. - */ - public static final Uri CONTENT_URI = Uri.parse("content://sync/status"); - - // utility class - private Status() {} - - /** - * returns a cursor that queries the authority sync history in descending event order of - * ACCOUNT, AUTHORITY - * @param contentResolver the ContentResolver to use for the query - * @return the cursor on the AuthorityHistory table - */ - public static Cursor query(ContentResolver contentResolver) { - return contentResolver.query(CONTENT_URI, null, null, null, - ACCOUNT_TYPE + "," + ACCOUNT + "," + AUTHORITY); - } - - public static class QueryMap extends ContentQueryMap { - public QueryMap(ContentResolver contentResolver, - boolean keepUpdated, - Handler handlerForUpdateNotifications) { - super(contentResolver.query(CONTENT_URI, null, null, null, null), - _ID, keepUpdated, handlerForUpdateNotifications); - } - - public ContentValues get(Account account, String authority) { - Map<String, ContentValues> rows = getRows(); - for (ContentValues values : rows.values()) { - if (values.getAsString(ACCOUNT).equals(account.mName) - && values.getAsString(ACCOUNT_TYPE).equals(account.mType) - && values.getAsString(AUTHORITY).equals(authority)) { - return values; - } - } - return null; - } - } - } - - /** - * Provides constants and utility methods to access and use the pending syncs table - */ - public static final class Pending implements BaseColumns, - StatsColumns { - - /** - * The content url for this table. - */ - public static final Uri CONTENT_URI = Uri.parse("content://sync/pending"); - - // utility class - private Pending() {} - - public static class QueryMap extends ContentQueryMap { - public QueryMap(ContentResolver contentResolver, boolean keepUpdated, - Handler handlerForUpdateNotifications) { - super(contentResolver.query(CONTENT_URI, null, null, null, null), _ID, keepUpdated, - handlerForUpdateNotifications); - } - - public boolean isPending(Account account, String authority) { - Map<String, ContentValues> rows = getRows(); - for (ContentValues values : rows.values()) { - if (values.getAsString(ACCOUNT).equals(account.mName) - && values.getAsString(ACCOUNT_TYPE).equals(account.mType) - && values.getAsString(AUTHORITY).equals(authority)) { - return true; - } - } - return false; - } - } - } - - /** - * Columns from the history table. - */ - public interface ActiveColumns { - /** - * The wallclock time of when the active sync started. - * <P>Type: INTEGER</P> - */ - public static final String START_TIME = "startTime"; - } - - /** - * Provides constants and utility methods to access and use the pending syncs table - */ - public static final class Active implements BaseColumns, - StatsColumns, - ActiveColumns { - - /** - * The content url for this table. - */ - public static final Uri CONTENT_URI = Uri.parse("content://sync/active"); - - // utility class - private Active() {} - - public static class QueryMap extends ContentQueryMap { - public QueryMap(ContentResolver contentResolver, boolean keepUpdated, - Handler handlerForUpdateNotifications) { - super(contentResolver.query(CONTENT_URI, null, null, null, null), _ID, keepUpdated, - handlerForUpdateNotifications); - } - - public ContentValues getActiveSyncInfo() { - Map<String, ContentValues> rows = getRows(); - for (ContentValues values : rows.values()) { - return values; - } - return null; - } - - public Account getSyncingAccount() { - ContentValues values = getActiveSyncInfo(); - if (values == null || TextUtils.isEmpty(values.getAsString(ACCOUNT))) { - return null; - } - return new Account(values.getAsString(ACCOUNT), values.getAsString(ACCOUNT_TYPE)); - } - - public String getSyncingAuthority() { - ContentValues values = getActiveSyncInfo(); - return (values == null) ? null : values.getAsString(AUTHORITY); - } - - public long getSyncStartTime() { - ContentValues values = getActiveSyncInfo(); - return (values == null) ? -1 : values.getAsLong(START_TIME); - } - } - } - - /** - * Columns in the settings table, which holds key/value pairs of settings. - */ - public interface SettingsColumns { - /** - * The key of the setting - * <P>Type: TEXT</P> - */ - public static final String KEY = "name"; - - /** - * The value of the settings - * <P>Type: TEXT</P> - */ - public static final String VALUE = "value"; - } - - /** - * Provides constants and utility methods to access and use the settings - * table. - */ - public static final class Settings implements BaseColumns, SettingsColumns { - /** - * The Uri of the settings table. This table behaves a little differently than - * normal tables. Updates are not allowed, only inserts, and inserts cause a replace - * to be performed, which first deletes the row if it is already present. - */ - public static final Uri CONTENT_URI = Uri.parse("content://sync/settings"); - - /** controls whether or not the device listens for sync tickles */ - public static final String SETTING_LISTEN_FOR_TICKLES = "listen_for_tickles"; - - /** controls whether or not the individual provider is synced when tickles are received */ - public static final String SETTING_SYNC_PROVIDER_PREFIX = "sync_provider_"; - - /** query column project */ - private static final String[] PROJECTION = { KEY, VALUE }; - - /** - * Convenience function for updating a single settings value as a - * boolean. This will either create a new entry in the table if the - * given name does not exist, or modify the value of the existing row - * with that name. Note that internally setting values are always - * stored as strings, so this function converts the given value to a - * string before storing it. - * - * @param contentResolver the ContentResolver to use to access the settings table - * @param name The name of the setting to modify. - * @param val The new value for the setting. - */ - static private void putBoolean(ContentResolver contentResolver, String name, boolean val) { - ContentValues values = new ContentValues(); - values.put(KEY, name); - values.put(VALUE, Boolean.toString(val)); - // this insert is translated into an update by the underlying Sync provider - contentResolver.insert(CONTENT_URI, values); - } - - /** - * Convenience function for getting a setting value as a boolean without using the - * QueryMap for light-weight setting querying. - * @param contentResolver The ContentResolver for querying the setting. - * @param name The name of the setting to query - * @param def The default value for the setting. - * @return The value of the setting. - */ - static public boolean getBoolean(ContentResolver contentResolver, - String name, boolean def) { - Cursor cursor = contentResolver.query( - CONTENT_URI, - PROJECTION, - KEY + "=?", - new String[] { name }, - null); - try { - if (cursor != null && cursor.moveToFirst()) { - return Boolean.parseBoolean(cursor.getString(1)); - } - } finally { - if (cursor != null) cursor.close(); - } - return def; - } - - /** - * A convenience method to set whether or not the provider is synced when - * it receives a network tickle. - * - * @param contentResolver the ContentResolver to use to access the settings table - * @param providerName the provider whose behavior is being controlled - * @param sync true if the provider should be synced when tickles are received for it - */ - static public void setSyncProviderAutomatically(ContentResolver contentResolver, - String providerName, boolean sync) { - putBoolean(contentResolver, SETTING_SYNC_PROVIDER_PREFIX + providerName, sync); - } - - /** - * A convenience method to set whether or not the device should listen to tickles. - * - * @param contentResolver the ContentResolver to use to access the settings table - * @param flag true if it should listen. - */ - static public void setListenForNetworkTickles(ContentResolver contentResolver, - boolean flag) { - putBoolean(contentResolver, SETTING_LISTEN_FOR_TICKLES, flag); - } - - public static class QueryMap extends ContentQueryMap { - private ContentResolver mContentResolver; - - public QueryMap(ContentResolver contentResolver, boolean keepUpdated, - Handler handlerForUpdateNotifications) { - super(contentResolver.query(CONTENT_URI, null, null, null, null), KEY, keepUpdated, - handlerForUpdateNotifications); - mContentResolver = contentResolver; - } - - /** - * Check if the provider should be synced when a network tickle is received - * @param providerName the provider whose setting we are querying - * @return true of the provider should be synced when a network tickle is received - */ - public boolean getSyncProviderAutomatically(String providerName) { - return getBoolean(SETTING_SYNC_PROVIDER_PREFIX + providerName, true); - } - - /** - * Set whether or not the provider is synced when it receives a network tickle. - * - * @param providerName the provider whose behavior is being controlled - * @param sync true if the provider should be synced when tickles are received for it - */ - public void setSyncProviderAutomatically(String providerName, boolean sync) { - Settings.setSyncProviderAutomatically(mContentResolver, providerName, sync); - } - - /** - * Set whether or not the device should listen for tickles. - * - * @param flag true if it should listen. - */ - public void setListenForNetworkTickles(boolean flag) { - Settings.setListenForNetworkTickles(mContentResolver, flag); - } - - /** - * Check if the device should listen to tickles. - - * @return true if it should - */ - public boolean getListenForNetworkTickles() { - return getBoolean(SETTING_LISTEN_FOR_TICKLES, true); - } - - /** - * Convenience function for retrieving a single settings value - * as a boolean. - * - * @param name The name of the setting to retrieve. - * @param def Value to return if the setting is not defined. - * @return The setting's current value, or 'def' if it is not defined. - */ - private boolean getBoolean(String name, boolean def) { - ContentValues values = getValues(name); - return values != null ? values.getAsBoolean(VALUE) : def; - } - } - } -} diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java index 9992420..3cd2cc4 100644 --- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java +++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java @@ -16,9 +16,7 @@ import android.database.sqlite.SQLiteFullException; import android.app.AlarmManager; import android.app.PendingIntent; import android.os.Bundle; -import android.os.RemoteException; import android.text.TextUtils; -import android.net.Uri; import android.accounts.Account; import java.util.ArrayList; @@ -113,8 +111,9 @@ public class SubscribedFeedsIntentService extends IntentService { + "and " + SubscribedFeeds.Feeds.FEED + "= ?"; try { // TODO(fredq) fix the hardcoded type + final Account account = new Account(accountName, "com.google.GAIA"); c = context.getContentResolver().query(SubscribedFeeds.Feeds.CONTENT_URI, - null, where, new String[]{accountName, "com.google.GAIA", feed}, null); + null, where, new String[]{account.mName, account.mType, feed}, null); if (c.getCount() == 0) { Log.w(TAG, "received tickle for non-existent feed: " + "account " + accountName + ", feed " + feed); @@ -125,22 +124,14 @@ public class SubscribedFeedsIntentService extends IntentService { String authority = c.getString(c.getColumnIndexOrThrow( SubscribedFeeds.Feeds.AUTHORITY)); EventLog.writeEvent(LOG_TICKLE, authority); - try { - if (!ContentResolver.getContentService() - .getSyncProviderAutomatically(authority)) { - Log.d(TAG, "supressing tickle since provider " + authority - + " is configured to not sync automatically"); - continue; - } - } catch (RemoteException e) { + if (!ContentResolver.getSyncAutomatically(account, authority)) { + Log.d(TAG, "supressing tickle since provider " + authority + + " is configured to not sync automatically"); continue; } - Uri uri = Uri.parse("content://" + authority); Bundle extras = new Bundle(); - extras.putParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT, - new Account(accountName, "com.google.GAIA")); extras.putString("feed", feed); - context.getContentResolver().startSync(uri, extras); + ContentResolver.requestSync(account, authority, extras); } } finally { if (c != null) c.deactivate(); diff --git a/test-runner/android/test/SyncBaseInstrumentation.java b/test-runner/android/test/SyncBaseInstrumentation.java index bf9e783..a860bb3 100644 --- a/test-runner/android/test/SyncBaseInstrumentation.java +++ b/test-runner/android/test/SyncBaseInstrumentation.java @@ -19,7 +19,6 @@ package android.test; import android.content.ContentResolver; import android.content.Context; import android.os.Bundle; -import android.os.RemoteException; import android.os.SystemClock; import android.net.Uri; import android.accounts.Account; @@ -45,13 +44,12 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase { * Syncs the specified provider. * @throws Exception */ - protected void syncProvider(Uri uri, String account, String authority) throws Exception { + protected void syncProvider(Uri uri, String accountName, String authority) throws Exception { Bundle extras = new Bundle(); - extras.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true); - Account account1 = new Account(account, "com.google.GAIA"); - extras.putParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT, account1); + extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + Account account = new Account(accountName, "com.google.GAIA"); - mContentResolver.startSync(uri, extras); + ContentResolver.requestSync(account, authority, extras); long startTimeInMillis = SystemClock.elapsedRealtime(); long endTimeInMillis = startTimeInMillis + MAX_TIME_FOR_SYNC_IN_MINS * 60000; @@ -66,7 +64,7 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase { break; } - if (isSyncActive(account1, authority)) { + if (ContentResolver.isSyncActive(account, authority)) { counter = 0; continue; } @@ -75,24 +73,7 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase { } protected void cancelSyncsandDisableAutoSync() { - try { - ContentResolver.getContentService().setListenForNetworkTickles(false); - } catch (RemoteException e) { - } - mContentResolver.cancelSync(null); - } - - /** - * This method tests if any sync is active or not. Sync is considered to be active if the - * entry is in either the Pending or Active tables. - * @return - */ - private boolean isSyncActive(Account account, String authority) { - try { - return ContentResolver.getContentService().isSyncActive(account, - authority); - } catch (RemoteException e) { - return false; - } + ContentResolver.setMasterSyncAutomatically(false); + ContentResolver.cancelSync(null /* all accounts */, null /* all authorities */); } } |
