diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-18 17:39:46 -0700 | 
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-18 17:39:46 -0700 | 
| commit | 105925376f8d0f6b318c9938c7b83ef7fef094da (patch) | |
| tree | 3b19ee2bd8704cb9c6a0da7e42dec6759183de6d /core/java/android/webkit | |
| parent | ba87e3e6c985e7175152993b5efcc7dd2f0e1c93 (diff) | |
| download | frameworks_base-105925376f8d0f6b318c9938c7b83ef7fef094da.zip frameworks_base-105925376f8d0f6b318c9938c7b83ef7fef094da.tar.gz frameworks_base-105925376f8d0f6b318c9938c7b83ef7fef094da.tar.bz2 | |
auto import from //branches/cupcake_rel/...@140373
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; | 
