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:
Android (Google) Code Review
2009-06-23 15:54:43 -07:00
14 changed files with 763 additions and 891 deletions

View File

@@ -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="&quot;account&quot;"
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="&quot;force&quot;"
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>

View File

@@ -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());
}
}

View File

@@ -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";

View File

@@ -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);

View File

@@ -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);

View 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;

View File

@@ -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];
}
};
}

View File

@@ -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;
}
}

View 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);
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;

View File

@@ -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;
}
}
}
}

View File

@@ -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();

View File

@@ -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 */);
}
}