| /* |
| * Copyright (C) 2010 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 com.android.internal.R; |
| |
| import android.content.Context; |
| import android.content.res.Resources; |
| import android.graphics.Canvas; |
| import android.graphics.drawable.Drawable; |
| import android.view.View; |
| import android.widget.EdgeEffect; |
| |
| /** |
| * This class manages the edge glow effect when a WebView is flung or pulled beyond the edges. |
| * @hide |
| */ |
| public class OverScrollGlow { |
| private WebViewClassic mHostView; |
| |
| private EdgeEffect mEdgeGlowTop; |
| private EdgeEffect mEdgeGlowBottom; |
| private EdgeEffect mEdgeGlowLeft; |
| private EdgeEffect mEdgeGlowRight; |
| |
| private int mOverScrollDeltaX; |
| private int mOverScrollDeltaY; |
| |
| public OverScrollGlow(WebViewClassic host) { |
| mHostView = host; |
| Context context = host.getContext(); |
| mEdgeGlowTop = new EdgeEffect(context); |
| mEdgeGlowBottom = new EdgeEffect(context); |
| mEdgeGlowLeft = new EdgeEffect(context); |
| mEdgeGlowRight = new EdgeEffect(context); |
| } |
| |
| /** |
| * Pull leftover touch scroll distance into one of the edge glows as appropriate. |
| * |
| * @param x Current X scroll offset |
| * @param y Current Y scroll offset |
| * @param oldX Old X scroll offset |
| * @param oldY Old Y scroll offset |
| * @param maxX Maximum range for horizontal scrolling |
| * @param maxY Maximum range for vertical scrolling |
| */ |
| public void pullGlow(int x, int y, int oldX, int oldY, int maxX, int maxY) { |
| // Only show overscroll bars if there was no movement in any direction |
| // as a result of scrolling. |
| if (oldX == mHostView.getScrollX() && oldY == mHostView.getScrollY()) { |
| // Don't show left/right glows if we fit the whole content. |
| // Also don't show if there was vertical movement. |
| if (maxX > 0) { |
| final int pulledToX = oldX + mOverScrollDeltaX; |
| if (pulledToX < 0) { |
| mEdgeGlowLeft.onPull((float) mOverScrollDeltaX / mHostView.getWidth()); |
| if (!mEdgeGlowRight.isFinished()) { |
| mEdgeGlowRight.onRelease(); |
| } |
| } else if (pulledToX > maxX) { |
| mEdgeGlowRight.onPull((float) mOverScrollDeltaX / mHostView.getWidth()); |
| if (!mEdgeGlowLeft.isFinished()) { |
| mEdgeGlowLeft.onRelease(); |
| } |
| } |
| mOverScrollDeltaX = 0; |
| } |
| |
| if (maxY > 0 || mHostView.getWebView().getOverScrollMode() == View.OVER_SCROLL_ALWAYS) { |
| final int pulledToY = oldY + mOverScrollDeltaY; |
| if (pulledToY < 0) { |
| mEdgeGlowTop.onPull((float) mOverScrollDeltaY / mHostView.getHeight()); |
| if (!mEdgeGlowBottom.isFinished()) { |
| mEdgeGlowBottom.onRelease(); |
| } |
| } else if (pulledToY > maxY) { |
| mEdgeGlowBottom.onPull((float) mOverScrollDeltaY / mHostView.getHeight()); |
| if (!mEdgeGlowTop.isFinished()) { |
| mEdgeGlowTop.onRelease(); |
| } |
| } |
| mOverScrollDeltaY = 0; |
| } |
| } |
| } |
| |
| /** |
| * Set touch delta values indicating the current amount of overscroll. |
| * |
| * @param deltaX |
| * @param deltaY |
| */ |
| public void setOverScrollDeltas(int deltaX, int deltaY) { |
| mOverScrollDeltaX = deltaX; |
| mOverScrollDeltaY = deltaY; |
| } |
| |
| /** |
| * Absorb leftover fling velocity into one of the edge glows as appropriate. |
| * |
| * @param x Current X scroll offset |
| * @param y Current Y scroll offset |
| * @param oldX Old X scroll offset |
| * @param oldY Old Y scroll offset |
| * @param rangeX Maximum range for horizontal scrolling |
| * @param rangeY Maximum range for vertical scrolling |
| */ |
| public void absorbGlow(int x, int y, int oldX, int oldY, int rangeX, int rangeY) { |
| if (rangeY > 0 || mHostView.getWebView().getOverScrollMode() == View.OVER_SCROLL_ALWAYS) { |
| if (y < 0 && oldY >= 0) { |
| mEdgeGlowTop.onAbsorb((int) mHostView.mScroller.getCurrVelocity()); |
| if (!mEdgeGlowBottom.isFinished()) { |
| mEdgeGlowBottom.onRelease(); |
| } |
| } else if (y > rangeY && oldY <= rangeY) { |
| mEdgeGlowBottom.onAbsorb((int) mHostView.mScroller.getCurrVelocity()); |
| if (!mEdgeGlowTop.isFinished()) { |
| mEdgeGlowTop.onRelease(); |
| } |
| } |
| } |
| |
| if (rangeX > 0) { |
| if (x < 0 && oldX >= 0) { |
| mEdgeGlowLeft.onAbsorb((int) mHostView.mScroller.getCurrVelocity()); |
| if (!mEdgeGlowRight.isFinished()) { |
| mEdgeGlowRight.onRelease(); |
| } |
| } else if (x > rangeX && oldX <= rangeX) { |
| mEdgeGlowRight.onAbsorb((int) mHostView.mScroller.getCurrVelocity()); |
| if (!mEdgeGlowLeft.isFinished()) { |
| mEdgeGlowLeft.onRelease(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Draw the glow effect along the sides of the widget. mEdgeGlow* must be non-null. |
| * |
| * @param canvas Canvas to draw into, transformed into view coordinates. |
| * @return true if glow effects are still animating and the view should invalidate again. |
| */ |
| public boolean drawEdgeGlows(Canvas canvas) { |
| final int scrollX = mHostView.getScrollX(); |
| final int scrollY = mHostView.getScrollY(); |
| final int width = mHostView.getWidth(); |
| int height = mHostView.getHeight(); |
| |
| boolean invalidateForGlow = false; |
| if (!mEdgeGlowTop.isFinished()) { |
| final int restoreCount = canvas.save(); |
| |
| canvas.translate(scrollX, mHostView.getVisibleTitleHeight() + Math.min(0, scrollY)); |
| mEdgeGlowTop.setSize(width, height); |
| invalidateForGlow |= mEdgeGlowTop.draw(canvas); |
| canvas.restoreToCount(restoreCount); |
| } |
| if (!mEdgeGlowBottom.isFinished()) { |
| final int restoreCount = canvas.save(); |
| |
| canvas.translate(-width + scrollX, Math.max(mHostView.computeMaxScrollY(), scrollY) |
| + height); |
| canvas.rotate(180, width, 0); |
| mEdgeGlowBottom.setSize(width, height); |
| invalidateForGlow |= mEdgeGlowBottom.draw(canvas); |
| canvas.restoreToCount(restoreCount); |
| } |
| if (!mEdgeGlowLeft.isFinished()) { |
| final int restoreCount = canvas.save(); |
| |
| canvas.rotate(270); |
| canvas.translate(-height - scrollY, Math.min(0, scrollX)); |
| mEdgeGlowLeft.setSize(height, width); |
| invalidateForGlow |= mEdgeGlowLeft.draw(canvas); |
| canvas.restoreToCount(restoreCount); |
| } |
| if (!mEdgeGlowRight.isFinished()) { |
| final int restoreCount = canvas.save(); |
| |
| canvas.rotate(90); |
| canvas.translate(scrollY, |
| -(Math.max(mHostView.computeMaxScrollX(), scrollX) + width)); |
| mEdgeGlowRight.setSize(height, width); |
| invalidateForGlow |= mEdgeGlowRight.draw(canvas); |
| canvas.restoreToCount(restoreCount); |
| } |
| return invalidateForGlow; |
| } |
| |
| /** |
| * @return True if any glow is still animating |
| */ |
| public boolean isAnimating() { |
| return (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished() || |
| !mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished()); |
| } |
| |
| /** |
| * Release all glows from any touch pulls in progress. |
| */ |
| public void releaseAll() { |
| mEdgeGlowTop.onRelease(); |
| mEdgeGlowBottom.onRelease(); |
| mEdgeGlowLeft.onRelease(); |
| mEdgeGlowRight.onRelease(); |
| } |
| } |