From d2ed7976efcc9b5ebcebacf0d4fdae4a0436c8f3 Mon Sep 17 00:00:00 2001
From: srowen
Date: Wed, 12 Oct 2011 11:53:54 +0000
Subject: [PATCH] Merge from "Barcode Scanner Plus": avoid deprecated
AndroidHttpClient and use java.net for networking; better HTTP headers,
better redirect handling
git-svn-id: https://zxing.googlecode.com/svn/trunk@1958 59b500cc-1b3d-0410-9834-0bbf25fbcc57
---
.../client/android/AndroidHttpClient.java | 170 ------------------
.../zxing/client/android/HttpHelper.java | 168 +++++++++++++++++
.../client/android/book/NetworkWorker.java | 76 ++++++++
.../book/SearchBookContentsActivity.java | 117 +-----------
.../supplement/BookResultInfoRetriever.java | 4 +-
.../ProductResultInfoRetriever.java | 3 +-
.../supplement/SupplementalInfoRetriever.java | 46 -----
.../supplement/URIResultInfoRetriever.java | 64 ++-----
8 files changed, 269 insertions(+), 379 deletions(-)
delete mode 100644 android/src/com/google/zxing/client/android/AndroidHttpClient.java
create mode 100644 android/src/com/google/zxing/client/android/HttpHelper.java
create mode 100644 android/src/com/google/zxing/client/android/book/NetworkWorker.java
diff --git a/android/src/com/google/zxing/client/android/AndroidHttpClient.java b/android/src/com/google/zxing/client/android/AndroidHttpClient.java
deleted file mode 100644
index f8e93c786..000000000
--- a/android/src/com/google/zxing/client/android/AndroidHttpClient.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2008 ZXing authors
- *
- * 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.google.zxing.client.android;
-
-import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.ResponseHandler;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.client.protocol.ClientContext;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.HttpContext;
-
-import java.io.IOException;
-
-/**
- * Subclass of the Apache {@link DefaultHttpClient} that is configured with
- * reasonable default settings and registered schemes for Android, and
- * also lets the user add {@link HttpRequestInterceptor} classes.
- * Don't create this directly, use the {@link #newInstance} factory method.
- *
- * This client processes cookies but does not retain them by default.
- * To retain cookies, simply add a cookie store to the HttpContext:
- *
context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
- *
- */
-public final class AndroidHttpClient implements HttpClient {
-
- /**
- * Create a new HttpClient with reasonable defaults (which you can update).
- *
- * @param userAgent to report in your HTTP requests.
- * @return AndroidHttpClient for you to use for all your requests.
- */
- public static AndroidHttpClient newInstance(String userAgent) {
- HttpParams params = new BasicHttpParams();
-
- // Turn off stale checking. Our connections break all the time anyway,
- // and it's not worth it to pay the penalty of checking every time.
- HttpConnectionParams.setStaleCheckingEnabled(params, false);
-
- // Default connection and socket timeout of 20 seconds. Tweak to taste.
- HttpConnectionParams.setConnectionTimeout(params, 20 * 1000);
- HttpConnectionParams.setSoTimeout(params, 20 * 1000);
- HttpConnectionParams.setSocketBufferSize(params, 8192);
-
- // Don't handle redirects -- return them to the caller. Our code
- // often wants to re-POST after a redirect, which we must do ourselves.
- HttpClientParams.setRedirecting(params, false);
-
- // Set the specified user agent and register standard protocols.
- if (userAgent != null) {
- HttpProtocolParams.setUserAgent(params, userAgent);
- }
- SchemeRegistry schemeRegistry = new SchemeRegistry();
- schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
- ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);
-
- // We use a factory method to modify superclass initialization
- // parameters without the funny call-a-static-method dance.
- return new AndroidHttpClient(manager, params);
- }
-
- private final HttpClient delegate;
-
-
- private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) {
- this.delegate = new DelegateHttpClient(ccm, params);
- }
-
- /**
- * Release resources associated with this client. You must call this,
- * or significant resources (sockets and memory) may be leaked.
- */
- public void close() {
- getConnectionManager().shutdown();
- }
-
- public HttpParams getParams() {
- return delegate.getParams();
- }
-
- public ClientConnectionManager getConnectionManager() {
- return delegate.getConnectionManager();
- }
-
- public HttpResponse execute(HttpUriRequest request) throws IOException {
- return delegate.execute(request);
- }
-
- public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException {
- return delegate.execute(request, context);
- }
-
- public HttpResponse execute(HttpHost target, HttpRequest request) throws IOException {
- return delegate.execute(target, request);
- }
-
- public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException {
- return delegate.execute(target, request, context);
- }
-
- public T execute(HttpUriRequest request, ResponseHandler extends T> responseHandler) throws IOException {
- return delegate.execute(request, responseHandler);
- }
-
- public T execute(HttpUriRequest request, ResponseHandler extends T> responseHandler, HttpContext context)
- throws IOException {
- return delegate.execute(request, responseHandler, context);
- }
-
- public T execute(HttpHost target, HttpRequest request, ResponseHandler extends T> responseHandler)
- throws IOException {
- return delegate.execute(target, request, responseHandler);
- }
-
- public T execute(HttpHost target, HttpRequest request,
- ResponseHandler extends T> responseHandler,
- HttpContext context) throws IOException {
- return delegate.execute(target, request, responseHandler, context);
- }
-
- private static class DelegateHttpClient extends DefaultHttpClient {
-
- private DelegateHttpClient(ClientConnectionManager ccm, HttpParams params) {
- super(ccm, params);
- }
-
- @Override
- protected HttpContext createHttpContext() {
- // Same as DefaultHttpClient.createHttpContext() minus the
- // cookie store.
- HttpContext context = new BasicHttpContext();
- context.setAttribute(ClientContext.AUTHSCHEME_REGISTRY, getAuthSchemes());
- context.setAttribute(ClientContext.COOKIESPEC_REGISTRY, getCookieSpecs());
- context.setAttribute(ClientContext.CREDS_PROVIDER, getCredentialsProvider());
- return context;
- }
- }
-
-}
diff --git a/android/src/com/google/zxing/client/android/HttpHelper.java b/android/src/com/google/zxing/client/android/HttpHelper.java
new file mode 100644
index 000000000..ee30f7644
--- /dev/null
+++ b/android/src/com/google/zxing/client/android/HttpHelper.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2011 ZXing authors
+ *
+ * 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.google.zxing.client.android;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * Utility methods for retrieving content over HTTP using the more-supported {@code java.net} classes
+ * in Android.
+ */
+public final class HttpHelper {
+
+ private static final Collection REDIRECTOR_DOMAINS = new HashSet(Arrays.asList(
+ "amzn.to", "bit.ly", "bitly.com", "fb.me", "goo.gl", "is.gd", "j.mp", "lnkd.in", "ow.ly",
+ "SCN.BY", "su.pr", "t.co", "tinyurl.com", "tr.im"
+ ));
+
+ private HttpHelper() {
+ }
+
+ public enum ContentType {
+ /** HTML-like content type, including HTML, XHTML, etc. */
+ HTML,
+ /** JSON content */
+ JSON,
+ /** Plain text content */
+ TEXT,
+ }
+
+ /**
+ * @param uri URI to retrieve
+ * @param type expected text-like MIME type of that content
+ * @return content as a {@code String}
+ * @throws IOException if the content can't be retrieved because of a bad URI, network problem, etc.
+ */
+ public static String downloadViaHttp(String uri, ContentType type) throws IOException {
+ String contentTypes;
+ switch (type) {
+ case HTML:
+ contentTypes = "application/xhtml+xml,text/html,text/*,*/*";
+ break;
+ case JSON:
+ contentTypes = "application/json,text/*,*/*";
+ break;
+ case TEXT:
+ default:
+ contentTypes = "text/*,*/*";
+ }
+ return downloadViaHttp(uri, contentTypes);
+ }
+
+ private static String downloadViaHttp(String uri, String contentTypes) throws IOException {
+ URL url = new URL(uri);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestProperty("Accept", contentTypes);
+ connection.setRequestProperty("Accept-Charset", "utf-8,*");
+ connection.setRequestProperty("User-Agent", "ZXing (Android)");
+ try {
+ connection.connect();
+ if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ throw new IOException("Bad HTTP response: " + connection.getResponseCode());
+ }
+ return consume(connection);
+ } finally {
+ connection.disconnect();
+ }
+ }
+
+ private static String getEncoding(HttpURLConnection connection) {
+ String contentTypeHeader = connection.getHeaderField("Content-Type");
+ if (contentTypeHeader != null) {
+ int charsetStart = contentTypeHeader.indexOf("charset=");
+ if (charsetStart >= 0) {
+ return contentTypeHeader.substring(charsetStart + "charset=".length());
+ }
+ }
+ return "UTF-8";
+ }
+
+ private static String consume(HttpURLConnection connection) throws IOException {
+ String encoding = getEncoding(connection);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ InputStream in = connection.getInputStream();
+ try {
+ in = connection.getInputStream();
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = in.read(buffer)) > 0) {
+ out.write(buffer, 0, bytesRead);
+ }
+ } finally {
+ try {
+ in.close();
+ } catch (IOException ioe) {
+ // continue
+ }
+ }
+ try {
+ return new String(out.toByteArray(), encoding);
+ } catch (UnsupportedEncodingException uee) {
+ try {
+ return new String(out.toByteArray(), "UTF-8");
+ } catch (UnsupportedEncodingException uee2) {
+ // can't happen
+ throw new IllegalStateException(uee2);
+ }
+ }
+ }
+
+ public static URI unredirect(URI uri) throws IOException {
+ if (!REDIRECTOR_DOMAINS.contains(uri.getHost())) {
+ return uri;
+ }
+ URL url = uri.toURL();
+
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setInstanceFollowRedirects(false);
+ connection.setDoInput(false);
+ connection.setRequestMethod("HEAD");
+ connection.setRequestProperty("User-Agent", "ZXing (Android)");
+ try {
+ connection.connect();
+ switch (connection.getResponseCode()) {
+ case HttpURLConnection.HTTP_MULT_CHOICE:
+ case HttpURLConnection.HTTP_MOVED_PERM:
+ case HttpURLConnection.HTTP_MOVED_TEMP:
+ case HttpURLConnection.HTTP_SEE_OTHER:
+ case 307: // No constant for 307 Temporary Redirect ?
+ String location = connection.getHeaderField("Location");
+ if (location != null) {
+ try {
+ return new URI(location);
+ } catch (URISyntaxException e) {
+ // nevermind
+ }
+ }
+ }
+ return uri;
+ } finally {
+ connection.disconnect();
+ }
+ }
+
+}
diff --git a/android/src/com/google/zxing/client/android/book/NetworkWorker.java b/android/src/com/google/zxing/client/android/book/NetworkWorker.java
new file mode 100644
index 000000000..429000070
--- /dev/null
+++ b/android/src/com/google/zxing/client/android/book/NetworkWorker.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 ZXing authors
+ *
+ * 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.google.zxing.client.android.book;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import com.google.zxing.client.android.HttpHelper;
+import com.google.zxing.client.android.LocaleManager;
+import com.google.zxing.client.android.R;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+
+final class NetworkWorker implements Runnable {
+
+ private static final String TAG = NetworkWorker.class.getSimpleName();
+
+ private final String isbn;
+ private final String query;
+ private final Handler handler;
+
+ NetworkWorker(String isbn, String query, Handler handler) {
+ this.isbn = isbn;
+ this.query = query;
+ this.handler = handler;
+ }
+
+ @Override
+ public void run() {
+ try {
+ // These return a JSON result which describes if and where the query was found. This API may
+ // break or disappear at any time in the future. Since this is an API call rather than a
+ // website, we don't use LocaleManager to change the TLD.
+ String uri;
+ if (LocaleManager.isBookSearchUrl(isbn)) {
+ int equals = isbn.indexOf('=');
+ String volumeId = isbn.substring(equals + 1);
+ uri = "http://www.google.com/books?id=" + volumeId + "&jscmd=SearchWithinVolume2&q=" + query;
+ } else {
+ uri = "http://www.google.com/books?vid=isbn" + isbn + "&jscmd=SearchWithinVolume2&q=" + query;
+ }
+
+ try {
+ String content = HttpHelper.downloadViaHttp(uri, HttpHelper.ContentType.JSON);
+ JSONObject json = new JSONObject(content);
+ Message message = Message.obtain(handler, R.id.search_book_contents_succeeded);
+ message.obj = json;
+ message.sendToTarget();
+ } catch (IOException ioe) {
+ Message message = Message.obtain(handler, R.id.search_book_contents_failed);
+ message.sendToTarget();
+ }
+ } catch (JSONException je) {
+ Log.w(TAG, "Error accessing book search", je);
+ Message message = Message.obtain(handler, R.id.search_book_contents_failed);
+ message.sendToTarget();
+ }
+ }
+
+}
diff --git a/android/src/com/google/zxing/client/android/book/SearchBookContentsActivity.java b/android/src/com/google/zxing/client/android/book/SearchBookContentsActivity.java
index c9f422e96..3c5e10389 100644
--- a/android/src/com/google/zxing/client/android/book/SearchBookContentsActivity.java
+++ b/android/src/com/google/zxing/client/android/book/SearchBookContentsActivity.java
@@ -31,19 +31,10 @@ import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.client.methods.HttpUriRequest;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
@@ -51,7 +42,6 @@ import java.util.regex.Pattern;
import com.google.zxing.client.android.LocaleManager;
import com.google.zxing.client.android.R;
import com.google.zxing.client.android.Intents;
-import com.google.zxing.client.android.AndroidHttpClient;
/**
* Uses Google Book Search to find a word or phrase in the requested book.
@@ -59,16 +49,16 @@ import com.google.zxing.client.android.AndroidHttpClient;
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class SearchBookContentsActivity extends Activity {
+
private static final String TAG = SearchBookContentsActivity.class.getSimpleName();
- private static final String USER_AGENT = "ZXing (Android)";
private static final Pattern TAG_PATTERN = Pattern.compile("\\<.*?\\>");
private static final Pattern LT_ENTITY_PATTERN = Pattern.compile("<");
private static final Pattern GT_ENTITY_PATTERN = Pattern.compile(">");
private static final Pattern QUOTE_ENTITY_PATTERN = Pattern.compile("'");
private static final Pattern QUOT_ENTITY_PATTERN = Pattern.compile(""");
- private NetworkThread networkThread;
+ private Thread networkThread;
private String isbn;
private EditText queryTextView;
private Button queryButton;
@@ -169,7 +159,7 @@ public final class SearchBookContentsActivity extends Activity {
if (networkThread == null) {
String query = queryTextView.getText().toString();
if (query != null && query.length() > 0) {
- networkThread = new NetworkThread(isbn, query, handler);
+ networkThread = new Thread(new NetworkWorker(isbn, query, handler));
networkThread.start();
headerView.setText(R.string.msg_sbc_searching_book);
resultListView.setAdapter(null);
@@ -240,105 +230,4 @@ public final class SearchBookContentsActivity extends Activity {
}
}
- private static final class NetworkThread extends Thread {
- private final String isbn;
- private final String query;
- private final Handler handler;
-
- NetworkThread(String isbn, String query, Handler handler) {
- this.isbn = isbn;
- this.query = query;
- this.handler = handler;
- }
-
- @Override
- public void run() {
- AndroidHttpClient client = null;
- try {
- // These return a JSON result which describes if and where the query was found. This API may
- // break or disappear at any time in the future. Since this is an API call rather than a
- // website, we don't use LocaleManager to change the TLD.
- URI uri;
- if (LocaleManager.isBookSearchUrl(isbn)) {
- int equals = isbn.indexOf('=');
- String volumeId = isbn.substring(equals + 1);
- uri = new URI("http", null, "www.google.com", -1, "/books", "id=" + volumeId +
- "&jscmd=SearchWithinVolume2&q=" + query, null);
- } else {
- uri = new URI("http", null, "www.google.com", -1, "/books", "vid=isbn" + isbn +
- "&jscmd=SearchWithinVolume2&q=" + query, null);
- }
- HttpUriRequest get = new HttpGet(uri);
- get.setHeader("cookie", getCookie(uri.toString()));
- client = AndroidHttpClient.newInstance(USER_AGENT);
- HttpResponse response = client.execute(get);
- if (response.getStatusLine().getStatusCode() == 200) {
- HttpEntity entity = response.getEntity();
- ByteArrayOutputStream jsonHolder = new ByteArrayOutputStream();
- entity.writeTo(jsonHolder);
- jsonHolder.flush();
- JSONObject json = new JSONObject(jsonHolder.toString(getEncoding(entity)));
- jsonHolder.close();
-
- Message message = Message.obtain(handler, R.id.search_book_contents_succeeded);
- message.obj = json;
- message.sendToTarget();
- } else {
- Log.w(TAG, "HTTP returned " + response.getStatusLine().getStatusCode() + " for " + uri);
- Message message = Message.obtain(handler, R.id.search_book_contents_failed);
- message.sendToTarget();
- }
- } catch (Exception e) {
- Log.w(TAG, "Error accessing book search", e);
- Message message = Message.obtain(handler, R.id.search_book_contents_failed);
- message.sendToTarget();
- } finally {
- if (client != null) {
- client.close();
- }
- }
- }
-
- // Book Search requires a cookie to work, which we store persistently. If the cookie does
- // not exist, this could be the first search or it has expired. Either way, do a quick HEAD
- // request to fetch it, save it via the CookieSyncManager to flash, then return it.
- private static String getCookie(String url) {
- String cookie = CookieManager.getInstance().getCookie(url);
- if (cookie == null || cookie.length() == 0) {
- Log.d(TAG, "Book Search cookie was missing or expired");
- HttpUriRequest head = new HttpHead(url);
- AndroidHttpClient client = AndroidHttpClient.newInstance(USER_AGENT);
- try {
- HttpResponse response = client.execute(head);
- if (response.getStatusLine().getStatusCode() == 200) {
- Header[] cookies = response.getHeaders("set-cookie");
- for (Header theCookie : cookies) {
- CookieManager.getInstance().setCookie(url, theCookie.getValue());
- }
- CookieSyncManager.getInstance().sync();
- cookie = CookieManager.getInstance().getCookie(url);
- }
- } catch (IOException e) {
- Log.w(TAG, "Error setting book search cookie", e);
- }
- client.close();
- }
- return cookie;
- }
-
- private static String getEncoding(HttpEntity entity) {
- // FIXME: The server is returning ISO-8859-1 but the content is actually windows-1252.
- // Once Jeff fixes the HTTP response, remove this hardcoded value and go back to getting
- // the encoding dynamically.
- return "windows-1252";
-// HeaderElement[] elements = entity.getContentType().getElements();
-// if (elements != null && elements.length > 0) {
-// String encoding = elements[0].getParameterByName("charset").getValue();
-// if (encoding != null && encoding.length() > 0) {
-// return encoding;
-// }
-// }
-// return "UTF-8";
- }
- }
}
diff --git a/android/src/com/google/zxing/client/android/result/supplement/BookResultInfoRetriever.java b/android/src/com/google/zxing/client/android/result/supplement/BookResultInfoRetriever.java
index bdc8eb610..9479e7d0a 100644
--- a/android/src/com/google/zxing/client/android/result/supplement/BookResultInfoRetriever.java
+++ b/android/src/com/google/zxing/client/android/result/supplement/BookResultInfoRetriever.java
@@ -22,6 +22,7 @@ import java.util.Collection;
import android.content.Context;
import android.widget.TextView;
+import com.google.zxing.client.android.HttpHelper;
import com.google.zxing.client.android.LocaleManager;
import com.google.zxing.client.android.R;
import org.json.JSONArray;
@@ -58,7 +59,8 @@ public final class BookResultInfoRetriever extends SupplementalInfoRetriever {
@Override
void retrieveSupplementalInfo() throws IOException, InterruptedException {
- String contents = downloadViaHttp("https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn);
+ String contents = HttpHelper.downloadViaHttp("https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn,
+ HttpHelper.ContentType.JSON);
if (contents.length() == 0) {
return;
diff --git a/android/src/com/google/zxing/client/android/result/supplement/ProductResultInfoRetriever.java b/android/src/com/google/zxing/client/android/result/supplement/ProductResultInfoRetriever.java
index 5d873985b..919d35192 100644
--- a/android/src/com/google/zxing/client/android/result/supplement/ProductResultInfoRetriever.java
+++ b/android/src/com/google/zxing/client/android/result/supplement/ProductResultInfoRetriever.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.os.Handler;
import android.text.Html;
import android.widget.TextView;
+import com.google.zxing.client.android.HttpHelper;
import com.google.zxing.client.android.R;
import com.google.zxing.client.android.history.HistoryManager;
import com.google.zxing.client.android.LocaleManager;
@@ -56,7 +57,7 @@ final class ProductResultInfoRetriever extends SupplementalInfoRetriever {
String encodedProductID = URLEncoder.encode(productID, "UTF-8");
String uri = BASE_PRODUCT_URI + encodedProductID;
- String content = downloadViaHttp(uri);
+ String content = HttpHelper.downloadViaHttp(uri, HttpHelper.ContentType.HTML);
Matcher matcher = PRODUCT_NAME_PRICE_PATTERN.matcher(content);
if (matcher.find()) {
diff --git a/android/src/com/google/zxing/client/android/result/supplement/SupplementalInfoRetriever.java b/android/src/com/google/zxing/client/android/result/supplement/SupplementalInfoRetriever.java
index c40ad6e20..3c40aa752 100644
--- a/android/src/com/google/zxing/client/android/result/supplement/SupplementalInfoRetriever.java
+++ b/android/src/com/google/zxing/client/android/result/supplement/SupplementalInfoRetriever.java
@@ -24,21 +24,13 @@ import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.URLSpan;
import android.widget.TextView;
-import com.google.zxing.client.android.AndroidHttpClient;
import com.google.zxing.client.result.ISBNParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ProductParsedResult;
import com.google.zxing.client.result.URIParsedResult;
import com.google.zxing.client.android.history.HistoryManager;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpUriRequest;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
@@ -156,42 +148,4 @@ public abstract class SupplementalInfoRetriever implements Callable {
historyManager.addHistoryItemDetails(itemID, newText);
}
- protected static String downloadViaHttp(String uri) throws IOException {
- HttpUriRequest get = new HttpGet(uri);
- AndroidHttpClient client = AndroidHttpClient.newInstance(null);
- HttpResponse response = client.execute(get);
- int status = response.getStatusLine().getStatusCode();
- if (status != 200) {
- throw new IOException();
- }
- return consume(response.getEntity());
- }
-
- private static String consume(HttpEntity entity) throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- InputStream in = null;
- try {
- in = entity.getContent();
- byte[] buffer = new byte[1024];
- int bytesRead;
- while ((bytesRead = in.read(buffer)) > 0) {
- out.write(buffer, 0, bytesRead);
- }
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException ioe) {
- // continue
- }
- }
- }
- try {
- return new String(out.toByteArray(), "UTF-8");
- } catch (UnsupportedEncodingException uee) {
- // can't happen
- throw new IllegalStateException(uee);
- }
- }
-
}
diff --git a/android/src/com/google/zxing/client/android/result/supplement/URIResultInfoRetriever.java b/android/src/com/google/zxing/client/android/result/supplement/URIResultInfoRetriever.java
index 08cf74024..658e0c5f5 100644
--- a/android/src/com/google/zxing/client/android/result/supplement/URIResultInfoRetriever.java
+++ b/android/src/com/google/zxing/client/android/result/supplement/URIResultInfoRetriever.java
@@ -19,26 +19,18 @@ package com.google.zxing.client.android.result.supplement;
import android.content.Context;
import android.os.Handler;
import android.widget.TextView;
+import com.google.zxing.client.android.HttpHelper;
import com.google.zxing.client.android.history.HistoryManager;
-import com.google.zxing.client.android.AndroidHttpClient;
import com.google.zxing.client.android.R;
import com.google.zxing.client.result.URIParsedResult;
-import org.apache.http.Header;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.client.methods.HttpUriRequest;
import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
final class URIResultInfoRetriever extends SupplementalInfoRetriever {
- private static final String[] REDIRECTOR_HOSTS = {
- "http://bit.ly/",
- "http://tinyurl.com/",
- "http://tr.im/",
- "http://goo.gl/",
- "http://ow.ly/",
- };
+ private static final int MAX_REDIRECTS = 5;
private final URIParsedResult result;
private final String redirectString;
@@ -55,44 +47,22 @@ final class URIResultInfoRetriever extends SupplementalInfoRetriever {
@Override
void retrieveSupplementalInfo() throws IOException, InterruptedException {
- String oldURI = result.getURI();
- String newURI = unredirect(oldURI);
+ URI oldURI;
+ try {
+ oldURI = new URI(result.getURI());
+ } catch (URISyntaxException e) {
+ return;
+ }
+ URI newURI = HttpHelper.unredirect(oldURI);
int count = 0;
- while (count < 3 && !oldURI.equals(newURI)) {
- append(result.getDisplayResult(), null, new String[] { redirectString + " : " + newURI }, newURI);
- count++;
+ while (count++ < MAX_REDIRECTS && !oldURI.equals(newURI)) {
+ append(result.getDisplayResult(),
+ null,
+ new String[] { redirectString + " : " + newURI },
+ newURI.toString());
oldURI = newURI;
- newURI = unredirect(newURI);
+ newURI = HttpHelper.unredirect(newURI);
}
}
- private static String unredirect(String uri) throws IOException {
- if (!isRedirector(uri)) {
- return uri;
- }
- HttpUriRequest head = new HttpHead(uri);
- AndroidHttpClient client = AndroidHttpClient.newInstance(null);
- HttpResponse response = client.execute(head);
- int status = response.getStatusLine().getStatusCode();
- if (status == 301 || status == 302) {
- Header redirect = response.getFirstHeader("Location");
- if (redirect != null) {
- String location = redirect.getValue();
- if (location != null) {
- return location;
- }
- }
- }
- return uri;
- }
-
- private static boolean isRedirector(String uri) {
- for (String redirectorHost : REDIRECTOR_HOSTS) {
- if (uri.startsWith(redirectorHost)) {
- return true;
- }
- }
- return false;
- }
-
}