diff options
author | Fred Quintana <fredq@google.com> | 2009-06-16 10:24:58 -0700 |
---|---|---|
committer | Fred Quintana <fredq@google.com> | 2009-06-16 15:25:24 -0700 |
commit | 21bb0deb36af32339521038cdbd827f74468df4a (patch) | |
tree | e8f8d47fd40cda7233e2a3fd7efe355613030500 /core/java/android/content/AbstractThreadedSyncAdapter.java | |
parent | d638d8d6305bf5861736045e0215099d2fb693f1 (diff) | |
download | frameworks_base-21bb0deb36af32339521038cdbd827f74468df4a.zip frameworks_base-21bb0deb36af32339521038cdbd827f74468df4a.tar.gz frameworks_base-21bb0deb36af32339521038cdbd827f74468df4a.tar.bz2 |
beef up the syncadapter API
Diffstat (limited to 'core/java/android/content/AbstractThreadedSyncAdapter.java')
-rw-r--r-- | core/java/android/content/AbstractThreadedSyncAdapter.java | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java new file mode 100644 index 0000000..f15a902 --- /dev/null +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -0,0 +1,176 @@ +/* + * 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; + +import android.accounts.Account; +import android.os.Bundle; +import android.os.Process; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * An abstract implementation of a SyncAdapter that spawns a thread to invoke a sync operation. + * If a sync operation is already in progress when a startSync() request is received then an error + * will be returned to the new request and the existing request will be allowed to continue. + * When a startSync() is received and there is no sync operation in progress then a thread + * will be started to run the operation and {@link #performSync} will be invoked on that thread. + * If a cancelSync() is received that matches an existing sync operation then the thread + * that is running that sync operation will be interrupted, which will indicate to the thread + * that the sync has been canceled. + * + * @hide + */ +public abstract class AbstractThreadedSyncAdapter { + private final Context mContext; + private final AtomicInteger mNumSyncStarts; + private final ISyncAdapterImpl mISyncAdapterImpl; + + // all accesses to this member variable must be synchronized on "this" + private SyncThread mSyncThread; + + /** Kernel event log tag. Also listed in data/etc/event-log-tags. */ + public static final int LOG_SYNC_DETAILS = 2743; + + /** + * Creates an {@link AbstractThreadedSyncAdapter}. + * @param context the {@link Context} that this is running within. + */ + public AbstractThreadedSyncAdapter(Context context) { + mContext = context; + mISyncAdapterImpl = new ISyncAdapterImpl(); + mNumSyncStarts = new AtomicInteger(0); + mSyncThread = null; + } + + class ISyncAdapterImpl extends ISyncAdapter.Stub { + public void startSync(ISyncContext syncContext, String authority, Account account, + Bundle extras) { + final SyncContext syncContextClient = new SyncContext(syncContext); + + boolean alreadyInProgress; + // synchronize to make sure that mSyncThread doesn't change between when we + // check it and when we use it + synchronized (this) { + if (mSyncThread == null) { + mSyncThread = new SyncThread( + "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), + syncContextClient, authority, account, extras); + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + mSyncThread.start(); + alreadyInProgress = false; + } else { + alreadyInProgress = true; + } + } + + // do this outside since we don't want to call back into the syncContext while + // holding the synchronization lock + if (alreadyInProgress) { + syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS); + } + } + + public void cancelSync(ISyncContext syncContext) { + // synchronize to make sure that mSyncThread doesn't change between when we + // check it and when we use it + synchronized (this) { + if (mSyncThread != null + && mSyncThread.mSyncContext.getISyncContext() == syncContext) { + mSyncThread.interrupt(); + } + } + } + } + + /** + * The thread that invokes performSync(). It also acquires the provider for this sync + * before calling performSync and releases it afterwards. Cancel this thread in order to + * cancel the sync. + */ + private class SyncThread extends Thread { + private final SyncContext mSyncContext; + private final String mAuthority; + private final Account mAccount; + private final Bundle mExtras; + + private SyncThread(String name, SyncContext syncContext, String authority, + Account account, Bundle extras) { + super(name); + mSyncContext = syncContext; + mAuthority = authority; + mAccount = account; + mExtras = extras; + } + + public void run() { + if (isCanceled()) { + return; + } + + SyncResult syncResult = new SyncResult(); + ContentProviderClient provider = null; + try { + provider = mContext.getContentResolver().acquireContentProviderClient(mAuthority); + if (provider != null) { + AbstractThreadedSyncAdapter.this.performSync(mAccount, mExtras, + mAuthority, provider, syncResult); + } else { + // TODO(fredq) update the syncResults to indicate that we were unable to + // find the provider. maybe with a ProviderError? + } + } finally { + if (provider != null) { + provider.release(); + } + if (!isCanceled()) { + mSyncContext.onFinished(syncResult); + } + // synchronize so that the assignment will be seen by other threads + // that also synchronize accesses to mSyncThread + synchronized (this) { + mSyncThread = null; + } + } + } + + private boolean isCanceled() { + return Thread.currentThread().isInterrupted(); + } + } + + /** + * @return a reference to the ISyncAdapter interface into this SyncAdapter implementation. + */ + public final ISyncAdapter getISyncAdapter() { + return mISyncAdapterImpl; + } + + /** + * Perform a sync for this account. SyncAdapter-specific parameters may + * be specified in extras, which is guaranteed to not be null. Invocations + * of this method are guaranteed to be serialized. + * + * @param account the account that should be synced + * @param extras SyncAdapter-specific parameters + * @param authority the authority of this sync request + * @param provider a ContentProviderClient that points to the ContentProvider for this + * authority + * @param syncResult SyncAdapter-specific parameters + */ + public abstract void performSync(Account account, Bundle extras, + String authority, ContentProviderClient provider, SyncResult syncResult); +}
\ No newline at end of file |