Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c4d04ac authored by Fred Quintana's avatar Fred Quintana
Browse files

allow sync adapter authors to control more policies

- let the SyncManager know that the SyncAdapter can handle
  parallel syncs even within sync adapter types
- allow indicating that the sync adapter should be auto
  initialized without requiring the sync adapter to run first.
  When this setting is used then setIsSyncable(1) is automatically
  called for the sync adapter.

Change-Id: Ib40eba95c2556eaee4bb0fe715f379af1b72b84a
parent 6a843d03
Loading
Loading
Loading
Loading
+86 −31
Original line number Diff line number Diff line
@@ -2143,6 +2143,17 @@
 visibility="public"
>
</field>
<field name="allowParallelSyncs"
 type="int"
 transient="false"
 volatile="false"
 value="16843585"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="allowSingleTap"
 type="int"
 transient="false"
@@ -5388,6 +5399,17 @@
 visibility="public"
>
</field>
<field name="isAlwaysSyncable"
 type="int"
 transient="false"
 volatile="false"
 value="16843586"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="isDefault"
 type="int"
 transient="false"
@@ -42266,6 +42288,20 @@
<parameter name="autoInitialize" type="boolean">
</parameter>
</constructor>
<constructor name="AbstractThreadedSyncAdapter"
 type="android.content.AbstractThreadedSyncAdapter"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="context" type="android.content.Context">
</parameter>
<parameter name="autoInitialize" type="boolean">
</parameter>
<parameter name="allowParallelSyncs" type="boolean">
</parameter>
</constructor>
<method name="getContext"
 return="android.content.Context"
 abstract="false"
@@ -42320,6 +42356,19 @@
 visibility="public"
>
</method>
<method name="onSyncCanceled"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="thread" type="java.lang.Thread">
</parameter>
</method>
<field name="LOG_SYNC_DETAILS"
 type="int"
 transient="false"
@@ -55429,25 +55478,20 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="authority" type="java.lang.String">
</parameter>
<parameter name="accountType" type="java.lang.String">
</parameter>
<parameter name="userVisible" type="boolean">
</parameter>
<parameter name="supportsUploading" type="boolean">
<parameter name="source" type="android.os.Parcel">
</parameter>
</constructor>
<constructor name="SyncAdapterType"
 type="android.content.SyncAdapterType"
<method name="allowParallelSyncs"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="source" type="android.os.Parcel">
</parameter>
</constructor>
</method>
<method name="describeContents"
 return="int"
 abstract="false"
@@ -55459,6 +55503,17 @@
 visibility="public"
>
</method>
<method name="isAlwaysSyncable"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="isUserVisible"
 return="boolean"
 abstract="false"
@@ -250525,7 +250580,7 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="t" type="T">
<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
@@ -264775,9 +264830,9 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="start" type="int">
<parameter name="beginIndex" type="int">
</parameter>
<parameter name="end" type="int">
<parameter name="endIndex" type="int">
</parameter>
</method>
<method name="ensureCapacity"
@@ -267475,7 +267530,7 @@
 native="false"
 synchronized="false"
 static="true"
 final="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
@@ -273798,7 +273853,7 @@
</exception>
</method>
<method name="getClass"
 return="java.lang.Class&lt;?&gt;"
 return="java.lang.Class&lt;? extends java.lang.Object&gt;"
 abstract="false"
 native="true"
 synchronized="false"
@@ -276588,9 +276643,9 @@
>
<parameter name="data" type="byte[]">
</parameter>
<parameter name="offset" type="int">
<parameter name="start" type="int">
</parameter>
<parameter name="byteCount" type="int">
<parameter name="length" type="int">
</parameter>
</constructor>
<constructor name="String"
@@ -276604,9 +276659,9 @@
</parameter>
<parameter name="high" type="int">
</parameter>
<parameter name="offset" type="int">
<parameter name="start" type="int">
</parameter>
<parameter name="byteCount" type="int">
<parameter name="length" type="int">
</parameter>
</constructor>
<constructor name="String"
@@ -276618,9 +276673,9 @@
>
<parameter name="data" type="byte[]">
</parameter>
<parameter name="offset" type="int">
<parameter name="start" type="int">
</parameter>
<parameter name="byteCount" type="int">
<parameter name="length" type="int">
</parameter>
<parameter name="charsetName" type="java.lang.String">
</parameter>
@@ -276650,9 +276705,9 @@
>
<parameter name="data" type="byte[]">
</parameter>
<parameter name="offset" type="int">
<parameter name="start" type="int">
</parameter>
<parameter name="byteCount" type="int">
<parameter name="length" type="int">
</parameter>
<parameter name="charset" type="java.nio.charset.Charset">
</parameter>
@@ -276688,9 +276743,9 @@
>
<parameter name="data" type="char[]">
</parameter>
<parameter name="offset" type="int">
<parameter name="start" type="int">
</parameter>
<parameter name="charCount" type="int">
<parameter name="length" type="int">
</parameter>
</constructor>
<constructor name="String"
@@ -276710,7 +276765,7 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="stringBuffer" type="java.lang.StringBuffer">
<parameter name="stringbuffer" type="java.lang.StringBuffer">
</parameter>
</constructor>
<constructor name="String"
@@ -276734,7 +276789,7 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="stringBuilder" type="java.lang.StringBuilder">
<parameter name="sb" type="java.lang.StringBuilder">
</parameter>
</constructor>
<method name="charAt"
@@ -276786,9 +276841,9 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="start" type="int">
<parameter name="beginIndex" type="int">
</parameter>
<parameter name="end" type="int">
<parameter name="endIndex" type="int">
</parameter>
</method>
<method name="compareTo"
+70 −16
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;

import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
@@ -47,10 +48,11 @@ public abstract class AbstractThreadedSyncAdapter {
    private final ISyncAdapterImpl mISyncAdapterImpl;

    // all accesses to this member variable must be synchronized on mSyncThreadLock
    private SyncThread mSyncThread;
    private final HashMap<Account, SyncThread> mSyncThreads = new HashMap<Account, SyncThread>();
    private final Object mSyncThreadLock = new Object();

    private final boolean mAutoInitialize;
    private boolean mAllowParallelSyncs;

    /**
     * Creates an {@link AbstractThreadedSyncAdapter}.
@@ -62,27 +64,53 @@ public abstract class AbstractThreadedSyncAdapter {
     * is currently set to <0.
     */
    public AbstractThreadedSyncAdapter(Context context, boolean autoInitialize) {
        this(context, autoInitialize, false /* allowParallelSyncs */);
    }

    /**
     * Creates an {@link AbstractThreadedSyncAdapter}.
     * @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.
     * @param allowParallelSyncs if true then allow syncs for different accounts to run
     * at the same time, each in their own thread. This must be consistent with the setting
     * in the SyncAdapter's configuration file.
     */
    public AbstractThreadedSyncAdapter(Context context,
            boolean autoInitialize, boolean allowParallelSyncs) {
        mContext = context;
        mISyncAdapterImpl = new ISyncAdapterImpl();
        mNumSyncStarts = new AtomicInteger(0);
        mSyncThread = null;
        mAutoInitialize = autoInitialize;
        mAllowParallelSyncs = allowParallelSyncs;
    }

    public Context getContext() {
        return mContext;
    }

    private Account toSyncKey(Account account) {
        if (mAllowParallelSyncs) {
            return account;
        } else {
            return null;
        }
    }

    private 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
            // synchronize to make sure that mSyncThreads doesn't change between when we
            // check it and when we use it
            final Account threadsKey = toSyncKey(account);
            synchronized (mSyncThreadLock) {
                if (mSyncThread == null) {
                if (!mSyncThreads.containsKey(threadsKey)) {
                    if (mAutoInitialize
                            && extras != null
                            && extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) {
@@ -92,10 +120,11 @@ public abstract class AbstractThreadedSyncAdapter {
                        syncContextClient.onFinished(new SyncResult());
                        return;
                    }
                    mSyncThread = new SyncThread(
                    SyncThread syncThread = new SyncThread(
                            "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(),
                            syncContextClient, authority, account, extras);
                    mSyncThread.start();
                    mSyncThreads.put(threadsKey, syncThread);
                    syncThread.start();
                    alreadyInProgress = false;
                } else {
                    alreadyInProgress = true;
@@ -110,17 +139,25 @@ public abstract class AbstractThreadedSyncAdapter {
        }

        public void cancelSync(ISyncContext syncContext) {
            // synchronize to make sure that mSyncThread doesn't change between when we
            // synchronize to make sure that mSyncThreads doesn't change between when we
            // check it and when we use it
            final SyncThread syncThread;
            SyncThread info = null;
            synchronized (mSyncThreadLock) {
                syncThread = mSyncThread;
                for (SyncThread current : mSyncThreads.values()) {
                    if (current.mSyncContext.getSyncContextBinder() == syncContext.asBinder()) {
                        info = current;
                        break;
                    }
                }
            }
            if (syncThread != null
                    && syncThread.mSyncContext.getSyncContextBinder() == syncContext.asBinder()) {
            if (info != null) {
                if (mAllowParallelSyncs) {
                    onSyncCanceled(info);
                } else {
                    onSyncCanceled();
                }
            }
        }

        public void initialize(Account account, String authority) throws RemoteException {
            Bundle extras = new Bundle();
@@ -139,6 +176,7 @@ public abstract class AbstractThreadedSyncAdapter {
        private final String mAuthority;
        private final Account mAccount;
        private final Bundle mExtras;
        private final Account mThreadsKey;

        private SyncThread(String name, SyncContext syncContext, String authority,
                Account account, Bundle extras) {
@@ -147,6 +185,7 @@ public abstract class AbstractThreadedSyncAdapter {
            mAuthority = authority;
            mAccount = account;
            mExtras = extras;
            mThreadsKey = toSyncKey(account);
        }

        public void run() {
@@ -174,9 +213,9 @@ public abstract class AbstractThreadedSyncAdapter {
                    mSyncContext.onFinished(syncResult);
                }
                // synchronize so that the assignment will be seen by other threads
                // that also synchronize accesses to mSyncThread
                // that also synchronize accesses to mSyncThreads
                synchronized (mSyncThreadLock) {
                    mSyncThread = null;
                    mSyncThreads.remove(mThreadsKey);
                }
            }
        }
@@ -212,15 +251,30 @@ public abstract class AbstractThreadedSyncAdapter {
     * Indicates that a sync operation has been canceled. This will be invoked on a separate
     * thread than the sync thread and so you must consider the multi-threaded implications
     * of the work that you do in this method.
     *
     * <p>
     * This will only be invoked when the SyncAdapter indicates that it doesn't support
     * parallel syncs.
     */
    public void onSyncCanceled() {
        final SyncThread syncThread;
        synchronized (mSyncThreadLock) {
            syncThread = mSyncThread;
            syncThread = mSyncThreads.get(null);
        }
        if (syncThread != null) {
            syncThread.interrupt();
        }
    }

    /**
     * Indicates that a sync operation has been canceled. This will be invoked on a separate
     * thread than the sync thread and so you must consider the multi-threaded implications
     * of the work that you do in this method.
     * <p>
     * This will only be invoked when the SyncAdapter indicates that it does support
     * parallel syncs.
     * @param thread the Thread of the sync that is to be canceled.
     */
    public void onSyncCanceled(Thread thread) {
        thread.interrupt();
    }
}
+64 −2
Original line number Diff line number Diff line
@@ -30,7 +30,10 @@ public class SyncAdapterType implements Parcelable {
    public final boolean isKey;
    private final boolean userVisible;
    private final boolean supportsUploading;
    private final boolean isAlwaysSyncable;
    private final boolean allowParallelSyncs;

    /** @hide */
    public SyncAdapterType(String authority, String accountType, boolean userVisible,
            boolean supportsUploading) {
        if (TextUtils.isEmpty(authority)) {
@@ -43,6 +46,28 @@ public class SyncAdapterType implements Parcelable {
        this.accountType = accountType;
        this.userVisible = userVisible;
        this.supportsUploading = supportsUploading;
        this.isAlwaysSyncable = false;
        this.allowParallelSyncs = false;
        this.isKey = false;
    }

    /** @hide */
    public SyncAdapterType(String authority, String accountType, boolean userVisible,
            boolean supportsUploading,
            boolean isAlwaysSyncable,
            boolean allowParallelSyncs) {
        if (TextUtils.isEmpty(authority)) {
            throw new IllegalArgumentException("the authority must not be empty: " + authority);
        }
        if (TextUtils.isEmpty(accountType)) {
            throw new IllegalArgumentException("the accountType must not be empty: " + accountType);
        }
        this.authority = authority;
        this.accountType = accountType;
        this.userVisible = userVisible;
        this.supportsUploading = supportsUploading;
        this.isAlwaysSyncable = isAlwaysSyncable;
        this.allowParallelSyncs = allowParallelSyncs;
        this.isKey = false;
    }

@@ -57,6 +82,8 @@ public class SyncAdapterType implements Parcelable {
        this.accountType = accountType;
        this.userVisible = true;
        this.supportsUploading = true;
        this.isAlwaysSyncable = false;
        this.allowParallelSyncs = false;
        this.isKey = true;
    }

@@ -76,6 +103,35 @@ public class SyncAdapterType implements Parcelable {
        return userVisible;
    }

    /**
     * @return True if this SyncAdapter supports syncing multiple accounts simultaneously.
     * If false then the SyncManager will take care to only start one sync at a time
     * using this SyncAdapter.
     */
    public boolean allowParallelSyncs() {
        if (isKey) {
            throw new IllegalStateException(
                    "this method is not allowed to be called when this is a key");
        }
        return allowParallelSyncs;
    }

    /**
     * If true then the SyncManager will never issue an initialization sync to the SyncAdapter
     * and will instead automatically call
     * {@link ContentResolver#setIsSyncable(android.accounts.Account, String, int)} with a
     * value of 1 for each account and provider that this sync adapter supports.
     * @return true if the SyncAdapter does not require initialization and if it is ok for the
     * SyncAdapter to treat it as syncable automatically.
     */
    public boolean isAlwaysSyncable() {
        if (isKey) {
            throw new IllegalStateException(
                    "this method is not allowed to be called when this is a key");
        }
        return isAlwaysSyncable;
    }

    public static SyncAdapterType newKey(String authority, String accountType) {
        return new SyncAdapterType(authority, accountType);
    }
@@ -106,6 +162,8 @@ public class SyncAdapterType implements Parcelable {
                    + ", type=" + accountType
                    + ", userVisible=" + userVisible
                    + ", supportsUploading=" + supportsUploading
                    + ", isAlwaysSyncable=" + isAlwaysSyncable
                    + ", allowParallelSyncs=" + allowParallelSyncs
                    + "}";
        }
    }
@@ -123,6 +181,8 @@ public class SyncAdapterType implements Parcelable {
        dest.writeString(accountType);
        dest.writeInt(userVisible ? 1 : 0);
        dest.writeInt(supportsUploading ? 1 : 0);
        dest.writeInt(isAlwaysSyncable ? 1 : 0);
        dest.writeInt(allowParallelSyncs ? 1 : 0);
    }

    public SyncAdapterType(Parcel source) {
@@ -130,6 +190,8 @@ public class SyncAdapterType implements Parcelable {
                source.readString(),
                source.readString(),
                source.readInt() != 0,
                source.readInt() != 0,
                source.readInt() != 0,
                source.readInt() != 0);
    }

+10 −3
Original line number Diff line number Diff line
@@ -60,7 +60,14 @@ import java.io.IOException;
            final boolean supportsUploading =
                    sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_supportsUploading,
                            true);
            return new SyncAdapterType(authority, accountType, userVisible, supportsUploading);
            final boolean isAlwaysSyncable =
                    sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_isAlwaysSyncable,
                            false);
            final boolean allowParallelSyncs =
                    sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_allowParallelSyncs,
                            false);
            return new SyncAdapterType(authority, accountType, userVisible, supportsUploading,
		    isAlwaysSyncable, allowParallelSyncs);
        } finally {
            sa.recycle();
        }
+82 −76

File changed.

Preview size limit exceeded, changes collapsed.

Loading