diff options
Diffstat (limited to 'core/java/android/webkit')
| -rw-r--r-- | core/java/android/webkit/CacheManager.java | 28 | ||||
| -rw-r--r-- | core/java/android/webkit/HttpAuthHandler.java | 21 | ||||
| -rw-r--r-- | core/java/android/webkit/LoadListener.java | 41 | ||||
| -rw-r--r-- | core/java/android/webkit/MimeTypeMap.java | 1 | ||||
| -rw-r--r-- | core/java/android/webkit/Network.java | 18 | ||||
| -rw-r--r-- | core/java/android/webkit/SslErrorHandler.java | 20 | ||||
| -rw-r--r-- | core/java/android/webkit/WebSettings.java | 15 | ||||
| -rw-r--r-- | core/java/android/webkit/WebView.java | 211 |
8 files changed, 252 insertions, 103 deletions
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java index dcf68cd..4528b73 100644 --- a/core/java/android/webkit/CacheManager.java +++ b/core/java/android/webkit/CacheManager.java @@ -282,9 +282,7 @@ public final class CacheManager { CacheResult result = mDataBase.getCache(url); if (result != null) { if (result.contentLength == 0) { - if (result.httpStatusCode != 301 - && result.httpStatusCode != 302 - && result.httpStatusCode != 307) { + if (!checkCacheRedirect(result.httpStatusCode)) { // this should not happen. If it does, remove it. mDataBase.removeCache(url); return null; @@ -350,6 +348,17 @@ public final class CacheManager { return null; } + // according to the rfc 2616, the 303 response MUST NOT be cached. + if (statusCode == 303) { + return null; + } + + // like the other browsers, do not cache redirects containing a cookie + // header. + if (checkCacheRedirect(statusCode) && !headers.getSetCookie().isEmpty()) { + return null; + } + CacheResult ret = parseHeaders(statusCode, headers, mimeType); if (ret != null) { setupFiles(url, ret); @@ -395,9 +404,7 @@ public final class CacheManager { } cacheRet.contentLength = cacheRet.outFile.length(); - if (cacheRet.httpStatusCode == 301 - || cacheRet.httpStatusCode == 302 - || cacheRet.httpStatusCode == 307) { + if (checkCacheRedirect(cacheRet.httpStatusCode)) { // location is in database, no need to keep the file cacheRet.contentLength = 0; cacheRet.localPath = new String(); @@ -471,6 +478,15 @@ public final class CacheManager { } } + private static boolean checkCacheRedirect(int statusCode) { + if (statusCode == 301 || statusCode == 302 || statusCode == 307) { + // as 303 can't be cached, we do not return true + return true; + } else { + return false; + } + } + @SuppressWarnings("deprecation") private static void setupFiles(String url, CacheResult cacheRet) { if (true) { diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java index 48b9eec..84dc9f0 100644 --- a/core/java/android/webkit/HttpAuthHandler.java +++ b/core/java/android/webkit/HttpAuthHandler.java @@ -80,8 +80,7 @@ public class HttpAuthHandler extends Handler { break; case AUTH_CANCEL: - - mNetwork.resetHandlersAndStopLoading(loader.getFrame()); + loader.handleAuthResponse(null, null); break; } @@ -126,24 +125,6 @@ public class HttpAuthHandler extends Handler { } /** - * Resets the HTTP-authentication request handler, removes - * all loaders that share the same BrowserFrame - * - * @param frame The browser frame - */ - /* package */ void reset(BrowserFrame frame) { - synchronized (mLoaderQueue) { - ListIterator<LoadListener> i = mLoaderQueue.listIterator(0); - while (i.hasNext()) { - LoadListener loader = i.next(); - if (frame == loader.getFrame()) { - i.remove(); - } - } - } - } - - /** * Enqueues the loader, if the loader is the only element * in the queue, starts processing the loader * diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java index f9fb0b0..c64200c 100644 --- a/core/java/android/webkit/LoadListener.java +++ b/core/java/android/webkit/LoadListener.java @@ -377,10 +377,6 @@ class LoadListener extends Handler implements EventHandler { } } - // if there is buffered data, commit them in the end - boolean needToCommit = mAuthHeader != null && !mustAuthenticate - && mNativeLoader != 0 && !mDataBuilder.isEmpty(); - // it is only here that we can reset the last mAuthHeader object // (if existed) and start a new one!!! mAuthHeader = null; @@ -415,10 +411,6 @@ class LoadListener extends Handler implements EventHandler { } } commitHeadersCheckRedirect(); - - if (needToCommit) { - commitLoad(); - } } /** @@ -452,6 +444,8 @@ class LoadListener extends Handler implements EventHandler { status.put("minor", minorVersion); status.put("code", code); status.put("reason", reasonPhrase); + // New status means new data. Clear the old. + mDataBuilder.clear(); sendMessageInternal(obtainMessage(MSG_STATUS, status)); } @@ -613,7 +607,6 @@ class LoadListener extends Handler implements EventHandler { // ask for it, so make sure we have a valid CacheLoader // before calling it. if (mCacheLoader != null) { - detachRequestHandle(); mCacheLoader.load(); if (Config.LOGV) { Log.v(LOGTAG, "LoadListener cache load url=" + url()); @@ -738,10 +731,16 @@ class LoadListener extends Handler implements EventHandler { if (mRequestHandle != null) { mRequestHandle.handleSslErrorResponse(proceed); } + if (!proceed) { + // Commit whatever data we have and tear down the loader. + commitLoad(); + tearDown(); + } } /** - * Uses user-supplied credentials to restar a request. + * Uses user-supplied credentials to restart a request. If the credentials + * are null, cancel the request. */ void handleAuthResponse(String username, String password) { if (Config.LOGV) { @@ -780,6 +779,10 @@ class LoadListener extends Handler implements EventHandler { } } } + } else { + // Commit whatever data we have and tear down the loader. + commitLoad(); + tearDown(); } } @@ -944,13 +947,12 @@ class LoadListener extends Handler implements EventHandler { * @return native response pointer */ private int createNativeResponse() { - // The reason we change HTTP_NOT_MODIFIED to HTTP_OK is because we know - // that WebCore never sends the if-modified-since header. Our - // CacheManager does it for us. If the server responds with a 304, then - // we treat it like it was a 200 code and proceed with loading the file - // from the cache. - int statusCode = mStatusCode == HTTP_NOT_MODIFIED - ? HTTP_OK : mStatusCode; + // If WebCore sends if-modified-since, mCacheLoader is null. If + // CacheManager sends it, mCacheLoader is not null. In this case, if the + // server responds with a 304, then we treat it like it was a 200 code + // and proceed with loading the file from the cache. + int statusCode = (mStatusCode == HTTP_NOT_MODIFIED && + mCacheLoader != null) ? HTTP_OK : mStatusCode; // pass content-type content-length and content-encoding final int nativeResponse = nativeCreateResponse( mUrl, statusCode, mStatusText, @@ -1181,8 +1183,6 @@ class LoadListener extends Handler implements EventHandler { // sync. Add 1 to account for the current redirect. mCacheRedirectCount = mRequestHandle.getRedirectCount() + 1; } - // Clear the buffered data since the redirect is valid. - mDataBuilder.clear(); } else { commitHeaders(); commitLoad(); @@ -1197,9 +1197,10 @@ class LoadListener extends Handler implements EventHandler { /** * Parses the content-type header. + * The first part only allows '-' if it follows x or X. */ private static final Pattern CONTENT_TYPE_PATTERN = - Pattern.compile("^([a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$"); + Pattern.compile("^((?:[xX]-)?[a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$"); private void parseContentTypeHeader(String contentType) { if (Config.LOGV) { diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java index c9cc208..85c2275 100644 --- a/core/java/android/webkit/MimeTypeMap.java +++ b/core/java/android/webkit/MimeTypeMap.java @@ -496,6 +496,7 @@ public /* package */ class MimeTypeMap { sMimeTypeMap.loadEntry("video/x-msvideo", "avi", false); sMimeTypeMap.loadEntry("video/x-sgi-movie", "movie", false); sMimeTypeMap.loadEntry("x-conference/x-cooltalk", "ice", false); + sMimeTypeMap.loadEntry("x-epoc/x-sisx-app", "sisx", false); } return sMimeTypeMap; diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java index 74622b3..6fa0775 100644 --- a/core/java/android/webkit/Network.java +++ b/core/java/android/webkit/Network.java @@ -261,24 +261,6 @@ class Network { } /** - * If we need to stop loading done in a handler (here, browser frame), we - * send a message to the handler to stop loading, and remove all loaders - * that share the same CallbackProxy in question from all local - * handlers (such as ssl-error and http-authentication handler). - * @param proxy The CallbackProxy responsible for cancelling the current - * load. - */ - public void resetHandlersAndStopLoading(BrowserFrame frame) { - if (Config.LOGV) { - Log.v(LOGTAG, "Network.resetHandlersAndStopLoading()"); - } - - frame.stopLoading(); - mSslErrorHandler.reset(frame); - mHttpAuthHandler.reset(frame); - } - - /** * Saves the state of network handlers (user SSL and HTTP-authentication * preferences). * @param outState The out-state to save (write) to. diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java index 115434a..2e2fa12 100644 --- a/core/java/android/webkit/SslErrorHandler.java +++ b/core/java/android/webkit/SslErrorHandler.java @@ -118,20 +118,6 @@ public class SslErrorHandler extends Handler { } /** - * Resets the SSL error handler, removes all loaders that - * share the same BrowserFrame. - */ - /* package */ synchronized void reset(BrowserFrame frame) { - ListIterator<LoadListener> i = mLoaderQueue.listIterator(0); - while (i.hasNext()) { - LoadListener loader = i.next(); - if (frame == loader.getFrame()) { - i.remove(); - } - } - } - - /** * Handles SSL error(s) on the way up to the user. */ /* package */ synchronized void handleSslErrorRequest(LoadListener loader) { @@ -244,12 +230,8 @@ public class SslErrorHandler extends Handler { primary > mSslPrefTable.getInt(host)) { mSslPrefTable.putInt(host, new Integer(primary)); } - - loader.handleSslErrorResponse(proceed); - } else { - loader.handleSslErrorResponse(proceed); - mNetwork.resetHandlersAndStopLoading(loader.getFrame()); } + loader.handleSslErrorResponse(proceed); } } } diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 65544d4..025e6bb 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -153,6 +153,7 @@ public class WebSettings { private boolean mNeedInitialFocus = true; private boolean mNavDump = false; private boolean mSupportZoom = true; + private boolean mBuiltInZoomControls = false; private boolean mAllowFileAccess = true; // Class to handle messages before WebCore is ready. @@ -364,6 +365,20 @@ public class WebSettings { } /** + * Sets whether the zoom mechanism built into WebView is used. + */ + public void setBuiltInZoomControls(boolean enabled) { + mBuiltInZoomControls = enabled; + } + + /** + * Returns true if the zoom mechanism built into WebView is being used. + */ + public boolean getBuiltInZoomControls() { + return mBuiltInZoomControls; + } + + /** * Enable or disable file access within WebView. File access is enabled by * default. */ diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 753267f..3205820 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -56,17 +56,20 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewTreeObserver; +import android.view.animation.AlphaAnimation; import android.view.inputmethod.InputMethodManager; import android.webkit.TextDialog.AutoCompleteAdapter; import android.webkit.WebViewCore.EventHub; import android.widget.AbsoluteLayout; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ListView; import android.widget.Scroller; import android.widget.Toast; import android.widget.ZoomButtonsController; +import android.widget.ZoomControls; import android.widget.AdapterView.OnItemClickListener; import java.io.File; @@ -85,6 +88,9 @@ import java.util.List; * It uses the WebKit rendering engine to display * web pages and includes methods to navigate forward and backward * through a history, zoom in and out, perform text searches and more.</p> + * <p>To enable the built-in zoom, set + * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)} + * (introduced in API version 3). * <p>Note that, in order for your Activity to access the Internet and load web pages * in a WebView, you must add the <var>INTERNET</var> permissions to your * Android Manifest file:</p> @@ -106,6 +112,57 @@ public class WebView extends AbsoluteLayout static final boolean DEBUG = false; static final boolean LOGV_ENABLED = DEBUG ? Config.LOGD : Config.LOGV; + private class ExtendedZoomControls extends FrameLayout { + public ExtendedZoomControls(Context context, AttributeSet attrs) { + super(context, attrs); + LayoutInflater inflater = (LayoutInflater) + context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(com.android.internal.R.layout.zoom_magnify, this, true); + mZoomControls = (ZoomControls) findViewById(com.android.internal.R.id.zoomControls); + mZoomMagnify = (ImageView) findViewById(com.android.internal.R.id.zoomMagnify); + } + + public void show(boolean showZoom, boolean canZoomOut) { + mZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE); + mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE); + fade(View.VISIBLE, 0.0f, 1.0f); + } + + public void hide() { + fade(View.GONE, 1.0f, 0.0f); + } + + private void fade(int visibility, float startAlpha, float endAlpha) { + AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha); + anim.setDuration(500); + startAnimation(anim); + setVisibility(visibility); + } + + public void setIsZoomMagnifyEnabled(boolean isEnabled) { + mZoomMagnify.setEnabled(isEnabled); + } + + public boolean hasFocus() { + return mZoomControls.hasFocus() || mZoomMagnify.hasFocus(); + } + + public void setOnZoomInClickListener(OnClickListener listener) { + mZoomControls.setOnZoomInClickListener(listener); + } + + public void setOnZoomOutClickListener(OnClickListener listener) { + mZoomControls.setOnZoomOutClickListener(listener); + } + + public void setOnZoomMagnifyClickListener(OnClickListener listener) { + mZoomMagnify.setOnClickListener(listener); + } + + ZoomControls mZoomControls; + ImageView mZoomMagnify; + } + /** * Transportation object for returning WebView across thread boundaries. */ @@ -232,6 +289,9 @@ public class WebView extends AbsoluteLayout private static final int LONG_PRESS_TIMEOUT = 1000; // needed to avoid flinging after a pause of no movement private static final int MIN_FLING_TIME = 250; + // The time that the Zoom Controls are visible before fading away + private static final long ZOOM_CONTROLS_TIMEOUT = + ViewConfiguration.getZoomControlsTimeout(); // The amount of content to overlap between two screens when going through // pages with the space bar, in pixels. private static final int PAGE_SCROLL_OVERLAP = 24; @@ -472,6 +532,10 @@ public class WebView extends AbsoluteLayout } } + // The View containing the zoom controls + private ExtendedZoomControls mZoomControls; + private Runnable mZoomControlRunnable; + private ZoomButtonsController mZoomButtonsController; private ImageView mZoomOverviewButton; private ImageView mZoomFitPageButton; @@ -484,11 +548,6 @@ public class WebView extends AbsoluteLayout private ZoomButtonsController.OnZoomListener mZoomListener = new ZoomButtonsController.OnZoomListener() { - public void onCenter(int x, int y) { - // Don't translate when the control is invoked, hence we do nothing - // in this callback - } - public void onVisibilityChanged(boolean visible) { if (visible) { switchOutDrawHistory(); @@ -582,10 +641,26 @@ public class WebView extends AbsoluteLayout } private void updateZoomButtonsEnabled() { - mZoomButtonsController.setZoomInEnabled(mActualScale < mMaxZoomScale); - mZoomButtonsController.setZoomOutEnabled(mActualScale > mMinZoomScale); - mZoomFitPageButton.setEnabled(mActualScale != 1); - mZoomOverviewButton.setEnabled(canZoomScrollOut()); + boolean canZoomIn = mActualScale < mMaxZoomScale; + boolean canZoomOut = mActualScale > mMinZoomScale; + if (!canZoomIn && !canZoomOut) { + // Hide the zoom in and out buttons, as well as the fit to page + // button, if the page cannot zoom + mZoomButtonsController.getZoomControls().setVisibility(View.GONE); + mZoomFitPageButton.setVisibility(View.GONE); + } else { + // Bring back the hidden zoom controls. + mZoomButtonsController.getZoomControls() + .setVisibility(View.VISIBLE); + mZoomFitPageButton.setVisibility(View.VISIBLE); + // Set each one individually, as a page may be able to zoom in + // or out. + mZoomButtonsController.setZoomInEnabled(canZoomIn); + mZoomButtonsController.setZoomOutEnabled(canZoomOut); + mZoomFitPageButton.setEnabled(mActualScale != 1); + } + mZoomOverviewButton.setVisibility(canZoomScrollOut() ? View.VISIBLE: + View.GONE); } private void init() { @@ -1332,7 +1407,13 @@ public class WebView extends AbsoluteLayout return; } clearTextEntry(); - mZoomButtonsController.setVisible(true); + if (getSettings().getBuiltInZoomControls()) { + mZoomButtonsController.setVisible(true); + } else { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + } } /** @@ -2535,8 +2616,17 @@ public class WebView extends AbsoluteLayout private void startZoomScrollOut() { setHorizontalScrollBarEnabled(false); setVerticalScrollBarEnabled(false); - if (mZoomButtonsController.isVisible()) { - mZoomButtonsController.setVisible(false); + if (getSettings().getBuiltInZoomControls()) { + if (mZoomButtonsController.isVisible()) { + mZoomButtonsController.setVisible(false); + } + } else { + if (mZoomControlRunnable != null) { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + } + if (mZoomControls != null) { + mZoomControls.hide(); + } } int width = getViewWidth(); int height = getViewHeight(); @@ -3206,7 +3296,6 @@ public class WebView extends AbsoluteLayout // Clean up the zoom controller mZoomButtonsController.setVisible(false); - ZoomButtonsController.finishZoomTutorial(mContext, false); } // Implementation for OnHierarchyChangeListener @@ -3255,7 +3344,7 @@ public class WebView extends AbsoluteLayout // false for the first parameter } } else { - if (!mZoomButtonsController.isVisible()) { + if (getSettings().getBuiltInZoomControls() && !mZoomButtonsController.isVisible()) { /* * The zoom controls come in their own window, so our window * loses focus. Our policy is to not draw the focus ring if @@ -3527,7 +3616,9 @@ public class WebView extends AbsoluteLayout mWebViewCore .sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0); } - if (getSettings().supportZoom() + WebSettings settings = getSettings(); + if (settings.supportZoom() + && settings.getBuiltInZoomControls() && !mZoomButtonsController.isVisible() && (canZoomScrollOut() || mMinZoomScale < mMaxZoomScale)) { @@ -3594,6 +3685,21 @@ public class WebView extends AbsoluteLayout mLastTouchTime = eventTime; mUserScroll = true; } + + if (!getSettings().getBuiltInZoomControls()) { + boolean showPlusMinus = mMinZoomScale < mMaxZoomScale; + boolean showMagnify = canZoomScrollOut(); + if (mZoomControls != null && (showPlusMinus || showMagnify)) { + if (mZoomControls.getVisibility() == View.VISIBLE) { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + } else { + mZoomControls.show(showPlusMinus, showMagnify); + } + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + } + } + if (done) { // return false to indicate that we can't pan out of the // view space @@ -4050,18 +4156,83 @@ public class WebView extends AbsoluteLayout } } - // TODO: deprecate /** * Returns a view containing zoom controls i.e. +/- buttons. The caller is * in charge of installing this view to the view hierarchy. This view will * become visible when the user starts scrolling via touch and fade away if * the user does not interact with it. * <p/> - * From 1.5, WebView change to use ZoomButtonsController. This will return - * an invisible dummy view for backwards compatibility. + * API version 3 introduces a built-in zoom mechanism that is shown + * automatically by the MapView. This is the preferred approach for + * showing the zoom UI. + * + * @deprecated The built-in zoom mechanism is preferred, see + * {@link WebSettings#setBuiltInZoomControls(boolean)}. */ + @Deprecated public View getZoomControls() { - return mZoomButtonsController.getDummyZoomControls(); + if (!getSettings().supportZoom()) { + Log.w(LOGTAG, "This WebView doesn't support zoom."); + return null; + } + if (mZoomControls == null) { + mZoomControls = createZoomControls(); + + /* + * need to be set to VISIBLE first so that getMeasuredHeight() in + * {@link #onSizeChanged()} can return the measured value for proper + * layout. + */ + mZoomControls.setVisibility(View.VISIBLE); + mZoomControlRunnable = new Runnable() { + public void run() { + + /* Don't dismiss the controls if the user has + * focus on them. Wait and check again later. + */ + if (!mZoomControls.hasFocus()) { + mZoomControls.hide(); + } else { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + } + } + }; + } + return mZoomControls; + } + + private ExtendedZoomControls createZoomControls() { + ExtendedZoomControls zoomControls = new ExtendedZoomControls(mContext + , null); + zoomControls.setOnZoomInClickListener(new OnClickListener() { + public void onClick(View v) { + // reset time out + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + zoomIn(); + } + }); + zoomControls.setOnZoomOutClickListener(new OnClickListener() { + public void onClick(View v) { + // reset time out + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + zoomOut(); + } + }); + zoomControls.setOnZoomMagnifyClickListener(new OnClickListener() { + public void onClick(View v) { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + mPrivateHandler.postDelayed(mZoomControlRunnable, + ZOOM_CONTROLS_TIMEOUT); + zoomScrollOut(); + } + }); + return zoomControls; } /** @@ -4070,7 +4241,7 @@ public class WebView extends AbsoluteLayout * * @return The instance of {@link ZoomButtonsController} used by this class, * or null if it is unavailable. - * @hide pending API council + * @hide */ public ZoomButtonsController getZoomButtonsController() { return mZoomButtonsController; |
