New version of SampleSyncAdapter sample code that allows local editing
The changes made were pretty sweeping. The biggest addition was to allow on-device contact creation/editing, and supporting 2-way sync to the sample server that runs in Google App Engine. The client-side sample code also includes examples of how to support the user of AuthTokens (instead of always sending username/password to the server), how to change a contact's picture, and how to set IM-style status messages for each contact. I also greatly simplified the server code so that instead of mimicking both an addressbook and an IM-style status update system for multiple users, it really just simulates an addressbook for a single user. The server code also includes a cron job that (once a week) blows away the contact database, so that it's relatively self-cleaning. Change-Id: I017f1d3f9320a02fe05a20f1613846963107145e
This commit is contained in:
@@ -1,23 +1,27 @@
|
||||
/*
|
||||
* 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 com.example.android.samplesync.client;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.example.android.samplesync.authenticator.AuthenticatorActivity;
|
||||
@@ -37,11 +41,19 @@ import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.params.HttpConnectionParams;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@@ -52,31 +64,26 @@ import java.util.TimeZone;
|
||||
* Provides utility methods for communicating with the server.
|
||||
*/
|
||||
final public class NetworkUtilities {
|
||||
|
||||
/** The tag used to log to adb console. **/
|
||||
/** The tag used to log to adb console. */
|
||||
private static final String TAG = "NetworkUtilities";
|
||||
|
||||
/** The Intent extra to store password. **/
|
||||
public static final String PARAM_PASSWORD = "password";
|
||||
|
||||
/** The Intent extra to store username. **/
|
||||
/** POST parameter name for the user's account name */
|
||||
public static final String PARAM_USERNAME = "username";
|
||||
|
||||
public static final String PARAM_UPDATED = "timestamp";
|
||||
|
||||
public static final String USER_AGENT = "AuthenticationService/1.0";
|
||||
|
||||
public static final int REGISTRATION_TIMEOUT_MS = 30 * 1000; // ms
|
||||
|
||||
public static final String BASE_URL = "https://samplesyncadapter.appspot.com";
|
||||
|
||||
/** POST parameter name for the user's password */
|
||||
public static final String PARAM_PASSWORD = "password";
|
||||
/** POST parameter name for the user's authentication token */
|
||||
public static final String PARAM_AUTH_TOKEN = "authtoken";
|
||||
/** POST parameter name for the client's last-known sync state */
|
||||
public static final String PARAM_SYNC_STATE = "syncstate";
|
||||
/** POST parameter name for the sending client-edited contact info */
|
||||
public static final String PARAM_CONTACTS_DATA = "contacts";
|
||||
/** Timeout (in ms) we specify for each http request */
|
||||
public static final int HTTP_REQUEST_TIMEOUT_MS = 30 * 1000;
|
||||
/** Base URL for the v2 Sample Sync Service */
|
||||
public static final String BASE_URL = "https://samplesyncadapter2.appspot.com";
|
||||
/** URI for authentication service */
|
||||
public static final String AUTH_URI = BASE_URL + "/auth";
|
||||
|
||||
public static final String FETCH_FRIEND_UPDATES_URI = BASE_URL + "/fetch_friend_updates";
|
||||
|
||||
public static final String FETCH_STATUS_URI = BASE_URL + "/fetch_status";
|
||||
|
||||
private static HttpClient mHttpClient;
|
||||
/** URI for sync service */
|
||||
public static final String SYNC_CONTACTS_URI = BASE_URL + "/sync";
|
||||
|
||||
private NetworkUtilities() {
|
||||
}
|
||||
@@ -84,224 +91,188 @@ final public class NetworkUtilities {
|
||||
/**
|
||||
* Configures the httpClient to connect to the URL provided.
|
||||
*/
|
||||
public static void maybeCreateHttpClient() {
|
||||
if (mHttpClient == null) {
|
||||
mHttpClient = new DefaultHttpClient();
|
||||
final HttpParams params = mHttpClient.getParams();
|
||||
HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT_MS);
|
||||
HttpConnectionParams.setSoTimeout(params, REGISTRATION_TIMEOUT_MS);
|
||||
ConnManagerParams.setTimeout(params, REGISTRATION_TIMEOUT_MS);
|
||||
}
|
||||
public static HttpClient getHttpClient() {
|
||||
HttpClient httpClient = new DefaultHttpClient();
|
||||
final HttpParams params = httpClient.getParams();
|
||||
HttpConnectionParams.setConnectionTimeout(params, HTTP_REQUEST_TIMEOUT_MS);
|
||||
HttpConnectionParams.setSoTimeout(params, HTTP_REQUEST_TIMEOUT_MS);
|
||||
ConnManagerParams.setTimeout(params, HTTP_REQUEST_TIMEOUT_MS);
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the network requests on a separate thread.
|
||||
*
|
||||
* @param runnable The runnable instance containing network mOperations to
|
||||
* be executed.
|
||||
* Connects to the SampleSync test server, authenticates the provided
|
||||
* username and password.
|
||||
*
|
||||
* @param username The server account username
|
||||
* @param password The server account password
|
||||
* @return String The authentication token returned by the server (or null)
|
||||
*/
|
||||
public static Thread performOnBackgroundThread(final Runnable runnable) {
|
||||
final Thread t = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
runnable.run();
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the Voiper server, authenticates the provided username and
|
||||
* password.
|
||||
*
|
||||
* @param username The user's username
|
||||
* @param password The user's password
|
||||
* @param handler The hander instance from the calling UI thread.
|
||||
* @param context The context of the calling Activity.
|
||||
* @return boolean The boolean result indicating whether the user was
|
||||
* successfully authenticated.
|
||||
*/
|
||||
public static boolean authenticate(String username, String password, Handler handler,
|
||||
final Context context) {
|
||||
public static String authenticate(String username, String password) {
|
||||
|
||||
final HttpResponse resp;
|
||||
final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||
params.add(new BasicNameValuePair(PARAM_USERNAME, username));
|
||||
params.add(new BasicNameValuePair(PARAM_PASSWORD, password));
|
||||
HttpEntity entity = null;
|
||||
final HttpEntity entity;
|
||||
try {
|
||||
entity = new UrlEncodedFormEntity(params);
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
// this should never happen.
|
||||
throw new AssertionError(e);
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
Log.i(TAG, "Authenticating to: " + AUTH_URI);
|
||||
final HttpPost post = new HttpPost(AUTH_URI);
|
||||
post.addHeader(entity.getContentType());
|
||||
post.setEntity(entity);
|
||||
maybeCreateHttpClient();
|
||||
try {
|
||||
resp = mHttpClient.execute(post);
|
||||
resp = getHttpClient().execute(post);
|
||||
String authToken = null;
|
||||
if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "Successful authentication");
|
||||
InputStream istream = (resp.getEntity() != null) ? resp.getEntity().getContent()
|
||||
: null;
|
||||
if (istream != null) {
|
||||
BufferedReader ireader = new BufferedReader(new InputStreamReader(istream));
|
||||
authToken = ireader.readLine().trim();
|
||||
}
|
||||
sendResult(true, handler, context);
|
||||
return true;
|
||||
}
|
||||
if ((authToken != null) && (authToken.length() > 0)) {
|
||||
Log.v(TAG, "Successful authentication");
|
||||
return authToken;
|
||||
} else {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "Error authenticating" + resp.getStatusLine());
|
||||
}
|
||||
sendResult(false, handler, context);
|
||||
return false;
|
||||
Log.e(TAG, "Error authenticating" + resp.getStatusLine());
|
||||
return null;
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "IOException when getting authtoken", e);
|
||||
}
|
||||
sendResult(false, handler, context);
|
||||
return false;
|
||||
Log.e(TAG, "IOException when getting authtoken", e);
|
||||
return null;
|
||||
} finally {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "getAuthtoken completing");
|
||||
}
|
||||
Log.v(TAG, "getAuthtoken completing");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the authentication response from server back to the caller main UI
|
||||
* thread through its handler.
|
||||
*
|
||||
* @param result The boolean holding authentication result
|
||||
* @param handler The main UI thread's handler instance.
|
||||
* @param context The caller Activity's context.
|
||||
* Perform 2-way sync with the server-side contacts. We send a request that
|
||||
* includes all the locally-dirty contacts so that the server can process
|
||||
* those changes, and we receive (and return) a list of contacts that were
|
||||
* updated on the server-side that need to be updated locally.
|
||||
*
|
||||
* @param account The account being synced
|
||||
* @param authtoken The authtoken stored in the AccountManager for this
|
||||
* account
|
||||
* @param serverSyncState A token returned from the server on the last sync
|
||||
* @param dirtyContacts A list of the contacts to send to the server
|
||||
* @return A list of contacts that we need to update locally
|
||||
*/
|
||||
private static void sendResult(final Boolean result, final Handler handler,
|
||||
final Context context) {
|
||||
if (handler == null || context == null) {
|
||||
return;
|
||||
public static List<RawContact> syncContacts(
|
||||
Account account, String authtoken, long serverSyncState, List<RawContact> dirtyContacts)
|
||||
throws JSONException, ParseException, IOException, AuthenticationException {
|
||||
// Convert our list of User objects into a list of JSONObject
|
||||
List<JSONObject> jsonContacts = new ArrayList<JSONObject>();
|
||||
for (RawContact rawContact : dirtyContacts) {
|
||||
jsonContacts.add(rawContact.toJSONObject());
|
||||
}
|
||||
handler.post(new Runnable() {
|
||||
public void run() {
|
||||
((AuthenticatorActivity) context).onAuthenticationResult(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to authenticate the user credentials on the server.
|
||||
*
|
||||
* @param username The user's username
|
||||
* @param password The user's password to be authenticated
|
||||
* @param handler The main UI thread's handler instance.
|
||||
* @param context The caller Activity's context
|
||||
* @return Thread The thread on which the network mOperations are executed.
|
||||
*/
|
||||
public static Thread attemptAuth(final String username, final String password,
|
||||
final Handler handler, final Context context) {
|
||||
// Create a special JSONArray of our JSON contacts
|
||||
JSONArray buffer = new JSONArray(jsonContacts);
|
||||
|
||||
final Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
authenticate(username, password, handler, context);
|
||||
}
|
||||
};
|
||||
// run on background thread.
|
||||
return NetworkUtilities.performOnBackgroundThread(runnable);
|
||||
}
|
||||
// Create an array that will hold the server-side contacts
|
||||
// that have been changed (returned by the server).
|
||||
final ArrayList<RawContact> serverDirtyList = new ArrayList<RawContact>();
|
||||
|
||||
/**
|
||||
* Fetches the list of friend data updates from the server
|
||||
*
|
||||
* @param account The account being synced.
|
||||
* @param authtoken The authtoken stored in AccountManager for this account
|
||||
* @param lastUpdated The last time that sync was performed
|
||||
* @return list The list of updates received from the server.
|
||||
*/
|
||||
public static List<User> fetchFriendUpdates(Account account, String authtoken, Date lastUpdated)
|
||||
throws JSONException, ParseException, IOException, AuthenticationException {
|
||||
|
||||
final ArrayList<User> friendList = new ArrayList<User>();
|
||||
// Prepare our POST data
|
||||
final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||
params.add(new BasicNameValuePair(PARAM_USERNAME, account.name));
|
||||
params.add(new BasicNameValuePair(PARAM_PASSWORD, authtoken));
|
||||
if (lastUpdated != null) {
|
||||
final SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm");
|
||||
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
params.add(new BasicNameValuePair(PARAM_UPDATED, formatter.format(lastUpdated)));
|
||||
params.add(new BasicNameValuePair(PARAM_AUTH_TOKEN, authtoken));
|
||||
params.add(new BasicNameValuePair(PARAM_CONTACTS_DATA, buffer.toString()));
|
||||
if (serverSyncState > 0) {
|
||||
params.add(new BasicNameValuePair(PARAM_SYNC_STATE, Long.toString(serverSyncState)));
|
||||
}
|
||||
Log.i(TAG, params.toString());
|
||||
HttpEntity entity = null;
|
||||
entity = new UrlEncodedFormEntity(params);
|
||||
final HttpPost post = new HttpPost(FETCH_FRIEND_UPDATES_URI);
|
||||
HttpEntity entity = new UrlEncodedFormEntity(params);
|
||||
|
||||
// Send the updated friends data to the server
|
||||
Log.i(TAG, "Syncing to: " + SYNC_CONTACTS_URI);
|
||||
final HttpPost post = new HttpPost(SYNC_CONTACTS_URI);
|
||||
post.addHeader(entity.getContentType());
|
||||
post.setEntity(entity);
|
||||
maybeCreateHttpClient();
|
||||
final HttpResponse resp = mHttpClient.execute(post);
|
||||
final HttpResponse resp = getHttpClient().execute(post);
|
||||
final String response = EntityUtils.toString(resp.getEntity());
|
||||
if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
||||
// Succesfully connected to the samplesyncadapter server and
|
||||
// authenticated.
|
||||
// Extract friends data in json format.
|
||||
final JSONArray friends = new JSONArray(response);
|
||||
// Our request to the server was successful - so we assume
|
||||
// that they accepted all the changes we sent up, and
|
||||
// that the response includes the contacts that we need
|
||||
// to update on our side...
|
||||
final JSONArray serverContacts = new JSONArray(response);
|
||||
Log.d(TAG, response);
|
||||
for (int i = 0; i < friends.length(); i++) {
|
||||
friendList.add(User.valueOf(friends.getJSONObject(i)));
|
||||
for (int i = 0; i < serverContacts.length(); i++) {
|
||||
RawContact rawContact = RawContact.valueOf(serverContacts.getJSONObject(i));
|
||||
if (rawContact != null) {
|
||||
serverDirtyList.add(rawContact);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
Log.e(TAG, "Authentication exception in fetching remote contacts");
|
||||
Log.e(TAG, "Authentication exception in sending dirty contacts");
|
||||
throw new AuthenticationException();
|
||||
} else {
|
||||
Log.e(TAG, "Server error in fetching remote contacts: " + resp.getStatusLine());
|
||||
Log.e(TAG, "Server error in sending dirty contacts: " + resp.getStatusLine());
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
return friendList;
|
||||
|
||||
return serverDirtyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches status messages for the user's friends from the server
|
||||
*
|
||||
* @param account The account being synced.
|
||||
* @param authtoken The authtoken stored in the AccountManager for the
|
||||
* account
|
||||
* @return list The list of status messages received from the server.
|
||||
* Download the avatar image from the server.
|
||||
*
|
||||
* @param avatarUrl the URL pointing to the avatar image
|
||||
* @return a byte array with the raw JPEG avatar image
|
||||
*/
|
||||
public static List<User.Status> fetchFriendStatuses(Account account, String authtoken)
|
||||
throws JSONException, ParseException, IOException, AuthenticationException {
|
||||
|
||||
final ArrayList<User.Status> statusList = new ArrayList<User.Status>();
|
||||
final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||
params.add(new BasicNameValuePair(PARAM_USERNAME, account.name));
|
||||
params.add(new BasicNameValuePair(PARAM_PASSWORD, authtoken));
|
||||
HttpEntity entity = null;
|
||||
entity = new UrlEncodedFormEntity(params);
|
||||
final HttpPost post = new HttpPost(FETCH_STATUS_URI);
|
||||
post.addHeader(entity.getContentType());
|
||||
post.setEntity(entity);
|
||||
maybeCreateHttpClient();
|
||||
final HttpResponse resp = mHttpClient.execute(post);
|
||||
final String response = EntityUtils.toString(resp.getEntity());
|
||||
if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
||||
// Succesfully connected to the samplesyncadapter server and
|
||||
// authenticated.
|
||||
// Extract friends data in json format.
|
||||
final JSONArray statuses = new JSONArray(response);
|
||||
for (int i = 0; i < statuses.length(); i++) {
|
||||
statusList.add(User.Status.valueOf(statuses.getJSONObject(i)));
|
||||
}
|
||||
} else {
|
||||
if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
Log.e(TAG, "Authentication exception in fetching friend status list");
|
||||
throw new AuthenticationException();
|
||||
} else {
|
||||
Log.e(TAG, "Server error in fetching friend status list");
|
||||
throw new IOException();
|
||||
}
|
||||
public static byte[] downloadAvatar(final String avatarUrl) {
|
||||
// If there is no avatar, we're done
|
||||
if (TextUtils.isEmpty(avatarUrl)) {
|
||||
return null;
|
||||
}
|
||||
return statusList;
|
||||
|
||||
try {
|
||||
Log.i(TAG, "Downloading avatar: " + avatarUrl);
|
||||
// Request the avatar image from the server, and create a bitmap
|
||||
// object from the stream we get back.
|
||||
URL url = new URL(avatarUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.connect();
|
||||
try {
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
final Bitmap avatar = BitmapFactory.decodeStream(connection.getInputStream(),
|
||||
null, options);
|
||||
|
||||
// Take the image we received from the server, whatever format it
|
||||
// happens to be in, and convert it to a JPEG image. Note: we're
|
||||
// not resizing the avatar - we assume that the image we get from
|
||||
// the server is a reasonable size...
|
||||
Log.i(TAG, "Converting avatar to JPEG");
|
||||
ByteArrayOutputStream convertStream = new ByteArrayOutputStream(
|
||||
avatar.getWidth() * avatar.getHeight() * 4);
|
||||
avatar.compress(Bitmap.CompressFormat.JPEG, 95, convertStream);
|
||||
convertStream.flush();
|
||||
convertStream.close();
|
||||
// On pre-Honeycomb systems, it's important to call recycle on bitmaps
|
||||
avatar.recycle();
|
||||
return convertStream.toByteArray();
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
} catch (MalformedURLException muex) {
|
||||
// A bad URL - nothing we can really do about it here...
|
||||
Log.e(TAG, "Malformed avatar URL: " + avatarUrl);
|
||||
} catch (IOException ioex) {
|
||||
// If we're unable to download the avatar, it's a bummer but not the
|
||||
// end of the world. We'll try to get it next time we sync.
|
||||
Log.e(TAG, "Failed to download user avatar: " + avatarUrl);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* 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 com.example.android.samplesync.client;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.lang.StringBuilder;
|
||||
|
||||
/**
|
||||
* Represents a low-level contacts RawContact - or at least
|
||||
* the fields of the RawContact that we care about.
|
||||
*/
|
||||
final public class RawContact {
|
||||
|
||||
/** The tag used to log to adb console. **/
|
||||
private static final String TAG = "RawContact";
|
||||
|
||||
private final String mUserName;
|
||||
|
||||
private final String mFullName;
|
||||
|
||||
private final String mFirstName;
|
||||
|
||||
private final String mLastName;
|
||||
|
||||
private final String mCellPhone;
|
||||
|
||||
private final String mOfficePhone;
|
||||
|
||||
private final String mHomePhone;
|
||||
|
||||
private final String mEmail;
|
||||
|
||||
private final String mStatus;
|
||||
|
||||
private final String mAvatarUrl;
|
||||
|
||||
private final boolean mDeleted;
|
||||
|
||||
private final boolean mDirty;
|
||||
|
||||
private final long mServerContactId;
|
||||
|
||||
private final long mRawContactId;
|
||||
|
||||
private final long mSyncState;
|
||||
|
||||
public long getServerContactId() {
|
||||
return mServerContactId;
|
||||
}
|
||||
|
||||
public long getRawContactId() {
|
||||
return mRawContactId;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return mUserName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return mFirstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return mLastName;
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return mFullName;
|
||||
}
|
||||
|
||||
public String getCellPhone() {
|
||||
return mCellPhone;
|
||||
}
|
||||
|
||||
public String getOfficePhone() {
|
||||
return mOfficePhone;
|
||||
}
|
||||
|
||||
public String getHomePhone() {
|
||||
return mHomePhone;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return mEmail;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
public String getAvatarUrl() {
|
||||
return mAvatarUrl;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return mDeleted;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return mDirty;
|
||||
}
|
||||
|
||||
public long getSyncState() {
|
||||
return mSyncState;
|
||||
}
|
||||
|
||||
public String getBestName() {
|
||||
if (!TextUtils.isEmpty(mFullName)) {
|
||||
return mFullName;
|
||||
} else if (TextUtils.isEmpty(mFirstName)) {
|
||||
return mLastName;
|
||||
} else {
|
||||
return mFirstName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the RawContact object into a JSON string. From the
|
||||
* JSONString interface.
|
||||
* @return a JSON string representation of the object
|
||||
*/
|
||||
public JSONObject toJSONObject() {
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
try {
|
||||
if (!TextUtils.isEmpty(mFirstName)) {
|
||||
json.put("f", mFirstName);
|
||||
}
|
||||
if (!TextUtils.isEmpty(mLastName)) {
|
||||
json.put("l", mLastName);
|
||||
}
|
||||
if (!TextUtils.isEmpty(mCellPhone)) {
|
||||
json.put("m", mCellPhone);
|
||||
}
|
||||
if (!TextUtils.isEmpty(mOfficePhone)) {
|
||||
json.put("o", mOfficePhone);
|
||||
}
|
||||
if (!TextUtils.isEmpty(mHomePhone)) {
|
||||
json.put("h", mHomePhone);
|
||||
}
|
||||
if (!TextUtils.isEmpty(mEmail)) {
|
||||
json.put("e", mEmail);
|
||||
}
|
||||
if (mServerContactId > 0) {
|
||||
json.put("i", mServerContactId);
|
||||
}
|
||||
if (mRawContactId > 0) {
|
||||
json.put("c", mRawContactId);
|
||||
}
|
||||
if (mDeleted) {
|
||||
json.put("d", mDeleted);
|
||||
}
|
||||
} catch (final Exception ex) {
|
||||
Log.i(TAG, "Error converting RawContact to JSONObject" + ex.toString());
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public RawContact(String name, String fullName, String firstName, String lastName,
|
||||
String cellPhone, String officePhone, String homePhone, String email,
|
||||
String status, String avatarUrl, boolean deleted, long serverContactId,
|
||||
long rawContactId, long syncState, boolean dirty) {
|
||||
mUserName = name;
|
||||
mFullName = fullName;
|
||||
mFirstName = firstName;
|
||||
mLastName = lastName;
|
||||
mCellPhone = cellPhone;
|
||||
mOfficePhone = officePhone;
|
||||
mHomePhone = homePhone;
|
||||
mEmail = email;
|
||||
mStatus = status;
|
||||
mAvatarUrl = avatarUrl;
|
||||
mDeleted = deleted;
|
||||
mServerContactId = serverContactId;
|
||||
mRawContactId = rawContactId;
|
||||
mSyncState = syncState;
|
||||
mDirty = dirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an instance of the RawContact from the provided JSON data.
|
||||
*
|
||||
* @param user The JSONObject containing user data
|
||||
* @return user The new instance of Sample RawContact created from the JSON data.
|
||||
*/
|
||||
public static RawContact valueOf(JSONObject contact) {
|
||||
|
||||
try {
|
||||
final String userName = !contact.isNull("u") ? contact.getString("u") : null;
|
||||
final int serverContactId = !contact.isNull("i") ? contact.getInt("i") : -1;
|
||||
// If we didn't get either a username or serverId for the contact, then
|
||||
// we can't do anything with it locally...
|
||||
if ((userName == null) && (serverContactId <= 0)) {
|
||||
throw new JSONException("JSON contact missing required 'u' or 'i' fields");
|
||||
}
|
||||
|
||||
final int rawContactId = !contact.isNull("c") ? contact.getInt("c") : -1;
|
||||
final String firstName = !contact.isNull("f") ? contact.getString("f") : null;
|
||||
final String lastName = !contact.isNull("l") ? contact.getString("l") : null;
|
||||
final String cellPhone = !contact.isNull("m") ? contact.getString("m") : null;
|
||||
final String officePhone = !contact.isNull("o") ? contact.getString("o") : null;
|
||||
final String homePhone = !contact.isNull("h") ? contact.getString("h") : null;
|
||||
final String email = !contact.isNull("e") ? contact.getString("e") : null;
|
||||
final String status = !contact.isNull("s") ? contact.getString("s") : null;
|
||||
final String avatarUrl = !contact.isNull("a") ? contact.getString("a") : null;
|
||||
final boolean deleted = !contact.isNull("d") ? contact.getBoolean("d") : false;
|
||||
final long syncState = !contact.isNull("x") ? contact.getLong("x") : 0;
|
||||
return new RawContact(userName, null, firstName, lastName, cellPhone,
|
||||
officePhone, homePhone, email, status, avatarUrl, deleted,
|
||||
serverContactId, rawContactId, syncState, false);
|
||||
} catch (final Exception ex) {
|
||||
Log.i(TAG, "Error parsing JSON contact object" + ex.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns RawContact instance from all the supplied parameters.
|
||||
*/
|
||||
public static RawContact create(String fullName, String firstName, String lastName,
|
||||
String cellPhone, String officePhone, String homePhone,
|
||||
String email, String status, boolean deleted, long rawContactId,
|
||||
long serverContactId) {
|
||||
return new RawContact(null, fullName, firstName, lastName, cellPhone, officePhone,
|
||||
homePhone, email, status, null, deleted, serverContactId, rawContactId,
|
||||
-1, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a User instance that represents a deleted user.
|
||||
* Since the user is deleted, all we need are the client/server IDs.
|
||||
* @param clientUserId The client-side ID for the contact
|
||||
* @param serverUserId The server-side ID for the contact
|
||||
* @return a minimal User object representing the deleted contact.
|
||||
*/
|
||||
public static RawContact createDeletedContact(long rawContactId, long serverContactId)
|
||||
{
|
||||
return new RawContact(null, null, null, null, null, null, null,
|
||||
null, null, null, true, serverContactId, rawContactId, -1, true);
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* 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 com.example.android.samplesync.client;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Represents a sample SyncAdapter user
|
||||
*/
|
||||
final public class User {
|
||||
|
||||
private final String mUserName;
|
||||
|
||||
private final String mFirstName;
|
||||
|
||||
private final String mLastName;
|
||||
|
||||
private final String mCellPhone;
|
||||
|
||||
private final String mOfficePhone;
|
||||
|
||||
private final String mHomePhone;
|
||||
|
||||
private final String mEmail;
|
||||
|
||||
private final boolean mDeleted;
|
||||
|
||||
private final int mUserId;
|
||||
|
||||
public int getUserId() {
|
||||
return mUserId;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return mUserName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return mFirstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return mLastName;
|
||||
}
|
||||
|
||||
public String getCellPhone() {
|
||||
return mCellPhone;
|
||||
}
|
||||
|
||||
public String getOfficePhone() {
|
||||
return mOfficePhone;
|
||||
}
|
||||
|
||||
public String getHomePhone() {
|
||||
return mHomePhone;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return mEmail;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return mDeleted;
|
||||
}
|
||||
|
||||
private User(String name, String firstName, String lastName, String cellPhone,
|
||||
String officePhone, String homePhone, String email, Boolean deleted, Integer userId) {
|
||||
|
||||
mUserName = name;
|
||||
mFirstName = firstName;
|
||||
mLastName = lastName;
|
||||
mCellPhone = cellPhone;
|
||||
mOfficePhone = officePhone;
|
||||
mHomePhone = homePhone;
|
||||
mEmail = email;
|
||||
mDeleted = deleted;
|
||||
mUserId = userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an instance of the user from the provided JSON data.
|
||||
*
|
||||
* @param user The JSONObject containing user data
|
||||
* @return user The new instance of Voiper user created from the JSON data.
|
||||
*/
|
||||
public static User valueOf(JSONObject user) {
|
||||
|
||||
try {
|
||||
final String userName = user.getString("u");
|
||||
final String firstName = user.has("f") ? user.getString("f") : null;
|
||||
final String lastName = user.has("l") ? user.getString("l") : null;
|
||||
final String cellPhone = user.has("m") ? user.getString("m") : null;
|
||||
final String officePhone = user.has("o") ? user.getString("o") : null;
|
||||
final String homePhone = user.has("h") ? user.getString("h") : null;
|
||||
final String email = user.has("e") ? user.getString("e") : null;
|
||||
final boolean deleted = user.has("d") ? user.getBoolean("d") : false;
|
||||
final int userId = user.getInt("i");
|
||||
return new User(userName, firstName, lastName, cellPhone, officePhone, homePhone,
|
||||
email, deleted, userId);
|
||||
} catch (final Exception ex) {
|
||||
Log.i("User", "Error parsing JSON user object" + ex.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the User's status messages
|
||||
*
|
||||
*/
|
||||
final public static class Status {
|
||||
|
||||
private final Integer mUserId;
|
||||
|
||||
private final String mStatus;
|
||||
|
||||
public int getUserId() {
|
||||
return mUserId;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
public Status(Integer userId, String status) {
|
||||
mUserId = userId;
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
public static User.Status valueOf(JSONObject userStatus) {
|
||||
try {
|
||||
final int userId = userStatus.getInt("i");
|
||||
final String status = userStatus.getString("s");
|
||||
return new User.Status(userId, status);
|
||||
} catch (final Exception ex) {
|
||||
Log.i("User.Status", "Error parsing JSON user object");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user