1page.title=Creating a Sync Adapter
2
3trainingnavtop=true
4@jd:body
5
6<div id="tb-wrapper">
7<div id="tb">
8
9<h2>This lesson teaches you to</h2>
10<ol>
11    <li>
12        <a href="#CreateSyncAdapter"
13        >Create the Sync Adapter Class</a>
14    </li>
15    <li>
16        <a href="#CreateSyncAdapterService">Bind the Sync Adapter to the Framework</a>
17    </li>
18    <li>
19        <a href="#CreateAccountTypeAccount"
20        >Add the Account Required by the Framework</a>
21    </li>
22    <li>
23        <a href="#CreateSyncAdapterMetadata">Add the Sync Adapter Metadata File</a>
24    </li>
25    <li>
26        <a href="#DeclareSyncAdapterManifest">Declare the Sync Adapter in the Manifest</a>
27    </li>
28</ol>
29
30<h2>You should also read</h2>
31<ul>
32    <li>
33        <a href="{@docRoot}guide/components/bound-services.html">Bound Services</a>
34    </li>
35    <li>
36        <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
37    </li>
38    <li>
39        <a href="{@docRoot}training/id-auth/custom_auth.html">Creating a Custom Account Type</a>
40    </li>
41</ul>
42
43<h2>Try it out</h2>
44
45<div class="download-box">
46 <a href="http://developer.android.com/shareables/training/BasicSyncAdapter.zip" class="button">Download the sample</a>
47 <p class="filename">BasicSyncAdapter.zip</p>
48</div>
49
50</div>
51</div>
52<p>
53    The sync adapter component in your app encapsulates the code for the tasks that transfer
54    data between the device and a server. Based on the scheduling and triggers you provide in
55    your app, the sync adapter framework runs the code in the sync adapter component. To add a
56    sync adapter component to your app, you need to add the following pieces:
57<dl>
58    <dt>
59        Sync adapter class.
60    </dt>
61    <dd>
62        A class that wraps your data transfer code in an interface compatible with the sync adapter
63        framework.
64    </dd>
65    <dt>
66        Bound {@link android.app.Service}.
67    </dt>
68    <dd>
69        A component that allows the sync adapter framework to run the code in your sync adapter
70        class.
71    </dd>
72    <dt>
73        Sync adapter XML metadata file.
74    </dt>
75    <dd>
76        A file containing information about your sync adapter. The framework reads this file to
77        find out how to load and schedule your data transfer.
78    </dd>
79    <dt>
80        Declarations in the app manifest.
81    </dt>
82    <dd>
83        XML that declares the bound service and points to sync adapter-specific metadata.
84    </dd>
85</dl>
86<p>
87    This lesson shows you how to define these elements.
88</p>
89<h2 id="CreateSyncAdapter">Create a Sync Adapter Class</h2>
90<p>
91    In this part of the lesson you learn how to create the sync adapter class that encapsulates the
92    data transfer code. Creating the class includes extending the sync adapter base class, defining
93    constructors for the class, and implementing the method where you define the data transfer
94    tasks.
95</p>
96<h3>Extend the base sync adapter class AbstractThreadedSyncAdapter</h3>
97<p>
98    To create the sync adapter component, start by extending
99    {@link android.content.AbstractThreadedSyncAdapter} and writing its constructors. Use the
100    constructors to run setup tasks each time your sync adapter component is created from
101    scratch, just as you use {@link android.app.Activity#onCreate Activity.onCreate()} to set up an
102    activity. For example, if your app uses a content provider to store data, use the constructors
103    to get a {@link android.content.ContentResolver} instance. Since a second form of the
104    constructor was added in Android platform version 3.0 to support the {@code parallelSyncs}
105    argument, you need to create two forms of the constructor to maintain compatibility.
106</p>
107<p class="note">
108    <strong>Note:</strong> The sync adapter framework is designed to work with sync adapter
109    components that are singleton instances. Instantiating the sync adapter component is covered
110    in more detail in the section
111    <a href="#CreateSyncAdapterService">Bind the Sync Adapter to the Framework</a>.
112</p>
113<p>
114    The following example shows you how to implement
115    {@link android.content.AbstractThreadedSyncAdapter}and its constructors:
116</p>
117<pre style="clear: right">
118/**
119 * Handle the transfer of data between a server and an
120 * app, using the Android sync adapter framework.
121 */
122public class SyncAdapter extends AbstractThreadedSyncAdapter {
123    ...
124    // Global variables
125    // Define a variable to contain a content resolver instance
126    ContentResolver mContentResolver;
127    /**
128     * Set up the sync adapter
129     */
130    public SyncAdapter(Context context, boolean autoInitialize) {
131        super(context, autoInitialize);
132        /*
133         * If your app uses a content resolver, get an instance of it
134         * from the incoming Context
135         */
136        mContentResolver = context.getContentResolver();
137    }
138    ...
139    /**
140     * Set up the sync adapter. This form of the
141     * constructor maintains compatibility with Android 3.0
142     * and later platform versions
143     */
144    public SyncAdapter(
145            Context context,
146            boolean autoInitialize,
147            boolean allowParallelSyncs) {
148        super(context, autoInitialize, allowParallelSyncs);
149        /*
150         * If your app uses a content resolver, get an instance of it
151         * from the incoming Context
152         */
153        mContentResolver = context.getContentResolver();
154        ...
155    }
156</pre>
157<h3>Add the data transfer code to onPerformSync()</h3>
158<p>
159    The sync adapter component does not automatically do data transfer. Instead, it
160    encapsulates your data transfer code, so that the sync adapter framework can run the
161    data transfer in the background, without involvement from your app. When the framework is ready
162    to sync your application's data, it invokes your implementation of the method
163    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()}.
164</p>
165<p>
166    To facilitate the transfer of data from your main app code to the sync adapter component,
167    the sync adapter framework calls
168    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} with the
169    following arguments:
170</p>
171<dl>
172    <dt>
173        Account
174    </dt>
175    <dd>
176        An {@link android.accounts.Account} object associated with the event that triggered
177        the sync adapter. If your server doesn't use accounts, you don't need to use the
178        information in this object.
179    </dd>
180    <dt>
181        Extras
182    </dt>
183    <dd>
184        A {@link android.os.Bundle} containing flags sent by the event that triggered the sync
185        adapter.
186    </dd>
187    <dt>
188        Authority
189    </dt>
190    <dd>
191        The authority of a content provider in the system. Your app has to have access to
192        this provider. Usually, the authority corresponds to a content provider in your own app.
193    </dd>
194    <dt>
195        Content provider client
196    </dt>
197    <dd>
198        A {@link android.content.ContentProviderClient} for the content provider pointed to by the
199        authority argument. A {@link android.content.ContentProviderClient} is a lightweight public
200        interface to a content provider. It has the same basic functionality as a
201        {@link android.content.ContentResolver}. If you're using a content provider to store data
202        for your app, you can connect to the provider with this object. Otherwise, you can ignore
203        it.
204    </dd>
205    <dt>
206        Sync result
207    </dt>
208    <dd>
209        A {@link android.content.SyncResult} object that you use to send information to the sync
210        adapter framework.
211    </dd>
212</dl>
213<p>
214    The following snippet shows the overall structure of
215    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()}:
216</p>
217<pre>
218    /*
219     * Specify the code you want to run in the sync adapter. The entire
220     * sync adapter runs in a background thread, so you don't have to set
221     * up your own background processing.
222     */
223    &#64;Override
224    public void onPerformSync(
225            Account account,
226            Bundle extras,
227            String authority,
228            ContentProviderClient provider,
229            SyncResult syncResult) {
230    /*
231     * Put the data transfer code here.
232     */
233    ...
234    }
235</pre>
236<p>
237    While the actual implementation of
238    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} is specific to
239    your app's data synchronization requirements and server connection protocols, there are a few
240    general tasks your implementation should perform:
241</p>
242<dl>
243    <dt>
244        Connecting to a server
245    </dt>
246    <dd>
247        Although you can assume that the network is available when your data transfer starts, the
248        sync adapter framework doesn't automatically connect to a server.
249    </dd>
250    <dt>
251        Downloading and uploading data
252    </dt>
253    <dd>
254        A sync adapter doesn't automate any data transfer tasks. If you want to download
255        data from a server and store it in a content provider, you have to provide the code that
256        requests the data, downloads it, and inserts it in the provider. Similarly, if you want to
257        send data to a server, you have to read it from a file, database, or provider, and send
258        the necessary upload request. You also have to handle network errors that occur while your
259        data transfer is running.
260    </dd>
261    <dt>
262        Handling data conflicts or determining how current the data is
263    </dt>
264    <dd>
265        A sync adapter doesn't automatically handle conflicts between data on the server and data
266        on the device. Also, it doesn't automatically detect if the data on the server is newer than
267        the data on the device, or vice versa. Instead, you have to provide your own algorithms for
268        handling this situation.
269    </dd>
270    <dt>
271        Clean up.
272    </dt>
273    <dd>
274        Always close connections to a server and clean up temp files and caches at the end of
275        your data transfer.
276    </dd>
277</dl>
278<p class="note">
279    <strong>Note:</strong> The sync adapter framework runs
280    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} on a
281    background thread, so you don't have to set up your own background processing.
282</p>
283<p>
284    In addition to your sync-related tasks, you should try to combine your regular
285    network-related tasks and add them to
286    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()}.
287    By concentrating all of your network tasks in this method, you conserve the battery power that's
288    needed to start and stop the network interfaces. To learn more about making network access more
289    efficient, see the training class <a href="{@docRoot}training/efficient-downloads/index.html"
290    >Transferring Data Without Draining the Battery</a>, which describes several network access
291    tasks you can include in your data transfer code.
292</p>
293<h2 id="CreateSyncAdapterService">Bind the Sync Adapter to the Framework</h2>
294<p>
295    You now have your data transfer code encapsulated in a sync adapter component, but you have
296    to provide the framework with access to your code. To do this, you need to create a bound
297    {@link android.app.Service} that passes a special Android binder object from the sync adapter
298    component to the framework. With this binder object, the framework can invoke the
299    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} method and
300    pass data to it.
301</p>
302<p>
303    Instantiate your sync adapter component as a singleton in the
304    {@link android.app.Service#onCreate onCreate()} method of the service. By instantiating
305    the component in {@link android.app.Service#onCreate onCreate()}, you defer
306    creating it until the service starts, which happens when the framework first tries to run your
307    data transfer. You need to instantiate the component in a thread-safe manner, in case the sync
308    adapter framework queues up multiple executions of your sync adapter in response to triggers or
309    scheduling.
310</p>
311<p>
312    For example, the following snippet shows you how to create a class that implements the
313    bound {@link android.app.Service}, instantiates your sync adapter component, and gets the
314    Android binder object:
315</p>
316<pre>
317package com.example.android.syncadapter;
318/**
319 * Define a Service that returns an {@link android.os.IBinder} for the
320 * sync adapter class, allowing the sync adapter framework to call
321 * onPerformSync().
322 */
323public class SyncService extends Service {
324    // Storage for an instance of the sync adapter
325    private static SyncAdapter sSyncAdapter = null;
326    // Object to use as a thread-safe lock
327    private static final Object sSyncAdapterLock = new Object();
328    /*
329     * Instantiate the sync adapter object.
330     */
331    &#64;Override
332    public void onCreate() {
333        /*
334         * Create the sync adapter as a singleton.
335         * Set the sync adapter as syncable
336         * Disallow parallel syncs
337         */
338        synchronized (sSyncAdapterLock) {
339            if (sSyncAdapter == null) {
340                sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
341            }
342        }
343    }
344    /**
345     * Return an object that allows the system to invoke
346     * the sync adapter.
347     *
348     */
349    &#64;Override
350    public IBinder onBind(Intent intent) {
351        /*
352         * Get the object that allows external processes
353         * to call onPerformSync(). The object is created
354         * in the base class code when the SyncAdapter
355         * constructors call super()
356         */
357        return sSyncAdapter.getSyncAdapterBinder();
358    }
359}
360</pre>
361<p class="note">
362    <strong>Note:</strong> To see a more detailed example of a bound service for a sync adapter,
363    see the sample app.
364</p>
365<h2 id="CreateAccountTypeAccount">Add the Account Required by the Framework</h2>
366<p>
367    The sync adapter framework requires each sync adapter to have an account type. You declared
368    the account type value in the section
369    <a href="creating-authenticator.html#CreateAuthenticatorFile"
370    >Add the Authenticator Metadata File</a>. Now you have to set up this account type in the
371    Android system. To set up the account type, add a dummy account that uses the account type
372    by calling {@link android.accounts.AccountManager#addAccountExplicitly addAccountExplicitly()}.
373</p>
374<p>
375    The best place to call the method is in the
376    {@link android.support.v4.app.FragmentActivity#onCreate onCreate()} method of your app's
377    opening activity. The following code snippet shows you how to do this:
378</p>
379<pre>
380public class MainActivity extends FragmentActivity {
381    ...
382    ...
383    // Constants
384    // The authority for the sync adapter's content provider
385    public static final String AUTHORITY = "com.example.android.datasync.provider"
386    // An account type, in the form of a domain name
387    public static final String ACCOUNT_TYPE = "example.com";
388    // The account name
389    public static final String ACCOUNT = "dummyaccount";
390    // Instance fields
391    Account mAccount;
392    ...
393    &#64;Override
394    protected void onCreate(Bundle savedInstanceState) {
395        super.onCreate(savedInstanceState);
396        ...
397        // Create the dummy account
398        mAccount = CreateSyncAccount(this);
399        ...
400    }
401    ...
402    /**
403     * Create a new dummy account for the sync adapter
404     *
405     * @param context The application context
406     */
407    public static Account CreateSyncAccount(Context context) {
408        // Create the account type and default account
409        Account newAccount = new Account(
410                ACCOUNT, ACCOUNT_TYPE);
411        // Get an instance of the Android account manager
412        AccountManager accountManager =
413                (AccountManager) context.getSystemService(
414                        ACCOUNT_SERVICE);
415        /*
416         * Add the account and account type, no password or user data
417         * If successful, return the Account object, otherwise report an error.
418         */
419        if (accountManager.addAccountExplicitly(newAccount, null, null))) {
420            /*
421             * If you don't set android:syncable="true" in
422             * in your &lt;provider&gt; element in the manifest,
423             * then call context.setIsSyncable(account, AUTHORITY, 1)
424             * here.
425             */
426        } else {
427            /*
428             * The account exists or some other error occurred. Log this, report it,
429             * or handle it internally.
430             */
431        }
432    }
433    ...
434}
435</pre>
436<h2 id="CreateSyncAdapterMetadata">Add the Sync Adapter Metadata File</h2>
437<p>
438    To plug your sync adapter component into the framework, you need to provide the framework
439    with metadata that describes the component and provides additional flags. The metadata specifies
440    the account type you've created for your sync adapter, declares a content provider authority
441    associated with your app, controls a part of the system user interface related to sync adapters,
442    and declares other sync-related flags. Declare this metadata in a special XML file stored in
443    the {@code /res/xml/} directory in your app project. You can give any name to the file,
444    although it's usually called {@code syncadapter.xml}.
445</p>
446<p>
447    This XML file contains a single XML element <code>&lt;sync-adapter&gt;</code> that has the
448    following attributes:
449</p>
450<dl>
451    <dt><code>android:contentAuthority</code></dt>
452    <dd>
453        The URI authority for your content provider. If you created a stub content provider for
454        your app in the previous lesson <a href="creating-stub-provider.html"
455        >Creating a Stub Content Provider</a>, use the value you specified for the
456        attribute
457<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">android:authorities</a></code>
458        in the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"
459        >&lt;provider&gt;</a></code> element you added to your app manifest. This attribute is
460        described in more detail in the section
461        <a href="creating-stub-provider.html#DeclareProvider"
462        >Declare the Provider in the Manifest</a>.
463        <br/>
464        If you're transferring data from a content provider to a server with your sync adapter, this
465        value should be the same as the content URI authority you're using for that data. This value
466        is also one of the authorities you specify in the
467<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">android:authorities</a></code>
468        attribute of the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"
469        >&lt;provider&gt;</a></code> element that declares your provider in your app manifest.
470    </dd>
471    <dt><code>android:accountType</code></dt>
472    <dd>
473        The account type required by the sync adapter framework. The value must be the same
474        as the account type value you provided when you created the authenticator metadata file, as
475        described in the section <a href="creating-authenticator.html#CreateAuthenticatorFile"
476        >Add the Authenticator Metadata File</a>. It's also the value you specified for the
477        constant {@code ACCOUNT_TYPE} in the code snippet in the section
478        <a href="#CreateAccountTypeAccount">Add the Account Required by the Framework</a>.
479    </dd>
480    <dt>Settings attributes</dt>
481    <dd>
482        <dl>
483            <dt>
484                {@code android:userVisible}
485            </dt>
486            <dd>
487                Sets the visibility of the sync adapter's account type. By default, the
488                account icon and label associated with the account type are visible in the
489                <b>Accounts</b> section of the system's Settings app, so you should make your sync
490                adapter invisible unless you have an account type or domain that's easily associated
491                with your app. If you make your account type invisible, you can still allow users to
492                control your sync adapter with a user interface in one of your app's activities.
493            </dd>
494            <dt>
495                {@code android:supportsUploading}
496            </dt>
497            <dd>
498                Allows you to upload data to the cloud. Set this to {@code false} if your app only
499                downloads data.
500            </dd>
501            <dt>
502                {@code android:allowParallelSyncs}
503            </dt>
504            <dd>
505                Allows multiple instances of your sync adapter component to run at the same time.
506                Use this if your app supports multiple user accounts and you want to allow multiple
507                users to transfer data in parallel. This flag has no effect if you never run
508                multiple data transfers.
509            </dd>
510            <dt>
511                {@code android:isAlwaysSyncable}
512            </dt>
513            <dd>
514                Indicates to the sync adapter framework that it can run your sync adapter at any
515                time you've specified. If you want to programmatically control when your sync
516                adapter can run, set this flag to {@code false}, and then call
517                {@link android.content.ContentResolver#requestSync requestSync()} to run the
518                sync adapter. To learn more about running a sync adapter, see the lesson
519                <a href="running-sync-adapter.html">Running a Sync Adapter</a>
520            </dd>
521        </dl>
522    </dd>
523</dl>
524<p>
525    The following example shows the XML for a sync adapter that uses a single dummy account and
526    only does downloads.
527</p>
528<pre>
529&lt;?xml version="1.0" encoding="utf-8"?&gt;
530&lt;sync-adapter
531        xmlns:android="http://schemas.android.com/apk/res/android"
532        android:contentAuthority="com.example.android.datasync.provider"
533        android:accountType="com.android.example.datasync"
534        android:userVisible="false"
535        android:supportsUploading="false"
536        android:allowParallelSyncs="false"
537        android:isAlwaysSyncable="true"/&gt;
538</pre>
539
540<h2 id="DeclareSyncAdapterManifest">Declare the Sync Adapter in the Manifest</h2>
541<p>
542    Once you've added the sync adapter component to your app, you have to request permissions
543    related to using the component, and you have to declare the bound {@link android.app.Service}
544    you've added.
545</p>
546<p>
547    Since the sync adapter component runs code that transfers data between the network and the
548    device, you need to request permission to access the Internet. In addition, your app needs
549    to request permission to read and write sync adapter settings, so you can control the sync
550    adapter programmatically from other components in your app. You also need to request a
551    special permission that allows your app to use the authenticator component you created
552    in the lesson <a href="creating-authenticator.html">Creating a Stub Authenticator</a>.
553</p>
554<p>
555    To request these permissions, add the following to your app manifest as child elements of
556<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>:
557</p>
558<dl>
559    <dt>
560        {@link android.Manifest.permission#INTERNET android.permission.INTERNET}
561    </dt>
562    <dd>
563        Allows the sync adapter code to access the Internet so that it can download or upload data
564        from the device to a server. You don't need to add this permission again if you were
565        requesting it previously.
566    </dd>
567    <dt>
568{@link android.Manifest.permission#READ_SYNC_SETTINGS android.permission.READ_SYNC_SETTINGS}
569    </dt>
570    <dd>
571        Allows your app to read the current sync adapter settings. For example, you need this
572        permission in order to call {@link android.content.ContentResolver#getIsSyncable
573        getIsSyncable()}.
574    </dd>
575    <dt>
576{@link android.Manifest.permission#WRITE_SYNC_SETTINGS android.permission.WRITE_SYNC_SETTINGS}
577    </dt>
578    <dd>
579        Allows your app to control sync adapter settings. You need this permission in order to
580        set periodic sync adapter runs using {@link android.content.ContentResolver#addPeriodicSync
581        addPeriodicSync()}. This permission is <b>not</b> required to call
582        {@link android.content.ContentResolver#requestSync requestSync()}. To learn more about
583        running the sync adapter, see <a href="running-sync-adapter.html"
584        >Running A Sync Adapter</a>.
585    </dd>
586</dl>
587<p>
588    The following snippet shows how to add the permissions:
589</p>
590<pre>
591&lt;manifest&gt;
592...
593    &lt;uses-permission
594            android:name="android.permission.INTERNET"/&gt;
595    &lt;uses-permission
596            android:name="android.permission.READ_SYNC_SETTINGS"/&gt;
597    &lt;uses-permission
598            android:name="android.permission.WRITE_SYNC_SETTINGS"/&gt;
599    &lt;uses-permission
600            android:name="android.permission.AUTHENTICATE_ACCOUNTS"/&gt;
601...
602&lt;/manifest&gt;
603</pre>
604<p>
605    Finally, to declare the bound {@link android.app.Service} that the framework uses to
606    interact with your sync adapter, add the following XML to your app manifest as a child element
607    of <code><a href="{@docRoot}guide/topics/manifest/application-element.html"
608    >&lt;application&gt;</a></code>:
609</p>
610<pre>
611        &lt;service
612                android:name="com.example.android.datasync.SyncService"
613                android:exported="true"
614                android:process=":sync"&gt;
615            &lt;intent-filter&gt;
616                &lt;action android:name="android.content.SyncAdapter"/&gt;
617            &lt;/intent-filter&gt;
618            &lt;meta-data android:name="android.content.SyncAdapter"
619                    android:resource="&#64;xml/syncadapter" /&gt;
620        &lt;/service&gt;
621</pre>
622<p>
623    The
624<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
625    element sets up a filter that's triggered by the intent action
626    {@code android.content.SyncAdapter}, sent by the system to run the sync adapter. When the filter
627    is triggered, the system starts the bound service you've created, which in this example is
628    {@code SyncService}. The attribute
629<code><a href="{@docRoot}guide/topics/manifest/service-element.html#exported">android:exported="true"</a></code>
630    allows processes other than your app (including the system) to access the
631    {@link android.app.Service}. The attribute
632<code><a href="{@docRoot}guide/topics/manifest/service-element.html#proc">android:process=":sync"</a></code>
633    tells the system to run the {@link android.app.Service} in a global shared process named
634    {@code sync}. If you have multiple sync adapters in your app they can share this process,
635    which reduces overhead.
636</p>
637<p>
638    The
639<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
640    element provides provides the name of the sync adapter metadata XML file you created previously.
641    The
642<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code>
643    attribute indicates that this metadata is for the sync adapter framework. The
644<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#rsrc">android:resource</a></code>
645    element specifies the name of the metadata file.
646</p>
647<p>
648    You now have all of the components for your sync adapter. The next lesson shows you how to
649    tell the sync adapter framework to run your sync adapter, either in response to an event or on
650    a regular schedule.
651</p>
652