Home | History | Annotate | Download | only in content
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.content;
     18 
     19 import android.accounts.Account;
     20 import android.os.Bundle;
     21 import android.os.Parcel;
     22 import android.os.Parcelable;
     23 
     24 public class SyncRequest implements Parcelable {
     25     private static final String TAG = "SyncRequest";
     26     /** Account to pass to the sync adapter. May be null. */
     27     private final Account mAccountToSync;
     28     /** Authority string that corresponds to a ContentProvider. */
     29     private final String mAuthority;
     30     /** Sync service identifier. May be null.*/
     31     private final ComponentName mComponentInfo;
     32     /** Bundle containing user info as well as sync settings. */
     33     private final Bundle mExtras;
     34     /** Disallow this sync request on metered networks. */
     35     private final boolean mDisallowMetered;
     36     /**
     37      * Anticipated upload size in bytes.
     38      * TODO: Not yet used - we put this information into the bundle for simplicity.
     39      */
     40     private final long mTxBytes;
     41     /**
     42      * Anticipated download size in bytes.
     43      * TODO: Not yet used - we put this information into the bundle.
     44      */
     45     private final long mRxBytes;
     46     /**
     47      * Amount of time before {@link #mSyncRunTimeSecs} from which the sync may optionally be
     48      * started.
     49      */
     50     private final long mSyncFlexTimeSecs;
     51     /**
     52      * Specifies a point in the future at which the sync must have been scheduled to run.
     53      */
     54     private final long mSyncRunTimeSecs;
     55     /** Periodic versus one-off. */
     56     private final boolean mIsPeriodic;
     57     /** Service versus provider. */
     58     private final boolean mIsAuthority;
     59     /** Sync should be run in lieu of other syncs. */
     60     private final boolean mIsExpedited;
     61 
     62     /**
     63      * {@hide}
     64      * @return whether this sync is periodic or one-time. A Sync Request must be
     65      *         either one of these or an InvalidStateException will be thrown in
     66      *         Builder.build().
     67      */
     68     public boolean isPeriodic() {
     69         return mIsPeriodic;
     70     }
     71 
     72     /**
     73      * {@hide}
     74      * @return whether this is an expedited sync.
     75      */
     76     public boolean isExpedited() {
     77         return mIsExpedited;
     78     }
     79 
     80     /**
     81      * {@hide}
     82      * @return true if this sync uses an account/authority pair, or false if this sync is bound to
     83      * a Sync Service.
     84      */
     85     public boolean hasAuthority() {
     86         return mIsAuthority;
     87     }
     88 
     89     /**
     90      * {@hide}
     91      * @return account object for this sync.
     92      * @throws IllegalArgumentException if this function is called for a request that does not
     93      * specify an account/provider authority.
     94      */
     95     public Account getAccount() {
     96         if (!hasAuthority()) {
     97             throw new IllegalArgumentException("Cannot getAccount() for a sync that does not"
     98                     + "specify an authority.");
     99         }
    100         return mAccountToSync;
    101     }
    102 
    103     /**
    104      * {@hide}
    105      * @return provider for this sync.
    106      * @throws IllegalArgumentException if this function is called for a request that does not
    107      * specify an account/provider authority.
    108      */
    109     public String getProvider() {
    110         if (!hasAuthority()) {
    111             throw new IllegalArgumentException("Cannot getProvider() for a sync that does not"
    112                     + "specify a provider.");
    113         }
    114         return mAuthority;
    115     }
    116 
    117     /**
    118      * {@hide}
    119      * Retrieve bundle for this SyncRequest. Will not be null.
    120      */
    121     public Bundle getBundle() {
    122         return mExtras;
    123     }
    124 
    125     /**
    126      * {@hide}
    127      * @return the earliest point in time that this sync can be scheduled.
    128      */
    129     public long getSyncFlexTime() {
    130         return mSyncFlexTimeSecs;
    131     }
    132 
    133     /**
    134      * {@hide}
    135      * @return the last point in time at which this sync must scheduled.
    136      */
    137     public long getSyncRunTime() {
    138         return mSyncRunTimeSecs;
    139     }
    140 
    141     public static final Creator<SyncRequest> CREATOR = new Creator<SyncRequest>() {
    142 
    143         @Override
    144         public SyncRequest createFromParcel(Parcel in) {
    145             return new SyncRequest(in);
    146         }
    147 
    148         @Override
    149         public SyncRequest[] newArray(int size) {
    150             return new SyncRequest[size];
    151         }
    152     };
    153 
    154     @Override
    155     public int describeContents() {
    156         return 0;
    157     }
    158 
    159     @Override
    160     public void writeToParcel(Parcel parcel, int flags) {
    161         parcel.writeBundle(mExtras);
    162         parcel.writeLong(mSyncFlexTimeSecs);
    163         parcel.writeLong(mSyncRunTimeSecs);
    164         parcel.writeInt((mIsPeriodic ? 1 : 0));
    165         parcel.writeInt((mDisallowMetered ? 1 : 0));
    166         parcel.writeLong(mTxBytes);
    167         parcel.writeLong(mRxBytes);
    168         parcel.writeInt((mIsAuthority ? 1 : 0));
    169         parcel.writeInt((mIsExpedited? 1 : 0));
    170         if (mIsAuthority) {
    171             parcel.writeParcelable(mAccountToSync, flags);
    172             parcel.writeString(mAuthority);
    173         } else {
    174             parcel.writeParcelable(mComponentInfo, flags);
    175         }
    176     }
    177 
    178     private SyncRequest(Parcel in) {
    179         mExtras = in.readBundle();
    180         mSyncFlexTimeSecs = in.readLong();
    181         mSyncRunTimeSecs = in.readLong();
    182         mIsPeriodic = (in.readInt() != 0);
    183         mDisallowMetered = (in.readInt() != 0);
    184         mTxBytes = in.readLong();
    185         mRxBytes = in.readLong();
    186         mIsAuthority = (in.readInt() != 0);
    187         mIsExpedited = (in.readInt() != 0);
    188         if (mIsAuthority) {
    189             mComponentInfo = null;
    190             mAccountToSync = in.readParcelable(null);
    191             mAuthority = in.readString();
    192         } else {
    193             mComponentInfo = in.readParcelable(null);
    194             mAccountToSync = null;
    195             mAuthority = null;
    196         }
    197     }
    198 
    199     /** {@hide} Protected ctor to instantiate anonymous SyncRequest. */
    200     protected SyncRequest(SyncRequest.Builder b) {
    201         mSyncFlexTimeSecs = b.mSyncFlexTimeSecs;
    202         mSyncRunTimeSecs = b.mSyncRunTimeSecs;
    203         mAccountToSync = b.mAccount;
    204         mAuthority = b.mAuthority;
    205         mComponentInfo = b.mComponentName;
    206         mIsPeriodic = (b.mSyncType == Builder.SYNC_TYPE_PERIODIC);
    207         mIsAuthority = (b.mSyncTarget == Builder.SYNC_TARGET_ADAPTER);
    208         mIsExpedited = b.mExpedited;
    209         mExtras = new Bundle(b.mCustomExtras);
    210         // For now we merge the sync config extras & the custom extras into one bundle.
    211         // TODO: pass the configuration extras through separately.
    212         mExtras.putAll(b.mSyncConfigExtras);
    213         mDisallowMetered = b.mDisallowMetered;
    214         mTxBytes = b.mTxBytes;
    215         mRxBytes = b.mRxBytes;
    216     }
    217 
    218     /**
    219      * Builder class for a {@link SyncRequest}. As you build your SyncRequest this class will also
    220      * perform validation.
    221      */
    222     public static class Builder {
    223         /** Unknown sync type. */
    224         private static final int SYNC_TYPE_UNKNOWN = 0;
    225         /** Specify that this is a periodic sync. */
    226         private static final int SYNC_TYPE_PERIODIC = 1;
    227         /** Specify that this is a one-time sync. */
    228         private static final int SYNC_TYPE_ONCE = 2;
    229         /** Unknown sync target. */
    230         private static final int SYNC_TARGET_UNKNOWN = 0;
    231         /** Specify that this is an anonymous sync. */
    232         private static final int SYNC_TARGET_SERVICE = 1;
    233         /** Specify that this is a sync with a provider. */
    234         private static final int SYNC_TARGET_ADAPTER = 2;
    235         /** Earliest point of displacement into the future at which this sync can occur. */
    236         private long mSyncFlexTimeSecs;
    237         /** Latest point of displacement into the future at which this sync must occur. */
    238         private long mSyncRunTimeSecs;
    239         /**
    240          * Sync configuration information - custom user data explicitly provided by the developer.
    241          * This data is handed over to the sync operation.
    242          */
    243         private Bundle mCustomExtras;
    244         /**
    245          * Sync system configuration -  used to store system sync configuration. Corresponds to
    246          * ContentResolver.SYNC_EXTRAS_* flags.
    247          * TODO: Use this instead of dumping into one bundle. Need to decide if these flags should
    248          * discriminate between equivalent syncs.
    249          */
    250         private Bundle mSyncConfigExtras;
    251         /** Expected upload transfer in bytes. */
    252         private long mTxBytes = -1L;
    253         /** Expected download transfer in bytes. */
    254         private long mRxBytes = -1L;
    255         /** Whether or not this sync can occur on metered networks. Default false. */
    256         private boolean mDisallowMetered;
    257         /** Priority of this sync relative to others from calling app [-2, 2]. Default 0. */
    258         private int mPriority = 0;
    259         /**
    260          * Whether this builder is building a periodic sync, or a one-time sync.
    261          */
    262         private int mSyncType = SYNC_TYPE_UNKNOWN;
    263         /** Whether this will go to a sync adapter or to a sync service. */
    264         private int mSyncTarget = SYNC_TARGET_UNKNOWN;
    265         /** Whether this is a user-activated sync. */
    266         private boolean mIsManual;
    267         /**
    268          * Whether to retry this one-time sync if the sync fails. Not valid for
    269          * periodic syncs. See {@link ContentResolver#SYNC_EXTRAS_DO_NOT_RETRY}.
    270          */
    271         private boolean mNoRetry;
    272         /**
    273          * Whether to respect back-off for this one-time sync. Not valid for
    274          * periodic syncs. See
    275          * {@link ContentResolver#SYNC_EXTRAS_IGNORE_BACKOFF};
    276          */
    277         private boolean mIgnoreBackoff;
    278 
    279         /** Ignore sync system settings and perform sync anyway. */
    280         private boolean mIgnoreSettings;
    281 
    282         /** This sync will run in preference to other non-expedited syncs. */
    283         private boolean mExpedited;
    284 
    285         /**
    286          * The sync component that contains the sync logic if this is a provider-less sync,
    287          * otherwise null.
    288          */
    289         private ComponentName mComponentName;
    290         /**
    291          * The Account object that together with an Authority name define the SyncAdapter (if
    292          * this sync is bound to a provider), otherwise null.
    293          */
    294         private Account mAccount;
    295         /**
    296          * The Authority name that together with an Account define the SyncAdapter (if
    297          * this sync is bound to a provider), otherwise null.
    298          */
    299         private String mAuthority;
    300 
    301         public Builder() {
    302         }
    303 
    304         /**
    305          * Request that a sync occur immediately.
    306          *
    307          * Example
    308          * <pre>
    309          *     SyncRequest.Builder builder = (new SyncRequest.Builder()).syncOnce();
    310          * </pre>
    311          */
    312         public Builder syncOnce() {
    313             if (mSyncType != SYNC_TYPE_UNKNOWN) {
    314                 throw new IllegalArgumentException("Sync type has already been defined.");
    315             }
    316             mSyncType = SYNC_TYPE_ONCE;
    317             setupInterval(0, 0);
    318             return this;
    319         }
    320 
    321         /**
    322          * Build a periodic sync. Either this or syncOnce() <b>must</b> be called for this builder.
    323          * Syncs are identified by target {@link android.provider}/{@link android.accounts.Account}
    324          * and by the contents of the extras bundle.
    325          * You cannot reuse the same builder for one-time syncs (by calling this function) after
    326          * having specified a periodic sync. If you do, an <code>IllegalArgumentException</code>
    327          * will be thrown.
    328          *
    329          * Example usage.
    330          *
    331          * <pre>
    332          *     Request a periodic sync every 5 hours with 20 minutes of flex.
    333          *     SyncRequest.Builder builder =
    334          *         (new SyncRequest.Builder()).syncPeriodic(5 * HOUR_IN_SECS, 20 * MIN_IN_SECS);
    335          *
    336          *     Schedule a periodic sync every hour at any point in time during that hour.
    337          *     SyncRequest.Builder builder =
    338          *         (new SyncRequest.Builder()).syncPeriodic(1 * HOUR_IN_SECS, 1 * HOUR_IN_SECS);
    339          * </pre>
    340          *
    341          * N.B.: Periodic syncs are not allowed to have any of
    342          * {@link ContentResolver#SYNC_EXTRAS_DO_NOT_RETRY},
    343          * {@link ContentResolver#SYNC_EXTRAS_IGNORE_BACKOFF},
    344          * {@link ContentResolver#SYNC_EXTRAS_IGNORE_SETTINGS},
    345          * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE},
    346          * {@link ContentResolver#SYNC_EXTRAS_FORCE},
    347          * {@link ContentResolver#SYNC_EXTRAS_EXPEDITED},
    348          * {@link ContentResolver#SYNC_EXTRAS_MANUAL}
    349          * set to true. If any are supplied then an <code>IllegalArgumentException</code> will
    350          * be thrown.
    351          *
    352          * @param pollFrequency the amount of time in seconds that you wish
    353          *            to elapse between periodic syncs.
    354          * @param beforeSeconds the amount of flex time in seconds before
    355          *            {@code pollFrequency} that you permit for the sync to take
    356          *            place. Must be less than {@code pollFrequency}.
    357          */
    358         public Builder syncPeriodic(long pollFrequency, long beforeSeconds) {
    359             if (mSyncType != SYNC_TYPE_UNKNOWN) {
    360                 throw new IllegalArgumentException("Sync type has already been defined.");
    361             }
    362             mSyncType = SYNC_TYPE_PERIODIC;
    363             setupInterval(pollFrequency, beforeSeconds);
    364             return this;
    365         }
    366 
    367         /** {@hide} */
    368         private void setupInterval(long at, long before) {
    369             if (before > at) {
    370                 throw new IllegalArgumentException("Specified run time for the sync must be" +
    371                     " after the specified flex time.");
    372             }
    373             mSyncRunTimeSecs = at;
    374             mSyncFlexTimeSecs = before;
    375         }
    376 
    377         /**
    378          * {@hide}
    379          * Developer can provide insight into their payload size; optional. -1 specifies unknown,
    380          * so that you are not restricted to defining both fields.
    381          *
    382          * @param rxBytes Bytes expected to be downloaded.
    383          * @param txBytes Bytes expected to be uploaded.
    384          */
    385         public Builder setTransferSize(long rxBytes, long txBytes) {
    386             mRxBytes = rxBytes;
    387             mTxBytes = txBytes;
    388             return this;
    389         }
    390 
    391         /**
    392          * @see android.net.ConnectivityManager#isActiveNetworkMetered()
    393          * @param disallow true to enforce that this transfer not occur on metered networks.
    394          *                 Default false.
    395          */
    396         public Builder setDisallowMetered(boolean disallow) {
    397             mDisallowMetered = disallow;
    398             return this;
    399         }
    400 
    401         /**
    402          * Specify an authority and account for this transfer.
    403          *
    404          * @param authority String identifying which content provider to sync.
    405          * @param account Account to sync. Can be null unless this is a periodic sync.
    406          */
    407         public Builder setSyncAdapter(Account account, String authority) {
    408             if (mSyncTarget != SYNC_TARGET_UNKNOWN) {
    409                 throw new IllegalArgumentException("Sync target has already been defined.");
    410             }
    411             if (authority != null && authority.length() == 0) {
    412                 throw new IllegalArgumentException("Authority must be non-empty");
    413             }
    414             mSyncTarget = SYNC_TARGET_ADAPTER;
    415             mAccount = account;
    416             mAuthority = authority;
    417             mComponentName = null;
    418             return this;
    419         }
    420 
    421         /**
    422          * Optional developer-provided extras handed back in
    423          * {@link AbstractThreadedSyncAdapter#onPerformSync(Account, Bundle, String,
    424          * ContentProviderClient, SyncResult)} occurs. This bundle is copied into the SyncRequest
    425          * returned by {@link #build()}.
    426          *
    427          * Example:
    428          * <pre>
    429          *   String[] syncItems = {"dog", "cat", "frog", "child"};
    430          *   SyncRequest.Builder builder =
    431          *     new SyncRequest.Builder()
    432          *       .setSyncAdapter(dummyAccount, dummyProvider)
    433          *       .syncOnce(5 * MINUTES_IN_SECS);
    434          *
    435          *   for (String syncData : syncItems) {
    436          *     Bundle extras = new Bundle();
    437          *     extras.setString("data", syncData);
    438          *     builder.setExtras(extras);
    439          *     ContentResolver.sync(builder.build()); // Each sync() request is for a unique sync.
    440          *   }
    441          * </pre>
    442          * Only values of the following types may be used in the extras bundle:
    443          * <ul>
    444          * <li>Integer</li>
    445          * <li>Long</li>
    446          * <li>Boolean</li>
    447          * <li>Float</li>
    448          * <li>Double</li>
    449          * <li>String</li>
    450          * <li>Account</li>
    451          * <li>null</li>
    452          * </ul>
    453          * If any data is present in the bundle not of this type, build() will
    454          * throw a runtime exception.
    455          *
    456          * @param bundle extras bundle to set.
    457          */
    458         public Builder setExtras(Bundle bundle) {
    459             mCustomExtras = bundle;
    460             return this;
    461         }
    462 
    463         /**
    464          * Convenience function for setting {@link ContentResolver#SYNC_EXTRAS_DO_NOT_RETRY}.
    465          *
    466          * A one-off sync operation that fails will be retried with exponential back-off unless
    467          * this is set to false. Not valid for periodic sync and will throw an
    468          * <code>IllegalArgumentException</code> in build().
    469          *
    470          * @param noRetry true to not retry a failed sync. Default false.
    471          */
    472         public Builder setNoRetry(boolean noRetry) {
    473             mNoRetry = noRetry;
    474             return this;
    475         }
    476 
    477         /**
    478          * Convenience function for setting {@link ContentResolver#SYNC_EXTRAS_IGNORE_SETTINGS}.
    479          *
    480          * A sync can specify that system sync settings be ignored (user has turned sync off). Not
    481          * valid for periodic sync and will throw an <code>IllegalArgumentException</code> in
    482          * {@link #build()}.
    483          *
    484          * @param ignoreSettings true to ignore the sync automatically settings. Default false.
    485          */
    486         public Builder setIgnoreSettings(boolean ignoreSettings) {
    487             mIgnoreSettings = ignoreSettings;
    488             return this;
    489         }
    490 
    491         /**
    492          * Convenience function for setting {@link ContentResolver#SYNC_EXTRAS_IGNORE_BACKOFF}.
    493          *
    494          * Force the sync scheduling process to ignore any back-off that was the result of a failed
    495          * sync, as well as to invalidate any {@link SyncResult#delayUntil} value that may have
    496          * been set by the adapter. Successive failures will not honor this flag. Not valid for
    497          * periodic sync and will throw an <code>IllegalArgumentException</code> in
    498          * {@link #build()}.
    499          *
    500          * @param ignoreBackoff ignore back-off settings. Default false.
    501          */
    502         public Builder setIgnoreBackoff(boolean ignoreBackoff) {
    503             mIgnoreBackoff = ignoreBackoff;
    504             return this;
    505         }
    506 
    507         /**
    508          * Convenience function for setting {@link ContentResolver#SYNC_EXTRAS_MANUAL}.
    509          *
    510          * A manual sync is functionally equivalent to calling {@link #setIgnoreBackoff(boolean)}
    511          * and {@link #setIgnoreSettings(boolean)}. Not valid for periodic sync and will throw an
    512          * <code>IllegalArgumentException</code> in {@link #build()}.
    513          *
    514          * @param isManual User-initiated sync or not. Default false.
    515          */
    516         public Builder setManual(boolean isManual) {
    517             mIsManual = isManual;
    518             return this;
    519         }
    520 
    521         /**
    522          * An expedited sync runs immediately and will preempt another non-expedited running sync.
    523          *
    524          * Not valid for periodic sync and will throw an <code>IllegalArgumentException</code> in
    525          * {@link #build()}.
    526          *
    527          * @param expedited whether to run expedited. Default false.
    528          */
    529         public Builder setExpedited(boolean expedited) {
    530             mExpedited = expedited;
    531             return this;
    532         }
    533 
    534         /**
    535          * {@hide}
    536          * @param priority the priority of this request among all requests from the calling app.
    537          * Range of [-2,2] similar to how this is done with notifications.
    538          */
    539         public Builder setPriority(int priority) {
    540             if (priority < -2 || priority > 2) {
    541                 throw new IllegalArgumentException("Priority must be within range [-2, 2]");
    542             }
    543             mPriority = priority;
    544             return this;
    545         }
    546 
    547         /**
    548          * Performs validation over the request and throws the runtime exception
    549          * <code>IllegalArgumentException</code> if this validation fails.
    550          *
    551          * @return a SyncRequest with the information contained within this
    552          *         builder.
    553          */
    554         public SyncRequest build() {
    555             if (mCustomExtras == null) {
    556                 mCustomExtras = new Bundle();
    557             }
    558             // Validate the extras bundle
    559             ContentResolver.validateSyncExtrasBundle(mCustomExtras);
    560             // Combine builder extra flags into the config bundle.
    561             mSyncConfigExtras = new Bundle();
    562             if (mIgnoreBackoff) {
    563                 mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
    564             }
    565             if (mDisallowMetered) {
    566                 mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED, true);
    567             }
    568             if (mIgnoreSettings) {
    569                 mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
    570             }
    571             if (mNoRetry) {
    572                 mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true);
    573             }
    574             if (mExpedited) {
    575                 mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
    576             }
    577             if (mIsManual) {
    578                 mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
    579             }
    580             mSyncConfigExtras.putLong(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD, mTxBytes);
    581             mSyncConfigExtras.putLong(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD, mRxBytes);
    582             mSyncConfigExtras.putInt(ContentResolver.SYNC_EXTRAS_PRIORITY, mPriority);
    583             if (mSyncType == SYNC_TYPE_PERIODIC) {
    584                 // If this is a periodic sync ensure than invalid extras were not set.
    585                 validatePeriodicExtras(mCustomExtras);
    586                 validatePeriodicExtras(mSyncConfigExtras);
    587                 // Verify that account and provider are not null.
    588                 if (mAccount == null) {
    589                     throw new IllegalArgumentException("Account must not be null for periodic"
    590                             + " sync.");
    591                 }
    592                 if (mAuthority == null) {
    593                     throw new IllegalArgumentException("Authority must not be null for periodic"
    594                             + " sync.");
    595                 }
    596             } else if (mSyncType == SYNC_TYPE_UNKNOWN) {
    597                 throw new IllegalArgumentException("Must call either syncOnce() or syncPeriodic()");
    598             }
    599             // Ensure that a target for the sync has been set.
    600             if (mSyncTarget == SYNC_TARGET_UNKNOWN) {
    601                 throw new IllegalArgumentException("Must specify an adapter with "
    602                         + "setSyncAdapter(Account, String");
    603             }
    604             return new SyncRequest(this);
    605         }
    606 
    607         /**
    608          * Helper function to throw an <code>IllegalArgumentException</code> if any illegal
    609          * extras were set for a periodic sync.
    610          *
    611          * @param extras bundle to validate.
    612          */
    613         private void validatePeriodicExtras(Bundle extras) {
    614             if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
    615                     || extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
    616                     || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
    617                     || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
    618                     || extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
    619                     || extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
    620                     || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
    621                 throw new IllegalArgumentException("Illegal extras were set");
    622             }
    623         }
    624     }
    625 }
    626