• 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.Build;
36 import android.os.Bundle;
37 import android.text.TextUtils;
38 import android.util.Log;
39 
40 import java.io.IOException;
41 import java.util.List;
42 
43 /**
44  * SyncAdapter implementation for syncing sample SyncAdapter contacts to the
45  * platform ContactOperations provider.  This sample shows a basic 2-way
46  * sync between the client and a sample server.  It also contains an
47  * example of how to update the contacts' status messages, which
48  * would be useful for a messaging or social networking client.
49  */
50 public class SyncAdapter extends AbstractThreadedSyncAdapter {
51 
52     private static final String TAG = "SyncAdapter";
53     private static final String SYNC_MARKER_KEY = "com.example.android.samplesync.marker";
54     private static final boolean NOTIFY_AUTH_FAILURE = true;
55 
56     private final AccountManager mAccountManager;
57 
58     private final Context mContext;
59 
SyncAdapter(Context context, boolean autoInitialize)60     public SyncAdapter(Context context, boolean autoInitialize) {
61         super(context, autoInitialize);
62         mContext = context;
63         mAccountManager = AccountManager.get(context);
64     }
65 
66     @Override
onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)67     public void onPerformSync(Account account, Bundle extras, String authority,
68         ContentProviderClient provider, SyncResult syncResult) {
69 
70         try {
71             // see if we already have a sync-state attached to this account. By handing
72             // This value to the server, we can just get the contacts that have
73             // been updated on the server-side since our last sync-up
74             long lastSyncMarker = getServerSyncMarker(account);
75 
76             // By default, contacts from a 3rd party provider are hidden in the contacts
77             // list. So let's set the flag that causes them to be visible, so that users
78             // can actually see these contacts.
79             if (lastSyncMarker == 0) {
80                 ContactManager.setAccountContactsVisibility(getContext(), account, true);
81             }
82 
83             List<RawContact> dirtyContacts;
84             List<RawContact> updatedContacts;
85 
86             // Use the account manager to request the AuthToken we'll need
87             // to talk to our sample server.  If we don't have an AuthToken
88             // yet, this could involve a round-trip to the server to request
89             // and AuthToken.
90             final String authtoken = mAccountManager.blockingGetAuthToken(account,
91                     Constants.AUTHTOKEN_TYPE, NOTIFY_AUTH_FAILURE);
92 
93             // Make sure that the sample group exists
94             final long groupId = ContactManager.ensureSampleGroupExists(mContext, account);
95 
96             // Find the local 'dirty' contacts that we need to tell the server about...
97             // Find the local users that need to be sync'd to the server...
98             dirtyContacts = ContactManager.getDirtyContacts(mContext, account);
99 
100             // Send the dirty contacts to the server, and retrieve the server-side changes
101             updatedContacts = NetworkUtilities.syncContacts(account, authtoken,
102                     lastSyncMarker, dirtyContacts);
103 
104             // Update the local contacts database with the changes. updateContacts()
105             // returns a syncState value that indicates the high-water-mark for
106             // the changes we received.
107             Log.d(TAG, "Calling contactManager's sync contacts");
108             long newSyncState = ContactManager.updateContacts(mContext,
109                     account.name,
110                     updatedContacts,
111                     groupId,
112                     lastSyncMarker);
113 
114             // This is a demo of how you can update IM-style status messages
115             // for contacts on the client. This probably won't apply to
116             // 2-way contact sync providers - it's more likely that one-way
117             // sync providers (IM clients, social networking apps, etc) would
118             // use this feature.
119 
120             ContactManager.updateStatusMessages(mContext, updatedContacts);
121 
122             // This is a demo of how you can add stream items for contacts on
123             // the client. This probably won't apply to
124             // 2-way contact sync providers - it's more likely that one-way
125             // sync providers (IM clients, social networking apps, etc) would
126             // use this feature. This is only supported in ICS MR1 or above.
127 
128             if (Build.VERSION.SDK_INT >=
129                     Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
130                 ContactManager.addStreamItems(mContext, updatedContacts,
131                     account.name, account.type);
132             }
133 
134             // Save off the new sync marker. On our next sync, we only want to receive
135             // contacts that have changed since this sync...
136             setServerSyncMarker(account, newSyncState);
137 
138             if (dirtyContacts.size() > 0) {
139                 ContactManager.clearSyncFlags(mContext, dirtyContacts);
140             }
141 
142         } catch (final AuthenticatorException e) {
143             Log.e(TAG, "AuthenticatorException", e);
144             syncResult.stats.numParseExceptions++;
145         } catch (final OperationCanceledException e) {
146             Log.e(TAG, "OperationCanceledExcetpion", e);
147         } catch (final IOException e) {
148             Log.e(TAG, "IOException", e);
149             syncResult.stats.numIoExceptions++;
150         } catch (final AuthenticationException e) {
151             Log.e(TAG, "AuthenticationException", e);
152             syncResult.stats.numAuthExceptions++;
153         } catch (final ParseException e) {
154             Log.e(TAG, "ParseException", e);
155             syncResult.stats.numParseExceptions++;
156         } catch (final JSONException e) {
157             Log.e(TAG, "JSONException", e);
158             syncResult.stats.numParseExceptions++;
159         }
160     }
161 
162     /**
163      * This helper function fetches the last known high-water-mark
164      * we received from the server - or 0 if we've never synced.
165      * @param account the account we're syncing
166      * @return the change high-water-mark
167      */
getServerSyncMarker(Account account)168     private long getServerSyncMarker(Account account) {
169         String markerString = mAccountManager.getUserData(account, SYNC_MARKER_KEY);
170         if (!TextUtils.isEmpty(markerString)) {
171             return Long.parseLong(markerString);
172         }
173         return 0;
174     }
175 
176     /**
177      * Save off the high-water-mark we receive back from the server.
178      * @param account The account we're syncing
179      * @param marker The high-water-mark we want to save.
180      */
setServerSyncMarker(Account account, long marker)181     private void setServerSyncMarker(Account account, long marker) {
182         mAccountManager.setUserData(account, SYNC_MARKER_KEY, Long.toString(marker));
183     }
184 }
185 
186