/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package eu.ttbox.androgister.sync.syncadapter; import java.io.IOException; import java.util.List; import de.greenrobot.dao.query.LazyList; import de.greenrobot.dao.query.QueryBuilder; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.AbstractThreadedSyncAdapter; import android.content.ContentProviderClient; import android.content.Context; import android.content.SyncResult; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import eu.ttbox.androgister.AndroGisterApplication; import eu.ttbox.androgister.domain.Product; import eu.ttbox.androgister.domain.ProductDao; import eu.ttbox.androgister.domain.ProductDao.Properties; import eu.ttbox.androgister.sync.Constants; import eu.ttbox.androgister.sync.client.NetworkUtilities; import eu.ttbox.androgister.sync.client.RawContact; /** * SyncAdapter implementation for syncing sample SyncAdapter contacts to the * platform ContactOperations provider. This sample shows a basic 2-way sync * between the client and a sample server. It also contains an example of how to * update the contacts' status messages, which would be useful for a messaging * or social networking client. * * @see http * ://stackoverflow.com/questions/1859241/own-sync-adapter-for-android/ * 7795266 * @see http://dev.evernote.com/media/pdf/edam-sync.pdf */ public class ProductSyncAdapter extends AbstractThreadedSyncAdapter { private static final String TAG = "SyncAdapter"; private static final String SYNC_MARKER_KEY = "eu.ttbox.androgister.sync.marker.product"; private static final boolean NOTIFY_AUTH_FAILURE = true; private final AccountManager mAccountManager; private final Context mContext; private ProductDao productDao; public ProductSyncAdapter(Context context, boolean autoInitialize) { super(context, autoInitialize); mContext = context; mAccountManager = AccountManager.get(context); // Dao AndroGisterApplication app = (AndroGisterApplication) context.getApplicationContext(); productDao = app.getDaoSession().getProductDao(); } public QueryBuilder<Product> createSearchQuery(ProductDao entityDao) { QueryBuilder<Product> queryBuilder = productDao.queryBuilder(); queryBuilder.where(Properties.Dirty.eq(Boolean.TRUE)); return queryBuilder; } @Override public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { try { // see if we already have a sync-state attached to this account. By // handing // This value to the server, we can just get the contacts that have // been updated on the server-side since our last sync-up long lastSyncMarker = getServerSyncMarker(account); // // // By default, contacts from a 3rd party provider are hidden in // the // contacts // // list. So let's set the flag that causes them to be visible, so // that users // // can actually see these contacts. // if (lastSyncMarker == 0) { // ContactManager.setAccountContactsVisibility(getContext(), // account, // true); // } // List<Product> dirtyContacts; List<RawContact> updatedContacts; // Use the account manager to request the AuthToken we'll need // to talk to our sample server. If we don't have an AuthToken // yet, this could involve a round-trip to the server to request // and AuthToken. final String authtoken = mAccountManager.blockingGetAuthToken(account, Constants.AUTHTOKEN_TYPE, NOTIFY_AUTH_FAILURE); QueryBuilder<Product> queryBuilder = createSearchQuery(productDao); LazyList<Product> products = queryBuilder.build().listLazy(); try { for (Product product : products) { } } finally { products.close(); } // // // Make sure that the sample group exists // final long groupId = // ContactManager.ensureSampleGroupExists(mContext, account); // // Find the local 'dirty' contacts that we need to tell the server // about... // Find the local users that need to be sync'd to the server... dirtyContacts = ProductManager.getDirtyProducts(mContext, account); // // // Send the dirty contacts to the server, and retrieve the // server-side changes // updatedContacts = NetworkUtilities.syncContacts(account, // authtoken, lastSyncMarker, dirtyContacts); // // // Update the local contacts database with the changes. // updateContacts() // // returns a syncState value that indicates the high-water-mark // for // // the changes we received. // Log.d(TAG, "Calling contactManager's sync contacts"); // long newSyncState = ContactManager.updateContacts(mContext, // account.name, // updatedContacts, // groupId, // lastSyncMarker); // // // This is a demo of how you can update IM-style status messages // // for contacts on the client. This probably won't apply to // // 2-way contact sync providers - it's more likely that one-way // // sync providers (IM clients, social networking apps, etc) would // // use this feature. // // ContactManager.updateStatusMessages(mContext, updatedContacts); // // // This is a demo of how you can add stream items for contacts on // // the client. This probably won't apply to // // 2-way contact sync providers - it's more likely that one-way // // sync providers (IM clients, social networking apps, etc) would // // use this feature. This is only supported in ICS MR1 or above. // // if (Build.VERSION.SDK_INT >= // Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { // ContactManager.addStreamItems(mContext, updatedContacts, // account.name, account.type); // } // // Save off the new sync marker. On our next sync, we only want to // receive // contacts that have changed since this sync... // setServerSyncMarker(account, newSyncState); // // if (dirtyContacts.size() > 0) { // ContactManager.clearSyncFlags(mContext, dirtyContacts); // } } catch (final AuthenticatorException e) { Log.e(TAG, "AuthenticatorException", e); syncResult.stats.numParseExceptions++; } catch (final OperationCanceledException e) { Log.e(TAG, "OperationCanceledExcetpion", e); } catch (final IOException e) { Log.e(TAG, "IOException", e); syncResult.stats.numIoExceptions++; // } catch (final AuthenticationException e) { // Log.e(TAG, "AuthenticationException", e); // syncResult.stats.numAuthExceptions++; // } catch (final ParseException e) { // Log.e(TAG, "ParseException", e); // syncResult.stats.numParseExceptions++; // } catch (final JSONException e) { // Log.e(TAG, "JSONException", e); // syncResult.stats.numParseExceptions++; } } /** * This helper function fetches the last known high-water-mark we received * from the server - or 0 if we've never synced. * * @param account * the account we're syncing * @return the change high-water-mark */ private long getServerSyncMarker(Account account) { String markerString = mAccountManager.getUserData(account, SYNC_MARKER_KEY); if (!TextUtils.isEmpty(markerString)) { return Long.parseLong(markerString); } return 0; } /** * Save off the high-water-mark we receive back from the server. * * @param account * The account we're syncing * @param marker * The high-water-mark we want to save. */ private void setServerSyncMarker(Account account, long marker) { mAccountManager.setUserData(account, SYNC_MARKER_KEY, Long.toString(marker)); } }