summaryrefslogtreecommitdiffstats
path: root/core/java/android/webkit
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-05 14:34:35 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-05 14:34:35 -0800
commit4df2423a947bcd3f024cc3d3a1a315a8dc428598 (patch)
treee7dac2c5a367b169e7f05a36058cf470e93f003b /core/java/android/webkit
parentc474dec3ffa1c0fe37edb3e701684188f7e8e7bc (diff)
downloadframeworks_base-4df2423a947bcd3f024cc3d3a1a315a8dc428598.zip
frameworks_base-4df2423a947bcd3f024cc3d3a1a315a8dc428598.tar.gz
frameworks_base-4df2423a947bcd3f024cc3d3a1a315a8dc428598.tar.bz2
auto import from //depot/cupcake/@136594
Diffstat (limited to 'core/java/android/webkit')
-rw-r--r--core/java/android/webkit/BrowserFrame.java23
-rw-r--r--core/java/android/webkit/FrameLoader.java13
-rw-r--r--core/java/android/webkit/LoadListener.java14
-rw-r--r--core/java/android/webkit/PluginContentLoader.java96
-rw-r--r--core/java/android/webkit/PluginData.java116
-rw-r--r--core/java/android/webkit/TextDialog.java8
-rw-r--r--core/java/android/webkit/UrlInterceptHandler.java15
-rw-r--r--core/java/android/webkit/UrlInterceptRegistry.java34
-rw-r--r--core/java/android/webkit/WebView.java29
-rw-r--r--core/java/android/webkit/gears/UrlInterceptHandlerGears.java160
10 files changed, 349 insertions, 159 deletions
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 451af6d..5401a6e 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -201,10 +201,14 @@ class BrowserFrame extends Handler {
final String failingUrl) {
// As this is called for the main resource and loading will be stopped
// after, reset the state variables.
+ resetLoadingStates();
+ mCallbackProxy.onReceivedError(errorCode, description, failingUrl);
+ }
+
+ private void resetLoadingStates() {
mCommitted = true;
mWebViewCore.mEndScaleZoom = mFirstLayoutDone == false;
mFirstLayoutDone = true;
- mCallbackProxy.onReceivedError(errorCode, description, failingUrl);
}
/* package */boolean committed() {
@@ -290,6 +294,7 @@ class BrowserFrame extends Handler {
if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
if (isMainFrame) {
+ resetLoadingStates();
mCallbackProxy.switchOutDrawHistory();
mCallbackProxy.onPageFinished(url);
}
@@ -555,8 +560,11 @@ class BrowserFrame extends Handler {
method, isHighPriority);
loader.setHeaders(headers);
loader.setPostData(postData);
- loader.setCacheMode(cacheMode); // Set the load mode to the mode used
- // for the current page.
+ // Set the load mode to the mode used for the current page.
+ // If WebKit wants validation, go to network directly.
+ loader.setCacheMode(headers.containsKey("If-Modified-Since")
+ || headers.containsKey("If-None-Match") ?
+ WebSettings.LOAD_NO_CACHE : cacheMode);
// Set referrer to current URL?
if (!loader.executeLoad()) {
checker.responseAlert("startLoadingResource fail");
@@ -751,7 +759,14 @@ class BrowserFrame extends Handler {
/**
* Stop loading the current page.
*/
- public native void stopLoading();
+ public void stopLoading() {
+ if (mIsMainFrame) {
+ resetLoadingStates();
+ }
+ nativeStopLoading();
+ }
+
+ private native void nativeStopLoading();
/**
* Return true if the document has images.
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 5e323eb..42d03f0 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -21,7 +21,6 @@ import android.net.http.RequestHandle;
import android.util.Config;
import android.util.Log;
import android.webkit.CacheManager.CacheResult;
-import android.webkit.UrlInterceptRegistry;
import java.util.HashMap;
import java.util.Map;
@@ -234,12 +233,14 @@ class FrameLoader {
private boolean handleUrlIntercept() {
// Check if the URL can be served from UrlIntercept. If
// successful, return the data just like a cache hit.
- CacheResult result = UrlInterceptRegistry.getSurrogate(
+
+ PluginData data = UrlInterceptRegistry.getPluginData(
mListener.url(), mHeaders);
- if(result != null) {
- // Intercepted. The data is stored in result.stream. Setup
- // a load from the CacheResult.
- startCacheLoad(result);
+
+ if(data != null) {
+ PluginContentLoader loader =
+ new PluginContentLoader(mListener, data);
+ loader.load();
return true;
}
// Not intercepted. Carry on as normal.
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index dfae17d..8d4b220 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -1126,6 +1126,7 @@ class LoadListener extends Handler implements EventHandler {
mCacheResult = null;
}
+ // This will strip the anchor
setUrl(redirectTo);
// Redirect may be in the cache
@@ -1143,7 +1144,7 @@ class LoadListener extends Handler implements EventHandler {
// mRequestHandle can be null when the request was satisfied
// by the cache, and the cache returned a redirect
if (mRequestHandle != null) {
- mRequestHandle.setupRedirect(redirectTo, mStatusCode,
+ mRequestHandle.setupRedirect(mUrl, mStatusCode,
mRequestHeaders);
} else {
// If the original request came from the cache, there is no
@@ -1336,19 +1337,16 @@ class LoadListener extends Handler implements EventHandler {
*/
void setUrl(String url) {
if (url != null) {
- if (URLUtil.isDataUrl(url)) {
- // Don't strip anchor as that is a valid part of the URL
- mUrl = url;
- } else {
- mUrl = URLUtil.stripAnchor(url);
- }
mUri = null;
- if (URLUtil.isNetworkUrl(mUrl)) {
+ if (URLUtil.isNetworkUrl(url)) {
+ mUrl = URLUtil.stripAnchor(url);
try {
mUri = new WebAddress(mUrl);
} catch (ParseException e) {
e.printStackTrace();
}
+ } else {
+ mUrl = url;
}
}
}
diff --git a/core/java/android/webkit/PluginContentLoader.java b/core/java/android/webkit/PluginContentLoader.java
new file mode 100644
index 0000000..2069599
--- /dev/null
+++ b/core/java/android/webkit/PluginContentLoader.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 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 android.webkit;
+
+import android.net.http.Headers;
+
+import java.io.InputStream;
+import java.util.*;
+
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * This class is a concrete implementation of StreamLoader that uses a
+ * PluginData object as the source for the stream.
+ */
+class PluginContentLoader extends StreamLoader {
+
+ private PluginData mData; // Content source
+
+ /**
+ * Constructs a PluginDataLoader for use when loading content from
+ * a plugin.
+ *
+ * @param loadListener LoadListener to pass the content to
+ * @param data PluginData used as the source for the content.
+ */
+ PluginContentLoader(LoadListener loadListener, PluginData data) {
+ super(loadListener);
+ mData = data;
+ }
+
+ @Override
+ protected boolean setupStreamAndSendStatus() {
+ mDataStream = mData.getInputStream();
+ mContentLength = mData.getContentLength();
+ mHandler.status(1, 1, mData.getStatusCode(), "OK");
+ return true;
+ }
+
+ @Override
+ protected void buildHeaders(Headers headers) {
+ // Crate a CharArrayBuffer with an arbitrary initial capacity.
+ CharArrayBuffer buffer = new CharArrayBuffer(100);
+ Iterator<Map.Entry<String, String[]>> responseHeadersIt =
+ mData.getHeaders().entrySet().iterator();
+ while (responseHeadersIt.hasNext()) {
+ Map.Entry<String, String[]> entry = responseHeadersIt.next();
+ // Headers.parseHeader() expects lowercase keys, so keys
+ // such as "Accept-Ranges" will fail to parse.
+ //
+ // UrlInterceptHandler instances supply a mapping of
+ // lowercase key to [ unmodified key, value ], so for
+ // Headers.parseHeader() to succeed, we need to construct
+ // a string using the key (i.e. entry.getKey()) and the
+ // element denoting the header value in the
+ // [ unmodified key, value ] pair (i.e. entry.getValue()[1).
+ //
+ // The reason why UrlInterceptHandler instances supply such a
+ // mapping in the first place is historical. Early versions of
+ // the Gears plugin used java.net.HttpURLConnection, which always
+ // returned headers names as capitalized strings. When these were
+ // fed back into webkit, they failed to parse.
+ //
+ // Mewanwhile, Gears was modified to use Apache HTTP library
+ // instead, so this design is now obsolete. Changing it however,
+ // would require changes to the Gears C++ codebase and QA-ing and
+ // submitting a new binary to the Android tree. Given the
+ // timelines for the next Android release, we will not do this
+ // for now.
+ //
+ // TODO: fix C++ Gears to remove the need for this
+ // design.
+ String keyValue = entry.getKey() + ": " + entry.getValue()[1];
+ buffer.ensureCapacity(keyValue.length());
+ buffer.append(keyValue);
+ // Parse it into the header container.
+ headers.parseHeader(buffer);
+ // Clear the buffer
+ buffer.clear();
+ }
+ }
+}
diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java
new file mode 100644
index 0000000..2b539fe
--- /dev/null
+++ b/core/java/android/webkit/PluginData.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2009 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 android.webkit;
+
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * This class encapsulates the content generated by a plugin. The
+ * data itself is meant to be loaded into webkit via the
+ * PluginContentLoader class, which needs to be able to construct an
+ * HTTP response. For this, it needs a stream with the response body,
+ * the length of the body, the response headers, and the response
+ * status code. The PluginData class is the container for all these
+ * parts.
+ *
+ */
+public final class PluginData {
+ /**
+ * The content stream.
+ */
+ private InputStream mStream;
+ /**
+ * The content length.
+ */
+ private long mContentLength;
+ /**
+ * The associated HTTP response headers stored as a map of
+ * lowercase header name to [ unmodified header name, header value].
+ * TODO: This design was always a hack. Remove (involves updating
+ * the Gears C++ side).
+ */
+ private Map<String, String[]> mHeaders;
+
+ /**
+ * The index of the header value in the above mapping.
+ */
+ private int mHeaderValueIndex;
+ /**
+ * The associated HTTP response code.
+ */
+ private int mStatusCode;
+
+ /**
+ * Creates a PluginData instance.
+ *
+ * @param stream The stream that supplies content for the plugin.
+ * @param length The length of the plugin content.
+ * @param headers The response headers. Map of
+ * lowercase header name to [ unmodified header name, header value]
+ * @param length The HTTP response status code.
+ */
+ public PluginData(
+ InputStream stream,
+ long length,
+ Map<String, String[]> headers,
+ int code) {
+ mStream = stream;
+ mContentLength = length;
+ mHeaders = headers;
+ mStatusCode = code;
+ }
+
+ /**
+ * Returns the input stream that contains the plugin content.
+ *
+ * @return An InputStream instance with the plugin content.
+ */
+ public InputStream getInputStream() {
+ return mStream;
+ }
+
+ /**
+ * Returns the length of the plugin content.
+ *
+ * @return the length of the plugin content.
+ */
+ public long getContentLength() {
+ return mContentLength;
+ }
+
+ /**
+ * Returns the HTTP response headers associated with the plugin
+ * content.
+ *
+ * @return A Map<String, String[]> containing all headers. The
+ * mapping is 'lowercase header name' to ['unmodified header
+ * name', header value].
+ */
+ public Map<String, String[]> getHeaders() {
+ return mHeaders;
+ }
+
+ /**
+ * Returns the HTTP status code for the response.
+ *
+ * @return The HTTP statue code, e.g 200.
+ */
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+}
diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java
index 8a82411..39806dc 100644
--- a/core/java/android/webkit/TextDialog.java
+++ b/core/java/android/webkit/TextDialog.java
@@ -113,13 +113,7 @@ import java.util.ArrayList;
// that other applications that use embedded WebViews will properly
// display the text in textfields.
setTextColor(Color.BLACK);
- }
-
- @Override
- protected boolean shouldAdvanceFocusOnEnter() {
- // In the browser, single line textfields use enter as a form submit,
- // so we never want to advance the focus on enter.
- return false;
+ setImeOptions(EditorInfo.IME_ACTION_NONE);
}
@Override
diff --git a/core/java/android/webkit/UrlInterceptHandler.java b/core/java/android/webkit/UrlInterceptHandler.java
index e1c9d61..9216413 100644
--- a/core/java/android/webkit/UrlInterceptHandler.java
+++ b/core/java/android/webkit/UrlInterceptHandler.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.webkit.CacheManager.CacheResult;
+import android.webkit.PluginData;
import java.util.Map;
public interface UrlInterceptHandler {
@@ -29,6 +30,20 @@ public interface UrlInterceptHandler {
* @param url URL string.
* @param headers The headers associated with the request. May be null.
* @return The CacheResult containing the surrogate response.
+ * @Deprecated Use PluginData getPluginData(String url,
+ * Map<String, String> headers); instead
*/
+ @Deprecated
public CacheResult service(String url, Map<String, String> headers);
+
+ /**
+ * Given an URL, returns the PluginData which contains the
+ * surrogate response for the request, or null if the handler is
+ * not interested.
+ *
+ * @param url URL string.
+ * @param headers The headers associated with the request. May be null.
+ * @return The PluginData containing the surrogate response.
+ */
+ public PluginData getPluginData(String url, Map<String, String> headers);
}
diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java
index a218191..6051f29 100644
--- a/core/java/android/webkit/UrlInterceptRegistry.java
+++ b/core/java/android/webkit/UrlInterceptRegistry.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.webkit.CacheManager.CacheResult;
+import android.webkit.PluginData;
import android.webkit.UrlInterceptHandler;
import java.util.Iterator;
@@ -82,17 +83,21 @@ public final class UrlInterceptRegistry {
UrlInterceptHandler handler) {
return getHandlers().remove(handler);
}
-
+
/**
* Given an url, returns the CacheResult of the first
* UrlInterceptHandler interested, or null if none are.
- *
+ *
* @return A CacheResult containing surrogate content.
+ * @Deprecated Use PluginData getPluginData( String url,
+ * Map<String, String> headers) instead.
*/
+ @Deprecated
public static synchronized CacheResult getSurrogate(
String url, Map<String, String> headers) {
- if (urlInterceptDisabled())
+ if (urlInterceptDisabled()) {
return null;
+ }
Iterator iter = getHandlers().listIterator();
while (iter.hasNext()) {
UrlInterceptHandler handler = (UrlInterceptHandler) iter.next();
@@ -103,4 +108,27 @@ public final class UrlInterceptRegistry {
}
return null;
}
+
+ /**
+ * Given an url, returns the PluginData of the first
+ * UrlInterceptHandler interested, or null if none are or if
+ * intercepts are disabled.
+ *
+ * @return A PluginData instance containing surrogate content.
+ */
+ public static synchronized PluginData getPluginData(
+ String url, Map<String, String> headers) {
+ if (urlInterceptDisabled()) {
+ return null;
+ }
+ Iterator iter = getHandlers().listIterator();
+ while (iter.hasNext()) {
+ UrlInterceptHandler handler = (UrlInterceptHandler) iter.next();
+ PluginData data = handler.getPluginData(url, headers);
+ if (data != null) {
+ return data;
+ }
+ }
+ return null;
+ }
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5126ef0..91795a3 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -689,7 +689,10 @@ public class WebView extends AbsoluteLayout
return true;
}
- public void onSimpleZoom(boolean zoomIn) {
+ public void onSimpleZoom(boolean zoomIn, int centerX, int centerY) {
+ mZoomCenterX = (float) centerX;
+ mZoomCenterY = (float) centerY;
+
if (zoomIn) {
zoomIn();
} else {
@@ -736,12 +739,12 @@ public class WebView extends AbsoluteLayout
mFocusData.mY = 0;
mScroller = new Scroller(context);
mZoomRingController = new ZoomRingController(context, this);
- mZoomRingController.setResetThumbAutomatically(false);
mZoomRingController.setCallback(mZoomListener);
- mZoomRingController.setZoomRingTrack(
+ mZoomRingController.setTrackDrawable(
com.android.internal.R.drawable.zoom_ring_track_absolute);
- mZoomRingController.setPannerAcceleration(160);
- mZoomRingController.setPannerStartAcceleratingDuration(700);
+ float density = context.getResources().getDisplayMetrics().density;
+ mZoomRingController.setPannerAcceleration((int) (160 * density));
+ mZoomRingController.setPannerStartAcceleratingDuration((int) (700 * density));
createZoomRingOverviewTab();
mZoomButtonsController = new ZoomButtonsController(context, this);
mZoomButtonsController.setOverviewVisible(true);
@@ -760,7 +763,7 @@ public class WebView extends AbsoluteLayout
}
public void onZoom(boolean zoomIn) {
- mZoomListener.onSimpleZoom(zoomIn);
+ mZoomListener.onSimpleZoom(zoomIn, getWidth() / 2, getHeight() / 2);
}
});
}
@@ -4491,6 +4494,14 @@ public class WebView extends AbsoluteLayout
return zoomControls;
}
+ // This used to be the value returned by ViewConfiguration.getTouchSlop().
+ // We pass this to the navigation cache to find where the user clicked.
+ // TouchSlop has been increased for other purposes, but for the
+ // navigation cache it is too big, and may result in clicking the wrong
+ // spot. This is a concern when the cache is out of date, and clicking
+ // finds a node which is wrong but nearby.
+ private static final int NAV_SLOP = 12;
+
private void updateSelection() {
if (mNativeClass == 0) {
return;
@@ -4498,7 +4509,7 @@ public class WebView extends AbsoluteLayout
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
- int contentSize = ViewConfiguration.getTouchSlop();
+ int contentSize = NAV_SLOP;
Rect rect = new Rect(contentX - contentSize, contentY - contentSize,
contentX + contentSize, contentY + contentSize);
// If we were already focused on a textfield, update its cache.
@@ -4513,7 +4524,7 @@ public class WebView extends AbsoluteLayout
View v = mTextEntry;
int x = viewToContent((v.getLeft() + v.getRight()) >> 1);
int y = viewToContent((v.getTop() + v.getBottom()) >> 1);
- int contentSize = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+ int contentSize = NAV_SLOP;
nativeMotionUp(x, y, contentSize, true);
}
}
@@ -4526,7 +4537,7 @@ public class WebView extends AbsoluteLayout
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
- int contentSize = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+ int contentSize = NAV_SLOP;
if (nativeMotionUp(contentX, contentY, contentSize, true)) {
if (mLogEvent) {
Checkin.updateStats(mContext.getContentResolver(),
diff --git a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
index 2a5cbe9..43104bf 100644
--- a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
+++ b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
@@ -25,16 +25,14 @@
package android.webkit.gears;
-import android.net.http.Headers;
import android.util.Log;
-import android.webkit.CacheManager;
import android.webkit.CacheManager.CacheResult;
import android.webkit.Plugin;
+import android.webkit.PluginData;
import android.webkit.UrlInterceptRegistry;
import android.webkit.UrlInterceptHandler;
import android.webkit.WebView;
-import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.util.CharArrayBuffer;
import java.io.*;
@@ -53,12 +51,6 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
private static final String LOG_TAG = "Gears-J";
/** Buffer size for reading/writing streams. */
private static final int BUFFER_SIZE = 4096;
- /**
- * Number of milliseconds to expire LocalServer temporary entries in
- * the browser's cache. Somewhat arbitrarily chosen as a compromise
- * between being a) long enough not to expire during page load and
- * b) short enough to evict entries during a session. */
- private static final int CACHE_EXPIRY_MS = 60000; // 1 minute.
/** Enable/disable all logging in this class. */
private static boolean logEnabled = false;
/** The unmodified (case-sensitive) key in the headers map is the
@@ -140,6 +132,8 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
private String encoding;
// The stream which contains the body when read().
private InputStream inputStream;
+ // The length of the content body.
+ private long contentLength;
/**
* Initialize members using an in-memory array to return the body.
@@ -160,6 +154,7 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
this.mimeType = mimeType;
this.encoding = encoding;
// Setup a stream to read out of the byte array.
+ this.contentLength = body.length;
this.inputStream = new ByteArrayInputStream(body);
}
@@ -185,7 +180,9 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
this.encoding = encoding;
try {
// Setup a stream to read out of a file on disk.
- this.inputStream = new FileInputStream(new File(path));
+ File file = new File(path);
+ this.contentLength = file.length();
+ this.inputStream = new FileInputStream(file);
return true;
} catch (java.io.FileNotFoundException ex) {
log("File not found: " + path);
@@ -274,6 +271,13 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
public InputStream getInputStream() {
return inputStream;
}
+
+ /**
+ * @return The length of the response body.
+ */
+ public long getContentLength() {
+ return contentLength;
+ }
}
/**
@@ -319,44 +323,32 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
UrlInterceptRegistry.unregisterHandler(this);
}
- /**
- * Copy the entire InputStream to OutputStream.
- * @param inputStream The stream to read from.
- * @param outputStream The stream to write to.
- * @return True if the entire stream copied successfully, false on error.
- */
- private boolean copyStream(InputStream inputStream,
- OutputStream outputStream) {
- try {
- // Temporary buffer to copy stream through.
- byte[] buf = new byte[BUFFER_SIZE];
- for (;;) {
- // Read up to BUFFER_SIZE bytes.
- int bytes = inputStream.read(buf);
- if (bytes < 0) {
- break;
- }
- // Write the number of bytes we just read.
- outputStream.write(buf, 0, bytes);
- }
- } catch (IOException ex) {
- log("Got IOException copying stream: " + ex);
- return false;
+ /**
+ * Given an URL, returns the CacheResult which contains the
+ * surrogate response for the request, or null if the handler is
+ * not interested.
+ *
+ * @param url URL string.
+ * @param headers The headers associated with the request. May be null.
+ * @return The CacheResult containing the surrogate response.
+ * @Deprecated Use PluginData getPluginData(String url,
+ * Map<String, String> headers); instead
+ */
+ @Deprecated
+ public CacheResult service(String url, Map<String, String> headers) {
+ throw new UnsupportedOperationException("unimplemented");
}
- return true;
- }
/**
- * Given an URL, returns a CacheResult which contains the response
- * for the request. This implements the UrlInterceptHandler interface.
+ * Given an URL, returns a PluginData instance which contains the
+ * response for the request. This implements the UrlInterceptHandler
+ * interface.
*
- * @param url The fully qualified URL being requested.
+ * @param url The fully qualified URL being requested.
* @param requestHeaders The request headers for this URL.
- * @return If a response can be crafted, a CacheResult initialized
- * to return the surrogate response. If this URL cannot
- * be serviced, returns null.
+ * @return a PluginData object.
*/
- public CacheResult service(String url, Map<String, String> requestHeaders) {
+ public PluginData getPluginData(String url, Map<String, String> requestHeaders) {
// Thankfully the browser does call us with case-sensitive
// headers. We just need to map it case-insensitive.
Map<String, String[]> lowercaseRequestHeaders =
@@ -374,86 +366,10 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
// No result for this URL.
return null;
}
- // Translate the ServiceResponse to a CacheResult.
- // Translate http -> gears, https -> gearss, so we don't overwrite
- // existing entries.
- String gearsUrl = "gears" + url.substring("http".length());
- // Set the result to expire, so that entries don't pollute the
- // browser's cache for too long.
- long now_ms = System.currentTimeMillis();
- String expires = DateUtils.formatDate(new Date(now_ms + CACHE_EXPIRY_MS));
- response.setResponseHeader(ApacheHttpRequestAndroid.KEY_EXPIRES, expires);
- // The browser is only interested in a small subset of headers,
- // contained in a Headers object. Iterate the map of all headers
- // and add them to Headers.
- Headers headers = new Headers();
- Iterator<Map.Entry<String, String[]>> responseHeadersIt =
- response.getResponseHeaders().entrySet().iterator();
- while (responseHeadersIt.hasNext()) {
- Map.Entry<String, String[]> entry = responseHeadersIt.next();
- // Headers.parseHeader() expects lowercase keys.
- String keyValue = entry.getKey() + ": "
- + entry.getValue()[HEADERS_MAP_INDEX_VALUE];
- CharArrayBuffer buffer = new CharArrayBuffer(keyValue.length());
- buffer.append(keyValue);
- // Parse it into the header container.
- headers.parseHeader(buffer);
- }
- CacheResult cacheResult = CacheManager.createCacheFile(
- gearsUrl,
- response.getStatusCode(),
- headers,
- response.getMimeType(),
- true); // forceCache
-
- if (cacheResult == null) {
- // With the no-cache policy we could end up
- // with a null result
- return null;
- }
-
- // Set encoding if specified.
- String encoding = response.getEncoding();
- if (encoding != null) {
- cacheResult.setEncoding(encoding);
- }
- // Copy the response body to the CacheResult. This handles all
- // combinations of memory vs on-disk on both sides.
- InputStream inputStream = response.getInputStream();
- OutputStream outputStream = cacheResult.getOutputStream();
- boolean copied = copyStream(inputStream, outputStream);
- // Close the input and output streams to relinquish their
- // resources earlier.
- try {
- inputStream.close();
- } catch (IOException ex) {
- log("IOException closing InputStream: " + ex);
- copied = false;
- }
- try {
- outputStream.close();
- } catch (IOException ex) {
- log("IOException closing OutputStream: " + ex);
- copied = false;
- }
- if (!copied) {
- log("copyStream of local result failed");
- return null;
- }
- // Save the entry into the browser's cache.
- CacheManager.saveCacheFile(gearsUrl, cacheResult);
- // Get it back from the cache, this time properly initialized to
- // be used for input.
- cacheResult = CacheManager.getCacheFile(gearsUrl, null);
- if (cacheResult != null) {
- log("Returning surrogate result");
- return cacheResult;
- } else {
- // Not an expected condition, but handle gracefully. Perhaps out
- // of memory or disk?
- Log.e(LOG_TAG, "Lost CacheResult between save and get. Can't serve.\n");
- return null;
- }
+ return new PluginData(response.getInputStream(),
+ response.getContentLength(),
+ response.getResponseHeaders(),
+ response.getStatusCode());
}
/**