Merge mozilla-central into mozilla-inbound
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 03 Jan 2013 01:06:46 -0500
changeset 117421 d8603eadb9d01231f3afe42cc81074b98394b56a
parent 117420 c78f5379558a29a24b9e9e343a0754bffcc93073 (current diff)
parent 117370 6955309291ee4afe219fee09987f3838ccf5ac83 (diff)
child 117422 2fba029be56a2ba5f9754d04f5a8d3bff67c06fb
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone20.0a1
Merge mozilla-central into mozilla-inbound
--- a/browser/components/preferences/in-content/sync.js
+++ b/browser/components/preferences/in-content/sync.js
@@ -112,17 +112,17 @@ let gSyncPane = {
    * 
    * @param wizardType
    *        Indicates type of wizard to launch:
    *          null    -- regular set up wizard
    *          "pair"  -- pair a device first
    *          "reset" -- reset sync
    */
   openSetup: function (wizardType) {
-    var win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
+    let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
     if (win)
       win.focus();
     else {
       window.openDialog("chrome://browser/content/sync/setup.xul",
                         "weaveSetup", "centerscreen,chrome,resizable=no",
                         wizardType);
     }
   },
@@ -145,11 +145,11 @@ let gSyncPane = {
       win.focus();
     else 
       window.openDialog("chrome://browser/content/sync/addDevice.xul",
                         "syncAddDevice", "centerscreen,chrome,resizable=no");
   },
 
   resetSync: function () {
     this.openSetup("reset");
-  }
-}
+  },
+};
 
--- a/browser/components/preferences/sync.js
+++ b/browser/components/preferences/sync.js
@@ -113,17 +113,17 @@ let gSyncPane = {
    * 
    * @param wizardType
    *        Indicates type of wizard to launch:
    *          null    -- regular set up wizard
    *          "pair"  -- pair a device first
    *          "reset" -- reset sync
    */
   openSetup: function (wizardType) {
-    var win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
+    let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
     if (win)
       win.focus();
     else {
       window.openDialog("chrome://browser/content/sync/setup.xul",
                         "weaveSetup", "centerscreen,chrome,resizable=no",
                         wizardType);
     }
   },
@@ -146,11 +146,11 @@ let gSyncPane = {
       win.focus();
     else 
       window.openDialog("chrome://browser/content/sync/addDevice.xul",
                         "syncAddDevice", "centerscreen,chrome,resizable=no");
   },
 
   resetSync: function () {
     this.openSetup("reset");
-  }
-}
+  },
+};
 
--- a/mobile/android/base/android-services-files.mk
+++ b/mobile/android/base/android-services-files.mk
@@ -1,14 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # These files are managed in the android-sync repo. Do not modify directly, or your changes will be lost.
-SYNC_JAVA_FILES := background/announcements/Announcement.java background/announcements/AnnouncementPresenter.java background/announcements/AnnouncementsBroadcastReceiver.java background/announcements/AnnouncementsBroadcastService.java background/announcements/AnnouncementsFetchDelegate.java background/announcements/AnnouncementsFetcher.java background/announcements/AnnouncementsFetchResourceDelegate.java background/announcements/AnnouncementsService.java background/announcements/AnnouncementsStartReceiver.java background/BackgroundConstants.java sync/AlreadySyncingException.java sync/CollectionKeys.java sync/CommandProcessor.java sync/CommandRunner.java sync/config/AccountPickler.java sync/config/activities/SelectEnginesActivity.java sync/config/ClientRecordTerminator.java sync/config/ConfigurationMigrator.java sync/CredentialException.java sync/CredentialsSource.java sync/crypto/CryptoException.java sync/crypto/CryptoInfo.java sync/crypto/HKDF.java sync/crypto/HMACVerificationException.java sync/crypto/KeyBundle.java sync/crypto/MissingCryptoInputException.java sync/crypto/NoKeyBundleException.java sync/crypto/PersistedCrypto5Keys.java sync/CryptoRecord.java sync/DelayedWorkTracker.java sync/delegates/ClientsDataDelegate.java sync/delegates/FreshStartDelegate.java sync/delegates/GlobalSessionCallback.java sync/delegates/JSONRecordFetchDelegate.java sync/delegates/KeyUploadDelegate.java sync/delegates/MetaGlobalDelegate.java sync/delegates/WipeServerDelegate.java sync/EngineSettings.java sync/ExtendedJSONObject.java sync/GlobalSession.java sync/HTTPFailureException.java sync/InfoCollections.java sync/InfoCounts.java sync/jpake/BigIntegerHelper.java sync/jpake/Gx3OrGx4IsZeroOrOneException.java sync/jpake/IncorrectZkpException.java sync/jpake/JPakeClient.java sync/jpake/JPakeCrypto.java sync/jpake/JPakeJson.java sync/jpake/JPakeNoActivePairingException.java sync/jpake/JPakeNumGenerator.java sync/jpake/JPakeNumGeneratorRandom.java sync/jpake/JPakeParty.java sync/jpake/JPakeRequest.java sync/jpake/JPakeRequestDelegate.java sync/jpake/JPakeResponse.java sync/jpake/stage/CompleteStage.java sync/jpake/stage/ComputeFinalStage.java sync/jpake/stage/ComputeKeyVerificationStage.java sync/jpake/stage/ComputeStepOneStage.java sync/jpake/stage/ComputeStepTwoStage.java sync/jpake/stage/DecryptDataStage.java sync/jpake/stage/DeleteChannel.java sync/jpake/stage/GetChannelStage.java sync/jpake/stage/GetRequestStage.java sync/jpake/stage/JPakeStage.java sync/jpake/stage/PutRequestStage.java sync/jpake/stage/VerifyPairingStage.java sync/jpake/Zkp.java sync/JSONRecordFetcher.java sync/KeyBundleProvider.java sync/log/writers/AndroidLevelCachingLogWriter.java sync/log/writers/AndroidLogWriter.java sync/log/writers/LevelFilteringLogWriter.java sync/log/writers/LogWriter.java sync/log/writers/PrintLogWriter.java sync/log/writers/SimpleTagLogWriter.java sync/log/writers/StringLogWriter.java sync/log/writers/TagLogWriter.java sync/log/writers/ThreadLocalTagLogWriter.java sync/Logger.java sync/MetaGlobal.java sync/MetaGlobalException.java sync/MetaGlobalMissingEnginesException.java sync/MetaGlobalNotSetException.java sync/middleware/Crypto5MiddlewareRepository.java sync/middleware/Crypto5MiddlewareRepositorySession.java sync/middleware/MiddlewareRepository.java sync/middleware/MiddlewareRepositorySession.java sync/net/BaseResource.java sync/net/ConnectionMonitorThread.java sync/net/HandleProgressException.java sync/net/HttpResponseObserver.java sync/net/Resource.java sync/net/ResourceDelegate.java sync/net/SyncResourceDelegate.java sync/net/SyncResponse.java sync/net/SyncStorageCollectionRequest.java sync/net/SyncStorageCollectionRequestDelegate.java sync/net/SyncStorageRecordRequest.java sync/net/SyncStorageRequest.java sync/net/SyncStorageRequestDelegate.java sync/net/SyncStorageRequestIncrementalDelegate.java sync/net/SyncStorageResponse.java sync/net/TLSSocketFactory.java sync/net/WBOCollectionRequestDelegate.java sync/net/WBORequestDelegate.java sync/NoCollectionKeysSetException.java sync/NodeAuthenticationException.java sync/NonArrayJSONException.java sync/NonObjectJSONException.java sync/NullClusterURLException.java sync/PersistedMetaGlobal.java sync/PrefsSource.java sync/receivers/SyncAccountDeletedReceiver.java sync/receivers/SyncAccountDeletedService.java sync/receivers/UpgradeReceiver.java sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java sync/repositories/android/AndroidBrowserBookmarksRepository.java sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java sync/repositories/android/AndroidBrowserHistoryDataAccessor.java sync/repositories/android/AndroidBrowserHistoryDataExtender.java sync/repositories/android/AndroidBrowserHistoryRepository.java sync/repositories/android/AndroidBrowserHistoryRepositorySession.java sync/repositories/android/AndroidBrowserRepository.java sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java sync/repositories/android/AndroidBrowserRepositorySession.java sync/repositories/android/BookmarksDeletionManager.java sync/repositories/android/BookmarksInsertionManager.java sync/repositories/android/BrowserContractHelpers.java sync/repositories/android/CachedSQLiteOpenHelper.java sync/repositories/android/ClientsDatabase.java sync/repositories/android/ClientsDatabaseAccessor.java sync/repositories/android/FennecControlHelper.java sync/repositories/android/FennecTabsRepository.java sync/repositories/android/FormHistoryRepositorySession.java sync/repositories/android/PasswordsRepositorySession.java sync/repositories/android/RepoUtils.java sync/repositories/BookmarkNeedsReparentingException.java sync/repositories/BookmarksRepository.java sync/repositories/ConstrainedServer11Repository.java sync/repositories/delegates/DeferrableRepositorySessionCreationDelegate.java sync/repositories/delegates/DeferredRepositorySessionBeginDelegate.java sync/repositories/delegates/DeferredRepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/DeferredRepositorySessionFinishDelegate.java sync/repositories/delegates/DeferredRepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionBeginDelegate.java sync/repositories/delegates/RepositorySessionCleanDelegate.java sync/repositories/delegates/RepositorySessionCreationDelegate.java sync/repositories/delegates/RepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/RepositorySessionFinishDelegate.java sync/repositories/delegates/RepositorySessionGuidsSinceDelegate.java sync/repositories/delegates/RepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionWipeDelegate.java sync/repositories/domain/BookmarkRecord.java sync/repositories/domain/BookmarkRecordFactory.java sync/repositories/domain/ClientRecord.java sync/repositories/domain/ClientRecordFactory.java sync/repositories/domain/FormHistoryRecord.java sync/repositories/domain/HistoryRecord.java sync/repositories/domain/HistoryRecordFactory.java sync/repositories/domain/PasswordRecord.java sync/repositories/domain/Record.java sync/repositories/domain/TabsRecord.java sync/repositories/domain/VersionConstants.java sync/repositories/FetchFailedException.java sync/repositories/HashSetStoreTracker.java sync/repositories/HistoryRepository.java sync/repositories/IdentityRecordFactory.java sync/repositories/InactiveSessionException.java sync/repositories/InvalidBookmarkTypeException.java sync/repositories/InvalidRequestException.java sync/repositories/InvalidSessionTransitionException.java sync/repositories/MultipleRecordsForGuidException.java sync/repositories/NoContentProviderException.java sync/repositories/NoGuidForIdException.java sync/repositories/NoStoreDelegateException.java sync/repositories/NullCursorException.java sync/repositories/ParentNotFoundException.java sync/repositories/ProfileDatabaseException.java sync/repositories/RecordFactory.java sync/repositories/RecordFilter.java sync/repositories/Repository.java sync/repositories/RepositorySession.java sync/repositories/RepositorySessionBundle.java sync/repositories/Server11Repository.java sync/repositories/Server11RepositorySession.java sync/repositories/StoreFailedException.java sync/repositories/StoreTracker.java sync/repositories/StoreTrackingRepositorySession.java sync/Server11PreviousPostFailedException.java sync/Server11RecordPostFailedException.java sync/setup/activities/AccountActivity.java sync/setup/activities/ActivityUtils.java sync/setup/activities/ClientRecordArrayAdapter.java sync/setup/activities/RedirectToSetupActivity.java sync/setup/activities/SendTabActivity.java sync/setup/activities/SetupFailureActivity.java sync/setup/activities/SetupSuccessActivity.java sync/setup/activities/SetupSyncActivity.java sync/setup/activities/SyncActivity.java sync/setup/activities/WebViewActivity.java sync/setup/auth/AccountAuthenticator.java sync/setup/auth/AuthenticateAccountStage.java sync/setup/auth/AuthenticationResult.java sync/setup/auth/AuthenticatorStage.java sync/setup/auth/EnsureUserExistenceStage.java sync/setup/auth/FetchUserNodeStage.java sync/setup/Constants.java sync/setup/InvalidSyncKeyException.java sync/setup/SyncAccounts.java sync/setup/SyncAuthenticatorService.java sync/stage/AbstractNonRepositorySyncStage.java sync/stage/AndroidBrowserBookmarksServerSyncStage.java sync/stage/AndroidBrowserHistoryServerSyncStage.java sync/stage/CheckPreconditionsStage.java sync/stage/CompletedStage.java sync/stage/EnsureClusterURLStage.java sync/stage/EnsureCrypto5KeysStage.java sync/stage/FennecTabsServerSyncStage.java sync/stage/FetchInfoCollectionsStage.java sync/stage/FetchMetaGlobalStage.java sync/stage/FormHistoryServerSyncStage.java sync/stage/GlobalSyncStage.java sync/stage/NoSuchStageException.java sync/stage/NoSyncIDException.java sync/stage/PasswordsServerSyncStage.java sync/stage/SafeConstrainedServer11Repository.java sync/stage/ServerSyncStage.java sync/stage/SyncClientsEngineStage.java sync/stage/UploadMetaGlobalStage.java sync/StubActivity.java sync/syncadapter/SyncAdapter.java sync/syncadapter/SyncService.java sync/SyncConfiguration.java sync/SyncConfigurationException.java sync/SyncException.java sync/synchronizer/ConcurrentRecordConsumer.java sync/synchronizer/RecordConsumer.java sync/synchronizer/RecordsChannel.java sync/synchronizer/RecordsChannelDelegate.java sync/synchronizer/RecordsConsumerDelegate.java sync/synchronizer/SerialRecordConsumer.java sync/synchronizer/ServerLocalSynchronizer.java sync/synchronizer/ServerLocalSynchronizerSession.java sync/synchronizer/SessionNotBegunException.java sync/synchronizer/Synchronizer.java sync/synchronizer/SynchronizerDelegate.java sync/synchronizer/SynchronizerSession.java sync/synchronizer/SynchronizerSessionDelegate.java sync/synchronizer/UnbundleError.java sync/synchronizer/UnexpectedSessionException.java sync/SynchronizerConfiguration.java sync/ThreadPool.java sync/UnexpectedJSONException.java sync/UnknownSynchronizerConfigurationVersionException.java sync/Utils.java
+SYNC_JAVA_FILES := background/announcements/Announcement.java background/announcements/AnnouncementPresenter.java background/announcements/AnnouncementsBroadcastReceiver.java background/announcements/AnnouncementsBroadcastService.java background/announcements/AnnouncementsFetchDelegate.java background/announcements/AnnouncementsFetcher.java background/announcements/AnnouncementsFetchResourceDelegate.java background/announcements/AnnouncementsService.java background/announcements/AnnouncementsStartReceiver.java background/BackgroundConstants.java sync/AlreadySyncingException.java sync/CollectionKeys.java sync/CommandProcessor.java sync/CommandRunner.java sync/config/AccountPickler.java sync/config/activities/SelectEnginesActivity.java sync/config/ClientRecordTerminator.java sync/config/ConfigurationMigrator.java sync/CredentialException.java sync/CredentialsSource.java sync/crypto/CryptoException.java sync/crypto/CryptoInfo.java sync/crypto/HKDF.java sync/crypto/HMACVerificationException.java sync/crypto/KeyBundle.java sync/crypto/MissingCryptoInputException.java sync/crypto/NoKeyBundleException.java sync/crypto/PersistedCrypto5Keys.java sync/CryptoRecord.java sync/DelayedWorkTracker.java sync/delegates/ClientsDataDelegate.java sync/delegates/FreshStartDelegate.java sync/delegates/GlobalSessionCallback.java sync/delegates/JSONRecordFetchDelegate.java sync/delegates/KeyUploadDelegate.java sync/delegates/MetaGlobalDelegate.java sync/delegates/WipeServerDelegate.java sync/EngineSettings.java sync/ExtendedJSONObject.java sync/GlobalSession.java sync/HTTPFailureException.java sync/InfoCollections.java sync/InfoCounts.java sync/jpake/BigIntegerHelper.java sync/jpake/Gx3OrGx4IsZeroOrOneException.java sync/jpake/IncorrectZkpException.java sync/jpake/JPakeClient.java sync/jpake/JPakeCrypto.java sync/jpake/JPakeJson.java sync/jpake/JPakeNoActivePairingException.java sync/jpake/JPakeNumGenerator.java sync/jpake/JPakeNumGeneratorRandom.java sync/jpake/JPakeParty.java sync/jpake/JPakeRequest.java sync/jpake/JPakeRequestDelegate.java sync/jpake/JPakeResponse.java sync/jpake/stage/CompleteStage.java sync/jpake/stage/ComputeFinalStage.java sync/jpake/stage/ComputeKeyVerificationStage.java sync/jpake/stage/ComputeStepOneStage.java sync/jpake/stage/ComputeStepTwoStage.java sync/jpake/stage/DecryptDataStage.java sync/jpake/stage/DeleteChannel.java sync/jpake/stage/GetChannelStage.java sync/jpake/stage/GetRequestStage.java sync/jpake/stage/JPakeStage.java sync/jpake/stage/PutRequestStage.java sync/jpake/stage/VerifyPairingStage.java sync/jpake/Zkp.java sync/JSONRecordFetcher.java sync/KeyBundleProvider.java sync/log/writers/AndroidLevelCachingLogWriter.java sync/log/writers/AndroidLogWriter.java sync/log/writers/LevelFilteringLogWriter.java sync/log/writers/LogWriter.java sync/log/writers/PrintLogWriter.java sync/log/writers/SimpleTagLogWriter.java sync/log/writers/StringLogWriter.java sync/log/writers/TagLogWriter.java sync/log/writers/ThreadLocalTagLogWriter.java sync/Logger.java sync/MetaGlobal.java sync/MetaGlobalException.java sync/MetaGlobalMissingEnginesException.java sync/MetaGlobalNotSetException.java sync/middleware/Crypto5MiddlewareRepository.java sync/middleware/Crypto5MiddlewareRepositorySession.java sync/middleware/MiddlewareRepository.java sync/middleware/MiddlewareRepositorySession.java sync/net/AuthHeaderProvider.java sync/net/BaseResource.java sync/net/BaseResourceDelegate.java sync/net/BasicAuthHeaderProvider.java sync/net/BrowserIDAuthHeaderProvider.java sync/net/ConnectionMonitorThread.java sync/net/HandleProgressException.java sync/net/HMACAuthHeaderProvider.java sync/net/HttpResponseObserver.java sync/net/Resource.java sync/net/ResourceDelegate.java sync/net/SyncResponse.java sync/net/SyncStorageCollectionRequest.java sync/net/SyncStorageCollectionRequestDelegate.java sync/net/SyncStorageRecordRequest.java sync/net/SyncStorageRequest.java sync/net/SyncStorageRequestDelegate.java sync/net/SyncStorageRequestIncrementalDelegate.java sync/net/SyncStorageResponse.java sync/net/TLSSocketFactory.java sync/net/WBOCollectionRequestDelegate.java sync/net/WBORequestDelegate.java sync/NoCollectionKeysSetException.java sync/NodeAuthenticationException.java sync/NonArrayJSONException.java sync/NonObjectJSONException.java sync/NullClusterURLException.java sync/PersistedMetaGlobal.java sync/PrefsSource.java sync/receivers/SyncAccountDeletedReceiver.java sync/receivers/SyncAccountDeletedService.java sync/receivers/UpgradeReceiver.java sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java sync/repositories/android/AndroidBrowserBookmarksRepository.java sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java sync/repositories/android/AndroidBrowserHistoryDataAccessor.java sync/repositories/android/AndroidBrowserHistoryDataExtender.java sync/repositories/android/AndroidBrowserHistoryRepository.java sync/repositories/android/AndroidBrowserHistoryRepositorySession.java sync/repositories/android/AndroidBrowserRepository.java sync/repositories/android/AndroidBrowserRepositoryDataAccessor.java sync/repositories/android/AndroidBrowserRepositorySession.java sync/repositories/android/BookmarksDeletionManager.java sync/repositories/android/BookmarksInsertionManager.java sync/repositories/android/BrowserContractHelpers.java sync/repositories/android/CachedSQLiteOpenHelper.java sync/repositories/android/ClientsDatabase.java sync/repositories/android/ClientsDatabaseAccessor.java sync/repositories/android/FennecControlHelper.java sync/repositories/android/FennecTabsRepository.java sync/repositories/android/FormHistoryRepositorySession.java sync/repositories/android/PasswordsRepositorySession.java sync/repositories/android/RepoUtils.java sync/repositories/BookmarkNeedsReparentingException.java sync/repositories/BookmarksRepository.java sync/repositories/ConstrainedServer11Repository.java sync/repositories/delegates/DeferrableRepositorySessionCreationDelegate.java sync/repositories/delegates/DeferredRepositorySessionBeginDelegate.java sync/repositories/delegates/DeferredRepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/DeferredRepositorySessionFinishDelegate.java sync/repositories/delegates/DeferredRepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionBeginDelegate.java sync/repositories/delegates/RepositorySessionCleanDelegate.java sync/repositories/delegates/RepositorySessionCreationDelegate.java sync/repositories/delegates/RepositorySessionFetchRecordsDelegate.java sync/repositories/delegates/RepositorySessionFinishDelegate.java sync/repositories/delegates/RepositorySessionGuidsSinceDelegate.java sync/repositories/delegates/RepositorySessionStoreDelegate.java sync/repositories/delegates/RepositorySessionWipeDelegate.java sync/repositories/domain/BookmarkRecord.java sync/repositories/domain/BookmarkRecordFactory.java sync/repositories/domain/ClientRecord.java sync/repositories/domain/ClientRecordFactory.java sync/repositories/domain/FormHistoryRecord.java sync/repositories/domain/HistoryRecord.java sync/repositories/domain/HistoryRecordFactory.java sync/repositories/domain/PasswordRecord.java sync/repositories/domain/Record.java sync/repositories/domain/TabsRecord.java sync/repositories/domain/VersionConstants.java sync/repositories/FetchFailedException.java sync/repositories/HashSetStoreTracker.java sync/repositories/HistoryRepository.java sync/repositories/IdentityRecordFactory.java sync/repositories/InactiveSessionException.java sync/repositories/InvalidBookmarkTypeException.java sync/repositories/InvalidRequestException.java sync/repositories/InvalidSessionTransitionException.java sync/repositories/MultipleRecordsForGuidException.java sync/repositories/NoContentProviderException.java sync/repositories/NoGuidForIdException.java sync/repositories/NoStoreDelegateException.java sync/repositories/NullCursorException.java sync/repositories/ParentNotFoundException.java sync/repositories/ProfileDatabaseException.java sync/repositories/RecordFactory.java sync/repositories/RecordFilter.java sync/repositories/Repository.java sync/repositories/RepositorySession.java sync/repositories/RepositorySessionBundle.java sync/repositories/Server11Repository.java sync/repositories/Server11RepositorySession.java sync/repositories/StoreFailedException.java sync/repositories/StoreTracker.java sync/repositories/StoreTrackingRepositorySession.java sync/Server11PreviousPostFailedException.java sync/Server11RecordPostFailedException.java sync/setup/activities/AccountActivity.java sync/setup/activities/ActivityUtils.java sync/setup/activities/ClientRecordArrayAdapter.java sync/setup/activities/RedirectToSetupActivity.java sync/setup/activities/SendTabActivity.java sync/setup/activities/SetupFailureActivity.java sync/setup/activities/SetupSuccessActivity.java sync/setup/activities/SetupSyncActivity.java sync/setup/activities/SyncActivity.java sync/setup/activities/WebViewActivity.java sync/setup/auth/AccountAuthenticator.java sync/setup/auth/AuthenticateAccountStage.java sync/setup/auth/AuthenticationResult.java sync/setup/auth/AuthenticatorStage.java sync/setup/auth/EnsureUserExistenceStage.java sync/setup/auth/FetchUserNodeStage.java sync/setup/Constants.java sync/setup/InvalidSyncKeyException.java sync/setup/SyncAccounts.java sync/setup/SyncAuthenticatorService.java sync/stage/AbstractNonRepositorySyncStage.java sync/stage/AndroidBrowserBookmarksServerSyncStage.java sync/stage/AndroidBrowserHistoryServerSyncStage.java sync/stage/CheckPreconditionsStage.java sync/stage/CompletedStage.java sync/stage/EnsureClusterURLStage.java sync/stage/EnsureCrypto5KeysStage.java sync/stage/FennecTabsServerSyncStage.java sync/stage/FetchInfoCollectionsStage.java sync/stage/FetchMetaGlobalStage.java sync/stage/FormHistoryServerSyncStage.java sync/stage/GlobalSyncStage.java sync/stage/NoSuchStageException.java sync/stage/NoSyncIDException.java sync/stage/PasswordsServerSyncStage.java sync/stage/SafeConstrainedServer11Repository.java sync/stage/ServerSyncStage.java sync/stage/SyncClientsEngineStage.java sync/stage/UploadMetaGlobalStage.java sync/StubActivity.java sync/syncadapter/SyncAdapter.java sync/syncadapter/SyncService.java sync/SyncConfiguration.java sync/SyncConfigurationException.java sync/SyncException.java sync/synchronizer/ConcurrentRecordConsumer.java sync/synchronizer/RecordConsumer.java sync/synchronizer/RecordsChannel.java sync/synchronizer/RecordsChannelDelegate.java sync/synchronizer/RecordsConsumerDelegate.java sync/synchronizer/SerialRecordConsumer.java sync/synchronizer/ServerLocalSynchronizer.java sync/synchronizer/ServerLocalSynchronizerSession.java sync/synchronizer/SessionNotBegunException.java sync/synchronizer/Synchronizer.java sync/synchronizer/SynchronizerDelegate.java sync/synchronizer/SynchronizerSession.java sync/synchronizer/SynchronizerSessionDelegate.java sync/synchronizer/UnbundleError.java sync/synchronizer/UnexpectedSessionException.java sync/SynchronizerConfiguration.java sync/ThreadPool.java sync/UnexpectedJSONException.java sync/UnknownSynchronizerConfigurationVersionException.java sync/Utils.java
 SYNC_PP_JAVA_FILES := sync/GlobalConstants.java sync/SyncConstants.java background/announcements/AnnouncementsConstants.java
 SYNC_THIRDPARTY_JAVA_FILES := httpclientandroidlib/androidextra/HttpClientAndroidLog.java httpclientandroidlib/annotation/GuardedBy.java httpclientandroidlib/annotation/Immutable.java httpclientandroidlib/annotation/NotThreadSafe.java httpclientandroidlib/annotation/ThreadSafe.java httpclientandroidlib/auth/AUTH.java httpclientandroidlib/auth/AuthenticationException.java httpclientandroidlib/auth/AuthScheme.java httpclientandroidlib/auth/AuthSchemeFactory.java httpclientandroidlib/auth/AuthSchemeRegistry.java httpclientandroidlib/auth/AuthScope.java httpclientandroidlib/auth/AuthState.java httpclientandroidlib/auth/BasicUserPrincipal.java httpclientandroidlib/auth/ContextAwareAuthScheme.java httpclientandroidlib/auth/Credentials.java httpclientandroidlib/auth/InvalidCredentialsException.java httpclientandroidlib/auth/MalformedChallengeException.java httpclientandroidlib/auth/NTCredentials.java httpclientandroidlib/auth/NTUserPrincipal.java httpclientandroidlib/auth/params/AuthParamBean.java httpclientandroidlib/auth/params/AuthParams.java httpclientandroidlib/auth/params/AuthPNames.java httpclientandroidlib/auth/UsernamePasswordCredentials.java httpclientandroidlib/client/AuthCache.java httpclientandroidlib/client/AuthenticationHandler.java httpclientandroidlib/client/CircularRedirectException.java httpclientandroidlib/client/ClientProtocolException.java httpclientandroidlib/client/CookieStore.java httpclientandroidlib/client/CredentialsProvider.java httpclientandroidlib/client/entity/DecompressingEntity.java httpclientandroidlib/client/entity/DeflateDecompressingEntity.java httpclientandroidlib/client/entity/GzipDecompressingEntity.java httpclientandroidlib/client/entity/UrlEncodedFormEntity.java httpclientandroidlib/client/HttpClient.java httpclientandroidlib/client/HttpRequestRetryHandler.java httpclientandroidlib/client/HttpResponseException.java httpclientandroidlib/client/methods/AbortableHttpRequest.java httpclientandroidlib/client/methods/HttpDelete.java httpclientandroidlib/client/methods/HttpEntityEnclosingRequestBase.java httpclientandroidlib/client/methods/HttpGet.java httpclientandroidlib/client/methods/HttpHead.java httpclientandroidlib/client/methods/HttpOptions.java httpclientandroidlib/client/methods/HttpPost.java httpclientandroidlib/client/methods/HttpPut.java httpclientandroidlib/client/methods/HttpRequestBase.java httpclientandroidlib/client/methods/HttpTrace.java httpclientandroidlib/client/methods/HttpUriRequest.java httpclientandroidlib/client/NonRepeatableRequestException.java httpclientandroidlib/client/params/AllClientPNames.java httpclientandroidlib/client/params/AuthPolicy.java httpclientandroidlib/client/params/ClientParamBean.java httpclientandroidlib/client/params/ClientPNames.java httpclientandroidlib/client/params/CookiePolicy.java httpclientandroidlib/client/params/HttpClientParams.java httpclientandroidlib/client/protocol/ClientContext.java httpclientandroidlib/client/protocol/ClientContextConfigurer.java httpclientandroidlib/client/protocol/RequestAcceptEncoding.java httpclientandroidlib/client/protocol/RequestAddCookies.java httpclientandroidlib/client/protocol/RequestAuthCache.java httpclientandroidlib/client/protocol/RequestClientConnControl.java httpclientandroidlib/client/protocol/RequestDefaultHeaders.java httpclientandroidlib/client/protocol/RequestProxyAuthentication.java httpclientandroidlib/client/protocol/RequestTargetAuthentication.java httpclientandroidlib/client/protocol/ResponseAuthCache.java httpclientandroidlib/client/protocol/ResponseContentEncoding.java httpclientandroidlib/client/protocol/ResponseProcessCookies.java httpclientandroidlib/client/RedirectException.java httpclientandroidlib/client/RedirectHandler.java httpclientandroidlib/client/RedirectStrategy.java httpclientandroidlib/client/RequestDirector.java httpclientandroidlib/client/ResponseHandler.java httpclientandroidlib/client/UserTokenHandler.java httpclientandroidlib/client/utils/CloneUtils.java httpclientandroidlib/client/utils/Idn.java httpclientandroidlib/client/utils/JdkIdn.java httpclientandroidlib/client/utils/Punycode.java httpclientandroidlib/client/utils/Rfc3492Idn.java httpclientandroidlib/client/utils/URIUtils.java httpclientandroidlib/client/utils/URLEncodedUtils.java httpclientandroidlib/conn/BasicEofSensorWatcher.java httpclientandroidlib/conn/BasicManagedEntity.java httpclientandroidlib/conn/ClientConnectionManager.java httpclientandroidlib/conn/ClientConnectionManagerFactory.java httpclientandroidlib/conn/ClientConnectionOperator.java httpclientandroidlib/conn/ClientConnectionRequest.java httpclientandroidlib/conn/ConnectionKeepAliveStrategy.java httpclientandroidlib/conn/ConnectionPoolTimeoutException.java httpclientandroidlib/conn/ConnectionReleaseTrigger.java httpclientandroidlib/conn/ConnectTimeoutException.java httpclientandroidlib/conn/EofSensorInputStream.java httpclientandroidlib/conn/EofSensorWatcher.java httpclientandroidlib/conn/HttpHostConnectException.java httpclientandroidlib/conn/HttpRoutedConnection.java httpclientandroidlib/conn/ManagedClientConnection.java httpclientandroidlib/conn/MultihomePlainSocketFactory.java httpclientandroidlib/conn/OperatedClientConnection.java httpclientandroidlib/conn/params/ConnConnectionParamBean.java httpclientandroidlib/conn/params/ConnConnectionPNames.java httpclientandroidlib/conn/params/ConnManagerParamBean.java httpclientandroidlib/conn/params/ConnManagerParams.java httpclientandroidlib/conn/params/ConnManagerPNames.java httpclientandroidlib/conn/params/ConnPerRoute.java httpclientandroidlib/conn/params/ConnPerRouteBean.java httpclientandroidlib/conn/params/ConnRouteParamBean.java httpclientandroidlib/conn/params/ConnRouteParams.java httpclientandroidlib/conn/params/ConnRoutePNames.java httpclientandroidlib/conn/routing/BasicRouteDirector.java httpclientandroidlib/conn/routing/HttpRoute.java httpclientandroidlib/conn/routing/HttpRouteDirector.java httpclientandroidlib/conn/routing/HttpRoutePlanner.java httpclientandroidlib/conn/routing/RouteInfo.java httpclientandroidlib/conn/routing/RouteTracker.java httpclientandroidlib/conn/scheme/HostNameResolver.java httpclientandroidlib/conn/scheme/LayeredSchemeSocketFactory.java httpclientandroidlib/conn/scheme/LayeredSchemeSocketFactoryAdaptor.java httpclientandroidlib/conn/scheme/LayeredSocketFactory.java httpclientandroidlib/conn/scheme/LayeredSocketFactoryAdaptor.java httpclientandroidlib/conn/scheme/PlainSocketFactory.java httpclientandroidlib/conn/scheme/Scheme.java httpclientandroidlib/conn/scheme/SchemeRegistry.java httpclientandroidlib/conn/scheme/SchemeSocketFactory.java httpclientandroidlib/conn/scheme/SchemeSocketFactoryAdaptor.java httpclientandroidlib/conn/scheme/SocketFactory.java httpclientandroidlib/conn/scheme/SocketFactoryAdaptor.java httpclientandroidlib/conn/ssl/AbstractVerifier.java httpclientandroidlib/conn/ssl/AllowAllHostnameVerifier.java httpclientandroidlib/conn/ssl/BrowserCompatHostnameVerifier.java httpclientandroidlib/conn/ssl/SSLSocketFactory.java httpclientandroidlib/conn/ssl/StrictHostnameVerifier.java httpclientandroidlib/conn/ssl/TrustManagerDecorator.java httpclientandroidlib/conn/ssl/TrustSelfSignedStrategy.java httpclientandroidlib/conn/ssl/TrustStrategy.java httpclientandroidlib/conn/ssl/X509HostnameVerifier.java httpclientandroidlib/conn/util/InetAddressUtils.java httpclientandroidlib/ConnectionClosedException.java httpclientandroidlib/ConnectionReuseStrategy.java httpclientandroidlib/cookie/ClientCookie.java httpclientandroidlib/cookie/Cookie.java httpclientandroidlib/cookie/CookieAttributeHandler.java httpclientandroidlib/cookie/CookieIdentityComparator.java httpclientandroidlib/cookie/CookieOrigin.java httpclientandroidlib/cookie/CookiePathComparator.java httpclientandroidlib/cookie/CookieRestrictionViolationException.java httpclientandroidlib/cookie/CookieSpec.java httpclientandroidlib/cookie/CookieSpecFactory.java httpclientandroidlib/cookie/CookieSpecRegistry.java httpclientandroidlib/cookie/MalformedCookieException.java httpclientandroidlib/cookie/params/CookieSpecParamBean.java httpclientandroidlib/cookie/params/CookieSpecPNames.java httpclientandroidlib/cookie/SetCookie.java httpclientandroidlib/cookie/SetCookie2.java httpclientandroidlib/cookie/SM.java httpclientandroidlib/entity/AbstractHttpEntity.java httpclientandroidlib/entity/BasicHttpEntity.java httpclientandroidlib/entity/BufferedHttpEntity.java httpclientandroidlib/entity/ByteArrayEntity.java httpclientandroidlib/entity/ContentLengthStrategy.java httpclientandroidlib/entity/ContentProducer.java httpclientandroidlib/entity/EntityTemplate.java httpclientandroidlib/entity/FileEntity.java httpclientandroidlib/entity/HttpEntityWrapper.java httpclientandroidlib/entity/InputStreamEntity.java httpclientandroidlib/entity/SerializableEntity.java httpclientandroidlib/entity/StringEntity.java httpclientandroidlib/FormattedHeader.java httpclientandroidlib/Header.java httpclientandroidlib/HeaderElement.java httpclientandroidlib/HeaderElementIterator.java httpclientandroidlib/HeaderIterator.java httpclientandroidlib/HttpClientConnection.java httpclientandroidlib/HttpConnection.java httpclientandroidlib/HttpConnectionMetrics.java httpclientandroidlib/HttpEntity.java httpclientandroidlib/HttpEntityEnclosingRequest.java httpclientandroidlib/HttpException.java httpclientandroidlib/HttpHeaders.java httpclientandroidlib/HttpHost.java httpclientandroidlib/HttpInetConnection.java httpclientandroidlib/HttpMessage.java httpclientandroidlib/HttpRequest.java httpclientandroidlib/HttpRequestFactory.java httpclientandroidlib/HttpRequestInterceptor.java httpclientandroidlib/HttpResponse.java httpclientandroidlib/HttpResponseFactory.java httpclientandroidlib/HttpResponseInterceptor.java httpclientandroidlib/HttpServerConnection.java httpclientandroidlib/HttpStatus.java httpclientandroidlib/HttpVersion.java httpclientandroidlib/impl/AbstractHttpClientConnection.java httpclientandroidlib/impl/AbstractHttpServerConnection.java httpclientandroidlib/impl/auth/AuthSchemeBase.java httpclientandroidlib/impl/auth/BasicScheme.java httpclientandroidlib/impl/auth/BasicSchemeFactory.java httpclientandroidlib/impl/auth/DigestScheme.java httpclientandroidlib/impl/auth/DigestSchemeFactory.java httpclientandroidlib/impl/auth/NTLMEngine.java httpclientandroidlib/impl/auth/NTLMEngineException.java httpclientandroidlib/impl/auth/NTLMEngineImpl.java httpclientandroidlib/impl/auth/NTLMScheme.java httpclientandroidlib/impl/auth/NTLMSchemeFactory.java httpclientandroidlib/impl/auth/RFC2617Scheme.java httpclientandroidlib/impl/auth/SpnegoTokenGenerator.java httpclientandroidlib/impl/auth/UnsupportedDigestAlgorithmException.java httpclientandroidlib/impl/client/AbstractAuthenticationHandler.java httpclientandroidlib/impl/client/AbstractHttpClient.java httpclientandroidlib/impl/client/BasicAuthCache.java httpclientandroidlib/impl/client/BasicCookieStore.java httpclientandroidlib/impl/client/BasicCredentialsProvider.java httpclientandroidlib/impl/client/BasicResponseHandler.java httpclientandroidlib/impl/client/ClientParamsStack.java httpclientandroidlib/impl/client/ContentEncodingHttpClient.java httpclientandroidlib/impl/client/DefaultConnectionKeepAliveStrategy.java httpclientandroidlib/impl/client/DefaultHttpClient.java httpclientandroidlib/impl/client/DefaultHttpRequestRetryHandler.java httpclientandroidlib/impl/client/DefaultProxyAuthenticationHandler.java httpclientandroidlib/impl/client/DefaultRedirectHandler.java httpclientandroidlib/impl/client/DefaultRedirectStrategy.java httpclientandroidlib/impl/client/DefaultRedirectStrategyAdaptor.java httpclientandroidlib/impl/client/DefaultRequestDirector.java httpclientandroidlib/impl/client/DefaultTargetAuthenticationHandler.java httpclientandroidlib/impl/client/DefaultUserTokenHandler.java httpclientandroidlib/impl/client/EntityEnclosingRequestWrapper.java httpclientandroidlib/impl/client/RedirectLocations.java httpclientandroidlib/impl/client/RequestWrapper.java httpclientandroidlib/impl/client/RoutedRequest.java httpclientandroidlib/impl/client/TunnelRefusedException.java httpclientandroidlib/impl/conn/AbstractClientConnAdapter.java httpclientandroidlib/impl/conn/AbstractPooledConnAdapter.java httpclientandroidlib/impl/conn/AbstractPoolEntry.java httpclientandroidlib/impl/conn/ConnectionShutdownException.java httpclientandroidlib/impl/conn/DefaultClientConnection.java httpclientandroidlib/impl/conn/DefaultClientConnectionOperator.java httpclientandroidlib/impl/conn/DefaultHttpRoutePlanner.java httpclientandroidlib/impl/conn/DefaultResponseParser.java httpclientandroidlib/impl/conn/HttpInetSocketAddress.java httpclientandroidlib/impl/conn/IdleConnectionHandler.java httpclientandroidlib/impl/conn/LoggingSessionInputBuffer.java httpclientandroidlib/impl/conn/LoggingSessionOutputBuffer.java httpclientandroidlib/impl/conn/ProxySelectorRoutePlanner.java httpclientandroidlib/impl/conn/SchemeRegistryFactory.java httpclientandroidlib/impl/conn/SingleClientConnManager.java httpclientandroidlib/impl/conn/tsccm/AbstractConnPool.java httpclientandroidlib/impl/conn/tsccm/BasicPooledConnAdapter.java httpclientandroidlib/impl/conn/tsccm/BasicPoolEntry.java httpclientandroidlib/impl/conn/tsccm/BasicPoolEntryRef.java httpclientandroidlib/impl/conn/tsccm/ConnPoolByRoute.java httpclientandroidlib/impl/conn/tsccm/PoolEntryRequest.java httpclientandroidlib/impl/conn/tsccm/RefQueueHandler.java httpclientandroidlib/impl/conn/tsccm/RefQueueWorker.java httpclientandroidlib/impl/conn/tsccm/RouteSpecificPool.java httpclientandroidlib/impl/conn/tsccm/ThreadSafeClientConnManager.java httpclientandroidlib/impl/conn/tsccm/WaitingThread.java httpclientandroidlib/impl/conn/tsccm/WaitingThreadAborter.java httpclientandroidlib/impl/conn/Wire.java httpclientandroidlib/impl/cookie/AbstractCookieAttributeHandler.java httpclientandroidlib/impl/cookie/AbstractCookieSpec.java httpclientandroidlib/impl/cookie/BasicClientCookie.java httpclientandroidlib/impl/cookie/BasicClientCookie2.java httpclientandroidlib/impl/cookie/BasicCommentHandler.java httpclientandroidlib/impl/cookie/BasicDomainHandler.java httpclientandroidlib/impl/cookie/BasicExpiresHandler.java httpclientandroidlib/impl/cookie/BasicMaxAgeHandler.java httpclientandroidlib/impl/cookie/BasicPathHandler.java httpclientandroidlib/impl/cookie/BasicSecureHandler.java httpclientandroidlib/impl/cookie/BestMatchSpec.java httpclientandroidlib/impl/cookie/BestMatchSpecFactory.java httpclientandroidlib/impl/cookie/BrowserCompatSpec.java httpclientandroidlib/impl/cookie/BrowserCompatSpecFactory.java httpclientandroidlib/impl/cookie/CookieSpecBase.java httpclientandroidlib/impl/cookie/DateParseException.java httpclientandroidlib/impl/cookie/DateUtils.java httpclientandroidlib/impl/cookie/IgnoreSpec.java httpclientandroidlib/impl/cookie/IgnoreSpecFactory.java httpclientandroidlib/impl/cookie/NetscapeDomainHandler.java httpclientandroidlib/impl/cookie/NetscapeDraftHeaderParser.java httpclientandroidlib/impl/cookie/NetscapeDraftSpec.java httpclientandroidlib/impl/cookie/NetscapeDraftSpecFactory.java httpclientandroidlib/impl/cookie/PublicSuffixFilter.java httpclientandroidlib/impl/cookie/PublicSuffixListParser.java httpclientandroidlib/impl/cookie/RFC2109DomainHandler.java httpclientandroidlib/impl/cookie/RFC2109Spec.java httpclientandroidlib/impl/cookie/RFC2109SpecFactory.java httpclientandroidlib/impl/cookie/RFC2109VersionHandler.java httpclientandroidlib/impl/cookie/RFC2965CommentUrlAttributeHandler.java httpclientandroidlib/impl/cookie/RFC2965DiscardAttributeHandler.java httpclientandroidlib/impl/cookie/RFC2965DomainAttributeHandler.java httpclientandroidlib/impl/cookie/RFC2965PortAttributeHandler.java httpclientandroidlib/impl/cookie/RFC2965Spec.java httpclientandroidlib/impl/cookie/RFC2965SpecFactory.java httpclientandroidlib/impl/cookie/RFC2965VersionAttributeHandler.java httpclientandroidlib/impl/DefaultConnectionReuseStrategy.java httpclientandroidlib/impl/DefaultHttpClientConnection.java httpclientandroidlib/impl/DefaultHttpRequestFactory.java httpclientandroidlib/impl/DefaultHttpResponseFactory.java httpclientandroidlib/impl/DefaultHttpServerConnection.java httpclientandroidlib/impl/EnglishReasonPhraseCatalog.java httpclientandroidlib/impl/entity/EntityDeserializer.java httpclientandroidlib/impl/entity/EntitySerializer.java httpclientandroidlib/impl/entity/LaxContentLengthStrategy.java httpclientandroidlib/impl/entity/StrictContentLengthStrategy.java httpclientandroidlib/impl/HttpConnectionMetricsImpl.java httpclientandroidlib/impl/io/AbstractMessageParser.java httpclientandroidlib/impl/io/AbstractMessageWriter.java httpclientandroidlib/impl/io/AbstractSessionInputBuffer.java httpclientandroidlib/impl/io/AbstractSessionOutputBuffer.java httpclientandroidlib/impl/io/ChunkedInputStream.java httpclientandroidlib/impl/io/ChunkedOutputStream.java httpclientandroidlib/impl/io/ContentLengthInputStream.java httpclientandroidlib/impl/io/ContentLengthOutputStream.java httpclientandroidlib/impl/io/HttpRequestParser.java httpclientandroidlib/impl/io/HttpRequestWriter.java httpclientandroidlib/impl/io/HttpResponseParser.java httpclientandroidlib/impl/io/HttpResponseWriter.java httpclientandroidlib/impl/io/HttpTransportMetricsImpl.java httpclientandroidlib/impl/io/IdentityInputStream.java httpclientandroidlib/impl/io/IdentityOutputStream.java httpclientandroidlib/impl/io/SocketInputBuffer.java httpclientandroidlib/impl/io/SocketOutputBuffer.java httpclientandroidlib/impl/NoConnectionReuseStrategy.java httpclientandroidlib/impl/SocketHttpClientConnection.java httpclientandroidlib/impl/SocketHttpServerConnection.java httpclientandroidlib/io/BufferInfo.java httpclientandroidlib/io/EofSensor.java httpclientandroidlib/io/HttpMessageParser.java httpclientandroidlib/io/HttpMessageWriter.java httpclientandroidlib/io/HttpTransportMetrics.java httpclientandroidlib/io/SessionInputBuffer.java httpclientandroidlib/io/SessionOutputBuffer.java httpclientandroidlib/MalformedChunkCodingException.java httpclientandroidlib/message/AbstractHttpMessage.java httpclientandroidlib/message/BasicHeader.java httpclientandroidlib/message/BasicHeaderElement.java httpclientandroidlib/message/BasicHeaderElementIterator.java httpclientandroidlib/message/BasicHeaderIterator.java httpclientandroidlib/message/BasicHeaderValueFormatter.java httpclientandroidlib/message/BasicHeaderValueParser.java httpclientandroidlib/message/BasicHttpEntityEnclosingRequest.java httpclientandroidlib/message/BasicHttpRequest.java httpclientandroidlib/message/BasicHttpResponse.java httpclientandroidlib/message/BasicLineFormatter.java httpclientandroidlib/message/BasicLineParser.java httpclientandroidlib/message/BasicListHeaderIterator.java httpclientandroidlib/message/BasicNameValuePair.java httpclientandroidlib/message/BasicRequestLine.java httpclientandroidlib/message/BasicStatusLine.java httpclientandroidlib/message/BasicTokenIterator.java httpclientandroidlib/message/BufferedHeader.java httpclientandroidlib/message/HeaderGroup.java httpclientandroidlib/message/HeaderValueFormatter.java httpclientandroidlib/message/HeaderValueParser.java httpclientandroidlib/message/LineFormatter.java httpclientandroidlib/message/LineParser.java httpclientandroidlib/message/ParserCursor.java httpclientandroidlib/MethodNotSupportedException.java httpclientandroidlib/NameValuePair.java httpclientandroidlib/NoHttpResponseException.java httpclientandroidlib/params/AbstractHttpParams.java httpclientandroidlib/params/BasicHttpParams.java httpclientandroidlib/params/CoreConnectionPNames.java httpclientandroidlib/params/CoreProtocolPNames.java httpclientandroidlib/params/DefaultedHttpParams.java httpclientandroidlib/params/HttpAbstractParamBean.java httpclientandroidlib/params/HttpConnectionParamBean.java httpclientandroidlib/params/HttpConnectionParams.java httpclientandroidlib/params/HttpParams.java httpclientandroidlib/params/HttpProtocolParamBean.java httpclientandroidlib/params/HttpProtocolParams.java httpclientandroidlib/params/SyncBasicHttpParams.java httpclientandroidlib/ParseException.java httpclientandroidlib/protocol/BasicHttpContext.java httpclientandroidlib/protocol/BasicHttpProcessor.java httpclientandroidlib/protocol/DefaultedHttpContext.java httpclientandroidlib/protocol/ExecutionContext.java httpclientandroidlib/protocol/HTTP.java httpclientandroidlib/protocol/HttpContext.java httpclientandroidlib/protocol/HttpDateGenerator.java httpclientandroidlib/protocol/HttpExpectationVerifier.java httpclientandroidlib/protocol/HttpProcessor.java httpclientandroidlib/protocol/HttpRequestExecutor.java httpclientandroidlib/protocol/HttpRequestHandler.java httpclientandroidlib/protocol/HttpRequestHandlerRegistry.java httpclientandroidlib/protocol/HttpRequestHandlerResolver.java httpclientandroidlib/protocol/HttpRequestInterceptorList.java httpclientandroidlib/protocol/HttpResponseInterceptorList.java httpclientandroidlib/protocol/HttpService.java httpclientandroidlib/protocol/ImmutableHttpProcessor.java httpclientandroidlib/protocol/RequestConnControl.java httpclientandroidlib/protocol/RequestContent.java httpclientandroidlib/protocol/RequestDate.java httpclientandroidlib/protocol/RequestExpectContinue.java httpclientandroidlib/protocol/RequestTargetHost.java httpclientandroidlib/protocol/RequestUserAgent.java httpclientandroidlib/protocol/ResponseConnControl.java httpclientandroidlib/protocol/ResponseContent.java httpclientandroidlib/protocol/ResponseDate.java httpclientandroidlib/protocol/ResponseServer.java httpclientandroidlib/protocol/SyncBasicHttpContext.java httpclientandroidlib/protocol/UriPatternMatcher.java httpclientandroidlib/ProtocolException.java httpclientandroidlib/ProtocolVersion.java httpclientandroidlib/ReasonPhraseCatalog.java httpclientandroidlib/RequestLine.java httpclientandroidlib/StatusLine.java httpclientandroidlib/TokenIterator.java httpclientandroidlib/TruncatedChunkException.java httpclientandroidlib/UnsupportedHttpVersionException.java httpclientandroidlib/util/ByteArrayBuffer.java httpclientandroidlib/util/CharArrayBuffer.java httpclientandroidlib/util/EncodingUtils.java httpclientandroidlib/util/EntityUtils.java httpclientandroidlib/util/ExceptionUtils.java httpclientandroidlib/util/LangUtils.java httpclientandroidlib/util/VersionInfo.java json-simple/ItemList.java json-simple/JSONArray.java json-simple/JSONAware.java json-simple/JSONObject.java json-simple/JSONStreamAware.java json-simple/JSONValue.java json-simple/parser/ContainerFactory.java json-simple/parser/ContentHandler.java json-simple/parser/JSONParser.java json-simple/parser/ParseException.java json-simple/parser/Yylex.java json-simple/parser/Yytoken.java apache/commons/codec/binary/Base32.java apache/commons/codec/binary/Base32InputStream.java apache/commons/codec/binary/Base32OutputStream.java apache/commons/codec/binary/Base64.java apache/commons/codec/binary/Base64InputStream.java apache/commons/codec/binary/Base64OutputStream.java apache/commons/codec/binary/BaseNCodec.java apache/commons/codec/binary/BaseNCodecInputStream.java apache/commons/codec/binary/BaseNCodecOutputStream.java apache/commons/codec/binary/BinaryCodec.java apache/commons/codec/binary/Hex.java apache/commons/codec/binary/StringUtils.java apache/commons/codec/BinaryDecoder.java apache/commons/codec/BinaryEncoder.java apache/commons/codec/CharEncoding.java apache/commons/codec/Decoder.java apache/commons/codec/DecoderException.java apache/commons/codec/digest/DigestUtils.java apache/commons/codec/Encoder.java apache/commons/codec/EncoderException.java apache/commons/codec/language/AbstractCaverphone.java apache/commons/codec/language/Caverphone.java apache/commons/codec/language/Caverphone1.java apache/commons/codec/language/Caverphone2.java apache/commons/codec/language/ColognePhonetic.java apache/commons/codec/language/DoubleMetaphone.java apache/commons/codec/language/Metaphone.java apache/commons/codec/language/RefinedSoundex.java apache/commons/codec/language/Soundex.java apache/commons/codec/language/SoundexUtils.java apache/commons/codec/net/BCodec.java apache/commons/codec/net/QCodec.java apache/commons/codec/net/QuotedPrintableCodec.java apache/commons/codec/net/RFC1522Codec.java apache/commons/codec/net/URLCodec.java apache/commons/codec/net/Utils.java apache/commons/codec/StringDecoder.java apache/commons/codec/StringEncoder.java apache/commons/codec/StringEncoderComparator.java
 SYNC_RES_DRAWABLE := mobile/android/base/resources/drawable/desktop.png mobile/android/base/resources/drawable/mobile.png mobile/android/base/resources/drawable/pin_background.xml
 SYNC_RES_DRAWABLE_LDPI := 
 SYNC_RES_DRAWABLE_MDPI := 
 SYNC_RES_DRAWABLE_HDPI := 
 SYNC_RES_LAYOUT := res/layout/sync_account.xml res/layout/sync_list_item.xml res/layout/sync_redirect_to_setup.xml res/layout/sync_send_tab.xml res/layout/sync_setup.xml res/layout/sync_setup_failure.xml res/layout/sync_setup_jpake_waiting.xml res/layout/sync_setup_nointernet.xml res/layout/sync_setup_pair.xml res/layout/sync_setup_success.xml res/layout/sync_setup_webview.xml
 SYNC_RES_VALUES := res/values/sync_styles.xml
--- a/mobile/android/base/background/announcements/AnnouncementsFetchResourceDelegate.java
+++ b/mobile/android/base/background/announcements/AnnouncementsFetchResourceDelegate.java
@@ -10,33 +10,34 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NonArrayJSONException;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BaseResource;
+import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.net.Resource;
-import org.mozilla.gecko.sync.net.SyncResourceDelegate;
 import org.mozilla.gecko.sync.net.SyncResponse;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
 import ch.boye.httpclientandroidlib.impl.cookie.DateUtils;
 import ch.boye.httpclientandroidlib.protocol.HTTP;
 
 /**
  * Converts HTTP resource callbacks into AnnouncementsFetchDelegate callbacks.
  */
-public class AnnouncementsFetchResourceDelegate extends SyncResourceDelegate {
+public class AnnouncementsFetchResourceDelegate extends BaseResourceDelegate {
   private static final String ACCEPT_HEADER = "application/json;charset=utf-8";
 
   private static final String LOG_TAG = "AnnounceFetchRD";
 
   protected final long startTime;
   protected AnnouncementsFetchDelegate delegate;
 
   public AnnouncementsFetchResourceDelegate(Resource resource, AnnouncementsFetchDelegate delegate) {
@@ -167,12 +168,12 @@ public class AnnouncementsFetchResourceD
     delegate.onRemoteError(e);
   }
 
   /**
    * Be very thorough in case the superclass implementation changes.
    * We never want this to be an authenticated request.
    */
   @Override
-  public String getCredentials() {
+  public AuthHeaderProvider getAuthHeaderProvider() {
     return null;
   }
 }
\ No newline at end of file
--- a/mobile/android/base/sync/jpake/stage/DeleteChannel.java
+++ b/mobile/android/base/sync/jpake/stage/DeleteChannel.java
@@ -6,17 +6,17 @@ package org.mozilla.gecko.sync.jpake.sta
 
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
 import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncResourceDelegate;
+import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.auth.AccountAuthenticator;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
 import ch.boye.httpclientandroidlib.message.BasicHeader;
 
@@ -30,17 +30,17 @@ public class DeleteChannel {
     final BaseResource httpResource;
     try {
       httpResource = new BaseResource(jClient.channelUrl);
     } catch (URISyntaxException e) {
       Logger.debug(LOG_TAG, "Encountered URISyntax exception, displaying abort anyway.");
       jClient.displayAbort(reason);
       return;
     }
-    httpResource.delegate = new SyncResourceDelegate(httpResource) {
+    httpResource.delegate = new BaseResourceDelegate(httpResource) {
 
       @Override
       public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
         request.setHeader(new BasicHeader(KEYEXCHANGE_ID_HEADER,  jClient.clientId));
         request.setHeader(new BasicHeader(KEYEXCHANGE_CID_HEADER, jClient.channel));
       }
 
       @Override
--- a/mobile/android/base/sync/jpake/stage/GetChannelStage.java
+++ b/mobile/android/base/sync/jpake/stage/GetChannelStage.java
@@ -7,17 +7,17 @@ package org.mozilla.gecko.sync.jpake.sta
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
 import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.jpake.JPakeResponse;
 import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncResourceDelegate;
+import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
 import ch.boye.httpclientandroidlib.message.BasicHeader;
 
@@ -73,17 +73,17 @@ public class GetChannelStage extends JPa
       Logger.error(LOG_TAG, "Unexpected exception.", e);
       jClient.abort(Constants.JPAKE_ERROR_CHANNEL);
       return;
     }
   }
 
   private void makeChannelRequest(final GetChannelStageDelegate callbackDelegate, String getChannelUrl, final String clientId) throws URISyntaxException {
     final BaseResource httpResource = new BaseResource(getChannelUrl);
-    httpResource.delegate = new SyncResourceDelegate(httpResource) {
+    httpResource.delegate = new BaseResourceDelegate(httpResource) {
 
       @Override
       public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
         request.setHeader(new BasicHeader("X-KeyExchange-Id", clientId));
       }
 
       @Override
       public void handleHttpResponse(HttpResponse response) {
--- a/mobile/android/base/sync/jpake/stage/GetRequestStage.java
+++ b/mobile/android/base/sync/jpake/stage/GetRequestStage.java
@@ -9,18 +9,18 @@ import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 import java.util.Timer;
 import java.util.TimerTask;
 
 import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.jpake.JPakeResponse;
 import org.mozilla.gecko.sync.net.BaseResource;
+import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.net.Resource;
-import org.mozilla.gecko.sync.net.SyncResourceDelegate;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
 import ch.boye.httpclientandroidlib.message.BasicHeader;
@@ -95,17 +95,17 @@ public class GetRequestStage extends JPa
 
     Logger.debug(LOG_TAG, "Scheduling GET request.");
     getStepTimerTask = new GetStepTimerTask(httpRequest);
     timerScheduler.schedule(getStepTimerTask, jClient.jpakePollInterval);
   }
 
   private Resource createGetRequest(final GetRequestStageDelegate callbackDelegate, final JPakeClient jpakeClient) throws URISyntaxException {
     BaseResource httpResource = new BaseResource(jpakeClient.channelUrl);
-    httpResource.delegate = new SyncResourceDelegate(httpResource) {
+    httpResource.delegate = new BaseResourceDelegate(httpResource) {
 
       @Override
       public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
         request.setHeader(new BasicHeader("X-KeyExchange-Id", jpakeClient.clientId));
         if (jpakeClient.myEtag != null) {
           request.setHeader(new BasicHeader("If-None-Match", jpakeClient.myEtag));
         }
       }
--- a/mobile/android/base/sync/jpake/stage/PutRequestStage.java
+++ b/mobile/android/base/sync/jpake/stage/PutRequestStage.java
@@ -10,17 +10,17 @@ import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 import java.util.Timer;
 import java.util.TimerTask;
 
 import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.jpake.JPakeClient;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.Resource;
-import org.mozilla.gecko.sync.net.SyncResourceDelegate;
+import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
 import ch.boye.httpclientandroidlib.message.BasicHeader;
@@ -86,17 +86,17 @@ public class PutRequestStage extends JPa
       jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
       return;
     }
     Logger.debug(LOG_TAG, "Outgoing message: " + jClient.jOutgoing.toJSONString());
   }
 
   private Resource createPutRequest(final PutRequestStageDelegate callbackDelegate, final JPakeClient jpakeClient) throws URISyntaxException {
     BaseResource httpResource = new BaseResource(jpakeClient.channelUrl);
-    httpResource.delegate = new SyncResourceDelegate(httpResource) {
+    httpResource.delegate = new BaseResourceDelegate(httpResource) {
 
       @Override
       public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
         request.setHeader(new BasicHeader("X-KeyExchange-Id", jpakeClient.clientId));
         if (jpakeClient.theirEtag != null) {
           request.setHeader(new BasicHeader("If-Match", jpakeClient.theirEtag));
         } else {
           request.setHeader(new BasicHeader("If-None-Match", "*"));
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/sync/net/AuthHeaderProvider.java
@@ -0,0 +1,30 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.sync.net;
+
+import java.security.GeneralSecurityException;
+
+import ch.boye.httpclientandroidlib.Header;
+import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
+import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
+import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
+
+/**
+ * An <code>AuthHeaderProvider</code> generates HTTP Authorization headers for
+ * HTTP requests.
+ */
+public interface AuthHeaderProvider {
+  /**
+   * Generate an HTTP Authorization header.
+   *
+   * @param request HTTP request.
+   * @param context HTTP context.
+   * @param client HTTP client.
+   * @return HTTP Authorization header.
+   * @throws GeneralSecurityException usually wrapping a more specific exception.
+   */
+  Header getAuthHeader(HttpRequestBase request, BasicHttpContext context, DefaultHttpClient client)
+    throws GeneralSecurityException;
+}
--- a/mobile/android/base/sync/net/BaseResource.java
+++ b/mobile/android/base/sync/net/BaseResource.java
@@ -1,49 +1,51 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.net;
 
 import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.lang.ref.WeakReference;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 
 import javax.net.ssl.SSLContext;
 
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.Logger;
 
 import ch.boye.httpclientandroidlib.Header;
 import ch.boye.httpclientandroidlib.HttpEntity;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.HttpVersion;
-import ch.boye.httpclientandroidlib.auth.Credentials;
-import ch.boye.httpclientandroidlib.auth.UsernamePasswordCredentials;
 import ch.boye.httpclientandroidlib.client.AuthCache;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpDelete;
 import ch.boye.httpclientandroidlib.client.methods.HttpGet;
 import ch.boye.httpclientandroidlib.client.methods.HttpPost;
 import ch.boye.httpclientandroidlib.client.methods.HttpPut;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
 import ch.boye.httpclientandroidlib.client.protocol.ClientContext;
 import ch.boye.httpclientandroidlib.conn.ClientConnectionManager;
 import ch.boye.httpclientandroidlib.conn.scheme.PlainSocketFactory;
 import ch.boye.httpclientandroidlib.conn.scheme.Scheme;
 import ch.boye.httpclientandroidlib.conn.scheme.SchemeRegistry;
 import ch.boye.httpclientandroidlib.conn.ssl.SSLSocketFactory;
-import ch.boye.httpclientandroidlib.impl.auth.BasicScheme;
+import ch.boye.httpclientandroidlib.entity.StringEntity;
 import ch.boye.httpclientandroidlib.impl.client.BasicAuthCache;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
 import ch.boye.httpclientandroidlib.impl.conn.tsccm.ThreadSafeClientConnManager;
 import ch.boye.httpclientandroidlib.params.HttpConnectionParams;
 import ch.boye.httpclientandroidlib.params.HttpParams;
 import ch.boye.httpclientandroidlib.params.HttpProtocolParams;
 import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
 import ch.boye.httpclientandroidlib.protocol.HttpContext;
@@ -125,51 +127,36 @@ public class BaseResource implements Res
    * being no auth cache in the context.
    */
   private static void addAuthCacheToContext(HttpUriRequest request, HttpContext context) {
     AuthCache authCache = new BasicAuthCache();                // Not thread safe.
     context.setAttribute(ClientContext.AUTH_CACHE, authCache);
   }
 
   /**
-   * Return a Header object representing an Authentication header for HTTP Basic.
-   */
-  public static Header getBasicAuthHeader(final String credentials) {
-    Credentials creds = new UsernamePasswordCredentials(credentials);
-
-    // This must be UTF-8 to generate the same Basic Auth headers as desktop for non-ASCII passwords.
-    return BasicScheme.authenticate(creds, "UTF-8", false);
-  }
-
-  /**
-   * Apply the provided credentials string to the provided request.
-   * @param credentials a string, "user:pass".
-   */
-  private static void applyCredentials(String credentials, HttpUriRequest request, HttpContext context) {
-    request.addHeader(getBasicAuthHeader(credentials));
-    Logger.trace(LOG_TAG, "Adding Basic Auth header.");
-  }
-
-  /**
    * Invoke this after delegate and request have been set.
    * @throws NoSuchAlgorithmException
    * @throws KeyManagementException
    */
-  private void prepareClient() throws KeyManagementException, NoSuchAlgorithmException {
+  protected void prepareClient() throws KeyManagementException, NoSuchAlgorithmException, GeneralSecurityException {
     context = new BasicHttpContext();
 
     // We could reuse these client instances, except that we mess around
     // with their parameters… so we'd need a pool of some kind.
     client = new DefaultHttpClient(getConnectionManager());
 
     // TODO: Eventually we should use Apache HttpAsyncClient. It's not out of alpha yet.
     // Until then, we synchronously make the request, then invoke our delegate's callback.
-    String credentials = delegate.getCredentials();
-    if (credentials != null) {
-      BaseResource.applyCredentials(credentials, request, context);
+    AuthHeaderProvider authHeaderProvider = delegate.getAuthHeaderProvider();
+    if (authHeaderProvider != null) {
+      Header authHeader = authHeaderProvider.getAuthHeader(request, context, client);
+      if (authHeader != null) {
+        request.addHeader(authHeader);
+        Logger.debug(LOG_TAG, "Added auth header.");
+      }
     }
 
     addAuthCacheToContext(request, context);
 
     HttpParams params = client.getParams();
     HttpConnectionParams.setConnectionTimeout(params, delegate.connectionTimeout());
     HttpConnectionParams.setSoTimeout(params, delegate.socketTimeout());
     HttpConnectionParams.setStaleCheckingEnabled(params, false);
@@ -291,16 +278,20 @@ public class BaseResource implements Res
     } catch (KeyManagementException e) {
       Logger.error(LOG_TAG, "Couldn't prepare client.", e);
       delegate.handleTransportException(e);
       return;
     } catch (NoSuchAlgorithmException e) {
       Logger.error(LOG_TAG, "Couldn't prepare client.", e);
       delegate.handleTransportException(e);
       return;
+    } catch (GeneralSecurityException e) {
+      Logger.error(LOG_TAG, "Couldn't prepare client.", e);
+      delegate.handleTransportException(e);
+      return;
     } catch (Exception e) {
       // Bug 740731: Don't let an exception fall through. Wrapping isn't
       // optimal, but often the exception is treated as an Exception anyway.
       delegate.handleTransportException(new GeneralSecurityException(e));
       return;
     }
     this.execute();
   }
@@ -338,16 +329,46 @@ public class BaseResource implements Res
   @Override
   public void put(HttpEntity body) {
     Logger.debug(LOG_TAG, "HTTP PUT " + this.uri.toASCIIString());
     HttpPut request = new HttpPut(this.uri);
     request.setEntity(body);
     this.go(request);
   }
 
+  protected static StringEntity stringEntityWithContentTypeApplicationJSON(String s) throws UnsupportedEncodingException {
+    StringEntity e = new StringEntity(s, "UTF-8");
+    e.setContentType("application/json");
+    return e;
+  }
+
+  /**
+   * Helper for turning a JSON object into a payload.
+   * @throws UnsupportedEncodingException
+   */
+  protected static StringEntity jsonEntity(JSONObject body) throws UnsupportedEncodingException {
+    return stringEntityWithContentTypeApplicationJSON(body.toJSONString());
+  }
+
+  /**
+   * Helper for turning an extended JSON object into a payload.
+   * @throws UnsupportedEncodingException
+   */
+  protected static StringEntity jsonEntity(ExtendedJSONObject body) throws UnsupportedEncodingException {
+    return stringEntityWithContentTypeApplicationJSON(body.toJSONString());
+  }
+
+  /**
+   * Helper for turning a JSON array into a payload.
+   * @throws UnsupportedEncodingException
+   */
+  protected static HttpEntity jsonEntity(JSONArray toPOST) throws UnsupportedEncodingException {
+    return stringEntityWithContentTypeApplicationJSON(toPOST.toJSONString());
+  }
+
   /**
    * Best-effort attempt to ensure that the entity has been fully consumed and
    * that the underlying stream has been closed.
    *
    * This releases the connection back to the connection pool.
    *
    * @param entity The HttpEntity to be consumed.
    */
@@ -406,9 +427,21 @@ public class BaseResource implements Res
    */
   public static void consumeReader(BufferedReader reader) {
     try {
       reader.close();
     } catch (IOException e) {
       // Do nothing.
     }
   }
+
+  public void post(JSONArray jsonArray) throws UnsupportedEncodingException {
+    post(jsonEntity(jsonArray));
+  }
+
+  public void put(JSONObject jsonObject) throws UnsupportedEncodingException {
+    put(jsonEntity(jsonObject));
+  }
+
+  public void post(ExtendedJSONObject o) throws UnsupportedEncodingException {
+    post(jsonEntity(o));
+  }
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/sync/net/BaseResourceDelegate.java
@@ -0,0 +1,44 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.sync.net;
+
+import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
+import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
+
+/**
+ * Shared abstract class for resource delegate that use the same timeouts
+ * and no credentials.
+ *
+ * @author rnewman
+ *
+ */
+public abstract class BaseResourceDelegate implements ResourceDelegate {
+  public static int connectionTimeoutInMillis = 1000 * 30;     // Wait 30s for a connection to open.
+  public static int socketTimeoutInMillis     = 1000 * 2 * 60; // Wait 2 minutes for data.
+
+  protected Resource resource;
+  public BaseResourceDelegate(Resource resource) {
+    this.resource = resource;
+  }
+
+  @Override
+  public int connectionTimeout() {
+    return connectionTimeoutInMillis;
+  }
+
+  @Override
+  public int socketTimeout() {
+    return socketTimeoutInMillis;
+  }
+
+  @Override
+  public AuthHeaderProvider getAuthHeaderProvider() {
+    return null;
+  }
+
+  @Override
+  public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/sync/net/BasicAuthHeaderProvider.java
@@ -0,0 +1,51 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.sync.net;
+
+import ch.boye.httpclientandroidlib.Header;
+import ch.boye.httpclientandroidlib.auth.Credentials;
+import ch.boye.httpclientandroidlib.auth.UsernamePasswordCredentials;
+import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
+import ch.boye.httpclientandroidlib.impl.auth.BasicScheme;
+import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
+import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
+
+/**
+ * An <code>AuthHeaderProvider</code> that returns an HTTP Basic auth header.
+ */
+public class BasicAuthHeaderProvider implements AuthHeaderProvider {
+  protected final String credentials;
+
+  /**
+   * Constructor.
+   *
+   * @param credentials string in form "user:pass".
+   */
+  public BasicAuthHeaderProvider(String credentials) {
+    this.credentials = credentials;
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param user username.
+   * @param pass password.
+   */
+  public BasicAuthHeaderProvider(String user, String pass) {
+    this(user + ":" + pass);
+  }
+
+  /**
+   * Return a Header object representing an Authentication header for HTTP
+   * Basic.
+   */
+  @Override
+  public Header getAuthHeader(HttpRequestBase request, BasicHttpContext context, DefaultHttpClient client) {
+    Credentials creds = new UsernamePasswordCredentials(credentials);
+
+    // This must be UTF-8 to generate the same Basic Auth headers as desktop for non-ASCII passwords.
+    return BasicScheme.authenticate(creds, "UTF-8", false);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/sync/net/BrowserIDAuthHeaderProvider.java
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.sync.net;
+
+import ch.boye.httpclientandroidlib.Header;
+import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
+import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
+import ch.boye.httpclientandroidlib.message.BasicHeader;
+import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
+
+/**
+ * An <code>AuthHeaderProvider</code> that returns an Authorization header for
+ * Browser-ID assertions in the format expected by a Mozilla Services Token
+ * Server.
+ * <p>
+ * See <a href="http://docs.services.mozilla.com/token/apis.html">http://docs.services.mozilla.com/token/apis.html</a>.
+ */
+public class BrowserIDAuthHeaderProvider implements AuthHeaderProvider {
+  protected final String assertion;
+
+  public BrowserIDAuthHeaderProvider(String assertion) {
+    if (assertion == null) {
+      throw new IllegalArgumentException("assertion must not be null.");
+    }
+
+    this.assertion = assertion;
+  }
+
+  @Override
+  public Header getAuthHeader(HttpRequestBase request, BasicHttpContext context, DefaultHttpClient client) {
+    Header header = new BasicHeader("Authorization", "Browser-ID " + assertion);
+
+    return header;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/sync/net/HMACAuthHeaderProvider.java
@@ -0,0 +1,257 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.sync.net;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.mozilla.apache.commons.codec.binary.Base64;
+import org.mozilla.gecko.sync.Logger;
+import org.mozilla.gecko.sync.Utils;
+
+import ch.boye.httpclientandroidlib.Header;
+import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
+import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
+import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
+import ch.boye.httpclientandroidlib.message.BasicHeader;
+import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
+
+/**
+ * An <code>AuthHeaderProvider</code> that returns an Authorization header for
+ * HMAC-SHA1-signed requests in the format expected by Mozilla Services
+ * identity-attached services and specified by the MAC Authentication spec, available at
+ * <a href="https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac">https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac</a>.
+ * <p>
+ * See <a href="https://wiki.mozilla.org/Services/Sagrada/ServiceClientFlow#Access">https://wiki.mozilla.org/Services/Sagrada/ServiceClientFlow#Access</a>.
+ */
+public class HMACAuthHeaderProvider implements AuthHeaderProvider {
+  public static final String LOG_TAG = "HMACAuthHeaderProvider";
+
+  public static final int NONCE_LENGTH_IN_BYTES = 8;
+
+  public static final String HMAC_SHA1_ALGORITHM = "hmacSHA1";
+
+  public final String identifier;
+  public final String key;
+
+  public HMACAuthHeaderProvider(String identifier, String key) {
+    // Validate identifier string.  From the MAC Authentication spec:
+    // id             = "id" "=" string-value
+    // string-value   = ( <"> plain-string <"> ) / plain-string
+    // plain-string   = 1*( %x20-21 / %x23-5B / %x5D-7E )
+    // We add quotes around the id string, so input identifier must be a plain-string.
+    if (identifier == null) {
+      throw new IllegalArgumentException("identifier must not be null.");
+    }
+    if (!isPlainString(identifier)) {
+      throw new IllegalArgumentException("identifier must be a plain-string.");
+    }
+
+    if (key == null) {
+      throw new IllegalArgumentException("key must not be null.");
+    }
+
+    this.identifier = identifier;
+    this.key = key;
+  }
+
+  @Override
+  public Header getAuthHeader(HttpRequestBase request, BasicHttpContext context, DefaultHttpClient client) throws GeneralSecurityException {
+    long timestamp = System.currentTimeMillis() / 1000;
+    String nonce = Base64.encodeBase64String(Utils.generateRandomBytes(NONCE_LENGTH_IN_BYTES));
+    String extra = "";
+
+    try {
+      return getAuthHeader(request, context, client, timestamp, nonce, extra);
+    } catch (InvalidKeyException e) {
+      // We lie a little and make every exception a GeneralSecurityException.
+      throw new GeneralSecurityException(e);
+    } catch (UnsupportedEncodingException e) {
+      throw new GeneralSecurityException(e);
+    } catch (NoSuchAlgorithmException e) {
+      throw new GeneralSecurityException(e);
+    }
+  }
+
+  /**
+   * Test if input is a <code>plain-string</code>.
+   * <p>
+   * A plain-string is defined by the MAC Authentication spec as
+   * <code>plain-string   = 1*( %x20-21 / %x23-5B / %x5D-7E )</code>.
+   *
+   * @param input
+   *          as a String of "US-ASCII" bytes.
+   * @return true if input is a <code>plain-string</code>; false otherwise.
+   * @throws UnsupportedEncodingException
+   */
+  protected static boolean isPlainString(String input) {
+    if (input == null || input.length() == 0) {
+      return false;
+    }
+
+    byte[] bytes;
+    try {
+      bytes = input.getBytes("US-ASCII");
+    } catch (UnsupportedEncodingException e) {
+      // Should never happen.
+      Logger.warn(LOG_TAG, "Got exception in isPlainString; returning false.", e);
+      return false;
+    }
+
+    for (byte b : bytes) {
+      if ((0x20 <= b && b <= 0x21) || (0x23 <= b && b <= 0x5B) || (0x5D <= b && b <= 0x7E)) {
+        continue;
+      }
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * Helper function that generates an HTTP Authorization header given
+   * additional MAC Authentication specific data.
+   *
+   * @throws UnsupportedEncodingException
+   * @throws NoSuchAlgorithmException 
+   * @throws InvalidKeyException 
+   */
+  protected Header getAuthHeader(HttpRequestBase request, BasicHttpContext context, DefaultHttpClient client,
+      long timestamp, String nonce, String extra)
+      throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException {
+    // Validate timestamp.  From the MAC Authentication spec:
+    // timestamp      = 1*DIGIT
+    // This is equivalent to timestamp >= 0.
+    if (timestamp < 0) {
+      throw new IllegalArgumentException("timestamp must contain only [0-9].");
+    }
+
+    // Validate nonce string.  From the MAC Authentication spec:
+    // nonce          = "nonce" "=" string-value
+    // string-value   = ( <"> plain-string <"> ) / plain-string
+    // plain-string   = 1*( %x20-21 / %x23-5B / %x5D-7E )
+    // We add quotes around the nonce string, so input nonce must be a plain-string.
+    if (nonce == null) {
+      throw new IllegalArgumentException("nonce must not be null.");
+    }
+    if (!isPlainString(nonce)) {
+      throw new IllegalArgumentException("nonce must be a plain-string.");
+    }
+
+    // Validate extra string.  From the MAC Authentication spec:
+    // ext            = "ext" "=" string-value
+    // string-value   = ( <"> plain-string <"> ) / plain-string
+    // plain-string   = 1*( %x20-21 / %x23-5B / %x5D-7E )
+    // We add quotes around the extra string, so input extra must be a plain-string.
+    if (extra == null) {
+      throw new IllegalArgumentException("extra must not be null.");
+    }
+    if (!isPlainString(extra)) {
+      throw new IllegalArgumentException("extra must be a plain-string.");
+    }
+
+    String requestString = getRequestString(request, timestamp, nonce, extra);
+    String macString = getSignature(requestString, this.key);
+
+    String h = "MAC id=\"" + this.identifier + "\", " +
+               "ts=\""     + timestamp       + "\", " +
+               "nonce=\""  + nonce           + "\", " +
+               "mac=\""    + macString       + "\"";
+
+    if (extra != null) {
+      h += ", ext=\"" + extra + "\"";
+    }
+
+    Header header = new BasicHeader("Authorization", h);
+
+    return header;
+  }
+
+  protected static byte[] sha1(byte[] message, byte[] key)
+      throws NoSuchAlgorithmException, InvalidKeyException {
+
+    SecretKeySpec keySpec = new SecretKeySpec(key, HMAC_SHA1_ALGORITHM);
+
+    Mac hasher = Mac.getInstance(HMAC_SHA1_ALGORITHM);
+    hasher.init(keySpec);
+    hasher.update(message);
+
+    byte[] hmac = hasher.doFinal();
+
+    return hmac;
+  }
+
+  /**
+   * Sign an HMAC request string.
+   *
+   * @param requestString to sign.
+   * @param key as <code>String</code>.
+   * @return signature as base-64 encoded string.
+   * @throws InvalidKeyException
+   * @throws NoSuchAlgorithmException
+   * @throws UnsupportedEncodingException
+   */
+  protected static String getSignature(String requestString, String key)
+      throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
+    String macString = Base64.encodeBase64String(sha1(requestString.getBytes("UTF-8"), key.getBytes("UTF-8")));
+
+    return macString;
+  }
+
+  /**
+   * Generate an HMAC request string.
+   * <p>
+   * This method trusts its inputs to be valid as per the MAC Authentication spec.
+   *
+   * @param request HTTP request.
+   * @param timestamp to use.
+   * @param nonce to use.
+   * @param extra to use.
+   * @return request string.
+   */
+  protected static String getRequestString(HttpUriRequest request, long timestamp, String nonce, String extra) {
+    String method = request.getMethod().toUpperCase();
+
+    URI uri = request.getURI();
+    String host = uri.getHost();
+
+    String path = uri.getRawPath();
+    if (uri.getRawQuery() != null) {
+      path += "?";
+      path += uri.getRawQuery();
+    }
+    if (uri.getRawFragment() != null) {
+      path += "#";
+      path += uri.getRawFragment();
+    }
+
+    int port = uri.getPort();
+    String scheme = uri.getScheme();
+    if (port != -1) {
+    } else if ("http".equalsIgnoreCase(scheme)) {
+      port = 80;
+    } else if ("https".equalsIgnoreCase(scheme)) {
+      port = 443;
+    } else {
+      throw new IllegalArgumentException("Unsupported URI scheme: " + scheme + ".");
+    }
+
+    String requestString = timestamp + "\n" +
+        nonce       + "\n" +
+        method      + "\n" +
+        path        + "\n" +
+        host        + "\n" +
+        port        + "\n" +
+        extra       + "\n";
+
+    return requestString;
+  }
+}
--- a/mobile/android/base/sync/net/ResourceDelegate.java
+++ b/mobile/android/base/sync/net/ResourceDelegate.java
@@ -18,17 +18,17 @@ import ch.boye.httpclientandroidlib.impl
  * the pool:
  *
  *          EntityUtils.consume(entity);
  * @author rnewman
  *
  */
 public interface ResourceDelegate {
   // Request augmentation.
-  String getCredentials();
+  AuthHeaderProvider getAuthHeaderProvider();
   void addHeaders(HttpRequestBase request, DefaultHttpClient client);
 
   // Response handling.
 
   /**
    * Override this to handle an HttpResponse.
    *
    * ResourceDelegate implementers <b>must</b> ensure that HTTP responses are
--- a/mobile/android/base/sync/net/SyncStorageCollectionRequest.java
+++ b/mobile/android/base/sync/net/SyncStorageCollectionRequest.java
@@ -45,17 +45,17 @@ public class SyncStorageCollectionReques
       this.resource.request.abort();
     } catch (Exception e) {
       // Just in case.
       Logger.warn(LOG_TAG, "Got exception in abort: " + e);
     }
   }
 
   @Override
-  protected SyncResourceDelegate makeResourceDelegate(SyncStorageRequest request) {
+  protected BaseResourceDelegate makeResourceDelegate(SyncStorageRequest request) {
     return new SyncCollectionResourceDelegate((SyncStorageCollectionRequest) request);
   }
 
   // TODO: this is awful.
   public class SyncCollectionResourceDelegate extends
       SyncStorageResourceDelegate {
 
     private static final String CONTENT_TYPE_INCREMENTAL = "application/newlines";
--- a/mobile/android/base/sync/net/SyncStorageRecordRequest.java
+++ b/mobile/android/base/sync/net/SyncStorageRecordRequest.java
@@ -8,19 +8,16 @@ import java.io.UnsupportedEncodingExcept
 import java.net.URI;
 import java.net.URISyntaxException;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.ThreadPool;
 
-import ch.boye.httpclientandroidlib.HttpEntity;
-import ch.boye.httpclientandroidlib.entity.StringEntity;
-
 /**
  * Resource class that implements expected headers and processing for Sync.
  * Accepts a simplified delegate.
  *
  * Includes:
  * * Basic Auth headers (via Resource)
  * * Error responses:
  *   * 401
@@ -48,68 +45,46 @@ public class SyncStorageRecordRequest ex
     super(uri);
   }
 
   public SyncStorageRecordRequest(String url) throws URISyntaxException {
     this(new URI(url));
   }
 
   @Override
-  protected SyncResourceDelegate makeResourceDelegate(SyncStorageRequest request) {
+  protected BaseResourceDelegate makeResourceDelegate(SyncStorageRequest request) {
     return new SyncStorageRecordResourceDelegate(request);
   }
 
-  protected static StringEntity stringEntity(String s) throws UnsupportedEncodingException {
-    StringEntity e = new StringEntity(s, "UTF-8");
-    e.setContentType("application/json");
-    return e;
-  }
-
-  /**
-   * Helper for turning a JSON object into a payload.
-   * @throws UnsupportedEncodingException
-   */
-  protected static StringEntity jsonEntity(JSONObject body) throws UnsupportedEncodingException {
-    return stringEntity(body.toJSONString());
-  }
-
-  /**
-   * Helper for turning a JSON array into a payload.
-   * @throws UnsupportedEncodingException
-   */
-  protected static HttpEntity jsonEntity(JSONArray toPOST) throws UnsupportedEncodingException {
-    return stringEntity(toPOST.toJSONString());
-  }
-
   @SuppressWarnings("unchecked")
   public void post(JSONObject body) {
     // Let's do this the trivial way for now.
     // Note that POSTs should be an array, so we wrap here.
     final JSONArray toPOST = new JSONArray();
     toPOST.add(body);
     try {
-      this.resource.post(jsonEntity(toPOST));
+      this.resource.post(toPOST);
     } catch (UnsupportedEncodingException e) {
       this.delegate.handleRequestError(e);
     }
   }
 
   public void post(JSONArray body) {
     // Let's do this the trivial way for now.
     try {
-      this.resource.post(jsonEntity(body));
+      this.resource.post(body);
     } catch (UnsupportedEncodingException e) {
       this.delegate.handleRequestError(e);
     }
   }
 
   public void put(JSONObject body) {
     // Let's do this the trivial way for now.
     try {
-      this.resource.put(jsonEntity(body));
+      this.resource.put(body);
     } catch (UnsupportedEncodingException e) {
       this.delegate.handleRequestError(e);
     }
   }
 
   public void post(CryptoRecord record) {
     this.post(record.toJSONObject());
   }
--- a/mobile/android/base/sync/net/SyncStorageRequest.java
+++ b/mobile/android/base/sync/net/SyncStorageRequest.java
@@ -76,28 +76,33 @@ public class SyncStorageRequest implemen
     this.resource = new BaseResource(uri);
     this.resourceDelegate = this.makeResourceDelegate(this);
     this.resource.delegate = this.resourceDelegate;
   }
 
   /**
    * A ResourceDelegate that mediates between Resource-level notifications and the SyncStorageRequest.
    */
-  public class SyncStorageResourceDelegate extends SyncResourceDelegate {
+  public class SyncStorageResourceDelegate extends BaseResourceDelegate {
     private static final String LOG_TAG = "SSResourceDelegate";
     protected SyncStorageRequest request;
 
     SyncStorageResourceDelegate(SyncStorageRequest request) {
       super(request);
       this.request = request;
     }
 
     @Override
-    public String getCredentials() {
-      return this.request.delegate.credentials();
+    public AuthHeaderProvider getAuthHeaderProvider() {
+      String credentials = request.delegate.credentials();
+      if (credentials == null) {
+        return null;
+      }
+
+      return new BasicAuthHeaderProvider(credentials);
     }
 
     @Override
     public void handleHttpResponse(HttpResponse response) {
       Logger.debug(LOG_TAG, "SyncStorageResourceDelegate handling response: " + response.getStatusLine() + ".");
       SyncStorageRequestDelegate d = this.request.delegate;
       SyncStorageResponse res = new SyncStorageResponse(response);
       // It is the responsibility of the delegate handlers to completely consume the response.
@@ -140,26 +145,26 @@ public class SyncStorageRequest implemen
         request.setHeader("x-if-unmodified-since", ifUnmodifiedSince);
       }
       if (request.getMethod().equalsIgnoreCase("DELETE")) {
         request.addHeader("x-confirm-delete", "1");
       }
     }
   }
 
-  protected SyncResourceDelegate resourceDelegate;
+  protected BaseResourceDelegate resourceDelegate;
   public SyncStorageRequestDelegate delegate;
   protected BaseResource resource;
 
   public SyncStorageRequest() {
     super();
   }
 
   // Default implementation. Override this.
-  protected SyncResourceDelegate makeResourceDelegate(SyncStorageRequest request) {
+  protected BaseResourceDelegate makeResourceDelegate(SyncStorageRequest request) {
     return new SyncStorageResourceDelegate(request);
   }
 
   public void get() {
     this.resource.get();
   }
 
   public void delete() {
--- a/mobile/android/base/sync/setup/auth/AuthenticateAccountStage.java
+++ b/mobile/android/base/sync/setup/auth/AuthenticateAccountStage.java
@@ -1,27 +1,27 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.setup.auth;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
 import org.mozilla.apache.commons.codec.binary.Base64;
 import org.mozilla.gecko.sync.SyncConstants;
 import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncResourceDelegate;
+import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
 import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
 import ch.boye.httpclientandroidlib.message.BasicHeader;
 
@@ -90,17 +90,17 @@ public class AuthenticateAccountStage im
    *        Delegate to deal with HTTP response.
    * @param authRequestUrl
    * @param authHeader
    * @throws URISyntaxException
    */
   // Made public for testing.
   public void authenticateAccount(final AuthenticateAccountStageDelegate callbackDelegate, final String authRequestUrl, final String authHeader) throws URISyntaxException {
     final BaseResource httpResource = new BaseResource(authRequestUrl);
-    httpResource.delegate = new SyncResourceDelegate(httpResource) {
+    httpResource.delegate = new BaseResourceDelegate(httpResource) {
 
       @Override
       public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
         // Make reference to request, to abort if necessary.
         httpRequest = request;
         client.log.enableDebug(true);
         request.setHeader(new BasicHeader("User-Agent", SyncConstants.SYNC_USER_AGENT));
         // Host header is not set for some reason, so do it explicitly.
--- a/mobile/android/base/sync/setup/auth/EnsureUserExistenceStage.java
+++ b/mobile/android/base/sync/setup/auth/EnsureUserExistenceStage.java
@@ -9,17 +9,17 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
 import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncResourceDelegate;
+import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 
 public class EnsureUserExistenceStage implements AuthenticatorStage {
   private final String LOG_TAG = "EnsureUserExistence";
 
@@ -50,17 +50,17 @@ public class EnsureUserExistenceStage im
         Logger.info(LOG_TAG, "Error checking for user existence.");
         aa.abort(AuthenticationResult.FAILURE_SERVER, e);
       }
 
     };
 
     String userRequestUrl = aa.nodeServer + Constants.AUTH_NODE_PATHNAME + Constants.AUTH_NODE_VERSION + aa.username;
     final BaseResource httpResource = new BaseResource(userRequestUrl);
-    httpResource.delegate = new SyncResourceDelegate(httpResource) {
+    httpResource.delegate = new BaseResourceDelegate(httpResource) {
 
       @Override
       public void handleHttpResponse(HttpResponse response) {
         int statusCode = response.getStatusLine().getStatusCode();
         switch(statusCode) {
         case 200:
           try {
             InputStream content = response.getEntity().getContent();
--- a/mobile/android/base/sync/setup/auth/FetchUserNodeStage.java
+++ b/mobile/android/base/sync/setup/auth/FetchUserNodeStage.java
@@ -1,24 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.setup.auth;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
 import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncResourceDelegate;
+import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 import org.mozilla.gecko.sync.setup.Constants;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 
 public class FetchUserNodeStage implements AuthenticatorStage {
   private final String LOG_TAG = "FetchUserNodeStage";
 
@@ -72,17 +72,17 @@ public class FetchUserNodeStage implemen
         httpResource.get();
       }
     });
   }
 
   private BaseResource makeFetchNodeRequest(final FetchNodeStageDelegate callbackDelegate, String fetchNodeUrl) throws URISyntaxException {
     // Fetch node containing user.
     final BaseResource httpResource = new BaseResource(fetchNodeUrl);
-    httpResource.delegate = new SyncResourceDelegate(httpResource) {
+    httpResource.delegate = new BaseResourceDelegate(httpResource) {
 
       @Override
       public void handleHttpResponse(HttpResponse response) {
         int statusCode = response.getStatusLine().getStatusCode();
         switch(statusCode) {
         case 200:
           try {
             InputStream content = response.getEntity().getContent();
--- a/mobile/android/base/sync/stage/EnsureClusterURLStage.java
+++ b/mobile/android/base/sync/stage/EnsureClusterURLStage.java
@@ -13,17 +13,17 @@ import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.Logger;
 import org.mozilla.gecko.sync.NodeAuthenticationException;
 import org.mozilla.gecko.sync.NullClusterURLException;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncResourceDelegate;
+import org.mozilla.gecko.sync.net.BaseResourceDelegate;
 
 import ch.boye.httpclientandroidlib.HttpEntity;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.ClientProtocolException;
 
 public class EnsureClusterURLStage extends AbstractNonRepositorySyncStage {
   public EnsureClusterURLStage(GlobalSession session) {
     super(session);
@@ -67,17 +67,17 @@ public class EnsureClusterURLStage exten
    *          <code>https://server/pathname/version/username/node/weave</code>.
    * @throws URISyntaxException
    */
   public static void fetchClusterURL(final String nodeWeaveURL,
                                      final ClusterURLFetchDelegate delegate) throws URISyntaxException {
     Logger.info(LOG_TAG, "In fetchClusterURL: node/weave is " + nodeWeaveURL);
 
     BaseResource resource = new BaseResource(nodeWeaveURL);
-    resource.delegate = new SyncResourceDelegate(resource) {
+    resource.delegate = new BaseResourceDelegate(resource) {
 
       /**
        * Handle the response for GET https://server/pathname/version/username/node/weave.
        *
        * Returns the Sync Node that the client is located on.
        * Storage operations should be directed to that node.
        *
        * Return value: the node URL, an unadorned (not JSON) string.
--- a/mobile/android/services/java-sources.mn
+++ b/mobile/android/services/java-sources.mn
@@ -82,23 +82,27 @@ sync/Logger.java
 sync/MetaGlobal.java
 sync/MetaGlobalException.java
 sync/MetaGlobalMissingEnginesException.java
 sync/MetaGlobalNotSetException.java
 sync/middleware/Crypto5MiddlewareRepository.java
 sync/middleware/Crypto5MiddlewareRepositorySession.java
 sync/middleware/MiddlewareRepository.java
 sync/middleware/MiddlewareRepositorySession.java
+sync/net/AuthHeaderProvider.java
 sync/net/BaseResource.java
+sync/net/BaseResourceDelegate.java
+sync/net/BasicAuthHeaderProvider.java
+sync/net/BrowserIDAuthHeaderProvider.java
 sync/net/ConnectionMonitorThread.java
 sync/net/HandleProgressException.java
+sync/net/HMACAuthHeaderProvider.java
 sync/net/HttpResponseObserver.java
 sync/net/Resource.java
 sync/net/ResourceDelegate.java
-sync/net/SyncResourceDelegate.java
 sync/net/SyncResponse.java
 sync/net/SyncStorageCollectionRequest.java
 sync/net/SyncStorageCollectionRequestDelegate.java
 sync/net/SyncStorageRecordRequest.java
 sync/net/SyncStorageRequest.java
 sync/net/SyncStorageRequestDelegate.java
 sync/net/SyncStorageRequestIncrementalDelegate.java
 sync/net/SyncStorageResponse.java
--- a/services/common/rest.js
+++ b/services/common/rest.js
@@ -319,17 +319,23 @@ RESTRequest.prototype = {
     // will always be 'PUT'. Yeah, I know.
     channel.requestMethod = method;
 
     // Before opening the channel, set the charset that serves as a hint
     // as to what the response might be encoded as.
     channel.contentCharset = this.charset;
 
     // Blast off!
-    channel.asyncOpen(this, null);
+    try {
+      channel.asyncOpen(this, null);
+    } catch (ex) {
+      // asyncOpen can throw in a bunch of cases -- e.g., a forbidden port.
+      this._log.warn("Caught an error in asyncOpen: " + CommonUtils.exceptionStr(ex));
+      CommonUtils.nextTick(onComplete.bind(this, ex));
+    }
     this.status = this.SENT;
     this.delayTimeout();
     return this;
   },
 
   /**
    * Create or push back the abort timer that kills this request.
    */
--- a/services/common/tests/unit/test_restrequest.js
+++ b/services/common/tests/unit/test_restrequest.js
@@ -85,16 +85,32 @@ add_test(function test_proxy_auth_redire
     do_check_true(this.response.success);
     do_check_eq("TADA!", this.response.body);
     uninstallFakePAC();
     server.stop(run_next_test);
   });
 });
 
 /**
+ * Ensure that failures that cause asyncOpen to throw
+ * result in callbacks being invoked.
+ * Bug 826086.
+ */
+add_test(function test_forbidden_port() {
+  let request = new RESTRequest("http://localhost:6000/");
+  request.get(function(error) {
+    if (!error) {
+      do_throw("Should have got an error.");
+    }
+    do_check_eq(error.result, Components.results.NS_ERROR_PORT_ACCESS_NOT_ALLOWED);
+    run_next_test();
+  });
+});
+
+/**
  * Demonstrate API short-hand: create a request and dispatch it immediately.
  */
 add_test(function test_simple_get() {
   let handler = httpd_handler(200, "OK", "Huzzah!");
   let server = httpd_setup({"/resource": handler});
 
   let uri = TEST_RESOURCE_URL;
   let request = new RESTRequest(uri).get(function (error) {
--- a/services/sync/Makefile.in
+++ b/services/sync/Makefile.in
@@ -6,24 +6,22 @@ DEPTH     := @DEPTH@
 topsrcdir := @top_srcdir@
 srcdir    := @srcdir@
 VPATH     := @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 # Definitions used by constants.js.
 weave_version := 1.22.0
-weave_channel := rel
 weave_id      := {340c2bbc-ce74-4362-90b5-7c26312808ef}
 
 # Preprocess files.
 SYNC_PP := modules/constants.js
 SYNC_PP_FLAGS := \
  -Dweave_version=$(weave_version) \
- -Dweave_channel=$(weave_channel) \
  -Dweave_id=$(weave_id)
 SYNC_PP_PATH = $(FINAL_TARGET)/modules/services-sync
 PP_TARGETS += SYNC_PP
 
 # The set of core JavaScript modules for Sync. These are copied as-is.
 sync_modules := \
   addonsreconciler.js \
   addonutils.js \
--- a/services/sync/modules/constants.js
+++ b/services/sync/modules/constants.js
@@ -1,32 +1,27 @@
 #filter substitution
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Process each item in the "constants hash" to add to "global" and give a name
 this.EXPORTED_SYMBOLS = [((this[key] = val), key) for ([key, val] in Iterator({
 
-WEAVE_CHANNEL:                         "@weave_channel@",
 WEAVE_VERSION:                         "@weave_version@",
 
 // Sync Server API version that the client supports.
 SYNC_API_VERSION:                      "1.1",
 USER_API_VERSION:                      "1.0",
 MISC_API_VERSION:                      "1.0",
 
 // Version of the data format this client supports. The data format describes
 // how records are packaged; this is separate from the Server API version and
 // the per-engine cleartext formats.
 STORAGE_VERSION:                       5,
-
-UPDATED_DEV_URL:                       "https://services.mozilla.com/sync/updated/?version=@weave_version@&channel=@weave_channel@",
-UPDATED_REL_URL:                       "http://www.mozilla.com/firefox/sync/updated.html",
-
 PREFS_BRANCH:                          "services.sync.",
 
 // Host "key" to access Weave Identity in the password manager
 PWDMGR_HOST:                           "chrome://weave",
 PWDMGR_PASSWORD_REALM:                 "Mozilla Services Password",
 PWDMGR_PASSPHRASE_REALM:               "Mozilla Services Encryption Passphrase",
 PWDMGR_KEYBUNDLE_REALM:                "Mozilla Services Key Bundles",
 
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -88,20 +88,26 @@ Tracker.prototype = {
       this._log.debug("Not saving changedIDs.");
       return;
     }
     Utils.namedTimer(function() {
       Utils.jsonSave("changes/" + this.file, this, this.changedIDs, cb);
     }, 1000, this, "_lazySave");
   },
 
-  loadChangedIDs: function T_loadChangedIDs() {
+  loadChangedIDs: function (cb) {
     Utils.jsonLoad("changes/" + this.file, this, function(json) {
-      if (json) {
+      if (json && (typeof(json) == "object")) {
         this.changedIDs = json;
+      } else {
+        this._log.warn("Changed IDs file " + this.file + " contains non-object value.");
+        json = null;
+      }
+      if (cb) {
+        cb.call(this, json);
       }
     });
   },
 
   // ignore/unignore specific IDs.  Useful for ignoring items that are
   // being processed, or that shouldn't be synced.
   // But note: not persisted to disk
 
--- a/services/sync/modules/policies.js
+++ b/services/sync/modules/policies.js
@@ -168,20 +168,22 @@ SyncScheduler.prototype = {
         // should still be updated so that the next sync has a correct interval.
         this.updateClientMode();
         this.adjustSyncInterval();
         this.nextSync = 0;
         this.handleSyncError();
         break;
       case "weave:service:backoff:interval":
         let requested_interval = subject * 1000;
+        this._log.debug("Got backoff notification: " + requested_interval + "ms");
         // Leave up to 25% more time for the back off.
         let interval = requested_interval * (1 + Math.random() * 0.25);
         Status.backoffInterval = interval;
         Status.minimumNextSync = Date.now() + requested_interval;
+        this._log.debug("Fuzzed minimum next sync: " + Status.minimumNextSync);
         break;
       case "weave:service:ready":
         // Applications can specify this preference if they want autoconnect
         // to happen after a fixed delay.
         let delay = Svc.Prefs.get("autoconnectDelay");
         if (delay) {
           this.delayedAutoConnect(delay);
         }
@@ -800,23 +802,25 @@ ErrorHandler.prototype = {
         break;
 
       case 500:
       case 502:
       case 503:
       case 504:
         Status.enforceBackoff = true;
         if (resp.status == 503 && resp.headers["retry-after"]) {
+          let retryAfter = resp.headers["retry-after"];
+          this._log.debug("Got Retry-After: " + retryAfter);
           if (this.service.isLoggedIn) {
             Status.sync = SERVER_MAINTENANCE;
           } else {
             Status.login = SERVER_MAINTENANCE;
           }
           Svc.Obs.notify("weave:service:backoff:interval",
-                         parseInt(resp.headers["retry-after"], 10));
+                         parseInt(retryAfter, 10));
         }
         break;
     }
 
     switch (resp.result) {
       case Cr.NS_ERROR_UNKNOWN_HOST:
       case Cr.NS_ERROR_CONNECTION_REFUSED:
       case Cr.NS_ERROR_NET_TIMEOUT:
--- a/services/sync/modules/resource.js
+++ b/services/sync/modules/resource.js
@@ -215,17 +215,23 @@ AsyncResource.prototype = {
       channel.setUploadStream(stream, type, this._data.length);
     }
 
     // Setup a channel listener so that the actual network operation
     // is performed asynchronously.
     let listener = new ChannelListener(this._onComplete, this._onProgress,
                                        this._log, this.ABORT_TIMEOUT);
     channel.requestMethod = action;
-    channel.asyncOpen(listener, null);
+    try {
+      channel.asyncOpen(listener, null);
+    } catch (ex) {
+      // asyncOpen can throw in a bunch of cases -- e.g., a forbidden port.
+      this._log.warn("Caught an error in asyncOpen: " + CommonUtils.exceptionStr(ex));
+      CommonUtils.nextTick(callback.bind(this, ex));
+    }
   },
 
   _onComplete: function _onComplete(error, data, channel) {
     this._log.trace("In _onComplete. Error is " + error + ".");
 
     if (error) {
       this._callback(error);
       return;
@@ -280,23 +286,27 @@ AsyncResource.prototype = {
       channel.visitResponseHeaders({
         visitHeader: function visitHeader(header, value) {
           headers[header.toLowerCase()] = value;
         }
       });
 
       // This is a server-side safety valve to allow slowing down
       // clients without hurting performance.
-      if (headers["x-weave-backoff"])
+      if (headers["x-weave-backoff"]) {
+        let backoff = headers["x-weave-backoff"];
+        this._log.debug("Got X-Weave-Backoff: " + backoff);
         Observers.notify("weave:service:backoff:interval",
-                         parseInt(headers["x-weave-backoff"], 10));
+                         parseInt(backoff, 10));
+      }
 
-      if (success && headers["x-weave-quota-remaining"])
+      if (success && headers["x-weave-quota-remaining"]) {
         Observers.notify("weave:service:quota:remaining",
                          parseInt(headers["x-weave-quota-remaining"], 10));
+      }
     } catch (ex) {
       this._log.debug("Caught exception " + CommonUtils.exceptionStr(ex) +
                       " visiting headers in _onComplete.");
       this._log.debug(CommonUtils.stackTrace(ex));
     }
 
     let ret     = new String(data);
     ret.status  = status;
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -69,16 +69,20 @@ Sync11Service.prototype = {
   cryptoKeyURL: null,
 
   get enabledEngineNames() {
     return [e.name for each (e in this.engineManager.getEnabled())];
   },
 
   get serverURL() Svc.Prefs.get("serverURL"),
   set serverURL(value) {
+    if (!value.endsWith("/")) {
+      value += "/";
+    }
+
     // Only do work if it's actually changing
     if (value == this.serverURL)
       return;
 
     // A new server most likely uses a different cluster, so clear that
     Svc.Prefs.set("serverURL", value);
     Svc.Prefs.reset("clusterURL");
   },
@@ -113,20 +117,16 @@ Sync11Service.prototype = {
 
     return url + USER_API_VERSION + "/";
   },
 
   get pwResetURL() {
     return this.serverURL + "weave-password-reset";
   },
 
-  get updatedURL() {
-    return WEAVE_CHANNEL == "dev" ? UPDATED_DEV_URL : UPDATED_REL_URL;
-  },
-
   get syncID() {
     // Generate a random syncID id we don't have one
     let syncID = Svc.Prefs.get("client.syncID", "");
     return syncID == "" ? this.syncID = Utils.makeGUID() : syncID;
   },
   set syncID(value) {
     Svc.Prefs.set("client.syncID", value);
   },
--- a/services/sync/tests/unit/test_engine.js
+++ b/services/sync/tests/unit/test_engine.js
@@ -1,17 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/observers.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 
-
 function SteamStore(engine) {
   Store.call(this, "Steam", engine);
   this.wasWiped = false;
 }
 SteamStore.prototype = {
   __proto__: Store.prototype,
 
   wipe: function() {
@@ -59,58 +58,79 @@ let engineObserver = {
 };
 Observers.add("weave:engine:reset-client:start", engineObserver);
 Observers.add("weave:engine:reset-client:finish", engineObserver);
 Observers.add("weave:engine:wipe-client:start", engineObserver);
 Observers.add("weave:engine:wipe-client:finish", engineObserver);
 Observers.add("weave:engine:sync:start", engineObserver);
 Observers.add("weave:engine:sync:finish", engineObserver);
 
+function run_test() {
+  run_next_test();
+}
 
-function test_members() {
+add_test(function test_members() {
   _("Engine object members");
   let engine = new SteamEngine(Service);
   do_check_eq(engine.Name, "Steam");
   do_check_eq(engine.prefName, "steam");
   do_check_true(engine._store instanceof SteamStore);
   do_check_true(engine._tracker instanceof SteamTracker);
-}
+  run_next_test();
+});
 
-function test_score() {
+add_test(function test_score() {
   _("Engine.score corresponds to tracker.score and is readonly");
   let engine = new SteamEngine(Service);
   do_check_eq(engine.score, 0);
   engine._tracker.score += 5;
   do_check_eq(engine.score, 5);
 
   try {
     engine.score = 10;
   } catch(ex) {
     // Setting an attribute that has a getter produces an error in
     // Firefox <= 3.6 and is ignored in later versions.  Either way,
     // the attribute's value won't change.
   }
   do_check_eq(engine.score, 5);
-}
+  run_next_test();
+});
 
-function test_resetClient() {
+add_test(function test_resetClient() {
   _("Engine.resetClient calls _resetClient");
   let engine = new SteamEngine(Service);
   do_check_false(engine.wasReset);
 
   engine.resetClient();
   do_check_true(engine.wasReset);
   do_check_eq(engineObserver.topics[0], "weave:engine:reset-client:start");
   do_check_eq(engineObserver.topics[1], "weave:engine:reset-client:finish");
 
   engine.wasReset = false;
   engineObserver.reset();
-}
+  run_next_test();
+});
 
-function test_wipeClient() {
+add_test(function test_invalidChangedIDs() {
+  _("Test that invalid changed IDs on disk don't end up live.");
+  let engine = new SteamEngine(Service);
+  let tracker = engine._tracker;
+  tracker.changedIDs = 5;
+  tracker.saveChangedIDs(function onSaved() {
+      tracker.changedIDs = {placeholder: true};
+      tracker.loadChangedIDs(function onLoaded(json) {
+        do_check_null(json);
+        do_check_true(tracker.changedIDs.placeholder);
+        run_next_test();
+      });
+    });
+});
+
+add_test(function test_wipeClient() {
   _("Engine.wipeClient calls resetClient, wipes store, clears changed IDs");
   let engine = new SteamEngine(Service);
   do_check_false(engine.wasReset);
   do_check_false(engine._store.wasWiped);
   do_check_true(engine._tracker.addChangedID("a-changed-id"));
   do_check_true("a-changed-id" in engine._tracker.changedIDs);
 
   engine.wipeClient();
@@ -120,55 +140,49 @@ function test_wipeClient() {
   do_check_eq(engineObserver.topics[0], "weave:engine:wipe-client:start");
   do_check_eq(engineObserver.topics[1], "weave:engine:reset-client:start");
   do_check_eq(engineObserver.topics[2], "weave:engine:reset-client:finish");
   do_check_eq(engineObserver.topics[3], "weave:engine:wipe-client:finish");
 
   engine.wasReset = false;
   engine._store.wasWiped = false;
   engineObserver.reset();
-}
+  run_next_test();
+});
 
-function test_enabled() {
+add_test(function test_enabled() {
   _("Engine.enabled corresponds to preference");
   let engine = new SteamEngine(Service);
   try {
     do_check_false(engine.enabled);
     Svc.Prefs.set("engine.steam", true);
     do_check_true(engine.enabled);
 
     engine.enabled = false;
     do_check_false(Svc.Prefs.get("engine.steam"));
+    run_next_test();
   } finally {
     Svc.Prefs.resetBranch("");
   }
-}
+});
 
-function test_sync() {
+add_test(function test_sync() {
   let engine = new SteamEngine(Service);
   try {
     _("Engine.sync doesn't call _sync if it's not enabled");
     do_check_false(engine.enabled);
     do_check_false(engine.wasSynced);
     engine.sync();
     do_check_false(engine.wasSynced);
 
     _("Engine.sync calls _sync if it's enabled");
     engine.enabled = true;
     engine.sync();
     do_check_true(engine.wasSynced);
     do_check_eq(engineObserver.topics[0], "weave:engine:sync:start");
     do_check_eq(engineObserver.topics[1], "weave:engine:sync:finish");
+    run_next_test();
   } finally {
     Svc.Prefs.resetBranch("");
     engine.wasSynced = false;
     engineObserver.reset();
   }
-}
-
-function run_test() {
-  test_members();
-  test_score();
-  test_resetClient();
-  test_wipeClient();
-  test_enabled();
-  test_sync();
-}
+});
--- a/services/sync/tests/unit/test_resource_ua.js
+++ b/services/sync/tests/unit/test_resource_ua.js
@@ -4,95 +4,90 @@
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
 const TEST_GET_URL = "http://localhost:8080/1.1/johndoe/storage/meta/global";
 
-function test_resource_user_agent() {
-  let meta_global = new ServerWBO('global');
+// Tracking info/collections.
+let collectionsHelper = track_collections_helper();
+let collections = collectionsHelper.collections;
 
-  // Tracking info/collections.
-  let collectionsHelper = track_collections_helper();
-  let collections = collectionsHelper.collections;
+let meta_global;
+let server;
 
-  let ua;
-  function uaHandler(f) {
-    return function(request, response) {
-      ua = request.getHeader("User-Agent");
-      return f(request, response);
-    };
-  }
+let expectedUA;
+let ua;
+function uaHandler(f) {
+  return function(request, response) {
+    ua = request.getHeader("User-Agent");
+    return f(request, response);
+  };
+}
 
-  do_test_pending();
-  let server = httpd_setup({
+function run_test() {
+  meta_global = new ServerWBO('global');
+  server = httpd_setup({
     "/1.1/johndoe/info/collections": uaHandler(collectionsHelper.handler),
     "/1.1/johndoe/storage/meta/global": uaHandler(meta_global.handler()),
   });
 
   setBasicCredentials("johndoe", "ilovejane");
   Service.serverURL  = TEST_SERVER_URL;
   Service.clusterURL = TEST_CLUSTER_URL;
 
-  let expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
-                   " FxSync/" + WEAVE_VERSION + "." +
-                   Services.appinfo.appBuildID;
+  expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
+               " FxSync/" + WEAVE_VERSION + "." +
+               Services.appinfo.appBuildID;
+
+  run_next_test();
+}
 
-  function test_fetchInfo(next) {
-    _("Testing _fetchInfo.");
-    Service._fetchInfo();
+add_test(function test_fetchInfo() {
+  _("Testing _fetchInfo.");
+  Service._fetchInfo();
+  _("User-Agent: " + ua);
+  do_check_eq(ua, expectedUA + ".desktop");
+  ua = "";
+  run_next_test();
+});
+
+add_test(function test_desktop_post() {
+  _("Testing direct Resource POST.");
+  let r = new AsyncResource(TEST_GET_URL);
+  r.post("foo=bar", function (error, content) {
     _("User-Agent: " + ua);
     do_check_eq(ua, expectedUA + ".desktop");
     ua = "";
-    next();
-  }
+    run_next_test();
+  });
+});
 
-  function test_desktop_post(next) {
-    _("Testing direct Resource POST.");
-    let r = new AsyncResource(TEST_GET_URL);
-    r.post("foo=bar", function (error, content) {
-      _("User-Agent: " + ua);
-      do_check_eq(ua, expectedUA + ".desktop");
-      ua = "";
-      next();
-    });
-  }
-
-  function test_desktop_get(next) {
-    _("Testing async.");
-    Svc.Prefs.set("client.type", "desktop");
-    let r = new AsyncResource(TEST_GET_URL);
-    r.get(function(error, content) {
-      _("User-Agent: " + ua);
-      do_check_eq(ua, expectedUA + ".desktop");
-      ua = "";
-      next();
-    });
-  }
+add_test(function test_desktop_get() {
+  _("Testing async.");
+  Svc.Prefs.set("client.type", "desktop");
+  let r = new AsyncResource(TEST_GET_URL);
+  r.get(function(error, content) {
+    _("User-Agent: " + ua);
+    do_check_eq(ua, expectedUA + ".desktop");
+    ua = "";
+    run_next_test();
+  });
+});
 
-  function test_mobile_get(next) {
-    _("Testing mobile.");
-    Svc.Prefs.set("client.type", "mobile");
-    let r = new AsyncResource(TEST_GET_URL);
-    r.get(function (error, content) {
-      _("User-Agent: " + ua);
-      do_check_eq(ua, expectedUA + ".mobile");
-      ua = "";
-      next();
-    });
-  }
+add_test(function test_mobile_get() {
+  _("Testing mobile.");
+  Svc.Prefs.set("client.type", "mobile");
+  let r = new AsyncResource(TEST_GET_URL);
+  r.get(function (error, content) {
+    _("User-Agent: " + ua);
+    do_check_eq(ua, expectedUA + ".mobile");
+    ua = "";
+    run_next_test();
+  });
+});
 
-  Async.chain(
-    test_fetchInfo,
-    test_desktop_post,
-    test_desktop_get,
-    test_mobile_get,
-    function (next) {
-      server.stop(next);
-    },
-    do_test_finished)();
-}
+add_test(function tear_down() {
+  server.stop(run_next_test);
+});
 
-function run_test() {
-  test_resource_user_agent();
-}
new file mode 100644
--- /dev/null
+++ b/services/sync/tests/unit/test_service_set_serverURL.js
@@ -0,0 +1,13 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource://services-sync/service.js");
+
+function run_test() {
+  Service.serverURL = "http://example.com/sync";
+  do_check_eq(Service.serverURL, "http://example.com/sync/");
+
+  Service.serverURL = "http://example.com/sync/";
+  do_check_eq(Service.serverURL, "http://example.com/sync/");
+}
+
--- a/services/sync/tests/unit/xpcshell.ini
+++ b/services/sync/tests/unit/xpcshell.ini
@@ -66,16 +66,17 @@ skip-if = os == "mac" || os == "linux"
 # Bug 752243: Profile cleanup frequently fails
 skip-if = os == "mac" || os == "linux"
 [test_service_detect_upgrade.js]
 [test_service_getStorageInfo.js]
 [test_service_login.js]
 [test_service_migratePrefs.js]
 [test_service_passwordUTF8.js]
 [test_service_persistLogin.js]
+[test_service_set_serverURL.js]
 [test_service_startOver.js]
 [test_service_startup.js]
 [test_service_sync_401.js]
 [test_service_sync_locked.js]
 [test_service_sync_remoteSetup.js]
 # Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
 skip-if = os == "android"
 [test_service_sync_updateEnabledEngines.js]
--- a/testing/tps/tps/cli.py
+++ b/testing/tps/tps/cli.py
@@ -66,17 +66,19 @@ def main():
 
   # load the config file
   f = open(configfile, 'r')
   configcontent = f.read()
   f.close()
   config = json.loads(configcontent)
 
   rlock = RLock()
- 
+
+  print 'using result file', options.resultfile
+
   extensionDir = config.get("extensiondir")
   if not extensionDir or extensionDir == '__EXTENSIONDIR__':
     extensionDir = os.path.join(os.getcwd(), "..", "..", "services", "sync", "tps")
   else:
     if sys.platform == 'win32':
       # replace msys-style paths with proper Windows paths
       import re
       m = re.match('^\/\w\/', extensionDir)
@@ -86,13 +88,14 @@ def main():
 
   TPS = TPSTestRunner(extensionDir,
                       testfile=options.testfile,
                       logfile=options.logfile,
                       binary=options.binary,
                       config=config,
                       rlock=rlock,
                       mobile=options.mobile,
+                      resultfile=options.resultfile,
                       ignore_unused_engines=options.ignore_unused_engines)
   TPS.run_tests()
 
 if __name__ == "__main__":
   main()
--- a/testing/tps/tps/testrunner.py
+++ b/testing/tps/tps/testrunner.py
@@ -127,31 +127,38 @@ class TPSTestRunner(object):
 
     f = open(self.logfile, 'a')
     f.write(msg)
     f.close()
     if printToConsole:
       print msg
 
   def writeToResultFile(self, postdata, body=None,
-                        sendTo='crossweave@mozilla.com'):
+                        sendTo=['crossweave@mozilla.com']):
     """Writes results to test file"""
-    f = open(self.resultfile, 'a')
+
+    results = {'results': []}
+
+    if os.access(self.resultfile, os.F_OK):
+      f = open(self.resultfile, 'r')
+      results = json.loads(f.read())
+      f.close()
+
+    f = open(self.resultfile, 'w')
     if body is not None:
       postdata['body'] = body
     if self.numpassed is not None:
       postdata['numpassed'] = self.numpassed
     if self.numfailed is not None:
       postdata['numfailed'] = self.numfailed
     if self.firefoxRunner and self.firefoxRunner.url:
       postdata['firefoxrunnerurl'] = self.firefoxRunner.url
 
     postdata['sendTo'] = sendTo
-    results = {}
-    results['results'] = postdata
+    results['results'].append(postdata)
     f.write(json.dumps(results, indent=2))
     f.close()
 
   def _zip_add_file(self, zip, file, rootDir):
     zip.write(os.path.join(rootDir, file), file)
 
   def _zip_add_dir(self, zip, dir, rootDir):
     try:
@@ -334,17 +341,23 @@ class TPSTestRunner(object):
       self.numfailed = 1
       try:
         self.writeToResultFile(self.postdata,
                                '<pre>%s</pre>' % traceback.format_exc())
       except:
         traceback.print_exc()
     else:
       try:
-        self.writeToResultFile(self.postdata)
+
+        if self.numfailed > 0 or self.numpassed == 0:
+          To = self.config['email'].get('notificationlist')
+        else:
+          To = self.config['email'].get('passednotificationlist')
+        self.writeToResultFile(self.postdata,
+                               sendTo=To)
       except:
         traceback.print_exc()
         try:
           self.writeToResultFile(self.postdata,
                                  '<pre>%s</pre>' % traceback.format_exc())
         except:
           traceback.print_exc()