blob: d91f86038a9e0308b7d90bf24a27888eb2d1e07e [file] [log] [blame]
/*
* 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();
}
}