Home | History | Annotate | Download | only in webkit
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package android.webkit;
     17 
     18 import com.android.internal.R;
     19 
     20 import android.content.Context;
     21 import android.content.res.Resources;
     22 import android.graphics.Canvas;
     23 import android.graphics.drawable.Drawable;
     24 import android.view.View;
     25 import android.widget.EdgeEffect;
     26 
     27 /**
     28  * This class manages the edge glow effect when a WebView is flung or pulled beyond the edges.
     29  * @hide
     30  */
     31 public class OverScrollGlow {
     32     private WebViewClassic mHostView;
     33 
     34     private EdgeEffect mEdgeGlowTop;
     35     private EdgeEffect mEdgeGlowBottom;
     36     private EdgeEffect mEdgeGlowLeft;
     37     private EdgeEffect mEdgeGlowRight;
     38 
     39     private int mOverScrollDeltaX;
     40     private int mOverScrollDeltaY;
     41 
     42     public OverScrollGlow(WebViewClassic host) {
     43         mHostView = host;
     44         Context context = host.getContext();
     45         mEdgeGlowTop = new EdgeEffect(context);
     46         mEdgeGlowBottom = new EdgeEffect(context);
     47         mEdgeGlowLeft = new EdgeEffect(context);
     48         mEdgeGlowRight = new EdgeEffect(context);
     49     }
     50 
     51     /**
     52      * Pull leftover touch scroll distance into one of the edge glows as appropriate.
     53      *
     54      * @param x Current X scroll offset
     55      * @param y Current Y scroll offset
     56      * @param oldX Old X scroll offset
     57      * @param oldY Old Y scroll offset
     58      * @param maxX Maximum range for horizontal scrolling
     59      * @param maxY Maximum range for vertical scrolling
     60      */
     61     public void pullGlow(int x, int y, int oldX, int oldY, int maxX, int maxY) {
     62         // Only show overscroll bars if there was no movement in any direction
     63         // as a result of scrolling.
     64         if (oldX == mHostView.getScrollX() && oldY == mHostView.getScrollY()) {
     65             // Don't show left/right glows if we fit the whole content.
     66             // Also don't show if there was vertical movement.
     67             if (maxX > 0) {
     68                 final int pulledToX = oldX + mOverScrollDeltaX;
     69                 if (pulledToX < 0) {
     70                     mEdgeGlowLeft.onPull((float) mOverScrollDeltaX / mHostView.getWidth());
     71                     if (!mEdgeGlowRight.isFinished()) {
     72                         mEdgeGlowRight.onRelease();
     73                     }
     74                 } else if (pulledToX > maxX) {
     75                     mEdgeGlowRight.onPull((float) mOverScrollDeltaX / mHostView.getWidth());
     76                     if (!mEdgeGlowLeft.isFinished()) {
     77                         mEdgeGlowLeft.onRelease();
     78                     }
     79                 }
     80                 mOverScrollDeltaX = 0;
     81             }
     82 
     83             if (maxY > 0 || mHostView.getWebView().getOverScrollMode() == View.OVER_SCROLL_ALWAYS) {
     84                 final int pulledToY = oldY + mOverScrollDeltaY;
     85                 if (pulledToY < 0) {
     86                     mEdgeGlowTop.onPull((float) mOverScrollDeltaY / mHostView.getHeight());
     87                     if (!mEdgeGlowBottom.isFinished()) {
     88                         mEdgeGlowBottom.onRelease();
     89                     }
     90                 } else if (pulledToY > maxY) {
     91                     mEdgeGlowBottom.onPull((float) mOverScrollDeltaY / mHostView.getHeight());
     92                     if (!mEdgeGlowTop.isFinished()) {
     93                         mEdgeGlowTop.onRelease();
     94                     }
     95                 }
     96                 mOverScrollDeltaY = 0;
     97             }
     98         }
     99     }
    100 
    101     /**
    102      * Set touch delta values indicating the current amount of overscroll.
    103      *
    104      * @param deltaX
    105      * @param deltaY
    106      */
    107     public void setOverScrollDeltas(int deltaX, int deltaY) {
    108         mOverScrollDeltaX = deltaX;
    109         mOverScrollDeltaY = deltaY;
    110     }
    111 
    112     /**
    113      * Absorb leftover fling velocity into one of the edge glows as appropriate.
    114      *
    115      * @param x Current X scroll offset
    116      * @param y Current Y scroll offset
    117      * @param oldX Old X scroll offset
    118      * @param oldY Old Y scroll offset
    119      * @param rangeX Maximum range for horizontal scrolling
    120      * @param rangeY Maximum range for vertical scrolling
    121      */
    122     public void absorbGlow(int x, int y, int oldX, int oldY, int rangeX, int rangeY) {
    123         if (rangeY > 0 || mHostView.getWebView().getOverScrollMode() == View.OVER_SCROLL_ALWAYS) {
    124             if (y < 0 && oldY >= 0) {
    125                 mEdgeGlowTop.onAbsorb((int) mHostView.mScroller.getCurrVelocity());
    126                 if (!mEdgeGlowBottom.isFinished()) {
    127                     mEdgeGlowBottom.onRelease();
    128                 }
    129             } else if (y > rangeY && oldY <= rangeY) {
    130                 mEdgeGlowBottom.onAbsorb((int) mHostView.mScroller.getCurrVelocity());
    131                 if (!mEdgeGlowTop.isFinished()) {
    132                     mEdgeGlowTop.onRelease();
    133                 }
    134             }
    135         }
    136 
    137         if (rangeX > 0) {
    138             if (x < 0 && oldX >= 0) {
    139                 mEdgeGlowLeft.onAbsorb((int) mHostView.mScroller.getCurrVelocity());
    140                 if (!mEdgeGlowRight.isFinished()) {
    141                     mEdgeGlowRight.onRelease();
    142                 }
    143             } else if (x > rangeX && oldX <= rangeX) {
    144                 mEdgeGlowRight.onAbsorb((int) mHostView.mScroller.getCurrVelocity());
    145                 if (!mEdgeGlowLeft.isFinished()) {
    146                     mEdgeGlowLeft.onRelease();
    147                 }
    148             }
    149         }
    150     }
    151 
    152     /**
    153      * Draw the glow effect along the sides of the widget. mEdgeGlow* must be non-null.
    154      *
    155      * @param canvas Canvas to draw into, transformed into view coordinates.
    156      * @return true if glow effects are still animating and the view should invalidate again.
    157      */
    158     public boolean drawEdgeGlows(Canvas canvas) {
    159         final int scrollX = mHostView.getScrollX();
    160         final int scrollY = mHostView.getScrollY();
    161         final int width = mHostView.getWidth();
    162         int height = mHostView.getHeight();
    163 
    164         boolean invalidateForGlow = false;
    165         if (!mEdgeGlowTop.isFinished()) {
    166             final int restoreCount = canvas.save();
    167 
    168             canvas.translate(scrollX, mHostView.getVisibleTitleHeight() + Math.min(0, scrollY));
    169             mEdgeGlowTop.setSize(width, height);
    170             invalidateForGlow |= mEdgeGlowTop.draw(canvas);
    171             canvas.restoreToCount(restoreCount);
    172         }
    173         if (!mEdgeGlowBottom.isFinished()) {
    174             final int restoreCount = canvas.save();
    175 
    176             canvas.translate(-width + scrollX, Math.max(mHostView.computeMaxScrollY(), scrollY)
    177                     + height);
    178             canvas.rotate(180, width, 0);
    179             mEdgeGlowBottom.setSize(width, height);
    180             invalidateForGlow |= mEdgeGlowBottom.draw(canvas);
    181             canvas.restoreToCount(restoreCount);
    182         }
    183         if (!mEdgeGlowLeft.isFinished()) {
    184             final int restoreCount = canvas.save();
    185 
    186             canvas.rotate(270);
    187             canvas.translate(-height - scrollY, Math.min(0, scrollX));
    188             mEdgeGlowLeft.setSize(height, width);
    189             invalidateForGlow |= mEdgeGlowLeft.draw(canvas);
    190             canvas.restoreToCount(restoreCount);
    191         }
    192         if (!mEdgeGlowRight.isFinished()) {
    193             final int restoreCount = canvas.save();
    194 
    195             canvas.rotate(90);
    196             canvas.translate(scrollY,
    197                     -(Math.max(mHostView.computeMaxScrollX(), scrollX) + width));
    198             mEdgeGlowRight.setSize(height, width);
    199             invalidateForGlow |= mEdgeGlowRight.draw(canvas);
    200             canvas.restoreToCount(restoreCount);
    201         }
    202         return invalidateForGlow;
    203     }
    204 
    205     /**
    206      * @return True if any glow is still animating
    207      */
    208     public boolean isAnimating() {
    209         return (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished() ||
    210                 !mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished());
    211     }
    212 
    213     /**
    214      * Release all glows from any touch pulls in progress.
    215      */
    216     public void releaseAll() {
    217         mEdgeGlowTop.onRelease();
    218         mEdgeGlowBottom.onRelease();
    219         mEdgeGlowLeft.onRelease();
    220         mEdgeGlowRight.onRelease();
    221     }
    222 }
    223