am 2464acc6: moved the gdata library to vendor/google
Merge commit '2464acc6da6393f0163894094468f68b8e496cea' into eclair-mr2-plus-aosp * commit '2464acc6da6393f0163894094468f68b8e496cea': moved the gdata library to vendor/google
This commit is contained in:
@@ -525,7 +525,6 @@ include $(BUILD_DROIDDOC)
|
||||
|
||||
ext_dirs := \
|
||||
../../external/apache-http/src \
|
||||
../../external/gdata/src \
|
||||
../../external/tagsoup/src
|
||||
|
||||
ext_src_files := $(call all-java-files-under,$(ext_dirs))
|
||||
|
||||
@@ -33,17 +33,6 @@ import android.text.format.Time;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
import android.accounts.Account;
|
||||
import com.android.internal.database.ArrayListCursor;
|
||||
import com.google.android.gdata.client.AndroidGDataClient;
|
||||
import com.google.android.gdata.client.AndroidXmlParserFactory;
|
||||
import com.google.wireless.gdata.calendar.client.CalendarClient;
|
||||
import com.google.wireless.gdata.calendar.data.EventEntry;
|
||||
import com.google.wireless.gdata.calendar.data.Who;
|
||||
import com.google.wireless.gdata.calendar.parser.xml.XmlCalendarGDataParserFactory;
|
||||
import com.google.wireless.gdata.data.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* The Calendar provider contains all calendar events.
|
||||
@@ -547,8 +536,6 @@ public final class Calendar {
|
||||
AttendeesColumns.ATTENDEE_TYPE,
|
||||
AttendeesColumns.ATTENDEE_STATUS };
|
||||
|
||||
private static CalendarClient sCalendarClient = null;
|
||||
|
||||
public static final Cursor query(ContentResolver cr, String[] projection) {
|
||||
return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
|
||||
}
|
||||
@@ -600,7 +587,7 @@ public final class Calendar {
|
||||
|
||||
// where
|
||||
String where = extractValue(event, "LOCATION");
|
||||
if (!StringUtils.isEmpty(where)) {
|
||||
if (!TextUtils.isEmpty(where)) {
|
||||
values.put(EVENT_LOCATION, where);
|
||||
}
|
||||
|
||||
@@ -686,47 +673,6 @@ public final class Calendar {
|
||||
return cr.insert(CONTENT_URI, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a singleton instance of the CalendarClient used to fetch entries from the
|
||||
* calendar server.
|
||||
* @param cr The ContentResolver used to lookup the address of the calendar server in the
|
||||
* settings database.
|
||||
* @return The singleton instance of the CalendarClient used to fetch entries from the
|
||||
* calendar server.
|
||||
*/
|
||||
private static synchronized CalendarClient getCalendarClient(ContentResolver cr) {
|
||||
if (sCalendarClient == null) {
|
||||
sCalendarClient = new CalendarClient(
|
||||
new AndroidGDataClient(cr),
|
||||
new XmlCalendarGDataParserFactory(new AndroidXmlParserFactory()));
|
||||
}
|
||||
return sCalendarClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the attendees information out of event and adds it to a new ArrayList of columns
|
||||
* within the supplied ArrayList of rows. These rows are expected to be used within an
|
||||
* {@link ArrayListCursor}.
|
||||
*/
|
||||
private static final void extractAttendeesIntoArrayList(EventEntry event,
|
||||
ArrayList<ArrayList> rows) {
|
||||
Log.d(TAG, "EVENT: " + event.toString());
|
||||
Vector<Who> attendees = (Vector<Who>) event.getAttendees();
|
||||
|
||||
int numAttendees = attendees == null ? 0 : attendees.size();
|
||||
|
||||
for (int i = 0; i < numAttendees; ++i) {
|
||||
Who attendee = attendees.elementAt(i);
|
||||
ArrayList row = new ArrayList();
|
||||
row.add(attendee.getValue());
|
||||
row.add(attendee.getEmail());
|
||||
row.add(attendee.getRelationship());
|
||||
row.add(attendee.getType());
|
||||
row.add(attendee.getStatus());
|
||||
rows.add(row);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The content:// style URL for this table
|
||||
*/
|
||||
|
||||
@@ -1,508 +0,0 @@
|
||||
// Copyright 2007 The Android Open Source Project
|
||||
|
||||
package com.google.android.gdata.client;
|
||||
|
||||
import com.google.android.net.GoogleHttpClient;
|
||||
import com.google.wireless.gdata.client.GDataClient;
|
||||
import com.google.wireless.gdata.client.HttpException;
|
||||
import com.google.wireless.gdata.client.QueryParams;
|
||||
import com.google.wireless.gdata.data.StringUtils;
|
||||
import com.google.wireless.gdata.parser.ParseException;
|
||||
import com.google.wireless.gdata.serializer.GDataSerializer;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.entity.AbstractHttpEntity;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.http.AndroidHttpClient;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
import android.os.SystemProperties;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* Implementation of a GDataClient using GoogleHttpClient to make HTTP
|
||||
* requests. Always issues GETs and POSTs, using the X-HTTP-Method-Override
|
||||
* header when a PUT or DELETE is desired, to avoid issues with firewalls, etc.,
|
||||
* that do not allow methods other than GET or POST.
|
||||
*/
|
||||
public class AndroidGDataClient implements GDataClient {
|
||||
|
||||
private static final String TAG = "GDataClient";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
|
||||
|
||||
private static final String X_HTTP_METHOD_OVERRIDE =
|
||||
"X-HTTP-Method-Override";
|
||||
|
||||
private static final String DEFAULT_USER_AGENT_APP_VERSION = "Android-GData/1.1";
|
||||
|
||||
private static final int MAX_REDIRECTS = 10;
|
||||
|
||||
// boolean system property that can be used to control whether or not
|
||||
// requests/responses are gzip'd.
|
||||
private static final String NO_GZIP_SYSTEM_PROPERTY = "sync.nogzip";
|
||||
|
||||
private final GoogleHttpClient mHttpClient;
|
||||
private ContentResolver mResolver;
|
||||
|
||||
/**
|
||||
* Interface for creating HTTP requests. Used by
|
||||
* {@link AndroidGDataClient#createAndExecuteMethod}, since HttpUriRequest does not allow for
|
||||
* changing the URI after creation, e.g., when you want to follow a redirect.
|
||||
*/
|
||||
private interface HttpRequestCreator {
|
||||
HttpUriRequest createRequest(URI uri);
|
||||
}
|
||||
|
||||
private static class GetRequestCreator implements HttpRequestCreator {
|
||||
public GetRequestCreator() {
|
||||
}
|
||||
|
||||
public HttpUriRequest createRequest(URI uri) {
|
||||
HttpGet get = new HttpGet(uri);
|
||||
return get;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PostRequestCreator implements HttpRequestCreator {
|
||||
private final String mMethodOverride;
|
||||
private final HttpEntity mEntity;
|
||||
public PostRequestCreator(String methodOverride, HttpEntity entity) {
|
||||
mMethodOverride = methodOverride;
|
||||
mEntity = entity;
|
||||
}
|
||||
|
||||
public HttpUriRequest createRequest(URI uri) {
|
||||
HttpPost post = new HttpPost(uri);
|
||||
if (mMethodOverride != null) {
|
||||
post.addHeader(X_HTTP_METHOD_OVERRIDE, mMethodOverride);
|
||||
}
|
||||
post.setEntity(mEntity);
|
||||
return post;
|
||||
}
|
||||
}
|
||||
|
||||
// MAJOR TODO: make this work across redirects (if we can reset the InputStream).
|
||||
// OR, read the bits into a local buffer (yuck, the media could be large).
|
||||
private static class MediaPutRequestCreator implements HttpRequestCreator {
|
||||
private final InputStream mMediaInputStream;
|
||||
private final String mContentType;
|
||||
public MediaPutRequestCreator(InputStream mediaInputStream, String contentType) {
|
||||
mMediaInputStream = mediaInputStream;
|
||||
mContentType = contentType;
|
||||
}
|
||||
|
||||
public HttpUriRequest createRequest(URI uri) {
|
||||
HttpPost post = new HttpPost(uri);
|
||||
post.addHeader(X_HTTP_METHOD_OVERRIDE, "PUT");
|
||||
// mMediaInputStream.reset();
|
||||
InputStreamEntity entity = new InputStreamEntity(mMediaInputStream,
|
||||
-1 /* read until EOF */);
|
||||
entity.setContentType(mContentType);
|
||||
post.setEntity(entity);
|
||||
return post;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use AndroidGDAtaClient(Context) instead.
|
||||
*/
|
||||
public AndroidGDataClient(ContentResolver resolver) {
|
||||
mHttpClient = new GoogleHttpClient(resolver, DEFAULT_USER_AGENT_APP_VERSION,
|
||||
true /* gzip capable */);
|
||||
mHttpClient.enableCurlLogging(TAG, Log.VERBOSE);
|
||||
mResolver = resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AndroidGDataClient.
|
||||
*
|
||||
* @param context The ContentResolver to get URL rewriting rules from
|
||||
* through the Android proxy server, using null to indicate not using proxy.
|
||||
* The context will also be used by GoogleHttpClient for configuration of
|
||||
* SSL session persistence.
|
||||
*/
|
||||
public AndroidGDataClient(Context context) {
|
||||
this(context, DEFAULT_USER_AGENT_APP_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AndroidGDataClient.
|
||||
*
|
||||
* @param context The ContentResolver to get URL rewriting rules from
|
||||
* through the Android proxy server, using null to indicate not using proxy.
|
||||
* The context will also be used by GoogleHttpClient for configuration of
|
||||
* SSL session persistence.
|
||||
* @param appAndVersion The application name and version to be used as the basis of the
|
||||
* User-Agent. e.g., Android-GData/1.5.0.
|
||||
*/
|
||||
public AndroidGDataClient(Context context, String appAndVersion) {
|
||||
mHttpClient = new GoogleHttpClient(context, appAndVersion,
|
||||
true /* gzip capable */);
|
||||
mHttpClient.enableCurlLogging(TAG, Log.VERBOSE);
|
||||
mResolver = context.getContentResolver();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
mHttpClient.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see GDataClient#encodeUri(java.lang.String)
|
||||
*/
|
||||
public String encodeUri(String uri) {
|
||||
String encodedUri;
|
||||
try {
|
||||
encodedUri = URLEncoder.encode(uri, "UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
// should not happen.
|
||||
Log.e("JakartaGDataClient",
|
||||
"UTF-8 not supported -- should not happen. "
|
||||
+ "Using default encoding.", uee);
|
||||
encodedUri = URLEncoder.encode(uri);
|
||||
}
|
||||
return encodedUri;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.google.wireless.gdata.client.GDataClient#createQueryParams()
|
||||
*/
|
||||
public QueryParams createQueryParams() {
|
||||
return new QueryParamsImpl();
|
||||
}
|
||||
|
||||
// follows redirects
|
||||
private InputStream createAndExecuteMethod(HttpRequestCreator creator,
|
||||
String uriString,
|
||||
String authToken)
|
||||
throws HttpException, IOException {
|
||||
|
||||
HttpResponse response = null;
|
||||
int status = 500;
|
||||
int redirectsLeft = MAX_REDIRECTS;
|
||||
|
||||
URI uri;
|
||||
try {
|
||||
uri = new URI(uriString);
|
||||
} catch (URISyntaxException use) {
|
||||
Log.w(TAG, "Unable to parse " + uriString + " as URI.", use);
|
||||
throw new IOException("Unable to parse " + uriString + " as URI: "
|
||||
+ use.getMessage());
|
||||
}
|
||||
|
||||
// we follow redirects ourselves, since we want to follow redirects even on POSTs, which
|
||||
// the HTTP library does not do. following redirects ourselves also allows us to log
|
||||
// the redirects using our own logging.
|
||||
while (redirectsLeft > 0) {
|
||||
|
||||
HttpUriRequest request = creator.createRequest(uri);
|
||||
|
||||
if (!SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) {
|
||||
AndroidHttpClient.modifyRequestToAcceptGzipResponse(request);
|
||||
}
|
||||
|
||||
// only add the auth token if not null (to allow for GData feeds that do not require
|
||||
// authentication.)
|
||||
if (!TextUtils.isEmpty(authToken)) {
|
||||
request.addHeader("Authorization", "GoogleLogin auth=" + authToken);
|
||||
}
|
||||
if (LOCAL_LOGV) {
|
||||
for (Header h : request.getAllHeaders()) {
|
||||
Log.v(TAG, h.getName() + ": " + h.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Executing " + request.getRequestLine().toString());
|
||||
}
|
||||
|
||||
response = null;
|
||||
|
||||
try {
|
||||
response = mHttpClient.execute(request);
|
||||
} catch (IOException ioe) {
|
||||
Log.w(TAG, "Unable to execute HTTP request." + ioe);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
StatusLine statusLine = response.getStatusLine();
|
||||
if (statusLine == null) {
|
||||
Log.w(TAG, "StatusLine is null.");
|
||||
throw new NullPointerException("StatusLine is null -- should not happen.");
|
||||
}
|
||||
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, response.getStatusLine().toString());
|
||||
for (Header h : response.getAllHeaders()) {
|
||||
Log.d(TAG, h.getName() + ": " + h.getValue());
|
||||
}
|
||||
}
|
||||
status = statusLine.getStatusCode();
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
|
||||
if ((status >= 200) && (status < 300) && entity != null) {
|
||||
InputStream in = AndroidHttpClient.getUngzippedContent(entity);
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
in = logInputStreamContents(in);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
// TODO: handle 301, 307?
|
||||
// TODO: let the http client handle the redirects, if we can be sure we'll never get a
|
||||
// redirect on POST.
|
||||
if (status == 302) {
|
||||
// consume the content, so the connection can be closed.
|
||||
entity.consumeContent();
|
||||
Header location = response.getFirstHeader("Location");
|
||||
if (location == null) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Redirect requested but no Location "
|
||||
+ "specified.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Following redirect to " + location.getValue());
|
||||
}
|
||||
try {
|
||||
uri = new URI(location.getValue());
|
||||
} catch (URISyntaxException use) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Unable to parse " + location.getValue() + " as URI.", use);
|
||||
throw new IOException("Unable to parse " + location.getValue()
|
||||
+ " as URI.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
--redirectsLeft;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "Received " + status + " status code.");
|
||||
}
|
||||
String errorMessage = null;
|
||||
HttpEntity entity = response.getEntity();
|
||||
try {
|
||||
if (response != null && entity != null) {
|
||||
InputStream in = AndroidHttpClient.getUngzippedContent(entity);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buf = new byte[8192];
|
||||
int bytesRead = -1;
|
||||
while ((bytesRead = in.read(buf)) != -1) {
|
||||
baos.write(buf, 0, bytesRead);
|
||||
}
|
||||
// TODO: use appropriate encoding, picked up from Content-Type.
|
||||
errorMessage = new String(baos.toByteArray());
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, errorMessage);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (entity != null) {
|
||||
entity.consumeContent();
|
||||
}
|
||||
}
|
||||
String exceptionMessage = "Received " + status + " status code";
|
||||
if (errorMessage != null) {
|
||||
exceptionMessage += (": " + errorMessage);
|
||||
}
|
||||
throw new HttpException(exceptionMessage, status, null /* InputStream */);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see GDataClient#getFeedAsStream(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public InputStream getFeedAsStream(String feedUrl,
|
||||
String authToken)
|
||||
throws HttpException, IOException {
|
||||
|
||||
InputStream in = createAndExecuteMethod(new GetRequestCreator(), feedUrl, authToken);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to access feed.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the contents of the input stream.
|
||||
* The original input stream is consumed, so the caller must use the
|
||||
* BufferedInputStream that is returned.
|
||||
* @param in InputStream
|
||||
* @return replacement input stream for caller to use
|
||||
* @throws IOException
|
||||
*/
|
||||
private InputStream logInputStreamContents(InputStream in) throws IOException {
|
||||
if (in == null) {
|
||||
return in;
|
||||
}
|
||||
// bufferSize is the (arbitrary) maximum amount to log.
|
||||
// The original InputStream is wrapped in a
|
||||
// BufferedInputStream with a 16K buffer. This lets
|
||||
// us read up to 16K, write it to the log, and then
|
||||
// reset the stream so the the original client can
|
||||
// then read the data. The BufferedInputStream
|
||||
// provides the mark and reset support, even when
|
||||
// the original InputStream does not.
|
||||
final int bufferSize = 16384;
|
||||
BufferedInputStream bin = new BufferedInputStream(in, bufferSize);
|
||||
bin.mark(bufferSize);
|
||||
int wanted = bufferSize;
|
||||
int totalReceived = 0;
|
||||
byte buf[] = new byte[wanted];
|
||||
while (wanted > 0) {
|
||||
int got = bin.read(buf, totalReceived, wanted);
|
||||
if (got <= 0) break; // EOF
|
||||
wanted -= got;
|
||||
totalReceived += got;
|
||||
}
|
||||
Log.d(TAG, new String(buf, 0, totalReceived, "UTF-8"));
|
||||
bin.reset();
|
||||
return bin;
|
||||
}
|
||||
|
||||
public InputStream getMediaEntryAsStream(String mediaEntryUrl, String authToken)
|
||||
throws HttpException, IOException {
|
||||
|
||||
InputStream in = createAndExecuteMethod(new GetRequestCreator(), mediaEntryUrl, authToken);
|
||||
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to access media entry.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see GDataClient#createEntry
|
||||
*/
|
||||
public InputStream createEntry(String feedUrl,
|
||||
String authToken,
|
||||
GDataSerializer entry)
|
||||
throws HttpException, IOException {
|
||||
|
||||
HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_CREATE);
|
||||
InputStream in = createAndExecuteMethod(
|
||||
new PostRequestCreator(null /* override */, entity),
|
||||
feedUrl,
|
||||
authToken);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to create entry.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see GDataClient#updateEntry
|
||||
*/
|
||||
public InputStream updateEntry(String editUri,
|
||||
String authToken,
|
||||
GDataSerializer entry)
|
||||
throws HttpException, IOException {
|
||||
HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_UPDATE);
|
||||
InputStream in = createAndExecuteMethod(
|
||||
new PostRequestCreator("PUT", entity),
|
||||
editUri,
|
||||
authToken);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to update entry.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see GDataClient#deleteEntry
|
||||
*/
|
||||
public void deleteEntry(String editUri, String authToken)
|
||||
throws HttpException, IOException {
|
||||
if (StringUtils.isEmpty(editUri)) {
|
||||
throw new IllegalArgumentException(
|
||||
"you must specify an non-empty edit url");
|
||||
}
|
||||
InputStream in =
|
||||
createAndExecuteMethod(
|
||||
new PostRequestCreator("DELETE", null /* entity */),
|
||||
editUri,
|
||||
authToken);
|
||||
if (in == null) {
|
||||
throw new IOException("Unable to delete entry.");
|
||||
}
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ioe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream updateMediaEntry(String editUri, String authToken,
|
||||
InputStream mediaEntryInputStream, String contentType)
|
||||
throws HttpException, IOException {
|
||||
InputStream in = createAndExecuteMethod(
|
||||
new MediaPutRequestCreator(mediaEntryInputStream, contentType),
|
||||
editUri,
|
||||
authToken);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to write media entry.");
|
||||
}
|
||||
|
||||
private HttpEntity createEntityForEntry(GDataSerializer entry, int format) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
entry.serialize(baos, format);
|
||||
} catch (IOException ioe) {
|
||||
Log.e(TAG, "Unable to serialize entry.", ioe);
|
||||
throw ioe;
|
||||
} catch (ParseException pe) {
|
||||
Log.e(TAG, "Unable to serialize entry.", pe);
|
||||
throw new IOException("Unable to serialize entry: " + pe.getMessage());
|
||||
}
|
||||
|
||||
byte[] entryBytes = baos.toByteArray();
|
||||
|
||||
if (entryBytes != null && Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
try {
|
||||
Log.d(TAG, "Serialized entry: " + new String(entryBytes, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
// should not happen
|
||||
throw new IllegalStateException("UTF-8 should be supported!",
|
||||
uee);
|
||||
}
|
||||
}
|
||||
|
||||
AbstractHttpEntity entity;
|
||||
if (SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) {
|
||||
entity = new ByteArrayEntity(entryBytes);
|
||||
} else {
|
||||
entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver);
|
||||
}
|
||||
entity.setContentType(entry.getContentType());
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.google.android.gdata.client;
|
||||
|
||||
import com.google.wireless.gdata.parser.xml.XmlParserFactory;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import android.util.Xml;
|
||||
|
||||
/**
|
||||
* XmlParserFactory for the Android platform.
|
||||
*/
|
||||
public class AndroidXmlParserFactory implements XmlParserFactory {
|
||||
|
||||
/*
|
||||
* (non-javadoc)
|
||||
* @see XmlParserFactory#createParser
|
||||
*/
|
||||
public XmlPullParser createParser() throws XmlPullParserException {
|
||||
return Xml.newPullParser();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-javadoc)
|
||||
* @see XmlParserFactory#createSerializer
|
||||
*/
|
||||
public XmlSerializer createSerializer() throws XmlPullParserException {
|
||||
return Xml.newSerializer();
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package com.google.android.gdata.client;
|
||||
|
||||
import com.google.wireless.gdata.client.QueryParams;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Simple implementation of the QueryParams interface.
|
||||
*/
|
||||
// TODO: deal with categories
|
||||
public class QueryParamsImpl extends QueryParams {
|
||||
|
||||
private final Map<String,String> mParams = new HashMap<String,String>();
|
||||
|
||||
/**
|
||||
* Creates a new empty QueryParamsImpl.
|
||||
*/
|
||||
public QueryParamsImpl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
setEntryId(null);
|
||||
mParams.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateQueryUrl(String feedUrl) {
|
||||
|
||||
if (TextUtils.isEmpty(getEntryId()) &&
|
||||
mParams.isEmpty()) {
|
||||
// nothing to do
|
||||
return feedUrl;
|
||||
}
|
||||
|
||||
// handle entry IDs
|
||||
if (!TextUtils.isEmpty(getEntryId())) {
|
||||
if (!mParams.isEmpty()) {
|
||||
throw new IllegalStateException("Cannot set both an entry ID "
|
||||
+ "and other query paramters.");
|
||||
}
|
||||
return feedUrl + '/' + getEntryId();
|
||||
}
|
||||
|
||||
// otherwise, append the querystring params.
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(feedUrl);
|
||||
Set<String> params = mParams.keySet();
|
||||
boolean first = true;
|
||||
if (feedUrl.contains("?")) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append('?');
|
||||
}
|
||||
for (String param : params) {
|
||||
String value = mParams.get(param);
|
||||
if (value == null) continue;
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append('&');
|
||||
}
|
||||
sb.append(param);
|
||||
sb.append('=');
|
||||
|
||||
String encodedValue = null;
|
||||
|
||||
try {
|
||||
encodedValue = URLEncoder.encode(value, "UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
// should not happen.
|
||||
Log.w("QueryParamsImpl",
|
||||
"UTF-8 not supported -- should not happen. "
|
||||
+ "Using default encoding.", uee);
|
||||
encodedValue = URLEncoder.encode(value);
|
||||
}
|
||||
sb.append(encodedValue);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParamValue(String param) {
|
||||
if (!(mParams.containsKey(param))) {
|
||||
return null;
|
||||
}
|
||||
return mParams.get(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParamValue(String param, String value) {
|
||||
mParams.put(param, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,603 +0,0 @@
|
||||
// Copyright 2007 The Android Open Source Project
|
||||
|
||||
package com.google.android.gdata2.client;
|
||||
|
||||
import com.google.android.net.GoogleHttpClient;
|
||||
import com.google.wireless.gdata2.client.GDataClient;
|
||||
import com.google.wireless.gdata2.client.HttpException;
|
||||
import com.google.wireless.gdata2.client.QueryParams;
|
||||
import com.google.wireless.gdata2.data.StringUtils;
|
||||
import com.google.wireless.gdata2.parser.ParseException;
|
||||
import com.google.wireless.gdata2.serializer.GDataSerializer;
|
||||
import com.google.android.gdata2.client.QueryParamsImpl;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.params.BasicHttpParams;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.entity.AbstractHttpEntity;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.http.AndroidHttpClient;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
import android.os.SystemProperties;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* Implementation of a GDataClient using GoogleHttpClient to make HTTP
|
||||
* requests. Always issues GETs and POSTs, using the X-HTTP-Method-Override
|
||||
* header when a PUT or DELETE is desired, to avoid issues with firewalls, etc.,
|
||||
* that do not allow methods other than GET or POST.
|
||||
*/
|
||||
public class AndroidGDataClient implements GDataClient {
|
||||
|
||||
private static final String TAG = "GDataClient";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
|
||||
|
||||
private static final String X_HTTP_METHOD_OVERRIDE =
|
||||
"X-HTTP-Method-Override";
|
||||
|
||||
private static final String DEFAULT_USER_AGENT_APP_VERSION = "Android-GData/1.2";
|
||||
|
||||
private static final int MAX_REDIRECTS = 10;
|
||||
private static String DEFAULT_GDATA_VERSION = "2.0";
|
||||
|
||||
// boolean system property that can be used to control whether or not
|
||||
// requests/responses are gzip'd.
|
||||
private static final String NO_GZIP_SYSTEM_PROPERTY = "sync.nogzip";
|
||||
|
||||
private String mGDataVersion;
|
||||
private final GoogleHttpClient mHttpClient;
|
||||
private ContentResolver mResolver;
|
||||
|
||||
/**
|
||||
* Interface for creating HTTP requests. Used by
|
||||
* {@link AndroidGDataClient#createAndExecuteMethod}, since HttpUriRequest does not allow for
|
||||
* changing the URI after creation, e.g., when you want to follow a redirect.
|
||||
*/
|
||||
private interface HttpRequestCreator {
|
||||
HttpUriRequest createRequest(URI uri);
|
||||
}
|
||||
|
||||
private static class GetRequestCreator implements HttpRequestCreator {
|
||||
public GetRequestCreator() {
|
||||
}
|
||||
|
||||
public HttpUriRequest createRequest(URI uri) {
|
||||
HttpGet get = new HttpGet(uri);
|
||||
return get;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PostRequestCreator implements HttpRequestCreator {
|
||||
private final String mMethodOverride;
|
||||
private final HttpEntity mEntity;
|
||||
public PostRequestCreator(String methodOverride, HttpEntity entity) {
|
||||
mMethodOverride = methodOverride;
|
||||
mEntity = entity;
|
||||
}
|
||||
|
||||
public HttpUriRequest createRequest(URI uri) {
|
||||
HttpPost post = new HttpPost(uri);
|
||||
if (mMethodOverride != null) {
|
||||
post.addHeader(X_HTTP_METHOD_OVERRIDE, mMethodOverride);
|
||||
}
|
||||
post.setEntity(mEntity);
|
||||
return post;
|
||||
}
|
||||
}
|
||||
|
||||
// MAJOR TODO: make this work across redirects (if we can reset the InputStream).
|
||||
// OR, read the bits into a local buffer (yuck, the media could be large).
|
||||
private static class MediaPutRequestCreator implements HttpRequestCreator {
|
||||
private final InputStream mMediaInputStream;
|
||||
private final String mContentType;
|
||||
public MediaPutRequestCreator(InputStream mediaInputStream, String contentType) {
|
||||
mMediaInputStream = mediaInputStream;
|
||||
mContentType = contentType;
|
||||
}
|
||||
|
||||
public HttpUriRequest createRequest(URI uri) {
|
||||
HttpPost post = new HttpPost(uri);
|
||||
post.addHeader(X_HTTP_METHOD_OVERRIDE, "PUT");
|
||||
// mMediaInputStream.reset();
|
||||
InputStreamEntity entity = new InputStreamEntity(mMediaInputStream,
|
||||
-1 /* read until EOF */);
|
||||
entity.setContentType(mContentType);
|
||||
post.setEntity(entity);
|
||||
return post;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new AndroidGDataClient.
|
||||
*
|
||||
* @param context The ContentResolver to get URL rewriting rules from
|
||||
* through the Android proxy server, using null to indicate not using proxy.
|
||||
* The context will also be used by GoogleHttpClient for configuration of
|
||||
* SSL session persistence.
|
||||
*/
|
||||
public AndroidGDataClient(Context context) {
|
||||
this(context, DEFAULT_USER_AGENT_APP_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AndroidGDataClient.
|
||||
*
|
||||
* @param context The ContentResolver to get URL rewriting rules from
|
||||
* through the Android proxy server, using null to indicate not using proxy.
|
||||
* The context will also be used by GoogleHttpClient for configuration of
|
||||
* SSL session persistence.
|
||||
* @param appAndVersion The application name and version to be used as the basis of the
|
||||
* User-Agent. e.g., Android-GData/1.5.0.
|
||||
*/
|
||||
public AndroidGDataClient(Context context, String appAndVersion) {
|
||||
this(context, appAndVersion, DEFAULT_GDATA_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AndroidGDataClient.
|
||||
*
|
||||
* @param context The ContentResolver to get URL rewriting rules from
|
||||
* through the Android proxy server, using null to indicate not using proxy.
|
||||
* The context will also be used by GoogleHttpClient for configuration of
|
||||
* SSL session persistence.
|
||||
* @param appAndVersion The application name and version to be used as the basis of the
|
||||
* User-Agent. e.g., Android-GData/1.5.0.
|
||||
* @param gdataVersion The gdata service version that should be
|
||||
* used, e.g. "2.0"
|
||||
*
|
||||
*/
|
||||
public AndroidGDataClient(Context context, String appAndVersion, String gdataVersion) {
|
||||
mHttpClient = new GoogleHttpClient(context, appAndVersion,
|
||||
true /* gzip capable */);
|
||||
mHttpClient.enableCurlLogging(TAG, Log.VERBOSE);
|
||||
mResolver = context.getContentResolver();
|
||||
mGDataVersion = gdataVersion;
|
||||
}
|
||||
|
||||
|
||||
public void close() {
|
||||
mHttpClient.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see GDataClient#encodeUri(java.lang.String)
|
||||
*/
|
||||
public String encodeUri(String uri) {
|
||||
String encodedUri;
|
||||
try {
|
||||
encodedUri = URLEncoder.encode(uri, "UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
// should not happen.
|
||||
Log.e("JakartaGDataClient",
|
||||
"UTF-8 not supported -- should not happen. "
|
||||
+ "Using default encoding.", uee);
|
||||
encodedUri = URLEncoder.encode(uri);
|
||||
}
|
||||
return encodedUri;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.google.wireless.gdata.client.GDataClient#createQueryParams()
|
||||
*/
|
||||
public QueryParams createQueryParams() {
|
||||
return new QueryParamsImpl();
|
||||
}
|
||||
|
||||
// follows redirects
|
||||
private InputStream createAndExecuteMethod(HttpRequestCreator creator,
|
||||
String uriString,
|
||||
String authToken,
|
||||
String eTag,
|
||||
String protocolVersion)
|
||||
throws HttpException, IOException {
|
||||
|
||||
HttpResponse response = null;
|
||||
int status = 500;
|
||||
int redirectsLeft = MAX_REDIRECTS;
|
||||
|
||||
URI uri;
|
||||
try {
|
||||
uri = new URI(uriString);
|
||||
} catch (URISyntaxException use) {
|
||||
Log.w(TAG, "Unable to parse " + uriString + " as URI.", use);
|
||||
throw new IOException("Unable to parse " + uriString + " as URI: "
|
||||
+ use.getMessage());
|
||||
}
|
||||
|
||||
// we follow redirects ourselves, since we want to follow redirects even on POSTs, which
|
||||
// the HTTP library does not do. following redirects ourselves also allows us to log
|
||||
// the redirects using our own logging.
|
||||
while (redirectsLeft > 0) {
|
||||
|
||||
HttpUriRequest request = creator.createRequest(uri);
|
||||
|
||||
if (!SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) {
|
||||
AndroidHttpClient.modifyRequestToAcceptGzipResponse(request);
|
||||
}
|
||||
|
||||
// only add the auth token if not null (to allow for GData feeds that do not require
|
||||
// authentication.)
|
||||
if (!TextUtils.isEmpty(authToken)) {
|
||||
request.addHeader("Authorization", "GoogleLogin auth=" + authToken);
|
||||
}
|
||||
|
||||
// while by default we have a 2.0 in this variable, it is possible to construct
|
||||
// a client that has an empty version field, to work with 1.0 services.
|
||||
if (!TextUtils.isEmpty(mGDataVersion)) {
|
||||
request.addHeader("GDataVersion", mGDataVersion);
|
||||
}
|
||||
|
||||
// if we have a passed down eTag value, we need to add several headers
|
||||
if (!TextUtils.isEmpty(eTag)) {
|
||||
String method = request.getMethod();
|
||||
Header overrideMethodHeader = request.getFirstHeader(X_HTTP_METHOD_OVERRIDE);
|
||||
if (overrideMethodHeader != null) {
|
||||
method = overrideMethodHeader.getValue();
|
||||
}
|
||||
if ("GET".equals(method)) {
|
||||
// add the none match header, if the resource is not changed
|
||||
// this request will result in a 304 now.
|
||||
request.addHeader("If-None-Match", eTag);
|
||||
} else if ("DELETE".equals(method)
|
||||
|| "PUT".equals(method)) {
|
||||
// now we send an if-match, but only if the passed in eTag is a strong eTag
|
||||
// as this only makes sense for a strong eTag
|
||||
if (!eTag.startsWith("W/")) {
|
||||
request.addHeader("If-Match", eTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (LOCAL_LOGV) {
|
||||
for (Header h : request.getAllHeaders()) {
|
||||
Log.v(TAG, h.getName() + ": " + h.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Executing " + request.getRequestLine().toString());
|
||||
}
|
||||
|
||||
response = null;
|
||||
|
||||
try {
|
||||
response = mHttpClient.execute(request);
|
||||
} catch (IOException ioe) {
|
||||
Log.w(TAG, "Unable to execute HTTP request." + ioe);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
StatusLine statusLine = response.getStatusLine();
|
||||
if (statusLine == null) {
|
||||
Log.w(TAG, "StatusLine is null.");
|
||||
throw new NullPointerException("StatusLine is null -- should not happen.");
|
||||
}
|
||||
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, response.getStatusLine().toString());
|
||||
for (Header h : response.getAllHeaders()) {
|
||||
Log.d(TAG, h.getName() + ": " + h.getValue());
|
||||
}
|
||||
}
|
||||
status = statusLine.getStatusCode();
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
|
||||
if ((status >= 200) && (status < 300) && entity != null) {
|
||||
InputStream in = AndroidHttpClient.getUngzippedContent(entity);
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
in = logInputStreamContents(in);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
// TODO: handle 301, 307?
|
||||
// TODO: let the http client handle the redirects, if we can be sure we'll never get a
|
||||
// redirect on POST.
|
||||
if (status == 302) {
|
||||
// consume the content, so the connection can be closed.
|
||||
entity.consumeContent();
|
||||
Header location = response.getFirstHeader("Location");
|
||||
if (location == null) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Redirect requested but no Location "
|
||||
+ "specified.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Following redirect to " + location.getValue());
|
||||
}
|
||||
try {
|
||||
uri = new URI(location.getValue());
|
||||
} catch (URISyntaxException use) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Unable to parse " + location.getValue() + " as URI.", use);
|
||||
throw new IOException("Unable to parse " + location.getValue()
|
||||
+ " as URI.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
--redirectsLeft;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "Received " + status + " status code.");
|
||||
}
|
||||
String errorMessage = null;
|
||||
HttpEntity entity = response.getEntity();
|
||||
try {
|
||||
if (response != null && entity != null) {
|
||||
InputStream in = AndroidHttpClient.getUngzippedContent(entity);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buf = new byte[8192];
|
||||
int bytesRead = -1;
|
||||
while ((bytesRead = in.read(buf)) != -1) {
|
||||
baos.write(buf, 0, bytesRead);
|
||||
}
|
||||
// TODO: use appropriate encoding, picked up from Content-Type.
|
||||
errorMessage = new String(baos.toByteArray());
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, errorMessage);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (entity != null) {
|
||||
entity.consumeContent();
|
||||
}
|
||||
}
|
||||
String exceptionMessage = "Received " + status + " status code";
|
||||
if (errorMessage != null) {
|
||||
exceptionMessage += (": " + errorMessage);
|
||||
}
|
||||
throw new HttpException(exceptionMessage, status, null /* InputStream */);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see GDataClient#getFeedAsStream(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public InputStream getFeedAsStream(String feedUrl,
|
||||
String authToken,
|
||||
String eTag,
|
||||
String protocolVersion)
|
||||
throws HttpException, IOException {
|
||||
|
||||
InputStream in = createAndExecuteMethod(new GetRequestCreator(), feedUrl, authToken, eTag, protocolVersion);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to access feed.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the contents of the input stream.
|
||||
* The original input stream is consumed, so the caller must use the
|
||||
* BufferedInputStream that is returned.
|
||||
* @param in InputStream
|
||||
* @return replacement input stream for caller to use
|
||||
* @throws IOException
|
||||
*/
|
||||
private InputStream logInputStreamContents(InputStream in) throws IOException {
|
||||
if (in == null) {
|
||||
return in;
|
||||
}
|
||||
// bufferSize is the (arbitrary) maximum amount to log.
|
||||
// The original InputStream is wrapped in a
|
||||
// BufferedInputStream with a 16K buffer. This lets
|
||||
// us read up to 16K, write it to the log, and then
|
||||
// reset the stream so the the original client can
|
||||
// then read the data. The BufferedInputStream
|
||||
// provides the mark and reset support, even when
|
||||
// the original InputStream does not.
|
||||
final int bufferSize = 16384;
|
||||
BufferedInputStream bin = new BufferedInputStream(in, bufferSize);
|
||||
bin.mark(bufferSize);
|
||||
int wanted = bufferSize;
|
||||
int totalReceived = 0;
|
||||
byte buf[] = new byte[wanted];
|
||||
while (wanted > 0) {
|
||||
int got = bin.read(buf, totalReceived, wanted);
|
||||
if (got <= 0) break; // EOF
|
||||
wanted -= got;
|
||||
totalReceived += got;
|
||||
}
|
||||
Log.d(TAG, new String(buf, 0, totalReceived, "UTF-8"));
|
||||
bin.reset();
|
||||
return bin;
|
||||
}
|
||||
|
||||
public InputStream getMediaEntryAsStream(String mediaEntryUrl, String authToken, String eTag, String protocolVersion)
|
||||
throws HttpException, IOException {
|
||||
|
||||
InputStream in = createAndExecuteMethod(new GetRequestCreator(), mediaEntryUrl, authToken, eTag, protocolVersion);
|
||||
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to access media entry.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see GDataClient#createEntry
|
||||
*/
|
||||
public InputStream createEntry(String feedUrl,
|
||||
String authToken,
|
||||
String protocolVersion,
|
||||
GDataSerializer entry)
|
||||
throws HttpException, IOException {
|
||||
|
||||
HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_CREATE);
|
||||
InputStream in = createAndExecuteMethod(
|
||||
new PostRequestCreator(null /* override */, entity),
|
||||
feedUrl,
|
||||
authToken,
|
||||
null,
|
||||
protocolVersion);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to create entry.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see GDataClient#updateEntry
|
||||
*/
|
||||
public InputStream updateEntry(String editUri,
|
||||
String authToken,
|
||||
String eTag,
|
||||
String protocolVersion,
|
||||
GDataSerializer entry)
|
||||
throws HttpException, IOException {
|
||||
HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_UPDATE);
|
||||
final String method = entry.getSupportsPartial() ? "PATCH" : "PUT";
|
||||
InputStream in = createAndExecuteMethod(
|
||||
new PostRequestCreator(method, entity),
|
||||
editUri,
|
||||
authToken,
|
||||
eTag,
|
||||
protocolVersion);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to update entry.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see GDataClient#deleteEntry
|
||||
*/
|
||||
public void deleteEntry(String editUri, String authToken, String eTag)
|
||||
throws HttpException, IOException {
|
||||
if (StringUtils.isEmpty(editUri)) {
|
||||
throw new IllegalArgumentException(
|
||||
"you must specify an non-empty edit url");
|
||||
}
|
||||
InputStream in =
|
||||
createAndExecuteMethod(
|
||||
new PostRequestCreator("DELETE", null /* entity */),
|
||||
editUri,
|
||||
authToken,
|
||||
eTag,
|
||||
null /* protocolVersion, not required for a delete */);
|
||||
if (in == null) {
|
||||
throw new IOException("Unable to delete entry.");
|
||||
}
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ioe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream updateMediaEntry(String editUri, String authToken, String eTag,
|
||||
String protocolVersion, InputStream mediaEntryInputStream, String contentType)
|
||||
throws HttpException, IOException {
|
||||
InputStream in = createAndExecuteMethod(
|
||||
new MediaPutRequestCreator(mediaEntryInputStream, contentType),
|
||||
editUri,
|
||||
authToken,
|
||||
eTag,
|
||||
protocolVersion);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to write media entry.");
|
||||
}
|
||||
|
||||
private HttpEntity createEntityForEntry(GDataSerializer entry, int format) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
entry.serialize(baos, format);
|
||||
} catch (IOException ioe) {
|
||||
Log.e(TAG, "Unable to serialize entry.", ioe);
|
||||
throw ioe;
|
||||
} catch (ParseException pe) {
|
||||
Log.e(TAG, "Unable to serialize entry.", pe);
|
||||
throw new IOException("Unable to serialize entry: " + pe.getMessage());
|
||||
}
|
||||
|
||||
byte[] entryBytes = baos.toByteArray();
|
||||
|
||||
if (entryBytes != null && Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
try {
|
||||
Log.d(TAG, "Serialized entry: " + new String(entryBytes, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
// should not happen
|
||||
throw new IllegalStateException("UTF-8 should be supported!",
|
||||
uee);
|
||||
}
|
||||
}
|
||||
|
||||
AbstractHttpEntity entity;
|
||||
if (SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) {
|
||||
entity = new ByteArrayEntity(entryBytes);
|
||||
} else {
|
||||
entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver);
|
||||
}
|
||||
|
||||
entity.setContentType(entry.getContentType());
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to a GData server (specified by the batchUrl) and submits a
|
||||
* batch for processing. The response from the server is returned as an
|
||||
* {@link InputStream}. The caller is responsible for calling
|
||||
* {@link InputStream#close()} on the returned {@link InputStream}.
|
||||
*
|
||||
* @param batchUrl The batch url to which the batch is submitted.
|
||||
* @param authToken the authentication token that should be used when
|
||||
* submitting the batch.
|
||||
* @param protocolVersion The version of the protocol that
|
||||
* should be used for this request.
|
||||
* @param batch The batch of entries to submit.
|
||||
* @throws IOException Thrown if an io error occurs while communicating with
|
||||
* the service.
|
||||
* @throws HttpException if the service returns an error response.
|
||||
*/
|
||||
public InputStream submitBatch(String batchUrl,
|
||||
String authToken,
|
||||
String protocolVersion,
|
||||
GDataSerializer batch)
|
||||
throws HttpException, IOException
|
||||
{
|
||||
HttpEntity entity = createEntityForEntry(batch, GDataSerializer.FORMAT_BATCH);
|
||||
InputStream in = createAndExecuteMethod(
|
||||
new PostRequestCreator("POST", entity),
|
||||
batchUrl,
|
||||
authToken,
|
||||
null,
|
||||
protocolVersion);
|
||||
if (in != null) {
|
||||
return in;
|
||||
}
|
||||
throw new IOException("Unable to process batch request.");
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.google.android.gdata2.client;
|
||||
|
||||
import com.google.wireless.gdata2.parser.xml.XmlParserFactory;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import android.util.Xml;
|
||||
|
||||
/**
|
||||
* XmlParserFactory for the Android platform.
|
||||
*/
|
||||
public class AndroidXmlParserFactory implements XmlParserFactory {
|
||||
|
||||
/*
|
||||
* (non-javadoc)
|
||||
* @see XmlParserFactory#createParser
|
||||
*/
|
||||
public XmlPullParser createParser() throws XmlPullParserException {
|
||||
return Xml.newPullParser();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-javadoc)
|
||||
* @see XmlParserFactory#createSerializer
|
||||
*/
|
||||
public XmlSerializer createSerializer() throws XmlPullParserException {
|
||||
return Xml.newSerializer();
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package com.google.android.gdata2.client;
|
||||
import com.google.wireless.gdata2.client.QueryParams;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Simple implementation of the QueryParams interface.
|
||||
*/
|
||||
// TODO: deal with categories
|
||||
public class QueryParamsImpl extends QueryParams {
|
||||
|
||||
private final Map<String,String> mParams = new HashMap<String,String>();
|
||||
|
||||
/**
|
||||
* Creates a new empty QueryParamsImpl.
|
||||
*/
|
||||
public QueryParamsImpl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
setEntryId(null);
|
||||
mParams.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateQueryUrl(String feedUrl) {
|
||||
|
||||
if (TextUtils.isEmpty(getEntryId()) &&
|
||||
mParams.isEmpty()) {
|
||||
// nothing to do
|
||||
return feedUrl;
|
||||
}
|
||||
|
||||
// handle entry IDs
|
||||
if (!TextUtils.isEmpty(getEntryId())) {
|
||||
if (!mParams.isEmpty()) {
|
||||
throw new IllegalStateException("Cannot set both an entry ID "
|
||||
+ "and other query paramters.");
|
||||
}
|
||||
return feedUrl + '/' + getEntryId();
|
||||
}
|
||||
|
||||
// otherwise, append the querystring params.
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(feedUrl);
|
||||
Set<String> params = mParams.keySet();
|
||||
boolean first = true;
|
||||
if (feedUrl.contains("?")) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append('?');
|
||||
}
|
||||
for (String param : params) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append('&');
|
||||
}
|
||||
sb.append(param);
|
||||
sb.append('=');
|
||||
String value = mParams.get(param);
|
||||
String encodedValue = null;
|
||||
|
||||
try {
|
||||
encodedValue = URLEncoder.encode(value, "UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
// should not happen.
|
||||
Log.w("QueryParamsImpl",
|
||||
"UTF-8 not supported -- should not happen. "
|
||||
+ "Using default encoding.", uee);
|
||||
encodedValue = URLEncoder.encode(value);
|
||||
}
|
||||
sb.append(encodedValue);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParamValue(String param) {
|
||||
if (!(mParams.containsKey(param))) {
|
||||
return null;
|
||||
}
|
||||
return mParams.get(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParamValue(String param, String value) {
|
||||
mParams.put(param, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1097,10 +1097,6 @@ com.android.internal.widget.NumberPicker$NumberRangeKeyListener
|
||||
com.android.internal.widget.NumberPickerButton
|
||||
com.android.internal.widget.RotarySelector
|
||||
com.android.internal.widget.Smileys
|
||||
com.google.android.gdata.client.AndroidGDataClient
|
||||
com.google.android.gdata.client.AndroidGDataClient$GetRequestCreator
|
||||
com.google.android.gdata.client.AndroidGDataClient$PostRequestCreator
|
||||
com.google.android.gdata.client.QueryParamsImpl
|
||||
com.google.android.gles_jni.EGLDisplayImpl
|
||||
com.google.android.gles_jni.EGLImpl
|
||||
com.google.android.gles_jni.EGLSurfaceImpl
|
||||
@@ -1115,17 +1111,6 @@ com.google.android.net.ParentalControlState
|
||||
com.google.android.net.ParentalControlState$1
|
||||
com.google.android.net.UrlRules
|
||||
com.google.android.net.UrlRules$Rule
|
||||
com.google.wireless.gdata.calendar.client.CalendarClient
|
||||
com.google.wireless.gdata.calendar.data.CalendarEntry
|
||||
com.google.wireless.gdata.calendar.data.CalendarsFeed
|
||||
com.google.wireless.gdata.calendar.data.EventEntry
|
||||
com.google.wireless.gdata.calendar.data.Who
|
||||
com.google.wireless.gdata.calendar.parser.xml.XmlCalendarGDataParserFactory
|
||||
com.google.wireless.gdata.calendar.serializer.xml.XmlEventEntryGDataSerializer
|
||||
com.google.wireless.gdata.client.GDataServiceClient
|
||||
com.google.wireless.gdata.client.QueryParams
|
||||
com.google.wireless.gdata.data.Entry
|
||||
com.google.wireless.gdata.parser.xml.XmlGDataParser
|
||||
com.ibm.icu4jni.charset.CharsetDecoderICU
|
||||
com.ibm.icu4jni.charset.CharsetEncoderICU
|
||||
com.ibm.icu4jni.charset.CharsetICU
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.android.unit_tests;
|
||||
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.PerformanceTestCase;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Xml;
|
||||
import com.google.wireless.gdata.data.Entry;
|
||||
import com.google.wireless.gdata.data.Feed;
|
||||
import com.google.wireless.gdata.parser.ParseException;
|
||||
import com.google.wireless.gdata.parser.xml.XmlGDataParser;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* Tests timing on parsing various formats of GData.
|
||||
*/
|
||||
public class GDataParseTest extends AndroidTestCase implements PerformanceTestCase {
|
||||
|
||||
private static void parseXml(InputStream is) throws ParseException, IOException {
|
||||
XmlPullParser xmlParser = Xml.newPullParser();
|
||||
XmlGDataParser parser = new XmlGDataParser(is, xmlParser);
|
||||
Feed feed = parser.init();
|
||||
Entry entry = null;
|
||||
while (parser.hasMoreData()) {
|
||||
entry = parser.readNextEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseXml(XmlPullParser xmlP) throws ParseException, IOException {
|
||||
XmlGDataParser parser = new XmlGDataParser(null /* in */, xmlP);
|
||||
Feed feed = parser.init();
|
||||
Entry entry = null;
|
||||
while (parser.hasMoreData()) {
|
||||
entry = parser.readNextEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private static void dumpXml(XmlPullParser parser) throws
|
||||
XmlPullParserException, IOException {
|
||||
int eventType = parser.nextTag();
|
||||
while (eventType != XmlPullParser.END_DOCUMENT) {
|
||||
switch (eventType) {
|
||||
case XmlPullParser.START_TAG:
|
||||
parser.getName();
|
||||
// System.out.print("<" + parser.getName());
|
||||
int nattrs = parser.getAttributeCount();
|
||||
for (int i = 0; i < nattrs; ++i) {
|
||||
parser.getAttributeName(i);
|
||||
parser.getAttributeValue(i);
|
||||
// System.out.print(" " + parser.getAttributeName(i) + "=\""
|
||||
// + parser.getAttributeValue(i) + "\"");
|
||||
}
|
||||
// System.out.print(">");
|
||||
break;
|
||||
case XmlPullParser.END_TAG:
|
||||
parser.getName();
|
||||
// System.out.print("</" + parser.getName() + ">");
|
||||
break;
|
||||
case XmlPullParser.TEXT:
|
||||
parser.getText();
|
||||
// System.out.print(parser.getText());
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
eventType = parser.next();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getBytesForResource(int resid) throws Exception {
|
||||
// all resources are written into a zip file, so the InputStream we
|
||||
// get for a resource is on top of zipped
|
||||
// data. in order to compare performance of parsing unzipped vs.
|
||||
// zipped content, we first read the data into an in-memory buffer.
|
||||
InputStream zipIs = null;
|
||||
try {
|
||||
zipIs = mContext.getResources().openRawResource(resid);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte buf[] = new byte[1024];
|
||||
int bytesRead = zipIs.read(buf);
|
||||
while (bytesRead > 0) {
|
||||
baos.write(buf, 0, bytesRead);
|
||||
bytesRead = zipIs.read(buf);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
} finally {
|
||||
if (zipIs != null) {
|
||||
zipIs.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPerformanceOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testXml() throws Exception {
|
||||
InputStream is = new ByteArrayInputStream(getBytesForResource(R.raw.calendarxml));
|
||||
try {
|
||||
is.reset();
|
||||
parseXml(is);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testXmlGzip() throws Exception {
|
||||
InputStream gzIs = new GZIPInputStream(
|
||||
new ByteArrayInputStream(getBytesForResource(R.raw.calendarxmlgz)));
|
||||
try {
|
||||
parseXml(gzIs);
|
||||
} finally {
|
||||
gzIs.close();
|
||||
}
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testJson() throws Exception {
|
||||
String jsonString = new String(getBytesForResource(R.raw.calendarjs), "UTF-8");
|
||||
JSONTokener tokens = new JSONTokener(jsonString);
|
||||
assertNotNull(new JSONObject(tokens));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testBinaryXml() throws Exception {
|
||||
XmlResourceParser parser = mContext.getResources().getXml(R.xml.calendar);
|
||||
parseXml(parser);
|
||||
parser.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user