diff options
author | Fred Quintana <fredq@google.com> | 2009-08-17 13:05:39 -0700 |
---|---|---|
committer | Fred Quintana <fredq@google.com> | 2009-08-18 11:06:52 -0700 |
commit | 4a6679b97e0285c5b65ec5c0d9080ff90d3e9e81 (patch) | |
tree | 3356b9b309a39344d320635140a4380d5e1e5318 /core | |
parent | 084cd8266ecbc70714fd3c7d27488411a00338b7 (diff) | |
download | frameworks_base-4a6679b97e0285c5b65ec5c0d9080ff90d3e9e81.zip frameworks_base-4a6679b97e0285c5b65ec5c0d9080ff90d3e9e81.tar.gz frameworks_base-4a6679b97e0285c5b65ec5c0d9080ff90d3e9e81.tar.bz2 |
make syncadapter set whether the account is syncable
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/content/AbstractThreadedSyncAdapter.java | 20 | ||||
-rw-r--r-- | core/java/android/content/ContentResolver.java | 14 | ||||
-rw-r--r-- | core/java/android/content/ContentService.java | 3 | ||||
-rw-r--r-- | core/java/android/content/SyncAdapter.java | 6 | ||||
-rw-r--r-- | core/java/android/content/SyncAdapterType.java | 17 | ||||
-rw-r--r-- | core/java/android/content/SyncAdaptersCache.java | 4 | ||||
-rw-r--r-- | core/java/android/content/SyncManager.java | 63 | ||||
-rw-r--r-- | core/java/android/content/SyncStorageEngine.java | 3 | ||||
-rw-r--r-- | core/java/android/content/TempProviderSyncAdapter.java | 46 | ||||
-rw-r--r-- | core/res/res/values/attrs.xml | 7 | ||||
-rw-r--r-- | core/res/res/values/public.xml | 7 |
11 files changed, 148 insertions, 42 deletions
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java index f15a902..538225a 100644 --- a/core/java/android/content/AbstractThreadedSyncAdapter.java +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -44,16 +44,23 @@ public abstract class AbstractThreadedSyncAdapter { /** Kernel event log tag. Also listed in data/etc/event-log-tags. */ public static final int LOG_SYNC_DETAILS = 2743; + private final boolean mAutoInitialize; /** * Creates an {@link AbstractThreadedSyncAdapter}. - * @param context the {@link Context} that this is running within. + * @param context the {@link android.content.Context} that this is running within. + * @param autoInitialize if true then sync requests that have + * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by + * {@link AbstractThreadedSyncAdapter} by calling + * {@link ContentResolver#setIsSyncable(android.accounts.Account, String, int)} with 1 if it + * is currently set to <0. */ - public AbstractThreadedSyncAdapter(Context context) { + public AbstractThreadedSyncAdapter(Context context, boolean autoInitialize) { mContext = context; mISyncAdapterImpl = new ISyncAdapterImpl(); mNumSyncStarts = new AtomicInteger(0); mSyncThread = null; + mAutoInitialize = autoInitialize; } class ISyncAdapterImpl extends ISyncAdapter.Stub { @@ -66,6 +73,15 @@ public abstract class AbstractThreadedSyncAdapter { // check it and when we use it synchronized (this) { if (mSyncThread == null) { + if (mAutoInitialize + && extras != null + && extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) { + if (ContentResolver.getIsSyncable(account, authority) < 0) { + ContentResolver.setIsSyncable(account, authority, 1); + } + syncContextClient.onFinished(new SyncResult()); + return; + } mSyncThread = new SyncThread( "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), syncContextClient, authority, account, extras); diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index bf1a442..239b3de 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -52,18 +52,29 @@ public abstract class ContentResolver { * @deprecated instead use * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} */ + @Deprecated public static final String SYNC_EXTRAS_ACCOUNT = "account"; public static final String SYNC_EXTRAS_EXPEDITED = "expedited"; /** * @deprecated instead use * {@link #SYNC_EXTRAS_MANUAL} */ + @Deprecated 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"; + /** + * Set by the SyncManager to request that the SyncAdapter initialize itself for + * the given account/authority pair. One required initialization step is to + * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been + * called with a >= 0 value. When this flag is set the SyncAdapter does not need to + * do a full sync, though it is allowed to do so. + */ + public static final String SYNC_EXTRAS_INITIALIZE = "initialize"; + public static final String SCHEME_CONTENT = "content"; public static final String SCHEME_ANDROID_RESOURCE = "android.resource"; public static final String SCHEME_FILE = "file"; @@ -1094,8 +1105,7 @@ public abstract class ContentResolver { } /** - * Returns the status that matches the authority. If there are multiples accounts for - * the authority, the one with the latest "lastSuccessTime" status is returned. + * Returns the status that matches the authority. * @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 diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java index c4d8aaf..f742448 100644 --- a/core/java/android/content/ContentService.java +++ b/core/java/android/content/ContentService.java @@ -197,7 +197,8 @@ public final class ContentService extends IContentService.Stub { try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { - syncManager.scheduleSync(account, authority, extras, 0 /* no delay */); + syncManager.scheduleSync(account, authority, extras, 0 /* no delay */, + false /* onlyThoseWithUnkownSyncableState */); } } finally { restoreCallingIdentity(identityToken); diff --git a/core/java/android/content/SyncAdapter.java b/core/java/android/content/SyncAdapter.java index 1d5ade1..88dc332 100644 --- a/core/java/android/content/SyncAdapter.java +++ b/core/java/android/content/SyncAdapter.java @@ -32,7 +32,7 @@ public abstract class SyncAdapter { class Transport extends ISyncAdapter.Stub { public void startSync(ISyncContext syncContext, String authority, Account account, Bundle extras) throws RemoteException { - SyncAdapter.this.startSync(new SyncContext(syncContext), account, extras); + SyncAdapter.this.startSync(new SyncContext(syncContext), account, authority, extras); } public void cancelSync(ISyncContext syncContext) throws RemoteException { @@ -58,9 +58,11 @@ public abstract class SyncAdapter { * @param syncContext the ISyncContext used to indicate the progress of the sync. When * the sync is finished (successfully or not) ISyncContext.onFinished() must be called. * @param account the account that should be synced + * @param authority the authority if the sync request * @param extras SyncAdapter-specific parameters */ - public abstract void startSync(SyncContext syncContext, Account account, Bundle extras); + public abstract void startSync(SyncContext syncContext, Account account, String authority, + Bundle extras); /** * Cancel the most recently initiated sync. Due to race conditions, this may arrive diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java index d3f8230..93b61ec 100644 --- a/core/java/android/content/SyncAdapterType.java +++ b/core/java/android/content/SyncAdapterType.java @@ -27,9 +27,9 @@ import android.os.Parcel; public class SyncAdapterType implements Parcelable { public final String authority; public final String accountType; - public final boolean isUserFacing = true; // TODO: implement logic to set this + public final boolean userVisible; - public SyncAdapterType(String authority, String accountType) { + public SyncAdapterType(String authority, String accountType, boolean userVisible) { if (TextUtils.isEmpty(authority)) { throw new IllegalArgumentException("the authority must not be empty: " + authority); } @@ -38,12 +38,18 @@ public class SyncAdapterType implements Parcelable { } this.authority = authority; this.accountType = accountType; + this.userVisible = userVisible; + } + + public static SyncAdapterType newKey(String authority, String accountType) { + return new SyncAdapterType(authority, accountType, true); } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof SyncAdapterType)) return false; final SyncAdapterType other = (SyncAdapterType)o; + // don't include userVisible in the equality check return authority.equals(other.authority) && accountType.equals(other.accountType); } @@ -51,11 +57,13 @@ public class SyncAdapterType implements Parcelable { int result = 17; result = 31 * result + authority.hashCode(); result = 31 * result + accountType.hashCode(); + // don't include userVisible in the hash return result; } public String toString() { - return "SyncAdapterType {name=" + authority + ", type=" + accountType + "}"; + return "SyncAdapterType {name=" + authority + ", type=" + accountType + + ", userVisible=" + userVisible + "}"; } public int describeContents() { @@ -65,10 +73,11 @@ public class SyncAdapterType implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(authority); dest.writeString(accountType); + dest.writeInt(userVisible ? 1 : 0); } public SyncAdapterType(Parcel source) { - this(source.readString(), source.readString()); + this(source.readString(), source.readString(), source.readInt() != 0); } public static final Creator<SyncAdapterType> CREATOR = new Creator<SyncAdapterType>() { diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java index ce47d76..c27fd25 100644 --- a/core/java/android/content/SyncAdaptersCache.java +++ b/core/java/android/content/SyncAdaptersCache.java @@ -47,7 +47,9 @@ import android.util.AttributeSet; if (authority == null || accountType == null) { return null; } - return new SyncAdapterType(authority, accountType); + final boolean userVisible = + sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_userVisible, true); + return new SyncAdapterType(authority, accountType, userVisible); } finally { sa.recycle(); } diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index f50fd74..34efc51 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -180,7 +180,8 @@ class SyncManager implements OnAccountsUpdatedListener { }; public void onAccountsUpdated(Account[] accounts) { - final boolean hadAccountsAlready = mAccounts != null; + // remember if this was the first time this was called after an update + final boolean justBootedUp = mAccounts == null; mAccounts = accounts; // if a sync is in progress yet it is no longer in the accounts list, @@ -200,10 +201,22 @@ class SyncManager implements OnAccountsUpdatedListener { mSyncStorageEngine.doDatabaseCleanup(accounts); - 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 - scheduleSync(null, null, null, 0 /* no delay */); + if (accounts.length > 0) { + // If this is the first time this was called after a bootup then + // the accounts haven't really changed, instead they were just loaded + // from the AccountManager. Otherwise at least one of the accounts + // has a change. + // + // If there was a real account change then force a sync of all accounts. + // This is a bit of overkill, but at least it will end up retrying syncs + // that failed due to an authentication failure and thus will recover if the + // account change was a password update. + // + // If this was the bootup case then don't sync everything, instead only + // sync those that have an unknown syncable state, which will give them + // a chance to set their syncable state. + boolean onlyThoseWithUnkownSyncableState = !justBootedUp; + scheduleSync(null, null, null, 0 /* no delay */, onlyThoseWithUnkownSyncableState); } } @@ -406,7 +419,7 @@ class SyncManager implements OnAccountsUpdatedListener { // perform a poll scheduleSync(null /* sync all syncable accounts */, null /* sync all syncable providers */, - new Bundle(), 0 /* no delay */); + new Bundle(), 0 /* no delay */, false /* onlyThoseWithUnkownSyncableState */); } private void writeSyncPollTime(long when) { @@ -508,9 +521,10 @@ class SyncManager implements OnAccountsUpdatedListener { * 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 + * @param onlyThoseWithUnkownSyncableState */ public void scheduleSync(Account requestedAccount, String requestedAuthority, - Bundle extras, long delay) { + Bundle extras, long delay, boolean onlyThoseWithUnkownSyncableState) { boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); if (isLoggable) { Log.v(TAG, "scheduleSync:" @@ -596,14 +610,22 @@ class SyncManager implements OnAccountsUpdatedListener { for (String authority : syncableAuthorities) { for (Account account : accounts) { - boolean isSyncable = mSyncStorageEngine.getIsSyncable(account, authority) > 0; - if (!isSyncable) { + int isSyncable = mSyncStorageEngine.getIsSyncable(account, authority); + if (isSyncable == 0) { + continue; + } + if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) { continue; } - if (mSyncAdapters.getServiceInfo(new SyncAdapterType(authority, account.type)) + if (mSyncAdapters.getServiceInfo(SyncAdapterType.newKey(authority, account.type)) != null) { + // make this an initialization sync if the isSyncable state is unknown + Bundle extrasCopy = new Bundle(extras); + if (isSyncable < 0) { + extrasCopy.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true); + } scheduleSyncOperation( - new SyncOperation(account, source, authority, extras, delay)); + new SyncOperation(account, source, authority, extrasCopy, delay)); } } } @@ -616,7 +638,8 @@ class SyncManager implements OnAccountsUpdatedListener { public void scheduleLocalSync(Account account, String authority) { final Bundle extras = new Bundle(); extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true); - scheduleSync(account, authority, extras, LOCAL_SYNC_DELAY); + scheduleSync(account, authority, extras, LOCAL_SYNC_DELAY, + false /* onlyThoseWithUnkownSyncableState */); } private IPackageManager getPackageManager() { @@ -1588,11 +1611,18 @@ class SyncManager implements OnAccountsUpdatedListener { final boolean syncAutomatically = mSyncStorageEngine.getSyncAutomatically(op.account, op.authority) && mSyncStorageEngine.getMasterSyncAutomatically(); - boolean isSyncable = - mSyncStorageEngine.getIsSyncable(op.account, op.authority) > 0; boolean syncAllowed = manualSync || (backgroundDataUsageAllowed && syncAutomatically); - if (!syncAllowed || !isSyncable) { + int isSyncable = mSyncStorageEngine.getIsSyncable(op.account, op.authority); + if (isSyncable == 0) { + // if not syncable, don't allow + syncAllowed = false; + } else if (isSyncable < 0) { + // if the syncable state is unknown, only allow initialization syncs + syncAllowed = + op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false); + } + if (!syncAllowed) { if (isLoggable) { Log.v(TAG, "runStateIdle: sync off, dropping " + op); } @@ -1636,8 +1666,7 @@ class SyncManager implements OnAccountsUpdatedListener { } // connect to the sync adapter - SyncAdapterType syncAdapterType = new SyncAdapterType(op.authority, - op.account.type); + SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type); RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType); if (syncAdapterInfo == null) { diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index 2647962..7f78e75 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -162,8 +162,7 @@ public class SyncStorageEngine extends Handler { this.authority = authority; this.ident = ident; enabled = SYNC_ENABLED_DEFAULT; - // TODO: change the default to -1 when the syncadapters are changed to set this - syncable = 1; + syncable = -1; // default to "unknown" } } diff --git a/core/java/android/content/TempProviderSyncAdapter.java b/core/java/android/content/TempProviderSyncAdapter.java index fb05fe7..b46c545 100644 --- a/core/java/android/content/TempProviderSyncAdapter.java +++ b/core/java/android/content/TempProviderSyncAdapter.java @@ -13,6 +13,10 @@ import android.util.EventLog; import android.util.Log; import android.util.TimingLogger; import android.accounts.Account; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; + +import java.io.IOException; /** * @hide @@ -84,6 +88,9 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { */ public abstract boolean isReadOnly(); + public abstract boolean getIsSyncable(Account account) + throws IOException, AuthenticatorException, OperationCanceledException; + /** * Get diffs from the server since the last completed sync and put them * into a temporary provider. @@ -173,6 +180,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { private class SyncThread extends Thread { private final Account mAccount; + private final String mAuthority; private final Bundle mExtras; private final SyncContext mSyncContext; private volatile boolean mIsCanceled = false; @@ -180,9 +188,10 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { private long mInitialRxBytes; private final SyncResult mResult; - SyncThread(SyncContext syncContext, Account account, Bundle extras) { + SyncThread(SyncContext syncContext, Account account, String authority, Bundle extras) { super("SyncThread"); mAccount = account; + mAuthority = authority; mExtras = extras; mSyncContext = syncContext; mResult = new SyncResult(); @@ -206,7 +215,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { mInitialTxBytes = NetStat.getUidTxBytes(uid); mInitialRxBytes = NetStat.getUidRxBytes(uid); try { - sync(mSyncContext, mAccount, mExtras); + sync(mSyncContext, mAccount, mAuthority, mExtras); } catch (SQLException e) { Log.e(TAG, "Sync failed", e); mResult.databaseError = true; @@ -220,13 +229,39 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { } } - private void sync(SyncContext syncContext, Account account, Bundle extras) { + private void sync(SyncContext syncContext, Account account, String authority, + Bundle extras) { mIsCanceled = false; mProviderSyncStarted = false; mAdapterSyncStarted = false; String message = null; + // always attempt to initialize if the isSyncable state isn't set yet + int isSyncable = ContentResolver.getIsSyncable(account, authority); + if (isSyncable < 0) { + try { + isSyncable = (getIsSyncable(account)) ? 1 : 0; + ContentResolver.setIsSyncable(account, authority, isSyncable); + } catch (IOException e) { + ++mResult.stats.numIoExceptions; + } catch (AuthenticatorException e) { + ++mResult.stats.numParseExceptions; + } catch (OperationCanceledException e) { + // do nothing + } + } + + // if this is an initialization request then our work is done here + if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) { + return; + } + + // if we aren't syncable then get out + if (isSyncable <= 0) { + return; + } + boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false); try { @@ -517,13 +552,14 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { EventLog.writeEvent(SyncAdapter.LOG_SYNC_DETAILS, TAG, bytesSent, bytesReceived, ""); } - public void startSync(SyncContext syncContext, Account account, Bundle extras) { + public void startSync(SyncContext syncContext, Account account, String authority, + Bundle extras) { if (mSyncThread != null) { syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS); return; } - mSyncThread = new SyncThread(syncContext, account, extras); + mSyncThread = new SyncThread(syncContext, account, authority, extras); mSyncThread.start(); } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 01253d3..eee87e6 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -361,7 +361,7 @@ <!-- Small inverse ProgressBar style. This is a small circular progress bar. --> <attr name="progressBarStyleSmallInverse" format="reference" /> <!-- Large inverse ProgressBar style. This is a large circular progress bar. --> - <attr name="progressBarStyleLargeInverse" format="reference" /> + <attr name="progressBarStyleLargeInverse" format="reference" /> <!-- Default SeekBar style. --> <attr name="seekBarStyle" format="reference" /> <!-- Default RatingBar style. --> @@ -2348,7 +2348,7 @@ <attr name="pivotY" /> <attr name="drawable" /> </declare-styleable> - + <declare-styleable name="InsetDrawable"> <attr name="visible" /> <attr name="drawable" /> @@ -2886,7 +2886,7 @@ results for "bo", it would not be queried again for "bob". The default value is <code>false</code>. <i>Optional attribute.</i>. --> <attr name="queryAfterZeroResults" format="boolean" /> - + <!-- If provided, this string will be used to describe the searchable item in the searchable items settings within system search settings. <i>Optional attribute.</i> --> @@ -3359,6 +3359,7 @@ <!-- the authority of a content provider. --> <attr name="contentAuthority" format="string"/> <attr name="accountType"/> + <attr name="userVisible" format="boolean"/> </declare-styleable> <!-- =============================== --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index d51b439..60b492a 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1130,17 +1130,17 @@ <public type="style" name="Widget.ProgressBar.Inverse" id="0x0103005b" /> <public type="style" name="Widget.ProgressBar.Large.Inverse" id="0x0103005c" /> - <public type="style" name="Widget.ProgressBar.Small.Inverse" id="0x0103005d" /> + <public type="style" name="Widget.ProgressBar.Small.Inverse" id="0x0103005d" /> <public type="drawable" name="stat_sys_vp_phone_call" id="0x010800a7" /> <public type="drawable" name="stat_sys_vp_phone_call_on_hold" id="0x010800a8" /> - + <public type="anim" name="anticipate_interpolator" id="0x010a0007" /> <public type="anim" name="overshoot_interpolator" id="0x010a0008" /> <public type="anim" name="anticipate_overshoot_interpolator" id="0x010a0009" /> <public type="anim" name="bounce_interpolator" id="0x010a000a" /> <public type="anim" name="linear_interpolator" id="0x010a000b" /> - + <!-- =============================================================== Resources added in Eclair. =============================================================== --> @@ -1148,6 +1148,7 @@ <public type="attr" name="accountType" /> <public type="attr" name="contentAuthority" /> + <public type="attr" name="userVisible" /> <public type="attr" name="windowShowWallpaper" /> <public type="style" name="Theme.Wallpaper" /> |