package org.ebookdroid.ui.viewer.viewers; import org.ebookdroid.common.settings.AppSettings; import org.ebookdroid.core.DecodeService; import org.ebookdroid.core.EventPool; import org.ebookdroid.core.Page; import org.ebookdroid.core.ViewState; import org.ebookdroid.ui.viewer.IActivityController; import org.ebookdroid.ui.viewer.IView; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.View; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import org.emdev.ui.gl.GLCanvas; import org.emdev.ui.gl.GLRootView; import org.emdev.ui.widget.Flinger; import org.emdev.utils.concurrent.Flag; public final class GLView extends GLRootView implements IView, SurfaceHolder.Callback { protected final IActivityController base; protected final Flinger scroller; protected DrawQueue drawQueue; protected ScrollEventThread scrollThread; protected boolean layoutLocked; protected final AtomicReference<Rect> layout = new AtomicReference<Rect>(); protected final Flag layoutFlag = new Flag(); protected final FullScreenCallback fullScreenCallback; public GLView(final IActivityController baseActivity) { super(baseActivity.getContext()); this.base = baseActivity; this.scroller = new Flinger(); setKeepScreenOn(AppSettings.current().keepScreenOn); setFocusable(true); setFocusableInTouchMode(true); fullScreenCallback = FullScreenCallback.get(baseActivity.getActivity(), this); drawQueue = new DrawQueue(); scrollThread = new ScrollEventThread(base, this); scrollThread.start(); } protected void draw(GLCanvas canvas) { ViewState viewState = drawQueue.takeLastTask(); if (viewState == null) { viewState = ViewState.get(base.getDocumentController()); viewState.addedToDrawQueue(); } EventPool.newGLEventDraw(viewState, canvas).process().releaseAfterDraw(); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#getView() */ @Override public final View getView() { return this; } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#getBase() */ @Override public final IActivityController getBase() { return base; } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#invalidateScroll() */ @Override public final void invalidateScroll() { stopScroller(); final float scrollScaleRatio = getScrollScaleRatio(); scrollTo((int) (getScrollX() * scrollScaleRatio), (int) (getScrollY() * scrollScaleRatio)); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#invalidateScroll(float, float) */ @Override public final void invalidateScroll(final float newZoom, final float oldZoom, @Nullable PointF center) { stopScroller(); final float ratio = newZoom / oldZoom; float centerX, centerY; if (center == null) { centerX = getWidth() / 2.0f; centerY = getHeight() / 2.0f; } else { centerX = center.x; centerY = center.y; } final int x = (int) ((getScrollX() + centerX) * ratio - centerX); final int y = (int) ((getScrollY() + centerY) * ratio - centerY); // if (LCTX.isDebugEnabled()) { // LCTX.d("invalidateScroll(" + newZoom + ", " + oldZoom + "): " + x + ", " + y); // } scrollTo(x, y); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#startPageScroll(int, int) */ @Override public void startPageScroll(final int dx, final int dy) { scroller.startScroll(getScrollX(), getScrollY(), dx, dy); redrawView(); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#startFling(float, float, android.graphics.Rect) */ @Override public void startFling(final float vX, final float vY, final Rect limits) { scroller.fling(getScrollX(), getScrollY(), -(int) vX, -(int) vY, limits.left, limits.right, limits.top, limits.bottom); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#continueScroll() */ @Override public void continueScroll() { if (scroller.computeScrollOffset()) { scrollTo(scroller.getCurrX(), scroller.getCurrY()); } } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#forceFinishScroll() */ @Override public boolean forceFinishScroll() { boolean wasFinished = scroller.isFinished(); scroller.forceFinished(); // to stop flinging on touch return !wasFinished; } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#isScrollFinished() */ @Override public boolean isScrollFinished() { return scroller.isFinished(); } /** * {@inheritDoc} * * @see android.view.View#onScrollChanged(int, int, int, int) */ @Override public void onScrollChanged(final int curX, final int curY, final int oldX, final int oldY) { super.onScrollChanged(curX, curY, oldX, oldY); scrollThread.onScrollChanged(curX, curY, oldX, oldY); } /** * {@inheritDoc} * * @see android.view.View#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(final MotionEvent ev) { mRenderLock.lock(); try { checkFullScreenMode(); if (base.getDocumentController().onTouchEvent(ev)) { return true; } return super.onTouchEvent(ev); } finally { mRenderLock.unlock(); } } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#checkFullScreenMode() */ @Override public void checkFullScreenMode() { if (fullScreenCallback != null) { fullScreenCallback.checkFullScreenMode(); } } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#scrollTo(int, int) */ @Override public final void scrollTo(final int x, final int y) { scrollThread.scrollTo(x, y); } @Override public void _scrollTo(int x, int y) { super.scrollTo(x, y); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#getViewRect() */ @Override public final RectF getViewRect() { return new RectF(getScrollX(), getScrollY(), getScrollX() + getWidth(), getScrollY() + getHeight()); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#changeLayoutLock(boolean) */ @Override public void changeLayoutLock(final boolean lock) { post(new Runnable() { @Override public void run() { layoutLocked = lock; } }); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#isLayoutLocked() */ @Override public boolean isLayoutLocked() { return layoutLocked; } /** * {@inheritDoc} * * @see android.view.View#onLayout(boolean, int, int, int, int) */ @Override protected final void onLayout(final boolean layoutChanged, final int left, final int top, final int right, final int bottom) { super.onLayout(layoutChanged, left, top, right, bottom); final Rect oldLayout = layout.getAndSet(new Rect(left, top, right, bottom)); base.getDocumentController().onLayoutChanged(layoutChanged, layoutLocked, oldLayout, layout.get()); if (oldLayout == null) { layoutFlag.set(); } } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#waitForInitialization() */ @Override @WorkerThread public final void waitForInitialization() { while (!layoutFlag.get()) { layoutFlag.waitFor(TimeUnit.SECONDS, 1); } } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#onDestroy() */ @Override public void onDestroy() { layoutFlag.set(); scrollThread.finish(); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#getScrollScaleRatio() */ @Override public float getScrollScaleRatio() { final Page page = base.getDocumentModel().getCurrentPageObject(); if (page == null) { return 0; } final float zoom = base.getZoomModel().getZoom(); return getWidth() * zoom / page.getBounds(zoom).width(); } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#stopScroller() */ @Override public void stopScroller() { if (!scroller.isFinished()) { scroller.abortAnimation(); } } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#redrawView() */ @Override public final void redrawView() { redrawView(ViewState.get(base.getDocumentController())); } @Override public final void redrawView(final ViewState viewState) { if (viewState != null) { if (drawQueue != null) { drawQueue.draw(viewState); } final DecodeService ds = base.getDecodeService(); if (ds != null) { ds.updateViewState(viewState); } requestRender(); } } /** * {@inheritDoc} * * @see org.ebookdroid.ui.viewer.IView#getBase(android.graphics.RectF) */ @Override public PointF getBase(final RectF viewRect) { return new PointF(viewRect.left, viewRect.top); } }