• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 package com.example.android.samplesync.syncadapter;
17 
18 import com.example.android.samplesync.Constants;
19 import com.example.android.samplesync.client.NetworkUtilities;
20 import com.example.android.samplesync.client.RawContact;
21 import com.example.android.samplesync.platform.ContactManager;
22 
23 import org.apache.http.ParseException;
24 import org.apache.http.auth.AuthenticationException;
25 import org.json.JSONException;
26 
27 import android.accounts.Account;
28 import android.accounts.AccountManager;
29 import android.accounts.AuthenticatorException;
30 import android.accounts.OperationCanceledException;
31 import android.content.AbstractThreadedSyncAdapter;
32 import android.content.ContentProviderClient;
33 import android.content.Context;
34 import android.content.SyncResult;
35 import android.os.Bundle;
36 import android.text.TextUtils;
37 import android.util.Log;
38 
39 import java.io.IOException;
40 import java.util.List;
41 
42 /**
43  * SyncAdapter implementation for syncing sample SyncAdapter contacts to the
44  * platform ContactOperations provider.  This sample shows a basic 2-way
45  * sync between the client and a sample server.  It also contains an
46  * example of how to update the contacts' status messages, which
47  * would be useful for a messaging or social networking client.
48  */
49 public class SyncAdapter extends AbstractThreadedSyncAdapter {
50 
51     private static final String TAG = "SyncAdapter";
52     private static final String SYNC_MARKER_KEY = "com.example.android.samplesync.marker";
53     private static final boolean NOTIFY_AUTH_FAILURE = true;
54 
55     private final AccountManager mAccountManager;
56 
57     private final Context mContext;
58 
SyncAdapter(Context context, boolean autoInitialize)59     public SyncAdapter(Context context, boolean autoInitialize) {
60         super(context, autoInitialize);
61         mContext = context;
62         mAccountManager = AccountManager.get(context);
63     }
64 
65     @Override
onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)66     public void onPerformSync(Account account, Bundle extras, String authority,
67         ContentProviderClient provider, SyncResult syncResult) {
68 
69         try {
70             // see if we already have a sync-state attached to this account. By handing
71             // This value to the server, we can just get the contacts that have
72             // been updated on the server-side since our last sync-up
73             long lastSyncMarker = getServerSyncMarker(account);
74 
75             // By default, contacts from a 3rd party provider are hidden in the contacts
76             // list. So let's set the flag that causes them to be visible, so that users
77             // can actually see these contacts.
78             if (lastSyncMarker == 0) {
79                 ContactManager.setAccountContactsVisibility(getContext(), account, true);
80             }
81 
82             List<RawContact> dirtyContacts;
83             List<RawContact> updatedContacts;
84 
85             // Use the account manager to request the AuthToken we'll need
86             // to talk to our sample server.  If we don't have an AuthToken
87             // yet, this could involve a round-trip to the server to request
88             // and AuthToken.
89             final String authtoken = mAccountManager.blockingGetAuthToken(account,
90                     Constants.AUTHTOKEN_TYPE, NOTIFY_AUTH_FAILURE);
91 
92             // Make sure that the sample group exists
93             final long groupId = ContactManager.ensureSampleGroupExists(mContext, account);
94 
95             // Find the local 'dirty' contacts that we need to tell the server about...
96             // Find the local users that need to be sync'd to the server...
97             dirtyContacts = ContactManager.getDirtyContacts(mContext, account);
98 
99             // Send the dirty contacts to the server, and retrieve the server-side changes
100             updatedContacts = NetworkUtilities.syncContacts(account, authtoken,
101                     lastSyncMarker, dirtyContacts);
102 
103             // Update the local contacts database with the changes. updateContacts()
104             // returns a syncState value that indicates the high-water-mark for
105             // the changes we received.
106             Log.d(TAG, "Calling contactManager's sync contacts");
107             long newSyncState = ContactManager.updateContacts(mContext,
108                     account.name,
109                     updatedContacts,
110                     groupId,
111                     lastSyncMarker);
112 
113             // This is a demo of how you can update IM-style status messages
114             // for contacts on the client. This probably won't apply to
115             // 2-way contact sync providers - it's more likely that one-way
116             // sync providers (IM clients, social networking apps, etc) would
117             // use this feature.
118             ContactManager.updateStatusMessages(mContext, updatedContacts);
119 
120             // Save off the new sync marker. On our next sync, we only want to receive
121             // contacts that have changed since this sync...
122             setServerSyncMarker(account, newSyncState);
123 
124             if (dirtyContacts.size() > 0) {
125                 ContactManager.clearSyncFlags(mContext, dirtyContacts);
126             }
127 
128         } catch (final AuthenticatorException e) {
129             Log.e(TAG, "AuthenticatorException", e);
130             syncResult.stats.numParseExceptions++;
131         } catch (final OperationCanceledException e) {
132             Log.e(TAG, "OperationCanceledExcetpion", e);
133         } catch (final IOException e) {
134             Log.e(TAG, "IOException", e);
135             syncResult.stats.numIoExceptions++;
136         } catch (final AuthenticationException e) {
137             Log.e(TAG, "AuthenticationException", e);
138             syncResult.stats.numAuthExceptions++;
139         } catch (final ParseException e) {
140             Log.e(TAG, "ParseException", e);
141             syncResult.stats.numParseExceptions++;
142         } catch (final JSONException e) {
143             Log.e(TAG, "JSONException", e);
144             syncResult.stats.numParseExceptions++;
145         }
146     }
147 
148     /**
149      * This helper function fetches the last known high-water-mark
150      * we received from the server - or 0 if we've never synced.
151      * @param account the account we're syncing
152      * @return the change high-water-mark
153      */
getServerSyncMarker(Account account)154     private long getServerSyncMarker(Account account) {
155         String markerString = mAccountManager.getUserData(account, SYNC_MARKER_KEY);
156         if (!TextUtils.isEmpty(markerString)) {
157             return Long.parseLong(markerString);
158         }
159         return 0;
160     }
161 
162     /**
163      * Save off the high-water-mark we receive back from the server.
164      * @param account The account we're syncing
165      * @param marker The high-water-mark we want to save.
166      */
setServerSyncMarker(Account account, long marker)167     private void setServerSyncMarker(Account account, long marker) {
168         mAccountManager.setUserData(account, SYNC_MARKER_KEY, Long.toString(marker));
169     }
170 }
171