/development/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java
Java | 271 lines | 172 code | 19 blank | 80 comment | 21 complexity | 3b8f2fcee1306b3f43245ff6b9d3e133 MD5 | raw file
- /*
- * 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 org.apache.http.HttpEntity;
- import org.apache.http.HttpResponse;
- import org.apache.http.HttpStatus;
- import org.apache.http.NameValuePair;
- import org.apache.http.ParseException;
- import org.apache.http.auth.AuthenticationException;
- import org.apache.http.client.HttpClient;
- import org.apache.http.client.entity.UrlEncodedFormEntity;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.conn.params.ConnManagerParams;
- import org.apache.http.impl.client.DefaultHttpClient;
- 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.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
- import android.accounts.Account;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.text.TextUtils;
- import android.util.Log;
- 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.util.ArrayList;
- import java.util.List;
- /**
- * Provides utility methods for communicating with the server.
- */
- final public class NetworkUtilities {
- /** The tag used to log to adb console. */
- private static final String TAG = "NetworkUtilities";
- /** POST parameter name for the user's account name */
- public static final String PARAM_USERNAME = "username";
- /** 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";
- /** URI for sync service */
- public static final String SYNC_CONTACTS_URI = BASE_URL + "/sync";
- private NetworkUtilities() {
- }
- /**
- * Configures the httpClient to connect to the URL provided.
- */
- 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;
- }
- /**
- * 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 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));
- final HttpEntity entity;
- try {
- entity = new UrlEncodedFormEntity(params);
- } catch (final UnsupportedEncodingException e) {
- // this should never happen.
- 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);
- try {
- resp = getHttpClient().execute(post);
- String authToken = null;
- if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
- InputStream istream = (resp.getEntity() != null) ? resp.getEntity().getContent()
- : null;
- if (istream != null) {
- BufferedReader ireader = new BufferedReader(new InputStreamReader(istream));
- authToken = ireader.readLine().trim();
- }
- }
- if ((authToken != null) && (authToken.length() > 0)) {
- Log.v(TAG, "Successful authentication");
- return authToken;
- } else {
- Log.e(TAG, "Error authenticating" + resp.getStatusLine());
- return null;
- }
- } catch (final IOException e) {
- Log.e(TAG, "IOException when getting authtoken", e);
- return null;
- } finally {
- Log.v(TAG, "getAuthtoken completing");
- }
- }
- /**
- * 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
- */
- 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());
- }
- // Create a special JSONArray of our JSON contacts
- JSONArray buffer = new JSONArray(jsonContacts);
- // 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>();
- // Prepare our POST data
- final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
- params.add(new BasicNameValuePair(PARAM_USERNAME, account.name));
- 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 = 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);
- final HttpResponse resp = getHttpClient().execute(post);
- final String response = EntityUtils.toString(resp.getEntity());
- if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
- // 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 < 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 sending dirty contacts");
- throw new AuthenticationException();
- } else {
- Log.e(TAG, "Server error in sending dirty contacts: " + resp.getStatusLine());
- throw new IOException();
- }
- }
- return serverDirtyList;
- }
- /**
- * 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 byte[] downloadAvatar(final String avatarUrl) {
- // If there is no avatar, we're done
- if (TextUtils.isEmpty(avatarUrl)) {
- return null;
- }
- 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;
- }
- }