resolved conflicts for merge of b8675943 to master
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user