Merge change 5102
* changes: - clean up the sync settings names to: (get|set)SyncAutomatically (get|set)MasterSyncAutomatically - change SYNC_EXTRAS_FORCE to SYNC_EXTRAS_MANUAL to mace clear that this overrides the .*SyncAutomatically settings - make ContentResolver methods that call the sync controls methods in IContentService so that SDK users can use them - rename startSync to requestSync to reinforce the fact that a sync is not immediately or always started when this method is called - add an Account parameter to all the sync settings and control methods - change the sync control methods to take a String authority rather than a Uri uri
This commit is contained in:
245
api/current.xml
245
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>
|
||||
@@ -29662,6 +29819,17 @@
|
||||
>
|
||||
</field>
|
||||
<field name="SYNC_EXTRAS_FORCE"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""force""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="SYNC_EXTRAS_MANUAL"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
@@ -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>
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(uri);
|
||||
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().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";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -65,18 +66,24 @@ 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);
|
||||
|
||||
|
||||
20
core/java/android/content/SyncAdapterType.aidl
Normal file
20
core/java/android/content/SyncAdapterType.aidl
Normal file
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
21
core/java/android/content/SyncStatusObserver.java
Normal file
21
core/java/android/content/SyncStatusObserver.java
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user