Merge mozilla-central into mozilla-inbound
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 03 Jan 2013 01:06:46 -0500
changeset 126523 d8603eadb9d01231f3afe42cc81074b98394b56a
parent 126522 c78f5379558a29a24b9e9e343a0754bffcc93073 (current diff)
parent 126472 6955309291ee4afe219fee09987f3838ccf5ac83 (diff)
child 126524 2fba029be56a2ba5f9754d04f5a8d3bff67c06fb
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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()