diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:35 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:35 -0800 |
commit | 4df2423a947bcd3f024cc3d3a1a315a8dc428598 (patch) | |
tree | e7dac2c5a367b169e7f05a36058cf470e93f003b /core/java/android/webkit | |
parent | c474dec3ffa1c0fe37edb3e701684188f7e8e7bc (diff) | |
download | frameworks_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.java | 23 | ||||
-rw-r--r-- | core/java/android/webkit/FrameLoader.java | 13 | ||||
-rw-r--r-- | core/java/android/webkit/LoadListener.java | 14 | ||||
-rw-r--r-- | core/java/android/webkit/PluginContentLoader.java | 96 | ||||
-rw-r--r-- | core/java/android/webkit/PluginData.java | 116 | ||||
-rw-r--r-- | core/java/android/webkit/TextDialog.java | 8 | ||||
-rw-r--r-- | core/java/android/webkit/UrlInterceptHandler.java | 15 | ||||
-rw-r--r-- | core/java/android/webkit/UrlInterceptRegistry.java | 34 | ||||
-rw-r--r-- | core/java/android/webkit/WebView.java | 29 | ||||
-rw-r--r-- | core/java/android/webkit/gears/UrlInterceptHandlerGears.java | 160 |
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()); } /** |